On Sat, Mar 07, 2026 at 05:38:10PM -0500, Jason Merrill wrote:
> On 3/7/26 12:04 PM, Marek Polacek wrote:
> > On Thu, Mar 05, 2026 at 10:46:22PM -0500, Jason Merrill wrote:
> > > On 3/5/26 7:03 PM, Marek Polacek wrote:
> > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> > > > 
> > > > -- >8 --
> > > > I noticed that we don't issue an error in the test in 
> > > > [dcl.attr.annotation]
> > > > for /4: "Substituting into an annotation is not in the immediate 
> > > > context":
> > > > 
> > > >     template<class T>
> > > >       [[=T::type()]] void f(T t);
> > > > 
> > > >     void f(int);
> > > > 
> > > >     void g() {
> > > >       f(0);         // OK
> > > >       f('0');       // error, substituting into the annotation results 
> > > > in an invalid expression
> > > >     }
> > > > 
> > > >         PR c++/124381
> > > > 
> > > > gcc/cp/ChangeLog:
> > > > 
> > > >         * pt.cc (tsubst_attribute): Always complain for annotations.
> > > > 
> > > > gcc/testsuite/ChangeLog:
> > > > 
> > > >         * g++.dg/reflect/annotations13.C: New test.
> > > > ---
> > > >    gcc/cp/pt.cc                                 |  5 +++++
> > > >    gcc/testsuite/g++.dg/reflect/annotations13.C | 15 +++++++++++++++
> > > >    2 files changed, 20 insertions(+)
> > > >    create mode 100644 gcc/testsuite/g++.dg/reflect/annotations13.C
> > > > 
> > > > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > > > index ddf492b3435..36b9fbeb0b6 100644
> > > > --- a/gcc/cp/pt.cc
> > > > +++ b/gcc/cp/pt.cc
> > > > @@ -12347,6 +12347,11 @@ tsubst_attribute (tree t, tree *decl_p, tree 
> > > > args,
> > > >    {
> > > >      gcc_assert (ATTR_IS_DEPENDENT (t));
> > > > +  /* [dcl.attr.annotation]/4: Substituting into an annotation is not in
> > > > +     the immediate context.  */
> > > > +  if (annotation_p (t))
> > > > +    complain = tf_warning_or_error;
> > > > +
> > > >      tree val = TREE_VALUE (t);
> > > >      if (val == NULL_TREE)
> > > >        /* Nothing to do.  */;
> > > > diff --git a/gcc/testsuite/g++.dg/reflect/annotations13.C 
> > > > b/gcc/testsuite/g++.dg/reflect/annotations13.C
> > > > new file mode 100644
> > > > index 00000000000..19306956e78
> > > > --- /dev/null
> > > > +++ b/gcc/testsuite/g++.dg/reflect/annotations13.C
> > > > @@ -0,0 +1,15 @@
> > > > +// PR c++/124381
> > > > +// { dg-do compile { target c++26 } }
> > > > +// { dg-additional-options "-freflection" }
> > > > +// Test from [dcl.attr.annotation].
> > > > +
> > > > +template<class T>
> > > > +[[=T::type()]] void f(T t);  // { dg-error "not a member" }
> > > > +
> > > > +void f(int);
> > > > +
> > > > +void g() {
> > > > +  f(0);         // OK
> > > > +  f('0');       // error, substituting into the annotation results in 
> > > > an invalid expression
> > > 
> > > What if there's another template that's a better match?  I'm concerned 
> > > that
> > > this only works because f(int) is a perfect match for the first call so we
> > > never even form the candidate from the template.
> > > 
> > > We don't want this error until we've chosen the annotated template as the
> > > best candidate.
> > 
> > If that's really then case then I'm misunderstanding something.  In
> > 
> > ```
> > template<typename T>
> > auto f(T, long) -> decltype([]() { T::invalid; } ()); // #1
> > template<typename T>
> > void f(T, int); // #2
> > 
> > void
> > g ()
> > {
> >    f (0, 0);
> > }
> > ```
> > 
> > we report a hard error due to [temp.deduct]/9: "When substituting into
> > a lambda-expression, substitution into its body is not in the immediate
> > context." even though #2 is a better match.
> 
> Yes.
> 
> > So I thought this was the same case.
> 
> I don't think it is, though.  Lambdas are unique in a lot of ways.
> 
> I think this is more like deferred instantiation of noexcept: a property of
> a declaration that does not participate in overload resolution, only later
> uses of the result.

Aha, I see, so:

```
template<typename T>
[[=T::type()]] void f(T, long);

template<typename T>
void f(T, int);

void g ()
{
  f (1, 1);
}
```

should compile but not if I swap long and int.

That's tricky to fix though, for noexcept we have maybe_instantiate_noexcept
but attributes are tsubsted more eagerly: tsubst_function_decl ->
apply_late_template_attributes -> tsubst_attribute and so by the time
we get around to calling finish_call_expr we've already tsubsted
annotations.  

> > Note though that the approach this patch takes and what we do in
> > tsubst_lambda_expr:
> > 
> >        /* [temp.deduct] A lambda-expression appearing in a function type or 
> > a
> >           template parameter is not considered part of the immediate 
> > context for
> >           the purposes of template argument deduction. */
> >        complain = tf_warning_or_error;
> > 
> > is flawed because it can cause the "error reporting routines re-entered"
> > crash.  I opened c++/124397.  Either we should not override complain
> > with tf_warning_or_error when we are dumping from cp_printer, or only do
> > it when in the fn_type_unification context?  But I don't see any flags for
> > either.
> 
> I'm not sure if there's already anything that tries to adjust for this. It
> might be useful to make global_diagnostic_context.m_lock accessible somehow.

Sounds good; I posted a patch for that.

Marek

Reply via email to