Re: [PATCH v4 2/2] c++: Fix instantiation of imported temploid friends [PR114275]

2024-04-29 Thread Jason Merrill

On 4/29/24 02:34, Nathaniel Shead wrote:

On Fri, Apr 26, 2024 at 09:16:40PM -0400, Jason Merrill wrote:

On 4/19/24 09:29, Nathaniel Shead wrote:

On Fri, Apr 19, 2024 at 12:14:06PM +1000, Nathaniel Shead wrote:

On Wed, Apr 17, 2024 at 02:02:21PM -0400, Patrick Palka wrote:

On Mon, 15 Apr 2024, Nathaniel Shead wrote:


I'm not a huge fan of always streaming 'imported_temploid_friends' for
all decls, but I don't think it adds much performance cost over adding a
new flag to categorise decls that might be marked as such.


IIUC this value is going to be almost always null which is encoded as a
single 0 byte, which should be fast to stream.  But I wonder how much
larger  gets?  Can we get away with streaming this value
only for TEMPLATE_DECLs?


Yes, it should either just be a 0 byte or an additional backref
somewhere, which will likely also be small. On my system it increases
the size by 0.26%, from 31186800 bytes to 31268672.

But I've just found that this patch has a bug anyway, in that it doesn't
correctly dedup if the friend types are instantiated in two separate
modules that are then both imported.  I'll see what I need to do to fix
this which may influence what we need to stream here.



Here's an updated version of the patch that fixes this. Also changed to
only stream when 'inner' is either TYPE_DECL or FUNCTION_DECL, which
cuts the size of  down a bit to 31246992 (0.19% growth).

Another alternative would be to add another boolean flag at the top of
'decl_value' and branch on that; that would make use of the bitpacking
logic and probably cut down on the size further.  (I haven't measured
this yet though.)

Bootstrapped and regtested (so far just dg.exp and modules.exp) on
x86_64-pc-linux-gnu, OK for trunk if full regtest succeeds?

-- >8 --

This patch fixes a number of issues with the handling of temploid friend
declarations.

The primary issue is that instantiations of friend declarations should
attach the declaration to the same module as the befriending class, by
[module.unit] p7.1 and [temp.friend] p2; this could be a different
module from the current TU, and so needs special handling.


This is only an issue for DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P, right?


It's true for any friend instantiations, including e.g. friend
functions, not just template class friends.



Hmm, CWG2588 should probably touch [module.unit]/7.1 as well as
[basic.link].


The other main issue here is that we can't assume that just because name
lookup didn't find a definition for a hidden template class, it doesn't
mean that it doesn't exist: it could be a non-exported entity that we've
nevertheless streamed in from an imported module.  We need to ensure
that when instantiating friend classes that we return the same TYPE_DECL
that we got from our imports, otherwise we will get later issues with
'duplicate_decls' (rightfully) complaining that they're different.


Tricksy.


This doesn't appear necessary for functions due to the existing name
lookup handling already finding these hidden declarations.

PR c++/105320
PR c++/114275

gcc/cp/ChangeLog:

