]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++/reflection: improve diagnostic for dependent splices
authorMarek Polacek <polacek@redhat.com>
Mon, 20 Apr 2026 17:00:52 +0000 (13:00 -0400)
committerMarek Polacek <polacek@redhat.com>
Tue, 28 Apr 2026 19:21:08 +0000 (15:21 -0400)
In the parser we've changed the "not usable in a splice" error messages
to the more helpful "expected a reflection of ...", but tsubst_splice_scope
still uses the former.  This patch updates the diagnostic there as well.
Let's also teach inform_tree_category about concepts and alias templates
now that a testcase exercises them.

gcc/cp/ChangeLog:

* error.cc (inform_tree_category): Also print concept and alias
template.
* pt.cc (tsubst_splice_scope): Reword the diagnostic messages.
Call inform_tree_category.

gcc/testsuite/ChangeLog:

* g++.dg/reflect/ns5.C: Adjust expected diagnostics.
* g++.dg/reflect/type9.C: Likewise.

Reviewed-by: Jason Merrill <jason@redhat.com>
gcc/cp/error.cc
gcc/cp/pt.cc
gcc/testsuite/g++.dg/reflect/ns5.C
gcc/testsuite/g++.dg/reflect/type9.C

index e7121dc1017557b391ff4b8743d186f616b10669..2ea9d1a7bcd64cb88fb6ec40a49d34c04cd83d7c 100644 (file)
@@ -4013,12 +4013,16 @@ inform_tree_category (tree t)
     inform (loc, "but %qE is a function template", t);
   else if (DECL_CLASS_TEMPLATE_P (t))
     inform (loc, "but %qE is a class template", t);
+  else if (DECL_ALIAS_TEMPLATE_P (t))
+    inform (loc, "but %qE is an alias template", t);
   else if (variable_template_p (t))
     inform (loc, "but %qE is a variable template", t);
   else if (TREE_CODE (t) == NAMESPACE_DECL)
     inform (loc, "but %qE is a namespace", t);
   else if (TREE_CODE (t) == CONST_DECL && !DECL_TEMPLATE_PARM_P (t))
     inform (loc, "but %qE is an enumerator", t);
