On Wed, Feb 11, 2026 at 06:07:24PM +0100, Jakub Jelinek wrote:
> On Wed, Feb 11, 2026 at 11:54:58AM -0500, Marek Polacek wrote:
> > > Though, why not just use %qE and make sure to pass a REFLECT_EXPR and
> > > ensure it is printed in human readable form (partly kind like
> > > display_string_of, but e.g. with ^^ at the start).
> > 
> > Would it be better if tree_category returned e.g.
> > 
> >   return G_(" (type)");
> > 
> > and is then used at the end of the error message like this:
> > 
> >   error_at (loc, "expected a reflection of ... "
> >         "instead of %qE" "%s", t, tree_category (t));
> > 
> > or is it still bad wrt translation?  %s because I don't want to
> > quote the category.  This would produce:
> > 
> > error: expected a reflection of a function template instead of 'x' 
> > (variable)
> 
> Maybe.
> 
> Yet another option would be a pair of diagnostic messages:
>   auto_diagnostic_group d;
>   error_at (loc, "expected a reflection of ... ");
>   inform (loc, "while %qE is a variable", t);
> where the inform could be done in a helper function which various
> error_at callers would call to explain stuff.

That sounds good, albeit a little bit more wordy.  But at least
we won't have translation problems.  Thanks,

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
This patch improves various reflection diagnostics as discussed in
<https://gcc.gnu.org/pipermail/gcc-patches/2025-December/704168.html>.

In particular:
- reword "not usable" diagnostics to say what kind of reflections we
  expected,
- use the new inform_tree_category to better describe what kind of reflection
  we actually got,
