[v2] c++/modules: Keep entity mapping info across duplicate_decls [PR99241]

Message ID 668cffde.170a0220.a8f8b.42fe@mx.google.com
State New
Headers
Series [v2] c++/modules: Keep entity mapping info across duplicate_decls [PR99241] |

Checks

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

Commit Message

Nathaniel Shead July 9, 2024, 9:16 a.m. UTC
  On Mon, Jul 08, 2024 at 11:21:55AM -0400, Patrick Palka wrote:
> On Mon, 8 Jul 2024, Nathaniel Shead wrote:
> 
> > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk/14?
> > 
> > -- >8 --
> > 
> > When duplicate_decls finds a match with an existing imported
> > declaration, it clears DECL_LANG_SPECIFIC of the olddecl and replaces it
> > with the contents of newdecl; this clears DECL_MODULE_ENTITY_P causing
> > an ICE if the same declaration is imported again later.
> > 
> > This fixes the issue by ensuring that the flag is transferred to newdecl
> > before clearing so that it ends up on olddecl again.
> > 
> > For future-proofing we also do the same with DECL_MODULE_KEYED_DECLS_P,
> > though because we don't yet support textual redefinition merging we
> > can't yet test this works as intended.  I don't expect it's possible for
> > a new declaration already to have extra keyed decls mismatching that of
> > the old declaration though, so I don't do anything with 'keyed_map' at
> > this time.
> 
> Makes sense, thanks for tracking this down!
> 
> > 
> > 	PR c++/99241
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	* decl.cc (duplicate_decls): Merge module entity information.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	* g++.dg/modules/pr99241_a.H: New test.
> > 	* g++.dg/modules/pr99241_b.H: New test.
> > 	* g++.dg/modules/pr99241_c.C: New test.
> > 
> > Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
> > ---
> >  gcc/cp/decl.cc                           | 17 +++++++++++++++++
> >  gcc/testsuite/g++.dg/modules/pr99241_a.H |  3 +++
> >  gcc/testsuite/g++.dg/modules/pr99241_b.H |  3 +++
> >  gcc/testsuite/g++.dg/modules/pr99241_c.C |  5 +++++
> >  4 files changed, 28 insertions(+)
> >  create mode 100644 gcc/testsuite/g++.dg/modules/pr99241_a.H
> >  create mode 100644 gcc/testsuite/g++.dg/modules/pr99241_b.H
> >  create mode 100644 gcc/testsuite/g++.dg/modules/pr99241_c.C
> > 
> > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> > index 29616100cfe..b3a770df926 100644
> > --- a/gcc/cp/decl.cc
> > +++ b/gcc/cp/decl.cc
> > @@ -3149,6 +3149,23 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
> >    if (TREE_CODE (newdecl) == FIELD_DECL)
> >      DECL_PACKED (olddecl) = DECL_PACKED (newdecl);
> >  
> > +  /* Merge module entity mapping information.  */
> > +  if (modules_p ())
> > +    {
> > +      tree old_nontmpl = STRIP_TEMPLATE (olddecl);
> 
> It seems duplicate_decls has an unconditional early exit code path for
> TEMPLATE_DECL
> 
>   if (TREE_CODE (newdecl) == TEMPLATE_DECL)
>     {
>       tree old_result = DECL_TEMPLATE_RESULT (olddecl);
>       ...
> 
>       return olddecl;
>     }
> 
> so I think these STRIP_TEMPLATEs are unneeded?  (And I guess this early
> exit explains why the testcase doesn't ICE when 'terminate' is a
> function template.)
> 

Ah right, thanks for spotting that.  That does make it look a bit
cleaner; here's an updated patch.

Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk/14?

-- >8 --

When duplicate_decls finds a match with an existing imported
declaration, it clears DECL_LANG_SPECIFIC of the olddecl and replaces it
with the contents of newdecl; this clears DECL_MODULE_ENTITY_P causing
an ICE if the same declaration is imported again later.

This fixes the issue by ensuring that the flag is transferred to newdecl
before clearing so that it ends up on olddecl again.

For future-proofing we also do the same with DECL_MODULE_KEYED_DECLS_P,
though because we don't yet support textual redefinition merging we
can't yet test this works as intended.  I don't expect it's possible for
a new declaration already to have extra keyed decls mismatching that of
the old declaration though, so I don't do anything with 'keyed_map' at
this time.

	PR c++/99241

gcc/cp/ChangeLog:

	* decl.cc (duplicate_decls): Merge module entity information.

gcc/testsuite/ChangeLog:

	* g++.dg/modules/pr99241_a.H: New test.
	* g++.dg/modules/pr99241_b.H: New test.
	* g++.dg/modules/pr99241_c.C: New test.

Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
---
 gcc/cp/decl.cc                           | 10 ++++++++++
 gcc/testsuite/g++.dg/modules/pr99241_a.H |  3 +++
 gcc/testsuite/g++.dg/modules/pr99241_b.H |  3 +++
 gcc/testsuite/g++.dg/modules/pr99241_c.C |  5 +++++
 4 files changed, 21 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/modules/pr99241_a.H
 create mode 100644 gcc/testsuite/g++.dg/modules/pr99241_b.H
 create mode 100644 gcc/testsuite/g++.dg/modules/pr99241_c.C
  

Comments

Jason Merrill July 9, 2024, 9:51 p.m. UTC | #1
On 7/9/24 5:16 AM, Nathaniel Shead wrote:
> 
> Ah right, thanks for spotting that.  That does make it look a bit
> cleaner; here's an updated patch.
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk/14?

OK.

> -- >8 --
> 
> When duplicate_decls finds a match with an existing imported
> declaration, it clears DECL_LANG_SPECIFIC of the olddecl and replaces it
> with the contents of newdecl; this clears DECL_MODULE_ENTITY_P causing
> an ICE if the same declaration is imported again later.
> 
> This fixes the issue by ensuring that the flag is transferred to newdecl
> before clearing so that it ends up on olddecl again.
> 
> For future-proofing we also do the same with DECL_MODULE_KEYED_DECLS_P,
> though because we don't yet support textual redefinition merging we
> can't yet test this works as intended.  I don't expect it's possible for
> a new declaration already to have extra keyed decls mismatching that of
> the old declaration though, so I don't do anything with 'keyed_map' at
> this time.
> 
> 	PR c++/99241
> 
> gcc/cp/ChangeLog:
> 
> 	* decl.cc (duplicate_decls): Merge module entity information.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/modules/pr99241_a.H: New test.
> 	* g++.dg/modules/pr99241_b.H: New test.
> 	* g++.dg/modules/pr99241_c.C: New test.
> 
> Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com>
> ---
>   gcc/cp/decl.cc                           | 10 ++++++++++
>   gcc/testsuite/g++.dg/modules/pr99241_a.H |  3 +++
>   gcc/testsuite/g++.dg/modules/pr99241_b.H |  3 +++
>   gcc/testsuite/g++.dg/modules/pr99241_c.C |  5 +++++
>   4 files changed, 21 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/modules/pr99241_a.H
>   create mode 100644 gcc/testsuite/g++.dg/modules/pr99241_b.H
>   create mode 100644 gcc/testsuite/g++.dg/modules/pr99241_c.C
> 
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index 29616100cfe..f184aa70aa4 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -3149,6 +3149,16 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
>     if (TREE_CODE (newdecl) == FIELD_DECL)
>       DECL_PACKED (olddecl) = DECL_PACKED (newdecl);
>   
> +  /* Merge module entity mapping information.  */
> +  if (DECL_LANG_SPECIFIC (olddecl)
> +      && (DECL_MODULE_ENTITY_P (olddecl)
> +	  || DECL_MODULE_KEYED_DECLS_P (olddecl)))
> +    {
> +      retrofit_lang_decl (newdecl);
> +      DECL_MODULE_ENTITY_P (newdecl) = DECL_MODULE_ENTITY_P (olddecl);
> +      DECL_MODULE_KEYED_DECLS_P (newdecl) = DECL_MODULE_KEYED_DECLS_P (olddecl);
> +    }
> +
>     /* The DECL_LANG_SPECIFIC information in OLDDECL will be replaced
>        with that from NEWDECL below.  */
>     if (DECL_LANG_SPECIFIC (olddecl))
> diff --git a/gcc/testsuite/g++.dg/modules/pr99241_a.H b/gcc/testsuite/g++.dg/modules/pr99241_a.H
> new file mode 100644
> index 00000000000..c7031f08eb5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/pr99241_a.H
> @@ -0,0 +1,3 @@
> +// { dg-additional-options "-fmodule-header" }
> +// { dg-module-cmi {} }
> +void terminate();
> diff --git a/gcc/testsuite/g++.dg/modules/pr99241_b.H b/gcc/testsuite/g++.dg/modules/pr99241_b.H
> new file mode 100644
> index 00000000000..c7031f08eb5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/pr99241_b.H
> @@ -0,0 +1,3 @@
> +// { dg-additional-options "-fmodule-header" }
> +// { dg-module-cmi {} }
> +void terminate();
> diff --git a/gcc/testsuite/g++.dg/modules/pr99241_c.C b/gcc/testsuite/g++.dg/modules/pr99241_c.C
> new file mode 100644
> index 00000000000..7f2b1bb43ea
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/pr99241_c.C
> @@ -0,0 +1,5 @@
> +// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
> +
> +import "pr99241_a.H";
> +void terminate();
> +import "pr99241_b.H";
  

Patch

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 29616100cfe..f184aa70aa4 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -3149,6 +3149,16 @@  duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
   if (TREE_CODE (newdecl) == FIELD_DECL)
     DECL_PACKED (olddecl) = DECL_PACKED (newdecl);
 
+  /* Merge module entity mapping information.  */
+  if (DECL_LANG_SPECIFIC (olddecl)
+      && (DECL_MODULE_ENTITY_P (olddecl)
+	  || DECL_MODULE_KEYED_DECLS_P (olddecl)))
+    {
+      retrofit_lang_decl (newdecl);
+      DECL_MODULE_ENTITY_P (newdecl) = DECL_MODULE_ENTITY_P (olddecl);
+      DECL_MODULE_KEYED_DECLS_P (newdecl) = DECL_MODULE_KEYED_DECLS_P (olddecl);
+    }
+
   /* The DECL_LANG_SPECIFIC information in OLDDECL will be replaced
      with that from NEWDECL below.  */
   if (DECL_LANG_SPECIFIC (olddecl))
diff --git a/gcc/testsuite/g++.dg/modules/pr99241_a.H b/gcc/testsuite/g++.dg/modules/pr99241_a.H
new file mode 100644
index 00000000000..c7031f08eb5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99241_a.H
@@ -0,0 +1,3 @@ 
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+void terminate();
diff --git a/gcc/testsuite/g++.dg/modules/pr99241_b.H b/gcc/testsuite/g++.dg/modules/pr99241_b.H
new file mode 100644
index 00000000000..c7031f08eb5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99241_b.H
@@ -0,0 +1,3 @@ 
+// { dg-additional-options "-fmodule-header" }
+// { dg-module-cmi {} }
+void terminate();
diff --git a/gcc/testsuite/g++.dg/modules/pr99241_c.C b/gcc/testsuite/g++.dg/modules/pr99241_c.C
new file mode 100644
index 00000000000..7f2b1bb43ea
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr99241_c.C
@@ -0,0 +1,5 @@ 
+// { dg-additional-options "-fmodules-ts -fno-module-lazy" }
+
+import "pr99241_a.H";
+void terminate();
+import "pr99241_b.H";