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