[RFA,(diagnostic)] c++: modules and #pragma diagnostic

Message ID 20250110030140.4145597-1-jason@redhat.com
State New
Headers
Series [RFA,(diagnostic)] c++: modules and #pragma diagnostic |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed

Commit Message

Jason Merrill Jan. 10, 2025, 3 a.m. UTC
  Tested x86_64-pc-linux-gnu.  Is the diagnostic.h change OK for trunk?

-- 8< --

To respect the #pragma diagnostic lines in libstdc++ headers when compiling
with module std, we need to represent them in the module.

I think it's reasonable to make module_state a friend of
diagnostic_option_classifier to allow direct access to the data.  This is a
different approach from how Jakub made PCH streaming members of
diagnostic_option_classifier, but it seems to me that modules handling
belongs in module.cc.

gcc/ChangeLog:

	* diagnostic.h: Add friends.

gcc/cp/ChangeLog:

	* module.cc (module_state::write_diagnostic_classification): New.
	(module_state::write_begin): Call it.
	(module_state::read_diagnostic_classification): New.
	(module_state::read_initial): Call it.

gcc/testsuite/ChangeLog:

	* g++.dg/modules/warn-spec-3_a.C: New test.
	* g++.dg/modules/warn-spec-3_b.C: New test.
---
 gcc/diagnostic.h                             |  4 +
 gcc/cp/module.cc                             | 86 +++++++++++++++++++-
 gcc/testsuite/g++.dg/modules/warn-spec-3_a.C | 20 +++++
 gcc/testsuite/g++.dg/modules/warn-spec-3_b.C |  8 ++
 4 files changed, 117 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/modules/warn-spec-3_a.C
 create mode 100644 gcc/testsuite/g++.dg/modules/warn-spec-3_b.C


base-commit: fab96de044f1f023f52d43af866205d17d8895fb
  

Patch

diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 202760b2f85..91bde3ff06c 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -299,6 +299,8 @@  private:
 
   /* For pragma push/pop.  */
   vec<int> m_push_list;
+
+  friend class module_state;
 };
 
 /* A bundle of options relating to printing the user's source code
@@ -807,6 +809,8 @@  private:
   /* The stack of sets of overridden diagnostic option severities.  */
   diagnostic_option_classifier m_option_classifier;
 
