After the previous changes in this series, the LTO front end always has an
appropriate linemap structure for interpreting diagnostic pragmas, so it is
straightforward to implement them, as is done here.

The pragmas are streamed out in each linemap section; since all locations
from a given linemap section will be contiguous in the reconstructed
linemap, they are automatically ordered properly for the existing diagnostic
pragma infrastructure to work as-is.

One wrinkle is that a single function may have been streamed out in multiple
sections. (For example, an inline function will be streamed out in all
partitions that need it.) In this case, when merging them, LTO keeps only
one of the sections, as directed by the linker resolution, so the diagnostic
pragmas that will be in force (in case they were not the same for the
different translation units) will be whichever were applicable to the
section LTO decided to keep.

gcc/ChangeLog:

        PR middle-end/80922
        PR middle-end/106823
        PR lto/107936
        * lto-streamer-in.cc (lto_create_loc_map): Process diagnostic
        pragmas from the linemap sections.
        * lto-streamer-out.cc (location_output::produce_linemap_section):
        Stream diagnostic pragmas into the linemap section.

gcc/testsuite/ChangeLog:

        PR middle-end/80922
        PR middle-end/106823
        PR lto/107936
        * gcc.dg/lto/pr106823_0.c: New test.
        * gcc.dg/lto/pr107936_0.c: New test.
        * gcc.dg/lto/pr107936_1.c: New test.
        * gcc.dg/lto/pr80922-1_0.c: New test.
        * gcc.dg/lto/pr80922-1_1.c: New test.
        * gcc.dg/lto/pr80922-2_0.c: New test.
        * gcc.dg/lto/pr80922-2_1.c: New test.
        * gcc.dg/lto/pr80922-2_2.c: New test.
---
 gcc/lto-streamer-in.cc                 | 31 ++++++++++++++++++++++++++
 gcc/lto-streamer-out.cc                | 20 +++++++++++++++++
 gcc/testsuite/gcc.dg/lto/pr106823_0.c  | 17 ++++++++++++++
 gcc/testsuite/gcc.dg/lto/pr107936_0.c  | 16 +++++++++++++
 gcc/testsuite/gcc.dg/lto/pr107936_1.c  |  5 +++++
 gcc/testsuite/gcc.dg/lto/pr80922-1_0.c | 29 ++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/lto/pr80922-1_1.c |  9 ++++++++
 gcc/testsuite/gcc.dg/lto/pr80922-2_0.c | 18 +++++++++++++++
 gcc/testsuite/gcc.dg/lto/pr80922-2_1.c | 11 +++++++++
 gcc/testsuite/gcc.dg/lto/pr80922-2_2.c |  1 +
 10 files changed, 157 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/lto/pr106823_0.c
 create mode 100644 gcc/testsuite/gcc.dg/lto/pr107936_0.c
 create mode 100644 gcc/testsuite/gcc.dg/lto/pr107936_1.c
 create mode 100644 gcc/testsuite/gcc.dg/lto/pr80922-1_0.c
 create mode 100644 gcc/testsuite/gcc.dg/lto/pr80922-1_1.c
 create mode 100644 gcc/testsuite/gcc.dg/lto/pr80922-2_0.c
 create mode 100644 gcc/testsuite/gcc.dg/lto/pr80922-2_1.c
 create mode 100644 gcc/testsuite/gcc.dg/lto/pr80922-2_2.c

diff --git a/gcc/lto-streamer-in.cc b/gcc/lto-streamer-in.cc
index 88e35f18076..d854dea2122 100644
--- a/gcc/lto-streamer-in.cc
+++ b/gcc/lto-streamer-in.cc
@@ -530,6 +530,37 @@ create_loc_map (lto_file_decl_data *file_data, unsigned 
linemap_id)
        lto_register_linemap_for_output (map_idx, file_data->order + 1);
     }
 
