On 2/12/26 7:33 AM, Marek Polacek wrote:
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);

How about using location_of (t) for these informs since the error was already at loc?

+  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);
+}

Reply via email to