- when we see a missing 'template' keyword, emit a -Wmissing-template-keyword
  warning instead of giving a hard error (this should only happen when the
  code would be valid with the 'template' added.

gcc/cp/ChangeLog:

        * cp-tree.h (inform_tree_category): Declare.
        * error.cc (inform_tree_category): New.
        * parser.cc (cp_parser_splice_specifier): Use OVL_FIRST when checking
        for TEMPLATE_DECL.
        (cp_parser_splice_type_specifier): Reword an error message.  Call
        inform_tree_category.
        (cp_parser_splice_expression): Check check_splice_expr earlier.  Reword
        error messages.  Call inform_tree_category.  Turn an error into an
        assert.  Use missing_template_diag instead of giving an error about
        a missing 'template' keyword.
        (cp_parser_splice_scope_specifier): Reword an error message.  Call
        inform_tree_category.
        (missing_template_diag): Forward declare.  Drop "enum" in a parameter.
        * reflect.cc (check_splice_expr): Reword error messages.  Call
        inform_tree_category.

gcc/testsuite/ChangeLog:

        * g++.dg/reflect/crash10.C: Adjust expected diagnostics.
        * g++.dg/reflect/crash2.C: Likewise.
        * g++.dg/reflect/crash3.C: Likewise.
        * g++.dg/reflect/crash7.C: Likewise.
        * g++.dg/reflect/crash9.C: Likewise.
        * g++.dg/reflect/dep5.C: Likewise.
        * g++.dg/reflect/diag1.C: Likewise.
        * g++.dg/reflect/error10.C: Likewise.
        * g++.dg/reflect/error12.C: Likewise.
        * g++.dg/reflect/error5.C: Likewise.
        * g++.dg/reflect/expr3.C: Likewise.
        * g++.dg/reflect/member1.C: Likewise.
        * g++.dg/reflect/ns2.C: Likewise.  Test more cases.
        * g++.dg/reflect/p2996-12.C: Likewise.
        * g++.dg/reflect/splice5.C: Likewise.
        * g++.dg/reflect/diag1a.C: New test.
        * g++.dg/reflect/diag1b.C: New test.
---
 gcc/cp/cp-tree.h                        |  1 +
 gcc/cp/error.cc                         | 34 +++++++++
 gcc/cp/parser.cc                        | 95 ++++++++++---------------
 gcc/cp/reflect.cc                       | 11 +--
 gcc/testsuite/g++.dg/reflect/crash10.C  |  6 +-
 gcc/testsuite/g++.dg/reflect/crash2.C   |  3 +-
 gcc/testsuite/g++.dg/reflect/crash3.C   |  6 +-
 gcc/testsuite/g++.dg/reflect/crash7.C   |  3 +-
 gcc/testsuite/g++.dg/reflect/crash9.C   |  6 +-
 gcc/testsuite/g++.dg/reflect/dep5.C     |  6 +-
 gcc/testsuite/g++.dg/reflect/diag1.C    |  6 +-
 gcc/testsuite/g++.dg/reflect/diag1a.C   | 24 +++++++
 gcc/testsuite/g++.dg/reflect/diag1b.C   | 23 ++++++
 gcc/testsuite/g++.dg/reflect/error10.C  | 27 +++++--
 gcc/testsuite/g++.dg/reflect/error12.C  | 30 +++++---
 gcc/testsuite/g++.dg/reflect/error5.C   |  3 +-
 gcc/testsuite/g++.dg/reflect/expr3.C    | 25 ++++---
 gcc/testsuite/g++.dg/reflect/member1.C  | 14 ++--
 gcc/testsuite/g++.dg/reflect/ns2.C      | 24 ++++++-
 gcc/testsuite/g++.dg/reflect/p2996-12.C |  3 +-
 gcc/testsuite/g++.dg/reflect/splice5.C  | 10 +--
 21 files changed, 247 insertions(+), 113 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/reflect/diag1a.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/diag1b.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index fcad67a662c..c9f0ba9c125 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7688,6 +7688,7 @@ extern bool pedwarn_cxx98                       
(location_t,
 extern location_t location_of                   (tree);
 extern void qualified_name_lookup_error                (tree, tree, tree,
                                                 location_t);
+void inform_tree_category                      (location_t, tree);
 
 struct decl_location_traits
   : simple_cache_map_traits<tree_decl_hash, location_t> { };
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index c184846066e..74c2c0935df 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -3976,6 +3976,40 @@ function_category (tree fn)
     return G_("In function %qD");
 }
 
+/* We expected some kind of tree but instead got T and emitted a diagnostic.
+   Print the category of T (type, expression, ...) if possible.  */
+
+void
+inform_tree_category (location_t loc, tree t)
+{
+  t = maybe_get_first_fn (t);
+  if (TREE_CODE (t) == TYPE_DECL)
+    t = TREE_TYPE (t);
+
+  if (TYPE_P (t))
+    inform (loc, "but %qE is a type", t);
+  else if (EXPR_P (t))
+    inform (loc, "but %qE is an expression", t);
+  else if (VAR_P (t))
+    inform (loc, "but %qE is a variable", t);
+  else if (TREE_CODE (t) == PARM_DECL)
+    inform (loc, "but %qE is a parameter", t);
+  else if (TREE_CODE (t) == FUNCTION_DECL)
+    inform (loc, "but %qE is a function", t);
+  else if (TREE_CODE (t) == FIELD_DECL)
+    inform (loc, "but %qE is a data member", t);
+  else if (DECL_FUNCTION_TEMPLATE_P (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 (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 (DECL_DECOMPOSITION_P (t) && !DECL_DECOMP_IS_BASE (t))
+    inform (loc, "but %qE is a structured binding", t);
+}
+
 /* Disable warnings about missing quoting in GCC diagnostics for
    the pp_verbatim calls.  Their format strings deliberately don't
    follow GCC diagnostic conventions.  */
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 8c46b260fff..845fd9557f3 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -279,6 +279,8 @@ static tree omp_start_variant_function
 static int omp_finish_variant_function
   (cp_parser *, tree, tree, tree, bool, bool);
 static void maybe_start_implicit_template (cp_parser *parser);
+static void missing_template_diag
+  (location_t, diagnostics::kind = diagnostics::kind::warning);
 
 /* Manifest constants.  */
 #define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token))
@@ -6182,7 +6184,9 @@ cp_parser_splice_specifier (cp_parser *parser, bool 
template_p = false,
       /* As a courtesy to the user, if there is a < after a template
         name, parse the construct as an s-s-s and warn about the missing
         'template'; it can't be anything else.  */
-      && (template_p || typename_p || TREE_CODE (expr) == TEMPLATE_DECL))
+      && (template_p
+         || typename_p
+         || TREE_CODE (OVL_FIRST (expr)) == TEMPLATE_DECL))
     {
       /* For member access splice-specialization-specifier, try to wrap
         non-dependent splice for function template into a BASELINK so
@@ -6251,7 +6255,11 @@ cp_parser_splice_type_specifier (cp_parser *parser)
   if (!valid_splice_type_p (type))
     {
       if (!cp_parser_simulate_error (parser))
-       error_at (loc, "reflection %qE not usable in a splice type", type);
+       {
+         auto_diagnostic_group d;
+         error_at (loc, "expected a reflection of a type");
+         inform_tree_category (loc, type);
+       }
       type = NULL_TREE;
     }
 
@@ -6312,63 +6320,42 @@ cp_parser_splice_expression (cp_parser *parser, bool 
template_p,
       return error_mark_node;
     }
 
+  /* Make sure this splice-expression produces an expression.  */
+  if (!check_splice_expr (loc, expr.get_start (), t, address_p,
+                         member_access_p, /*complain=*/true))
+    return error_mark_node;
+
   if (template_p)
     {
       /* [expr.prim.splice] For a splice-expression of the form template
         splice-specifier, the splice-specifier shall designate a function
         template.  */
-      if (!targs_p)
+      if (!targs_p
+         && !really_overloaded_fn (t)
+         && !dependent_splice_p (t))
        {
-         if (!really_overloaded_fn (t) && !dependent_splice_p (t))
-           {
-             auto_diagnostic_group d;
-             error_at (loc, "reflection %qE not usable in a template splice",
-                       t);
-             inform (loc, "only function templates are allowed here");
-             return error_mark_node;
-           }
+         auto_diagnostic_group d;
+         error_at (loc, "expected a reflection of a function template");
+         inform_tree_category (loc, t);
+         return error_mark_node;
        }
       /* [expr.prim.splice] For a splice-expression of the form
         template splice-specialization-specifier, the splice-specifier of the
-        splice-specialization-specifier shall designate a template.  */
-      else
-       {
-         if (really_overloaded_fn (t)
-             || get_template_info (t)
-             || TREE_CODE (t) == TEMPLATE_ID_EXPR)
-           /* OK */;
-         else
-           {
-             auto_diagnostic_group d;
-             error_at (loc, "reflection %qE not usable in a template splice",
-                       t);
-             inform (loc, "only templates are allowed here");
-             return error_mark_node;
-           }
-       }
+        splice-specialization-specifier shall designate a template.  Since
+        we would have already complained, just check that we have a template.  
*/
+      gcc_checking_assert (really_overloaded_fn (t)
+                          || get_template_info (t)
+                          || TREE_CODE (t) == TEMPLATE_ID_EXPR
+                          || dependent_splice_p (t));
     }
   else if (/* No 'template' but there were template arguments?  */
-          targs_p
-          /* No 'template' but the splice-specifier designates a template?  */
-          || really_overloaded_fn (t))
-    {
-      auto_diagnostic_group d;
-      if (targs_p)
-       error_at (loc, "reflection %qE not usable in a splice expression with "
-                 "template arguments", t);
-      else
-       error_at (loc, "reflection %qE not usable in a splice expression", t);
-      location_t sloc = expr.get_start ();
-      rich_location richloc (line_table, sloc);
-      richloc.add_fixit_insert_before (sloc, "template ");
-      inform (&richloc, "add %<template%> to denote a template");
-      return error_mark_node;
-    }
-
-  /* Make sure this splice-expression produces an expression.  */
-  if (!check_splice_expr (loc, expr.get_start (), t, address_p,
-                         member_access_p, /*complain=*/true))
-    return error_mark_node;
+          (targs_p
+           /* No 'template' but the splice-specifier designates a function
+              template?  */
+           || really_overloaded_fn (t))
+          && warning_enabled_at (loc, OPT_Wmissing_template_keyword))
+    /* Were 'template' present, this would be valid code, so keep going.  */
+    missing_template_diag (loc, diagnostics::kind::pedwarn);
 
   /* When doing foo.[: bar :], cp_parser_postfix_dot_deref_expression wants
      to see an identifier or a TEMPLATE_ID_EXPR, if we have something like
@@ -6470,13 +6457,9 @@ cp_parser_splice_scope_specifier (cp_parser *parser, 
bool typename_p,
   if (!valid_splice_scope_p (scope))
     {
       auto_diagnostic_group d;
-      error_at (loc, "reflection not usable in a splice scope");
-      if (TYPE_P (scope))
-       inform (loc, "%qT is not a class, namespace, or enumeration",
-               tree (scope));
-      else
-       inform (loc, "%qE is not a class, namespace, or enumeration",
-               tree (scope));
+      error_at (loc, "expected a reflection of a class, namespace, or "
+               "enumeration");
+      inform_tree_category (loc, tree (scope));
       scope = error_mark_node;
     }
 
@@ -7234,7 +7217,7 @@ cp_parser_primary_expression (cp_parser *parser,
 
 static void
 missing_template_diag (location_t loc,
-                      enum diagnostics::kind diag_kind = 
diagnostics::kind::warning)
+                      diagnostics::kind diag_kind/*=kind::warning*/)
 {
   if (warning_suppressed_at (loc, OPT_Wmissing_template_keyword))
     return;
diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index d04930d732c..e18e59090b8 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -8331,8 +8331,8 @@ check_splice_expr (location_t loc, location_t start_loc, 
tree t,
          if (TYPE_P (t))
            {
              auto_diagnostic_group d;
-             error_at (loc, "expected a reflection of an expression instead "
-                       "of type %qT", t);
+             error_at (loc, "expected a reflection of an expression");
+             inform_tree_category (loc, t);
              if (start_loc != UNKNOWN_LOCATION)
                {
                  rich_location richloc (line_table, start_loc);
@@ -8345,8 +8345,11 @@ check_splice_expr (location_t loc, location_t start_loc, 
tree t,
                        "a type-only context");
            }
          else
-           error_at (loc, "expected a reflection of an expression instead "
-                     "of %qD", t);
+           {
+             auto_diagnostic_group d;
+             error_at (loc, "expected a reflection of an expression");
+             inform_tree_category (loc, t);
+           }
        }
       return false;
     }
diff --git a/gcc/testsuite/g++.dg/reflect/crash10.C 
b/gcc/testsuite/g++.dg/reflect/crash10.C
index 05845846e23..8d3757d43c0 100644
--- a/gcc/testsuite/g++.dg/reflect/crash10.C
+++ b/gcc/testsuite/g++.dg/reflect/crash10.C
@@ -4,8 +4,10 @@
 struct S { };
 using X = S;
 
-template <auto V> constexpr int e = [:V:];  // { dg-error "expected a 
reflection of an expression instead of type .X." }
-template <auto V> constexpr int e2 = [:V:]; // { dg-error "expected a 
reflection of an expression instead of type .X." }
+template <auto V> constexpr int e = [:V:];  // { dg-error "expected a 
reflection of an expression" }
+// { dg-message "but .X. is a type" "" { target *-*-* } .-1 }
+template <auto V> constexpr int e2 = [:V:]; // { dg-error "expected a 
reflection of an expression" }
+// { dg-message "but .X. is a type" "" { target *-*-* } .-1 }
 constexpr auto h = ^^X;
 constexpr auto i = e<([:^^h:])>;
 constexpr auto j = e2<^^X>;
diff --git a/gcc/testsuite/g++.dg/reflect/crash2.C 
b/gcc/testsuite/g++.dg/reflect/crash2.C
index 83927fbdc7c..13c97f87456 100644
--- a/gcc/testsuite/g++.dg/reflect/crash2.C
+++ b/gcc/testsuite/g++.dg/reflect/crash2.C
@@ -13,8 +13,9 @@ void
 f ()
 {
   // Parsed as "S::tfn < S".
-  [: ^^T :]::tfn<[: ^^T :]>(); // { dg-error "expected 
primary-expression|expected a reflection of an expression instead of type .S." }
+  [: ^^T :]::tfn<[: ^^T :]>(); // { dg-error "expected 
primary-expression|expected a reflection of an expression" }
 // { dg-warning "expected .template. keyword" "" { target *-*-* } .-1 }
+// { dg-message "but .S. is a type" "" { target *-*-* } .-2 }
   int i = [: ^^T :]::var<int>; // { dg-error "missing|expected" }
 }
 
diff --git a/gcc/testsuite/g++.dg/reflect/crash3.C 
b/gcc/testsuite/g++.dg/reflect/crash3.C
index 51cf3d8b727..f2934fe98fc 100644
--- a/gcc/testsuite/g++.dg/reflect/crash3.C
+++ b/gcc/testsuite/g++.dg/reflect/crash3.C
@@ -1,8 +1,10 @@
 // { dg-do compile { target c++26 } }
 // { dg-additional-options "-freflection" }
 
-template <auto V> constexpr int e = [:V:];  // { dg-error "expected a 
reflection of an expression instead of type .int." }
-template <auto V> constexpr int e2 = [:V:]; // { dg-error "expected a 
reflection of an expression instead of type .int." }
+template <auto V> constexpr int e = [:V:];  // { dg-error "expected a 
reflection of an expression" }
+// { dg-message "but .int. is a type" "" { target *-*-* } .-1 }
+template <auto V> constexpr int e2 = [:V:]; // { dg-error "expected a 
reflection of an expression" }
+// { dg-message "but .int. is a type" "" { target *-*-* } .-1 }
 constexpr auto h = ^^int;
 constexpr auto i = e<([:^^h:])>;
 constexpr auto j = e2<^^int>;
diff --git a/gcc/testsuite/g++.dg/reflect/crash7.C 
b/gcc/testsuite/g++.dg/reflect/crash7.C
index 50905acc7a0..6ee687d4ab9 100644
--- a/gcc/testsuite/g++.dg/reflect/crash7.C
+++ b/gcc/testsuite/g++.dg/reflect/crash7.C
@@ -12,7 +12,8 @@ template<info R>
 void
 f ()
 {
-  int j = s.template [:R:]<int>; // { dg-error "expected a reflection of an 
expression instead of type .S." }
+  int j = s.template [:R:]<int>; // { dg-error "expected a reflection of an 
expression" }
+  // { dg-message "but .S. is a type" "" { target *-*-* } .-1 }
 }
 
 void
diff --git a/gcc/testsuite/g++.dg/reflect/crash9.C 
b/gcc/testsuite/g++.dg/reflect/crash9.C
index 1f8aff6a715..3c16991a40c 100644
--- a/gcc/testsuite/g++.dg/reflect/crash9.C
+++ b/gcc/testsuite/g++.dg/reflect/crash9.C
@@ -3,8 +3,10 @@
 
 namespace N { }
 
-template <auto V> constexpr int e = [:V:];  // { dg-error "expected a 
reflection of an expression instead of .N." }
-template <auto V> constexpr int e2 = [:V:]; // { dg-error "expected a 
reflection of an expression instead of .N." }
+template <auto V> constexpr int e = [:V:];  // { dg-error "expected a 
reflection of an expression" }
+// { dg-message "but .N. is a namespace" "" { target *-*-* } .-1 }
+template <auto V> constexpr int e2 = [:V:]; // { dg-error "expected a 
reflection of an expression" }
+// { dg-message "but .N. is a namespace" "" { target *-*-* } .-1 }
 constexpr auto h = ^^N;
 constexpr auto i = e<([:^^h:])>;
 constexpr auto j = e2<^^N>;
diff --git a/gcc/testsuite/g++.dg/reflect/dep5.C 
b/gcc/testsuite/g++.dg/reflect/dep5.C
index 4a118de1b70..e74abb95976 100644
--- a/gcc/testsuite/g++.dg/reflect/dep5.C
+++ b/gcc/testsuite/g++.dg/reflect/dep5.C
@@ -18,8 +18,10 @@ f ()
   static_assert ([: ^^T :]::x == 42);
   typename [: ^^T :]::type a = 42;
   [: ^^T :]::fn (42);
-  [: ^^T :]::template tfn<([: ^^T :])>();  // { dg-error "expected a 
reflection of an expression instead of type .S." }
-  auto x = [: ^^T :]::template var<([: ^^T :])>;  // { dg-error "expected a 
reflection of an expression instead of type .S." }
+  [: ^^T :]::template tfn<([: ^^T :])>();  // { dg-error "expected a 
reflection of an expression" }
+  // { dg-message "but .S. is a type" "" { target *-*-* } .-1 }
+  auto x = [: ^^T :]::template var<([: ^^T :])>;  // { dg-error "expected a 
reflection of an expression" }
+  // { dg-message "but .S. is a type" "" { target *-*-* } .-1 }
 }
 
 void
diff --git a/gcc/testsuite/g++.dg/reflect/diag1.C 
b/gcc/testsuite/g++.dg/reflect/diag1.C
index 2d34623a8ac..537929decb7 100644
--- a/gcc/testsuite/g++.dg/reflect/diag1.C
+++ b/gcc/testsuite/g++.dg/reflect/diag1.C
@@ -14,12 +14,10 @@ void
 f ()
 {
   S s;
-  s.[: ^^S::tfn :](42); // { dg-error "reflection .S::tfn. not usable in a 
splice expression" }
-// { dg-message "add .template. to denote a template" "" { target *-*-* } .-1 }
+  s.[: ^^S::tfn :](42); // { dg-error "expected 'template' keyword before 
dependent template name" }
   s.template [: ^^S::tfn :](42);
 
   constexpr auto r = ^^fortytwo;
-  constexpr int i1 = [:r:]<int>; // { dg-error "reflection .fortytwo<int>. not 
usable in a splice expression with template arguments" }
-// { dg-message "add .template. to denote a template" "" { target *-*-* } .-1 }
+  constexpr int i1 = [:r:]<int>; // { dg-error "expected 'template' keyword 
before dependent template name" }
   constexpr int i2 = template [:r:]<int>;
 }
diff --git a/gcc/testsuite/g++.dg/reflect/diag1a.C 
b/gcc/testsuite/g++.dg/reflect/diag1a.C
new file mode 100644
index 00000000000..d276a7d22f4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/diag1a.C
@@ -0,0 +1,24 @@
+// { dg-do compile { target c++26 } }
+// { dg-options "" }
+// { dg-additional-options "-freflection" }
+// Test that we offer some helpful diagnostic.
+
+struct S {
+  template<typename T>
+  void tfn (T) { }
+};
+
+template<typename T>
+constexpr T fortytwo = 42;
+
+void
+f ()
+{
+  S s;
+  s.[: ^^S::tfn :](42); // { dg-warning "expected 'template' keyword before 
dependent template name" }
+  s.template [: ^^S::tfn :](42);
+
+  constexpr auto r = ^^fortytwo;
+  constexpr int i1 = [:r:]<int>; // { dg-warning "expected 'template' keyword 
before dependent template name" }
+  constexpr int i2 = template [:r:]<int>;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/diag1b.C 
b/gcc/testsuite/g++.dg/reflect/diag1b.C
new file mode 100644
index 00000000000..b2c9bade331
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/diag1b.C
@@ -0,0 +1,23 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection -Wno-missing-template-keyword" }
+// Test that we offer some helpful diagnostic.
+
+struct S {
+  template<typename T>
+  void tfn (T) { }
+};
+
+template<typename T>
+constexpr T fortytwo = 42;
+
+void
+f ()
+{
+  S s;
+  s.[: ^^S::tfn :](42); // { dg-bogus "expected 'template' keyword before 
dependent template name" }
+  s.template [: ^^S::tfn :](42);
+
+  constexpr auto r = ^^fortytwo;
+  constexpr int i1 = [:r:]<int>; // { dg-bogus "expected 'template' keyword 
before dependent template name" }
+  constexpr int i2 = template [:r:]<int>;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/error10.C 
b/gcc/testsuite/g++.dg/reflect/error10.C
index 2ca2b18a1fa..3eb949d5255 100644
--- a/gcc/testsuite/g++.dg/reflect/error10.C
+++ b/gcc/testsuite/g++.dg/reflect/error10.C
@@ -4,29 +4,34 @@
 int g;
 
 void
-fn0 (int, typename [: ^^:: :] i) // { dg-error "reflection .::. not usable in 
a splice type|declared" }
+fn0 (int, typename [: ^^:: :] i) // { dg-error "expected a reflection of a 
type|declared" }
+// { dg-message "but .::. is a namespace" "" { target *-*-* } .-1 }
 {
 }
 
 void
-fn1 (int, typename [: ^^g :] i) // { dg-error "reflection .g. not usable in a 
splice type|declared" }
+fn1 (int, typename [: ^^g :] i) // { dg-error "expected a reflection of a 
type|declared" }
+// { dg-message "but .g. is a variable" "" { target *-*-* } .-1 }
 {
 }
 
 void
-fn2 (int, typename [: ^^fn1 :] i) // { dg-error "reflection .fn1. not usable 
in a splice type|declared" }
+fn2 (int, typename [: ^^fn1 :] i) // { dg-error "expected a reflection of a 
type|declared" }
+// { dg-message "but .fn1. is a function" "" { target *-*-* } .-1 }
 {
 }
 
 void
-fn3 (int p, typename [: ^^p :] i) // { dg-error "reflection .p. not usable in 
a splice type|declared" }
+fn3 (int p, typename [: ^^p :] i) // { dg-error "expected a reflection of a 
type|declared" }
+// { dg-message "but .p. is a parameter" "" { target *-*-* } .-1 }
 {
 }
 
 enum Harold { Budd };
 
 void
-fn4 (int, typename [: ^^Budd :] i) // { dg-error "reflection .Budd. not usable 
in a splice type|declared" }
+fn4 (int, typename [: ^^Budd :] i) // { dg-error "expected a reflection of a 
type|declared" }
+// { dg-message "but .Budd. is an enumerator" "" { target *-*-* } .-1 }
 {
 }
 
@@ -34,6 +39,16 @@ template<int>
 struct S {};
 
 void
-fn5 (int, typename [: ^^S :] i) // { dg-error "reflection .S. not usable in a 
splice type|declared" }
+fn5 (int, typename [: ^^S :] i) // { dg-error "expected a reflection of a 
type|declared" }
+// { dg-message "but .S. is a class template" "" { target *-*-* } .-1 }
+{
+}
+
+template<int>
+void bar ();
+
+void
+fn6 (int, typename [: ^^bar :] i) // { dg-error "expected a reflection of a 
type|declared" }
+// { dg-message "but .bar. is a function template" "" { target *-*-* } .-1 }
 {
 }
diff --git a/gcc/testsuite/g++.dg/reflect/error12.C 
b/gcc/testsuite/g++.dg/reflect/error12.C
index 7eb787f010d..718bdee5cd3 100644
--- a/gcc/testsuite/g++.dg/reflect/error12.C
+++ b/gcc/testsuite/g++.dg/reflect/error12.C
@@ -7,16 +7,26 @@ constexpr auto r = ^^i;
 constexpr bool b0 = template [:r:] < 0 > 0;  // { dg-error "not a template" }
 constexpr bool b1 = template [:r:] < 0 < 0;  // { dg-error "not a 
template|expected" }
 constexpr bool b2 = template [:r:] < 43;     // { dg-error "not a 
template|expected" }
-constexpr bool b3 = template [:r:] <= 43;    // { dg-error "template splice" }
-constexpr bool b4 = template [:r:] > 41;     // { dg-error "template splice" }
-constexpr bool b5 = template [:r:] >= 41;    // { dg-error "template splice" }
-constexpr bool b6 = template [:r:] == 42;    // { dg-error "template splice" }
-constexpr bool b7 = template [:r:] != 41;    // { dg-error "template splice" }
+constexpr bool b3 = template [:r:] <= 43;    // { dg-error "expected a 
reflection of a function template" }
+// { dg-message "but .i. is a variable" "" { target *-*-* } .-1 }
+constexpr bool b4 = template [:r:] > 41;     // { dg-error "expected a 
reflection of a function template" }
+// { dg-message "but .i. is a variable" "" { target *-*-* } .-1 }
+constexpr bool b5 = template [:r:] >= 41;    // { dg-error "expected a 
reflection of a function template" }
+// { dg-message "but .i. is a variable" "" { target *-*-* } .-1 }
+constexpr bool b6 = template [:r:] == 42;    // { dg-error "expected a 
reflection of a function template" }
+// { dg-message "but .i. is a variable" "" { target *-*-* } .-1 }
+constexpr bool b7 = template [:r:] != 41;    // { dg-error "expected a 
reflection of a function template" }
+// { dg-message "but .i. is a variable" "" { target *-*-* } .-1 }
 
 template<bool> struct S { };
 S<template [:r:] < 43> s1;    // { dg-error "not a template|invalid" }
-S<template [:r:] <= 43> s2;   // { dg-error "template splice|invalid" }
-S<(template [:r:] > 41)> s3;  // { dg-error "template splice|invalid" }
-S<template [:r:] >= 41> s4;   // { dg-error "template splice|invalid" }
-S<template [:r:] == 42> s5;   // { dg-error "template splice|invalid" }
-S<template[:r:] != 41> s6;    // { dg-error "template splice|invalid" }
+S<template [:r:] <= 43> s2;   // { dg-error "expected a reflection|invalid" }
+// { dg-message "but .i. is a variable" "" { target *-*-* } .-1 }
+S<(template [:r:] > 41)> s3;  // { dg-error "expected a reflection|invalid" }
+// { dg-message "but .i. is a variable" "" { target *-*-* } .-1 }
+S<template [:r:] >= 41> s4;   // { dg-error "expected a reflection|invalid" }
+// { dg-message "but .i. is a variable" "" { target *-*-* } .-1 }
+S<template [:r:] == 42> s5;   // { dg-error "expected a reflection|invalid" }
+// { dg-message "but .i. is a variable" "" { target *-*-* } .-1 }
+S<template[:r:] != 41> s6;    // { dg-error "expected a reflection|invalid" }
+// { dg-message "but .i. is a variable" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/reflect/error5.C 
b/gcc/testsuite/g++.dg/reflect/error5.C
index 2b125fffc1a..f1ac001283a 100644
--- a/gcc/testsuite/g++.dg/reflect/error5.C
+++ b/gcc/testsuite/g++.dg/reflect/error5.C
@@ -9,7 +9,8 @@ template<info R>
 void
 f ()
 {
-  int i = [:R:]; // { dg-error "expected a reflection of an expression instead 
of .N." }
+  int i = [:R:]; // { dg-error "expected a reflection of an expression" }
+  // { dg-message "but .N. is a namespace" "" { target *-*-* } .-1 }
 }
 
 void
diff --git a/gcc/testsuite/g++.dg/reflect/expr3.C 
b/gcc/testsuite/g++.dg/reflect/expr3.C
index de7cffe1a56..a1567174d40 100644
--- a/gcc/testsuite/g++.dg/reflect/expr3.C
+++ b/gcc/testsuite/g++.dg/reflect/expr3.C
@@ -24,28 +24,37 @@ void
 g ()
 {
   int i1 = [: ^^x :];
-  int i2 = template [: ^^x :];    // { dg-error "reflection .x. not usable in 
a template splice" }
+  int i2 = template [: ^^x :];    // { dg-error "expected a reflection of a 
function template" }
+  // { dg-message "but .x. is a variable" "" { target *-*-* } .-1 }
   int i3 = [: ^^two<int> :];
-  int i4 = template [: ^^two<int> :]; // { dg-error "reflection .two<int>. not 
usable in a template splice" }
-  int i5 = [: ^^foo :](42);          // { dg-error "reflection .foo. not 
usable in a splice expression" }
+  int i4 = template [: ^^two<int> :]; // { dg-error "expected a reflection of 
a function template" }
+  // { dg-message "but .two<int>. is a variable" "" { target *-*-* } .-1 }
+  int i5 = [: ^^foo :](42);          // { dg-error "expected 'template' 
keyword before dependent template name" }
   int i6 = template [: ^^foo :](42);
   int i7 = [: ^^foo<int> :](42);
-  int i8 = template [: ^^foo<int> :](42);   // { dg-error "reflection 
.foo<int>. not usable in a template splice" }
-  int i9 = [: ^^foo :]<int>(42);           // { dg-error "reflection .foo. not 
usable in a splice expression|expected" }
+  int i8 = template [: ^^foo<int> :](42);   // { dg-error "expected a 
reflection of a function template" }
+  // { dg-message "but .foo<int>. is a function" "" { target *-*-* } .-1 }
+  int i9 = [: ^^foo :]<int>(42);           // { dg-error "expected .template. 
keyword before dependent template name" }
   int i10 = template [: ^^foo :]<int>(42);
   int i11 = template [: ^^bar :]<int>(42);  // { dg-error "no matching 
function for call" }
-  int i12 = [: ^^two :]<int>;              // { dg-error "reflection 
.two<int>. not usable in a splice expression with template arguments" }
+  int i12 = [: ^^two :]<int>;              // { dg-error "expected 'template' 
keyword before dependent template name" }
   int i13 = template [: ^^two :]<int>;
 
-  [: ^^ST :]<int> c1;  // { dg-error "reflection .ST<int>. not usable in a 
splice expression with template arguments" }
+  [: ^^ST :]<int> c1;  // { dg-error "expected a reflection of an expression" }
+  // { dg-message "but .ST<int>. is a type" "" { target *-*-* } .-1 }
   typename [: ^^ST :]<int> c2;
   template [: ^^ST :]<int> c3;  // { dg-error "expected a reflection of an 
expression" }
+  // { dg-message "but .ST<int>. is a type" "" { target *-*-* } .-1 }
   [: ^^S :]<int> c4;   // { dg-error "expected a reflection of an 
expression|expected primary-expression" }
+  // { dg-message "but .S. is a type" "" { target *-*-* } .-1 }
+  // { dg-message "add .typename. to denote a type outside a type-only 
context" "" { target *-*-* } .-2 }
   template [: ^^S :]<int> c5;   // { dg-error ".S. is not a template" }
   typename [: ^^S :]<int> c6;   // { dg-error ".S. is not a template|expected" 
}
   [: ^^bar :]<int>();  // { dg-error "expected" }
 
-  auto x1 = [: ^^ST :]<int>{};   // { dg-error "reflection .ST<int>. not 
usable in a splice expression with template arguments" }
+  auto x1 = [: ^^ST :]<int>{};   // { dg-error "expected a reflection of an 
expression" }
+  // { dg-message "but .ST<int>. is a type" "" { target *-*-* } .-1 }
   auto x2 = template [: ^^ST :]<int>{};        // { dg-error "expected a 
reflection of an expression" }
+  // { dg-message "but .ST<int>. is a type" "" { target *-*-* } .-1 }
   auto x3 = typename [: ^^ST :]<int>{};
 }
diff --git a/gcc/testsuite/g++.dg/reflect/member1.C 
b/gcc/testsuite/g++.dg/reflect/member1.C
index e9d9a64d0eb..5566b20ef29 100644
--- a/gcc/testsuite/g++.dg/reflect/member1.C
+++ b/gcc/testsuite/g++.dg/reflect/member1.C
@@ -55,9 +55,9 @@ f ()
   sp->template [: ^^S::tfn :](42);
   s.template [: ^^S::tfn :]<int>(42);
   sp->template [: ^^S::tfn :]<int>(42);
-  s.[: ^^S::var :]<int> = 1; // { dg-error "reflection .var<int>. not usable 
in a splice expression with template arguments" }
+  s.[: ^^S::var :]<int> = 1; // { dg-error "expected 'template' keyword before 
dependent template name" }
   s.template [: ^^S::var :]<int> = 1;
-  sp->[: ^^S::var :]<int> = 1; // { dg-error "reflection .var<int>. not usable 
in a splice expression with template arguments" }
+  sp->[: ^^S::var :]<int> = 1; // { dg-error "expected 'template' keyword 
before dependent template name" }
   sp->template [: ^^S::var :]<int> = 1;
   s.[: ^^S::b :].[: ^^B::a :].val;
   sp->[: ^^S::b :].[: ^^B::a :].val;
@@ -74,9 +74,9 @@ f ()
   cp->template [: ^^C<int>::tfn :](42);
   c.template [: ^^C<int>::tfn :]<int>(42);
   cp->template [: ^^C<int>::tfn :]<int>(42);
-  c.[: ^^C<int>::var :]<int> = 1; // { dg-error "reflection .var<int>. not 
usable in a splice expression with template arguments" }
+  c.[: ^^C<int>::var :]<int> = 1; // { dg-error "expected 'template' keyword 
before dependent template name" }
   c.template [: ^^C<int>::var :]<int> = 1;
-  cp->[: ^^C<int>::var :]<int> = 1; // { dg-error "reflection .var<int>. not 
usable in a splice expression with template arguments" }
+  cp->[: ^^C<int>::var :]<int> = 1; // { dg-error "expected 'template' keyword 
before dependent template name" }
   cp->template [: ^^C<int>::var :]<int> = 1;
   c.[: ^^C<int>::b :].[: ^^B::a :].val;
   cp->[: ^^C<int>::b :].[: ^^B::a :].val;
@@ -92,8 +92,10 @@ f ()
   sp.[: ^^S::x :] = 2; // { dg-error "which is of pointer type" }
   c.[: ^^C<char>::x :] = 1; // { dg-error "is not a base of" }
   cp->[: ^^C<char>::x :] = 1; // { dg-error "is not a base of" }
-  s.template [: ^^S::N :].t;  // { dg-error "reflection .S::N. not usable in a 
template splice" }
+  s.template [: ^^S::N :].t;  // { dg-error "expected a reflection of a 
function template" }
+  // { dg-message "but .S::N. is a class template" "" { target *-*-* } .-1 }
   S::template [: ^^S::N<int> :] e1;  // { dg-error "expected unqualified-id" }
   C<int>::template [: ^^S::N<int> :] e2;  // { dg-error "expected 
unqualified-id" }
-  s.template [: ^^S::var<int> :] = 1;  // { dg-error "reflection .S::var<int>. 
not usable in a template splice" }
+  s.template [: ^^S::var<int> :] = 1;  // { dg-error "expected a reflection of 
a function template" }
+  // { dg-message "but .S::var<int>. is a variable" "" { target *-*-* } .-1 }
 }
diff --git a/gcc/testsuite/g++.dg/reflect/ns2.C 
b/gcc/testsuite/g++.dg/reflect/ns2.C
index 482b8754713..6611c26aa39 100644
--- a/gcc/testsuite/g++.dg/reflect/ns2.C
+++ b/gcc/testsuite/g++.dg/reflect/ns2.C
@@ -3,19 +3,37 @@
 // Test reflections on namespaces.  Invalid stuff.
 
 void foo (int);
+int i;
+enum E { EE };
+template<typename>
+struct S { };
+template<typename>
+void bar ();
 
 namespace N {
 }
 
 void
-f1 ()
+f1 (int p)
 {
   constexpr auto r = ^^::;
   [: r :] foo (0); // { dg-error "expected" }
 
   constexpr auto q = ^^int;
-  [: q :]::T x; // { dg-error "reflection not usable in a splice 
scope|expected" }
-  // { dg-message ".int. is not a class, namespace, or enumeration" "" { 
target *-*-* } .-1 }
+  [: q :]::T x; // { dg-error "expected a reflection of a class, namespace, or 
enumeration|expected" }
+  // { dg-message "but .int. is a type" "" { target *-*-* } .-1 }
+  [: ^^foo :]::X; // { dg-error "expected a reflection of a class, namespace, 
or enumeration" }
+  // { dg-message "but .foo. is a function" "" { target *-*-* } .-1 }
+  [: ^^EE :]::Y;  // { dg-error "expected a reflection of a class, namespace, 
or enumeration" }
+  // { dg-message "but .EE. is an enumerator" "" { target *-*-* } .-1 }
+  [: ^^S :]::Z;          // { dg-error "expected a reflection of a class, 
namespace, or enumeration" }
+  // { dg-message "but .S. is a class template" "" { target *-*-* } .-1 }
+  [: ^^bar :]::W; // { dg-error "expected a reflection of a class, namespace, 
or enumeration" }
+  // { dg-message "but .bar. is a function template" "" { target *-*-* } .-1 }
+  [: ^^i :]::U;          // { dg-error "expected a reflection of a class, 
namespace, or enumeration" }
+  // { dg-message "but .i. is a variable" "" { target *-*-* } .-1 }
+  [: ^^p :]::V;          // { dg-error "expected a reflection of a class, 
namespace, or enumeration" }
+  // { dg-message "but .p. is a parameter" "" { target *-*-* } .-1 }
 
   constexpr auto x = ^^N::X;  // { dg-error ".N::X. has not been declared" }
 }
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-12.C 
b/gcc/testsuite/g++.dg/reflect/p2996-12.C
index 58a145693f4..c70c1b8ca63 100644
--- a/gcc/testsuite/g++.dg/reflect/p2996-12.C
+++ b/gcc/testsuite/g++.dg/reflect/p2996-12.C
@@ -15,7 +15,8 @@ using alias = [:^^TCls:]<([:^^v:])>;
 static_assert(alias::s == 2);
 
 // error: < means less than
