On Fri, Jan 30, 2026 at 10:08:20AM +0800, Jason Merrill wrote:
> > +  tree oldarg, newarg;
> > +  for (oldarg = DECL_ARGUMENTS (olddecl), newarg = DECL_ARGUMENTS 
> > (newdecl);
> > +       oldarg && newarg;
> > +       oldarg = DECL_CHAIN (oldarg), newarg = DECL_CHAIN (newarg))
> > +    {
> > +      DECL_ATTRIBUTES (newarg)
> > +   = (*targetm.merge_decl_attributes) (oldarg, newarg);
> > +      if (lookup_attribute (NULL, "indeterminate", DECL_ATTRIBUTES 
> > (newarg))
> > +     && !lookup_attribute (NULL, "indeterminate",
> > +                           DECL_ATTRIBUTES (oldarg)))
> > +   {
> > +     auto_diagnostic_group d;
> > +     error_at (DECL_SOURCE_LOCATION (newarg),
> > +               "%<indeterminate%> attribute not specified for parameter "
> > +               "%qD on the first declaration of its function", newarg);
> > +     inform (DECL_SOURCE_LOCATION (oldarg), "earlier declaration");
> > +   }
> > +      DECL_ATTRIBUTES (oldarg) = DECL_ATTRIBUTES (newarg);
> 
> Hmm, I'm uncertain about unconditionally copying attributes from a local
> extern to a namespace-scope declaration, and am having trouble finding
> normative wording about what gets merged between declarations in different
> scopes for the same entity.  Default arguments don't, but they are
> properties of the declaration rather than the entity, while attributes are
> described as applying to the entity.  So I guess this is reasonable.
> 
> But since it's a change from existing behavior, let's limit it to
> !extern_alias || flag_reflection for GCC 16, and make it unconditional for
> GCC 17.
> 
> OK with that adjustment.

!extern_alias || flag_reflection could be done basically by only calling
the new function if (flag_reflection) from name-lookup.cc.
I'm not sure that is a good idea, having -freflection affect e.g. whether
indeterminate attribute will be diagnosed or not is just weird.

It could be guarded on if (cxx_dialect >= cxx26) for now, or it could
just do the if (flag_reflection) handling in the function and not the
attribute/indeterminate handling for now.

Note, some attribute "merging" is done already unconditionally, when
there is no existing decl at the namespace scope yet, we use copies of the
parameters (well, due to the bug the patch is also fixing first parameter
only) and so in that case the attributes on it are propagated.

And guess we should test whether annotations are or are not gathered
across the local externs and/or their parameters,
[[=1]] void foo ([[=2]] int);
void
bar ()
{
  [[=3]] extern void foo ([[=4]] int);
}
static_assert (annotations_of (^^foo).size () == 1);
static_assert (annotations_of (parameters_of (^^foo)[0]).size () == 2);

Though, e.g. the clang reflection branch returns 2 annotations for ^^foo
and doesn't support annotations on parameters yet.

CCing Daniel for his thoughts on this.

        Jakub

Reply via email to