+  friend class module_state;
+
   /* True if we should print any CWE identifiers associated with
      diagnostics.  */
   bool m_show_cwe;
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index 78fb21dc22f..49c9c092163 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -3876,6 +3876,9 @@  class GTY((chain_next ("%h.parent"), for_user)) module_state {
   void write_macro_maps (elf_out *to, range_t &, unsigned *crc_ptr);
   bool read_macro_maps (line_map_uint_t);
 
+  void write_diagnostic_classification (elf_out *, diagnostic_context *, unsigned *);
+  bool read_diagnostic_classification (diagnostic_context *);
+
  private:
   void write_define (bytes_out &, const cpp_macro *);
   cpp_macro *read_define (bytes_in &, cpp_reader *) const;
@@ -17637,6 +17640,78 @@  module_state::write_ordinary_maps (elf_out *to, range_t &info,
   dump.outdent ();
 }
 
+/* Write out any #pragma GCC diagnostic info to the .dgc section.  */
+
+void
+module_state::write_diagnostic_classification (elf_out *to,
+					       diagnostic_context *dc,
+					       unsigned *crc_p)
+{
+  auto &changes = dc->m_option_classifier.m_classification_history;
+
+  dump () && dump ("Writing diagnostic change locations");
+  dump.indent ();
+
+  bytes_out sec (to);
+  if (sec.streaming_p ())
+    sec.begin ();
+
+  unsigned len = changes.length ();
+  dump () && dump ("Diagnostic changes: %u", len);
+  if (sec.streaming_p ())
+    sec.u (len);
+
+  for (const auto &c: changes)
+    {
+      write_location (sec, c.location);
+      if (sec.streaming_p ())
+	{
+	  sec.u (c.option);
+	  sec.u (c.kind);
+	}
+    }
+
+  if (sec.streaming_p ())
+    sec.end (to, to->name (MOD_SNAME_PFX ".dgc"), crc_p);
+  dump.outdent ();
+}
+
+/* Read any #pragma GCC diagnostic info from the .dgc section.  */
+
+bool
+module_state::read_diagnostic_classification (diagnostic_context *dc)
+{
+  bytes_in sec;
+
+  if (!sec.begin (loc, from (), MOD_SNAME_PFX ".dgc"))
+    return false;
+
+  dump () && dump ("Reading diagnostic change locations");
+  dump.indent ();
+
+  unsigned len = sec.u ();
+  dump () && dump ("Diagnostic changes: %u", len);
+
+  auto &changes = dc->m_option_classifier.m_classification_history;
+  unsigned offset = changes.length ();
+  changes.reserve (len);
+  for (unsigned i = 0; i < len; ++i)
+    {
+      location_t loc = read_location (sec);
+      int opt = sec.u ();
+      diagnostic_t kind = (diagnostic_t) sec.u ();
+      if (kind == DK_POP)
+	opt += offset;
+      changes.quick_push ({ loc, opt, kind });
+    }
+
+  dump.outdent ();
+  if (!sec.end (from ()))
+    return false;
+
+  return true;
+}
+
 void
 module_state::write_macro_maps (elf_out *to, range_t &info, unsigned *crc_p)
 {
@@ -19231,6 +19306,8 @@  module_state::write_begin (elf_out *to, cpp_reader *reader,
   if (is_header ())
     macros = prepare_macros (reader);
 
+  write_diagnostic_classification (nullptr, global_dc, nullptr);
+
   config.num_imports = mod_hwm;
   config.num_partitions = modules->length () - mod_hwm;
   auto map_info = write_prepare_maps (&config, bool (config.num_partitions));
@@ -19372,7 +19449,10 @@  module_state::write_begin (elf_out *to, cpp_reader *reader,
 
   /* Write the line maps.  */
   if (config.ordinary_locs)
-    write_ordinary_maps (to, map_info, bool (config.num_partitions), &crc);
+    {
+      write_ordinary_maps (to, map_info, bool (config.num_partitions), &crc);
+      write_diagnostic_classification (to, global_dc, &crc);
+    }
   if (config.macro_locs)
     write_macro_maps (to, map_info, &crc);
 
@@ -19505,6 +19585,10 @@  module_state::read_initial (cpp_reader *reader)
   else if (!read_macro_maps (config.macro_locs))
     ok = false;
 
+  if (ok && have_locs && config.ordinary_locs
+      && !read_diagnostic_classification (global_dc))
+    ok = false;
+
   /* Note whether there's an active initializer.  */
   active_init_p = !is_header () && bool (config.active_init);
 
diff --git a/gcc/testsuite/g++.dg/modules/warn-spec-3_a.C b/gcc/testsuite/g++.dg/modules/warn-spec-3_a.C
new file mode 100644
index 00000000000..2e50303c41e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/warn-spec-3_a.C
@@ -0,0 +1,20 @@ 
+// { dg-do compile { target c++20 } }
+// { dg-additional-options -fmodules }
+// { dg-module-cmi M }
+
+module;
+
+#include <initializer_list>
+
+export module M;
+
+#pragma GCC diagnostic ignored "-Winit-list-lifetime"
+
+template <class T>
+struct myspan {
+  const T* p; unsigned s;
+  myspan (std::initializer_list<T> il)
+    : p (il.begin()), s (il.size()) { }
+};
+
+export void f(myspan<int>);
diff --git a/gcc/testsuite/g++.dg/modules/warn-spec-3_b.C b/gcc/testsuite/g++.dg/modules/warn-spec-3_b.C
new file mode 100644
index 00000000000..2a8e60af206
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/warn-spec-3_b.C
@@ -0,0 +1,8 @@ 
+// { dg-additional-options -fmodules }
+
+import M;
+
+int main()
+{
+  f({24,42});
+}