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.

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.

Jason

Reply via email to