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.  So I thought this was the
same case.


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.

Marek

Reply via email to