+  /* Process the diagnostics classification history.  */
+  auto &chist = global_dc->get_classification_history ();
+  const int pop_offset = chist.length ();
+  using DK = diagnostics::kind;
+  for (size_t i = 0, nc = bp_unpack_var_len_unsigned (&bp); i != nc; ++i)
+    {
+      const size_t map_idx = bp_unpack_var_len_unsigned (&bp);
+      const location_t offset = bp_unpack_var_len_unsigned (&bp);
+      const location_t loc = get_location_from_idx (map_idx, offset, loc_map);
+      const int option = bp_unpack_var_len_int (&bp);
+      const auto kind = bp_unpack_enum (&bp, diagnostics::kind,
+                                       DK::tot_num_diagnostic_kinds);
+      if (kind == DK::pop)
+       {
+         diagnostics::option_classifier::classification_change_t c = {};
+         c.location = loc;
+         c.option = option + pop_offset;
+         c.kind = kind;
+         chist.safe_push (c);
+       }
+      else
+       global_dc->classify_diagnostic (option, kind, loc);
+    }
+  /* Make sure we reset back to the baseline.  */
+  {
+    diagnostics::option_classifier::classification_change_t c = {};
+    c.location = line_table->highest_location;
+    c.kind = DK::pop;
+    chist.safe_push (c);
+  }
+
   lto_data_in_delete (data_in);
   lto_free_section_data (file_data, LTO_section_linemap, nullptr,
                         data, len, true);
diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc
index 2a2a40dbcfb..e7b5348759b 100644
--- a/gcc/lto-streamer-out.cc
+++ b/gcc/lto-streamer-out.cc
@@ -271,6 +271,14 @@ location_output::produce_linemap_section ()
   const auto ob = create_output_block (LTO_section_linemap);
   auto bp = bitpack_create (ob->main_stream);
 
+  /* Prepare the diagnostic classification history.  To make life easier on the
+     reader, which will need to build the line map before processing the
+     classification history, we will stream it out after the line map data.  
But
+     we need to call record_location() now.  */
+  const auto &chist = global_dc->get_classification_history ();
+  for (auto &c : chist)
+    record_location (c.location);
+
   /* Sort the maps in the order they need to be inserted later.  */
   const size_t nmaps = map_data_map.elements ();
   using KV = std::pair<const line_map_ordinary *, map_data>;
@@ -325,6 +333,18 @@ location_output::produce_linemap_section ()
        }
     }
 