* cp-tree.h (propagate_defining_module): Declare.
(lookup_imported_hidden_friend): Declare.
* decl.cc (duplicate_decls): Also check if hidden declarations
can be redeclared in this module.
* module.cc (imported_temploid_friends): New map.
(init_modules): Initialize it.
(trees_out::decl_value): Write it; don't consider imported
temploid friends as attached to this module.
(trees_in::decl_value): Read it.
(depset::hash::add_specializations): Don't treat instantiations
of a friend type as a specialisation.
(get_originating_module_decl): Follow the owning decl for an
imported temploid friend.
(propagate_defining_module): New function.
* name-lookup.cc (lookup_imported_hidden_friend): New function.
* pt.cc (tsubst_friend_function): Propagate defining module for
new friend functions.
(tsubst_friend_class): Lookup imported hidden friends. Check
for valid redeclaration. Propagate defining module for new
friend classes.

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index aa66da4829d..56752cf6872 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -2276,30 +2276,34 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
hiding, bool was_hidden)
 if (modules_p ()
 && TREE_CODE (CP_DECL_CONTEXT (olddecl)) == NAMESPACE_DECL
-  && TREE_CODE (olddecl) != NAMESPACE_DECL
-  && !hiding)
+  && TREE_CODE (olddecl) != NAMESPACE_DECL)
   {
 if (!module_may_redeclare (olddecl, newdecl))
return error_mark_node;
-  tree not_tmpl = STRIP_TEMPLATE (olddecl);
-  if (DECL_LANG_SPECIFIC (not_tmpl)
- && DECL_MODULE_ATTACH_P (not_tmpl)
- /* Typedefs are not entities and so are OK to be redeclared
-as exported: see [module.interface]/p6.  */
- && 

[PATCH v4 2/2] c++: Fix instantiation of imported temploid friends [PR114275]

2024-04-29 Thread Nathaniel Shead
On Fri, Apr 26, 2024 at 09:16:40PM -0400, Jason Merrill wrote:
> On 4/19/24 09:29, Nathaniel Shead wrote:
> > On Fri, Apr 19, 2024 at 12:14:06PM +1000, Nathaniel Shead wrote:
> > > On Wed, Apr 17, 2024 at 02:02:21PM -0400, Patrick Palka wrote:
> > > > On Mon, 15 Apr 2024, Nathaniel Shead wrote:
> > > > 
> > > > > I'm not a huge fan of always streaming 'imported_temploid_friends' for
> > > > > all decls, but I don't think it adds much performance cost over 
> > > > > adding a
> > > > > new flag to categorise decls that might be marked as such.
> > > > 
> > > > IIUC this value is going to be almost always null which is encoded as a
> > > > single 0 byte, which should be fast to stream.  But I wonder how much
> > > > larger  gets?  Can we get away with streaming this value
> > > > only for TEMPLATE_DECLs?
> > > 
> > > Yes, it should either just be a 0 byte or an additional backref
> > > somewhere, which will likely also be small. On my system it increases
> > > the size by 0.26%, from 31186800 bytes to 31268672.
> > > 
> > > But I've just found that this patch has a bug anyway, in that it doesn't
> > > correctly dedup if the friend types are instantiated in two separate
> > > modules that are then both imported.  I'll see what I need to do to fix
> > > this which may influence what we need to stream here.
> > > 
> > 
> > Here's an updated version of the patch that fixes this. Also changed to
> > only stream when 'inner' is either TYPE_DECL or FUNCTION_DECL, which
> > cuts the size of  down a bit to 31246992 (0.19% growth).
> > 
> > Another alternative would be to add another boolean flag at the top of
> > 'decl_value' and branch on that; that would make use of the bitpacking
> > logic and probably cut down on the size further.  (I haven't measured
> > this yet though.)
> > 
> > Bootstrapped and regtested (so far just dg.exp and modules.exp) on
> > x86_64-pc-linux-gnu, OK for trunk if full regtest succeeds?
> > 
> > -- >8 --
> > 
> > This patch fixes a number of issues with the handling of temploid friend
> > declarations.
> > 
> > The primary issue is that instantiations of friend declarations should
> > attach the declaration to the same module as the befriending class, by
> > [module.unit] p7.1 and [temp.friend] p2; this could be a different
> > module from the current TU, and so needs special handling.
> 
> This is only an issue for DECL_UNINSTANTIATED_TEMPLATE_FRIEND_P, right?

It's true for any friend instantiations, including e.g. friend
functions, not just template class friends.

> 
> Hmm, CWG2588 should probably touch [module.unit]/7.1 as well as
> [basic.link].
> 
> > The other main issue here is that we can't assume that just because name
> > lookup didn't find a definition for a hidden template class, it doesn't
> > mean that it doesn't exist: it could be a non-exported entity that we've
> > nevertheless streamed in from an imported module.  We need to ensure
> > that when instantiating friend classes that we return the same TYPE_DECL
> > that we got from our imports, otherwise we will get later issues with
> > 'duplicate_decls' (rightfully) complaining that they're different.
> 
> Tricksy.
> 
> > This doesn't appear necessary for functions due to the existing name
> > lookup handling already finding these hidden declarations.
> > 
> > PR c++/105320
> > PR c++/114275
> > 
> > gcc/cp/ChangeLog:
> > 
> > * cp-tree.h (propagate_defining_module): Declare.
> > (lookup_imported_hidden_friend): Declare.
> > * decl.cc (duplicate_decls): Also check if hidden declarations
> > can be redeclared in this module.
> > * module.cc (imported_temploid_friends): New map.
> > (init_modules): Initialize it.
> > (trees_out::decl_value): Write it; don't consider imported
> > temploid friends as attached to this module.
> > (trees_in::decl_value): Read it.
> > (depset::hash::add_specializations): Don't treat instantiations
> > of a friend type as a specialisation.
> > (get_originating_module_decl): Follow the owning decl for an
> > imported temploid friend.
> > (propagate_defining_module): New function.
> > * name-lookup.cc (lookup_imported_hidden_friend): New function.
> > * pt.cc (tsubst_friend_function): Propagate defining module for
> > new friend functions.
> > (tsubst_friend_class): Lookup imported hidden friends. Check
> > for valid redeclaration. Propagate defining module for new
> > friend classes.
> > 
> > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> > index aa66da4829d..56752cf6872 100644
> > --- a/gcc/cp/decl.cc
> > +++ b/gcc/cp/decl.cc
> > @@ -2276,30 +2276,34 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
> > hiding, bool was_hidden)
> > if (modules_p ()
> > && TREE_CODE (CP_DECL_CONTEXT (olddecl)) == NAMESPACE_DECL
> > -  && TREE_CODE (olddecl) != NAMESPACE_DECL
> > -  && !hiding)
> > +  && TREE_CODE (olddecl) != NAMESPACE_DECL)
> >   {
> > if (!module_may_redeclare