On Sat, 2025-05-31 at 23:25 -0400, Jason Merrill wrote:
> From f57505c7c6fa05a14e285c14a81021655a43ccbc Mon Sep 17 00:00:00
> 2001
> From: Jason Merrill <ja...@redhat.com>
> Date: Wed, 20 Nov 2024 16:20:52 +0100
> Subject: [PATCH] c++: modules and #pragma diagnostic
> To: gcc-patches@gcc.gnu.org
> 
> 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 give serializers direct access to the
> underlying
> data, as here with get_classification_history.  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 (diagnostic_option_classifier): Friend
>       diagnostic_context.
>       (diagnostic_context::get_classification_history): New.
> 
> 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                             | 10 +++
>  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, 123 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
> 
> diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
> index cdd6f26ba2a..b6cab0d52ed 100644
> --- a/gcc/diagnostic.h
> +++ b/gcc/diagnostic.h
> @@ -307,6 +307,9 @@ private:
>       diagnostic.  */
>    vec<diagnostic_classification_change_t> m_classification_history;
>  
> +  /* For diagnostic_context::get_classification_history, declared
> later.  */
> +  friend class diagnostic_context;
> +
>    /* For pragma push/pop.  */
>    vec<int> m_push_list;
>  };
> @@ -830,6 +833,13 @@ public:
>      m_abort_on_error = val;
>    }
>  
> +  /* Accessor for use in serialization, e.g. by C++ modules.  */
> +  auto &
> +  get_classification_history ()
> +  {
> +    return m_option_classifier.m_classification_history;
> +  }
> +
>  private:
>    void error_recursion () ATTRIBUTE_NORETURN;
>  
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index 2fa92b514d6..3f88baa7544 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -3879,6 +3879,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;
> @@ -18181,6 +18184,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->get_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->get_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 ();

Thanks for updating the "friend" stuff.

> +      if (kind == DK_POP)
> +     opt += offset;

I'm wondering why the offset is applied to "opt" here?  That feels
wrong to me, or, at least, I couldn't see what it's trying to do, which
got me thinking about the DK_POP case.

Does diagnostic_option_classifier's m_push_list get updated when
reading classification changes from the module?

What happens if you have a module that pushes a diagnostic
classification change, and later pops it?   (analogous to a header that
temporarily suppresses a warning, if I understand correctly)  If that's
reasonable to do, it would be good to have a test case for it, since I
don't think the existing test cases are covering the DK_POP case.

Probably less reasonable: what if a module pushes a diagnostics
classification change, but *doesn't* later pop it.  Can the change be
popped by consumers of the module?

[...snip...]

Hope this is constructive; sorry if I'm missing something here
Dave

Reply via email to