+  /* Output the diagnostics classification history.  */
+  bp_pack_var_len_unsigned (&bp, chist.length ());
+  for (auto &c : chist)
+    {
+      const location_id_t loc_id = record_location (c.location);
+      bp_pack_var_len_unsigned (&bp, loc_id.map_id.idx);
+      bp_pack_var_len_unsigned (&bp, loc_id.offset);
+      bp_pack_var_len_int (&bp, c.option);
+      using DK = diagnostics::kind;
+      bp_pack_enum (&bp, DK, DK::tot_num_diagnostic_kinds, c.kind);
+    }
+
   /* Finalize the section.  */
   streamer_write_bitpack (&bp);
   {
diff --git a/gcc/testsuite/gcc.dg/lto/pr106823_0.c 
b/gcc/testsuite/gcc.dg/lto/pr106823_0.c
new file mode 100644
index 00000000000..62b04ae353c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/pr106823_0.c
@@ -0,0 +1,17 @@
+/* PR middle-end/106823 */
+/* { dg-lto-do link } */
+__attribute__((__warning__("w"))) void f (int) {}
+void g (int i)
+{
+  /* It would be nice to also confirm that the warning is issued in the
+     absence of the pragma, but the LTO testsuite is not currently set up to
+     test for warnings emitted during the compile stage.  But pr80922
+     testcases do test this functionality.  */
+  #pragma GCC diagnostic ignored "-Wattribute-warning"
+  f (i);
+}
+
+int main ()
+{
+  g (1);
+}
diff --git a/gcc/testsuite/gcc.dg/lto/pr107936_0.c 
b/gcc/testsuite/gcc.dg/lto/pr107936_0.c
new file mode 100644
index 00000000000..1820eb454e2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/pr107936_0.c
@@ -0,0 +1,16 @@
+/* PR lto/107936 */
+/* { dg-lto-do link } */
+/* { dg-lto-additional-options "-Wstringop-overflow" } */
+void foo (char x[2]);
+
+int
+main ()
+{
+  char x[2];
+  /* It would be nice to also confirm that the warning is issued in the
+     absence of the pragma, but the LTO testsuite is not currently set up to
+     test for warnings emitted during the compile stage.  But pr80922
+     testcases do test this functionality.  */
+  #pragma GCC diagnostic ignored "-Wstringop-overflow"
+  foo (x + 1);
+}
diff --git a/gcc/testsuite/gcc.dg/lto/pr107936_1.c 
b/gcc/testsuite/gcc.dg/lto/pr107936_1.c
new file mode 100644
index 00000000000..94923aa97b8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/pr107936_1.c
@@ -0,0 +1,5 @@
+void
+foo (char x[2])
+{
+  asm volatile ("" : : "r" (&x[0]) : "memory");
+}
diff --git a/gcc/testsuite/gcc.dg/lto/pr80922-1_0.c 
b/gcc/testsuite/gcc.dg/lto/pr80922-1_0.c
new file mode 100644
index 00000000000..cf57fd9d4a1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/pr80922-1_0.c
@@ -0,0 +1,29 @@
+/* PR middle-end/80922 */
+
+/* { dg-lto-do link } */
+/* { dg-lto-additional-options "-O2 -Wfree-nonheap-object" } */
+
+void myfree (void *ptr1, void *ptr2, void *ptr3, void *ptr4)
+{
+  __builtin_free (ptr1); /* { dg-lto-warning "-Wfree-nonheap-object" } */
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+  __builtin_free (ptr2);
+  #pragma GCC diagnostic pop
+  __builtin_free (ptr3); /* { dg-lto-warning "-Wfree-nonheap-object" } */
+  _Pragma("GCC diagnostic push");
+  _Pragma("GCC diagnostic ignored \"-Wfree-nonheap-object\"");
+  #pragma GCC diagnostic push
+  __builtin_free (ptr4);
+}
+
+/* Since these two functions are in the same translation unit, the
+   diagnostic pragmas applied above are still in force.  */
+void myfree2 (void *ptr1, void *ptr2, void *ptr3)
+{
+  __builtin_free (ptr1);
+  #pragma GCC diagnostic pop
+  __builtin_free (ptr2);
+  _Pragma("GCC diagnostic pop");
+  __builtin_free (ptr3); /* { dg-lto-warning "-Wfree-nonheap-object" } */
+}
diff --git a/gcc/testsuite/gcc.dg/lto/pr80922-1_1.c 
b/gcc/testsuite/gcc.dg/lto/pr80922-1_1.c
new file mode 100644
index 00000000000..151ca506f50
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/pr80922-1_1.c
@@ -0,0 +1,9 @@
+void myfree (void *, void *, void *, void *);
+void myfree2 (void *, void *, void *);
+
+static char a, b, c, d;
+int main ()
+{
+  myfree (&a, &b, &c, &d);
+  myfree2 (&a, &b, &c);
+}
diff --git a/gcc/testsuite/gcc.dg/lto/pr80922-2_0.c 
b/gcc/testsuite/gcc.dg/lto/pr80922-2_0.c
new file mode 100644
index 00000000000..660ddc1c014
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/pr80922-2_0.c
@@ -0,0 +1,18 @@
+/* PR middle-end/80922 */
+/* This is similar to pr80922-1, but myfree() and myfree2() are split into
+   separate objects, so that they use two different line maps.  */
+
+/* { dg-lto-do link } */
+/* { dg-lto-additional-options "-O2 -Wfree-nonheap-object" } */
+
+void myfree (void *ptr1, void *ptr2, void *ptr3, void *ptr4)
+{
+  __builtin_free (ptr1); /* { dg-lto-warning "-Wfree-nonheap-object" } */
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+  __builtin_free (ptr2);
+  #pragma GCC diagnostic pop
+  __builtin_free (ptr3); /* { dg-lto-warning "-Wfree-nonheap-object" } */
+  _Pragma("GCC diagnostic ignored \"-Wfree-nonheap-object\"");
+  __builtin_free (ptr4);
+}
diff --git a/gcc/testsuite/gcc.dg/lto/pr80922-2_1.c 
b/gcc/testsuite/gcc.dg/lto/pr80922-2_1.c
new file mode 100644
index 00000000000..f8d8522f6e7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/pr80922-2_1.c
@@ -0,0 +1,11 @@
+/* The diagnostic pragmas left active in pr80922-2_0.c should not be in
+   force anymore.  */
+void myfree2 (void *ptr1, void *ptr2, void *ptr3)
+{
+  __builtin_free (ptr1); /* { dg-lto-warning "-Wfree-nonheap-object" } */
+  _Pragma("GCC diagnostic push")
+  #pragma GCC diagnostic ignored "-Wfree-nonheap-object"
+  __builtin_free (ptr2);
+  _Pragma("GCC diagnostic pop");
+  __builtin_free (ptr3); /* { dg-lto-warning "-Wfree-nonheap-object" } */
+}
diff --git a/gcc/testsuite/gcc.dg/lto/pr80922-2_2.c 
b/gcc/testsuite/gcc.dg/lto/pr80922-2_2.c
new file mode 100644
index 00000000000..079fc6e943b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/lto/pr80922-2_2.c
@@ -0,0 +1 @@
+#include "pr80922-1_1.c"

Reply via email to