-auto o1 = [:^^TCls:]<([:^^v:])>();  // { dg-error "reflection .TCls<1>. not 
usable" }
+auto o1 = [:^^TCls:]<([:^^v:])>();  // { dg-error "expected a reflection of an 
expression" }
+// { dg-message "but .TCls<1>. is a type" "" { target *-*-* } .-1 }
 // OK, o2 is an object of type TCls<1>
 auto o2 = typename [:^^TCls:]<([:^^v:])>();
 
diff --git a/gcc/testsuite/g++.dg/reflect/splice5.C 
b/gcc/testsuite/g++.dg/reflect/splice5.C
index 78144863337..5f4a52ecccf 100644
--- a/gcc/testsuite/g++.dg/reflect/splice5.C
+++ b/gcc/testsuite/g++.dg/reflect/splice5.C
@@ -13,10 +13,12 @@ struct S {
 void
 baz (S &s)
 {
-  template [: ^^foo :] (0);                    // { dg-error "reflection 'foo' 
not usable in a template splice" }
-  template [: ^^bar :] (0);                    // { dg-message "only function 
templates are allowed here" "" { target *-*-* } .-1 }
-  s.template [: ^^S::foo :] (0);               // { dg-error "reflection 
'S::foo' not usable in a template splice" }
-  s.template [: ^^S::bar :] (0);               // { dg-message "only function 
templates are allowed here" "" { target *-*-* } .-1 }
+  template [: ^^foo :] (0);                    // { dg-error "expected a 
reflection of a function template" }
+  // { dg-message "but .foo. is a function" "" { target *-*-* } .-1 }
+  template [: ^^bar :] (0);
+  s.template [: ^^S::foo :] (0);               // { dg-error "expected a 
reflection of a function template" }
+  // { dg-message "but .S::foo. is a function" "" { target *-*-* } .-1 }
+  s.template [: ^^S::bar :] (0);
 }
 
 template <int N>

base-commit: 62a9146a0e872dc00be654581a9cc38ea8d47481
-- 
2.53.0

Reply via email to