On Fri, 10 Jan 2025, Nathaniel Shead wrote: > Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk/14?
Nice approach, thanks for fixing this! > > -- >8 -- > > In the linked testcase, an ICE occurs because when reading the > (duplicate) function definition for _M_do_parse from module Y, the local > type definitions have already been streamed from module X and setup as > regular backreferences, rather than being found with find_duplicate, > causing issues with managing DECL_CHAIN. > > It is tempting to just skip setting up the DECL_CHAIN for this case. > However, for the future it would be best to ensure that the block vars > for the duplicate definition are accurate, so that we could implement > ODR checking on function definitions at some point. > > So to solve this, this patch creates a copy of the streamed-in local > type and chains that; it will be discarded along with the rest of the > duplicate function after we've finished processing. > > A couple of suggested implementations from the discussion on the PR that > don't work: > > - Replacing the `DECL_CHAIN` assertion with `(*chain && *chain != decl)` > doesn't handle the case where type definitions are followed by regular > local variables, since those won't have been imported as separate > backreferences and so the chains will diverge. > > - Correcting the purviewness of GMF template instantiations to force Y > to emit copies of the local types rather than backreferences into X is > insufficient, as it's still possible that the local types got streamed > in a separate cluster to the function definition, and so will be again > referred to via regular backreferences when importing. > > - Likewise, preventing the emission of function definitions where an > import has already provided that same definition also is insufficient, > for much the same reason. > > PR c++/114630 > > gcc/cp/ChangeLog: > > * module.cc (trees_in::core_vals) <BLOCK>: Chain a new node if > DECL_CHAIN already is set. > > gcc/testsuite/ChangeLog: > > * g++.dg/modules/pr114630.h: New test. > * g++.dg/modules/pr114630_a.C: New test. > * g++.dg/modules/pr114630_b.C: New test. > * g++.dg/modules/pr114630_c.C: New test. > > Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com> > --- > gcc/cp/module.cc | 14 +++++++++++++- > gcc/testsuite/g++.dg/modules/pr114630.h | 11 +++++++++++ > gcc/testsuite/g++.dg/modules/pr114630_a.C | 7 +++++++ > gcc/testsuite/g++.dg/modules/pr114630_b.C | 8 ++++++++ > gcc/testsuite/g++.dg/modules/pr114630_c.C | 4 ++++ > 5 files changed, 43 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/g++.dg/modules/pr114630.h > create mode 100644 gcc/testsuite/g++.dg/modules/pr114630_a.C > create mode 100644 gcc/testsuite/g++.dg/modules/pr114630_b.C > create mode 100644 gcc/testsuite/g++.dg/modules/pr114630_c.C > > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc > index 5350e6c4bad..ff2683de73e 100644 > --- a/gcc/cp/module.cc > +++ b/gcc/cp/module.cc > @@ -6928,11 +6928,23 @@ trees_in::core_vals (tree t) > body) anyway. */ > decl = maybe_duplicate (decl); > > - if (!DECL_P (decl) || DECL_CHAIN (decl)) > + if (!DECL_P (decl)) > { > set_overrun (); > break; > } > + > + /* If DECL_CHAIN is already set then this was a backreference to a > + local type or enumerator from a previous read (PR c++/114630). > + Let's copy the node so we can keep building the chain for ODR > + checking later. */ > + if (DECL_CHAIN (decl)) > + { > + gcc_checking_assert (TREE_CODE (decl) == TYPE_DECL > + && find_duplicate (DECL_CONTEXT (decl))); > + decl = copy_node (decl); Shall we use copy_decl here instead so that any DECL_LANG_SPECIFIC node is copied as well? IIUC we usually don't share DECL_LANG_SPECIFIC between decls. > + } > + > *chain = decl; > chain = &DECL_CHAIN (decl); > } > diff --git a/gcc/testsuite/g++.dg/modules/pr114630.h > b/gcc/testsuite/g++.dg/modules/pr114630.h > new file mode 100644 > index 00000000000..8730007f59f > --- /dev/null > +++ b/gcc/testsuite/g++.dg/modules/pr114630.h > @@ -0,0 +1,11 @@ > +template <typename _CharT> > +void _M_do_parse() { > + struct A {}; > + struct B {}; > + int x; > +} > + > +template <typename> struct formatter; > +template <> struct formatter<int> { > + void parse() { _M_do_parse<int>(); } > +}; > diff --git a/gcc/testsuite/g++.dg/modules/pr114630_a.C > b/gcc/testsuite/g++.dg/modules/pr114630_a.C > new file mode 100644 > index 00000000000..ecfd7ca0b28 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/modules/pr114630_a.C > @@ -0,0 +1,7 @@ > +// { dg-additional-options "-fmodules" } > +// { dg-module-cmi X } > + > +module; > +#include "pr114630.h" > +export module X; > +formatter<int> a; > diff --git a/gcc/testsuite/g++.dg/modules/pr114630_b.C > b/gcc/testsuite/g++.dg/modules/pr114630_b.C > new file mode 100644 > index 00000000000..52fe04e2ce0 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/modules/pr114630_b.C > @@ -0,0 +1,8 @@ > +// { dg-additional-options "-fmodules" } > +// { dg-module-cmi Y } > + > +module; > +#include "pr114630.h" > +export module Y; > +import X; > +formatter<int> b; > diff --git a/gcc/testsuite/g++.dg/modules/pr114630_c.C > b/gcc/testsuite/g++.dg/modules/pr114630_c.C > new file mode 100644 > index 00000000000..54a21f08057 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/modules/pr114630_c.C > @@ -0,0 +1,4 @@ > +// { dg-additional-options "-fmodules" } > + > +#include "pr114630.h" > +import Y; > -- > 2.47.0 > >