+  else if (concept_definition_p (t))
+    inform (loc, "but %qE is a concept", t);
 }
 
 /* Disable warnings about missing quoting in GCC diagnostics for
index ce324c87ecf8cacf3aea1b34aaada5d6e4af9181..05ecda2a0d8a8c539f7740468be02c3a2b194cad 100644 (file)
@@ -16902,21 +16902,25 @@ tsubst_splice_scope (tree t, tree args, tsubst_flags_t complain, tree in_decl)
   tree r = tsubst (SPLICE_SCOPE_EXPR (t), args, complain, in_decl);
   if (r == error_mark_node)
     return r;
+  const bool type_p = SPLICE_SCOPE_TYPE_P (t);
   if (dependent_splice_p (r))
-    return make_splice_scope (r, SPLICE_SCOPE_TYPE_P (t));
-  if (SPLICE_SCOPE_TYPE_P (t) && ctad_template_p (r))
+    return make_splice_scope (r, type_p);
+  if (type_p && ctad_template_p (r))
     r = make_template_placeholder (r);
-  if (SPLICE_SCOPE_TYPE_P (t)
+  if (type_p
       ? !valid_splice_type_p (r)
       : !valid_splice_scope_p (r))
     {
       if (complain & tf_error)
        {
          const location_t loc = EXPR_LOCATION (SPLICE_SCOPE_EXPR (t));
-         if (SPLICE_SCOPE_TYPE_P (t))
-           error_at (loc, "%qE is not usable in a splice type", r);
+         auto_diagnostic_group d;
+         if (type_p)
+           error_at (loc, "expected a reflection of a type");
          else
-           error_at (loc, "%qE is not usable in a splice scope", r);
+           error_at (loc, "expected a reflection of a class, namespace, or "
+                     "enumeration");
+         inform_tree_category (r);
        }
       return error_mark_node;
     }
index 236b292745305210446c35cdabca8eae9420a7d9..eb75481d9f1fb8c34a891d79870d8388c130884b 100644 (file)
@@ -5,12 +5,16 @@ using info = decltype(^^void);
 
 template<typename>
 void foo () { }
+template<typename>
+void foo2 () { }
 void bar () { }
 namespace N { }
 namespace M = N;
 template<typename T>
 T vt{};
 template<typename T>
+T vt2{};
+template<typename T>
 concept C = true;
 static int i;
 enum E { X };
@@ -20,23 +24,34 @@ struct D { static T di; };
 template<typename T>
 using Z = D<T>;
 
-template<info R> void fn1 () { typename [:R:]::X x; }  // { dg-error "not usable in a splice scope" }
-template<info R> void fn2 () { typename [:R:]::X x; }   // { dg-error "not usable in a splice scope" }
-template<info R> void fn3 () { typename [:R:]::X x; }   // { dg-error "not usable in a splice scope" }
-template<info R> void fn4 () { typename [:R:]::X x; }   // { dg-error "not usable in a splice scope" }
-template<info R> void fn5 () { typename [:R:]::X x; }   // { dg-error "not usable in a splice scope" }
-template<info R> void fn6 () { typename [:R:]::X x; }   // { dg-error "not usable in a splice scope" }
-template<info R> void fn7 () { typename [:R:]::X x; }   // { dg-error "not usable in a splice scope" }
-template<info R> void fn8 () { typename [:R:]::X x; }   // { dg-error "not usable in a splice scope" }
-template<info R> void fn9 () { typename [:R:]::X x; }   // { dg-error "not usable in a splice scope" }
-template<info R> void fn10 () { typename [:R:]::X x; }  // { dg-error "not usable in a splice scope" }
-template<info R> void fn11 () { typename [:R:]::X x; }  // { dg-error "not usable in a splice scope" }
+template<info R> void fn1 () { typename [:R:]::X x; }  // { dg-error "expected a reflection of a class, namespace, or enumeration" }
+// { dg-message "but .foo<int>. is a function" "" { target *-*-* } 7 }
+template<info R> void fn2 () { typename [:R:]::X x; }   // { dg-error "expected a reflection of a class, namespace, or enumeration" }
+// { dg-message "but .foo2. is a function template" "" { target *-*-* } 9 }
+template<info R> void fn3 () { typename [:R:]::X x; }   // { dg-error "expected a reflection of a class, namespace, or enumeration" }
+// { dg-message "but .bar. is a function" "" { target *-*-* } 10 }
+template<info R> void fn4 () { typename [:R:]::X x; }   // { dg-error "expected a reflection of a class, namespace, or enumeration" }
+// { dg-message "but .vt<int>. is a variable" "" { target *-*-* } 14 }
+template<info R> void fn5 () { typename [:R:]::X x; }   // { dg-error "expected a reflection of a class, namespace, or enumeration" }
+// { dg-message "but .vt2<T>. is a variable template" "" { target *-*-* } 16 }
+template<info R> void fn6 () { typename [:R:]::X x; }   // { dg-error "expected a reflection of a class, namespace, or enumeration" }
+// { dg-message "but .C. is a concept" "" { target *-*-* } 18 }
+template<info R> void fn7 () { typename [:R:]::X x; }   // { dg-error "expected a reflection of a class, namespace, or enumeration" }
+// { dg-message "but .i. is a variable" "" { target *-*-* } 19 }
+template<info R> void fn8 () { typename [:R:]::X x; }   // { dg-error "expected a reflection of a class, namespace, or enumeration" }
+// { dg-message "but .X. is an enumerator" "" { target *-*-* } 20 }
+template<info R> void fn9 () { typename [:R:]::X x; }   // { dg-error "expected a reflection of a class, namespace, or enumeration" }
+// { dg-message "but .S::si. is a variable" "" { target *-*-* } 21 }
+template<info R> void fn10 () { typename [:R:]::X x; }  // { dg-error "expected a reflection of a class, namespace, or enumeration" }
+// { dg-message "but .D<int>::di. is a variable" "" { target *-*-* } 23 }
+template<info R> void fn11 () { typename [:R:]::X x; }  // { dg-error "expected a reflection of a class, namespace, or enumeration" }
+// { dg-message "but .Z. is an alias template" "" { target *-*-* } 25 }
 
 template void fn1<^^foo<int>>(); // { dg-message "required from here" }
-template void fn2<^^foo>();     // { dg-message "required from here" }
+template void fn2<^^foo2>();    // { dg-message "required from here" }
 template void fn3<^^bar>();     // { dg-message "required from here" }
 template void fn4<^^vt<int>>();  // { dg-message "required from here" }
-template void fn5<^^vt>();      // { dg-message "required from here" }
+template void fn5<^^vt2>();     // { dg-message "required from here" }
 template void fn6<^^C>();       // { dg-message "required from here" }
 template void fn7<^^i>();       // { dg-message "required from here" }
 template void fn8<^^X>();       // { dg-message "required from here" }
index 2d0409e4b86457925862a0105dc571880bf04fed..99c6fd2781b91253a26e0c458f0d29af750f7f9f 100644 (file)
@@ -5,12 +5,16 @@ using info = decltype(^^void);
 
 template<typename>
 void foo () { }
+template<typename>
+void foo2 () { }
 void bar () { }
 namespace N { }
 namespace M = N;
 template<typename T>
 T vt{};
 template<typename T>
+T vt2{};
+template<typename T>
 concept C = true;
 static int i;
 enum E { X };
@@ -20,27 +24,39 @@ struct D { static T di; };
 template<typename T>
 using Z = D<T>;
 
-template<info R> void fn1 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
-template<info R> void fn2 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
-template<info R> void fn3 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
-template<info R> void fn4 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
-template<info R> void fn5 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
-template<info R> void fn6 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
-template<info R> void fn7 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
-template<info R> void fn8 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
-template<info R> void fn9 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
-template<info R> void fn10 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
-template<info R> void fn11 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
-template<info R> void fn12 () { int n = typename [:R:](42); } // { dg-error "not usable in a splice type" }
+template<info R> void fn1 () { int n = typename [:R:](42); } // { dg-error "expected a reflection of a type" }
+// { dg-message "but .foo<int>. is a function" "" { target *-*-* } 7 }
+template<info R> void fn2 () { int n = typename [:R:](42); } // { dg-error "expected a reflection of a type" }
+// { dg-message "but .foo2. is a function template" "" { target *-*-* } 9 }
+template<info R> void fn3 () { int n = typename [:R:](42); } // { dg-error "expected a reflection of a type" }
+// { dg-message "but .N. is a namespace" "" { target *-*-* } 11 }
+template<info R> void fn4 () { int n = typename [:R:](42); } // { dg-error "expected a reflection of a type" }
+// { dg-message "but .M. is a namespace" "" { target *-*-* } 12 }
+template<info R> void fn5 () { int n = typename [:R:](42); } // { dg-error "expected a reflection of a type" }
+// { dg-message "but .bar. is a function" "" { target *-*-* } 10 }
+template<info R> void fn6 () { int n = typename [:R:](42); } // { dg-error "expected a reflection of a type" }
+// { dg-message "but .vt<int>. is a variable" "" { target *-*-* } 14 }
+template<info R> void fn7 () { int n = typename [:R:](42); } // { dg-error "expected a reflection of a type" }
+// { dg-message "but .vt2<T>. is a variable template" "" { target *-*-* } 16 }
+template<info R> void fn8 () { int n = typename [:R:](42); } // { dg-error "expected a reflection of a type" }
+// { dg-message "but .C. is a concept" "" { target *-*-* } 18 }
+template<info R> void fn9 () { int n = typename [:R:](42); } // { dg-error "expected a reflection of a type" }
+// { dg-message "but .i. is a variable" "" { target *-*-* } 19 }
+template<info R> void fn10 () { int n = typename [:R:](42); } // { dg-error "expected a reflection of a type" }
+// { dg-message "but .X. is an enumerator" "" { target *-*-* } 20 }
+template<info R> void fn11 () { int n = typename [:R:](42); } // { dg-error "expected a reflection of a type" }
+// { dg-message "but .S::si. is a variable" "" { target *-*-* } 21 }
+template<info R> void fn12 () { int n = typename [:R:](42); } // { dg-error "expected a reflection of a type" }
+// { dg-message "but .D<int>::di. is a variable" "" { target *-*-* } 23 }
 template<info R> void fn13 () { int n = typename [:R:](42); } // { dg-error "class template argument deduction failed|no matching" }
 
 template void fn1<^^foo<int>>();  // { dg-message "required from here" }
-template void fn2<^^foo>();      // { dg-message "required from here" }
+template void fn2<^^foo2>();     // { dg-message "required from here" }
 template void fn3<^^N>();        // { dg-message "required from here" }
 template void fn4<^^M>();        // { dg-message "required from here" }
 template void fn5<^^bar>();      // { dg-message "required from here" }
 template void fn6<^^vt<int>>();          // { dg-message "required from here" }
-template void fn7<^^vt>();       // { dg-message "required from here" }
+template void fn7<^^vt2>();      // { dg-message "required from here" }
 template void fn8<^^C>();        // { dg-message "required from here" }
 template void fn9<^^i>();        // { dg-message "required from here" }
 template void fn10<^^X>();       // { dg-message "required from here" }