On Sat, Mar 29, 2025 at 11:14:46AM -0400, Jason Merrill wrote:
> Tested x86_64-pc-linux-gnu, applying to trunk.  Do you agree with my choice of
> how to adjust duplicate_decls?

Yes, that looks reasonable to me.  The point of this block is just to
ensure that we export any entities declared in the module, but an
injected friend isn't really a declaration in the same way.  I also
can't think of any other cases this might come up.

(Similarly, the fact that the early check for 'DECL_LANG_SPECIFIC'
breaks propagation of "not imported" for non-lang-specific decls doesn't
actually affect anything I can think of, because the only time this
would be relevant is if the new declaration was in module purview in
which case it would have a lang-specific.)

> 
> -- 8< --
> 
> Here we were failing to match the injected friend declaration to the
> definition because the latter isn't exported.  But the friend is attached to
> the module, so we need to look for any reachable declaration in that module,
> not just the exports.
> 
> The duplicate_decls change is to avoid clobbering DECL_MODULE_IMPORT_P on
> the imported definition; matching an injected friend doesn't change that
> it's imported.  I considered checking get_originating_module == 0 or
> !decl_defined_p instead of DECL_UNIQUE_FRIEND_P there, but I think this
> situation is specific to friends.
> 
> I removed an assert because we have a test for the same condition a few
> lines above.
> 
> gcc/cp/ChangeLog:
> 
>       * decl.cc (duplicate_decls): Don't clobber DECL_MODULE_IMPORT_P with
>       an injected friend.
>       * name-lookup.cc (check_module_override): Look at all reachable
>       decls in decl's originating module.
> 
> gcc/testsuite/ChangeLog:
> 
>       * g++.dg/modules/friend-9_a.C: New test.
>       * g++.dg/modules/friend-9_b.C: New test.
> ---
>  gcc/cp/decl.cc                            |  6 ++++--
>  gcc/cp/name-lookup.cc                     | 19 ++++++++++---------
>  gcc/testsuite/g++.dg/modules/friend-9_a.C | 13 +++++++++++++
>  gcc/testsuite/g++.dg/modules/friend-9_b.C | 13 +++++++++++++
>  4 files changed, 40 insertions(+), 11 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/modules/friend-9_a.C
>  create mode 100644 gcc/testsuite/g++.dg/modules/friend-9_b.C
> 
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index a785d5e79cb..7d10b228ec6 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -2539,8 +2539,10 @@ duplicate_decls (tree newdecl, tree olddecl, bool 
> hiding, bool was_hidden)
>       }
>  
>        /* Propagate purviewness and importingness as with
> -      set_instantiating_module.  */
> -      if (modules_p () && DECL_LANG_SPECIFIC (new_result))
> +      set_instantiating_module, unless newdecl is a friend injection.  */
> +      if (modules_p () && DECL_LANG_SPECIFIC (new_result)
> +       && !(TREE_CODE (new_result) == FUNCTION_DECL
> +            && DECL_UNIQUE_FRIEND_P (new_result)))
>       {
>         if (DECL_MODULE_PURVIEW_P (new_result))
>           DECL_MODULE_PURVIEW_P (old_result) = true;
> diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
> index df033edafc7..7fadbccfe39 100644
> --- a/gcc/cp/name-lookup.cc
> +++ b/gcc/cp/name-lookup.cc
> @@ -3777,6 +3777,10 @@ check_module_override (tree decl, tree mvec, bool 
> hiding,
>       any reachable declaration, so we should check for overriding here too.  
> */
>    bool any_reachable = deduction_guide_p (decl);
>  
> +  /* DECL might have an originating module if it's an instantiation of a
> +     friend; we want to look at all reachable decls in that module.  */
> +  unsigned decl_mod = get_originating_module (decl);
> +
>    if (BINDING_VECTOR_SLOTS_PER_CLUSTER == BINDING_SLOTS_FIXED)
>      {
>        cluster++;
> @@ -3789,18 +3793,15 @@ check_module_override (tree decl, tree mvec, bool 
> hiding,
>       /* Are we importing this module?  */
>       if (cluster->indices[jx].span != 1)
>         continue;
> -     if (!cluster->indices[jx].base)
> +     unsigned cluster_mod = cluster->indices[jx].base;
> +     if (!cluster_mod)
>         continue;
> -     if (!any_reachable
> -         && !bitmap_bit_p (imports, cluster->indices[jx].base))
> +     bool c_any_reachable = (any_reachable || cluster_mod == decl_mod);
> +     if (!c_any_reachable && !bitmap_bit_p (imports, cluster_mod))
>         continue;
>       /* Is it loaded? */
>       if (cluster->slots[jx].is_lazy ())
> -       {
> -         gcc_assert (cluster->indices[jx].span == 1);
> -         lazy_load_binding (cluster->indices[jx].base,
> -                            scope, name, &cluster->slots[jx]);
> -       }
> +       lazy_load_binding (cluster_mod, scope, name, &cluster->slots[jx]);
>       tree bind = cluster->slots[jx];
>       if (!bind)
>         /* Errors could cause there to be nothing.  */
> @@ -3812,7 +3813,7 @@ check_module_override (tree decl, tree mvec, bool 
> hiding,
>           /* If there was a matching STAT_TYPE here then xref_tag
>              should have found it, but we need to check anyway because
>              a conflicting using-declaration may exist.  */
> -         if (any_reachable)
> +         if (c_any_reachable)
>             {
>               type = STAT_TYPE (bind);
>               bind = STAT_DECL (bind);
> diff --git a/gcc/testsuite/g++.dg/modules/friend-9_a.C 
> b/gcc/testsuite/g++.dg/modules/friend-9_a.C
> new file mode 100644
> index 00000000000..ca95027b470
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/friend-9_a.C
> @@ -0,0 +1,13 @@
> +// { dg-additional-options -fmodules }
> +// { dg-module-cmi M }
> +// { dg-module-do link }
> +
> +export module M;
> +
> +export template <class T> struct A
> +{
> +  template <class U> friend void f (U);
> +};
> +
> +template <class U>
> +void f(U u) { }
> diff --git a/gcc/testsuite/g++.dg/modules/friend-9_b.C 
> b/gcc/testsuite/g++.dg/modules/friend-9_b.C
> new file mode 100644
> index 00000000000..9f583795099
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/modules/friend-9_b.C
> @@ -0,0 +1,13 @@
> +// { dg-additional-options -fmodules }
> +
> +// Check that f and A are mangled as attached to M.
> +// void f@M<A@M<main::loc> >(A@M<main::loc>)
> +// { dg-final { scan-assembler "_ZW1M1fIS_1AIZ4mainE3locEEvT_" } }
> +
> +import M;
> +
> +int main()
> +{
> +  struct loc {};
> +  f(A<loc>());
> +}
> 
> base-commit: 5ac4be28822a4e6f506a69096f92d4675a7d5a72
> -- 
> 2.49.0
> 

Reply via email to