https://gcc.gnu.org/g:68957163b8853996b09b86fee700359681e78c70
commit r16-7503-g68957163b8853996b09b86fee700359681e78c70 Author: Marek Polacek <[email protected]> Date: Tue Feb 10 13:24:44 2026 -0500 c++/reflection: various diagnostic tweaks 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. Reviewed-by: Jason Merrill <[email protected]> Diff: --- gcc/cp/cp-tree.h | 1 + gcc/cp/error.cc | 36 +++++++++++++ gcc/cp/parser.cc | 95 ++++++++++++++------------------- gcc/cp/reflect.cc | 11 ++-- gcc/testsuite/g++.dg/reflect/crash10.C | 5 +- 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 | 5 +- gcc/testsuite/g++.dg/reflect/dep5.C | 5 +- 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 | 21 ++++---- gcc/testsuite/g++.dg/reflect/error5.C | 3 +- gcc/testsuite/g++.dg/reflect/expr3.C | 22 +++++--- gcc/testsuite/g++.dg/reflect/member1.C | 14 ++--- gcc/testsuite/g++.dg/reflect/ns2.C | 32 +++++++++-- gcc/testsuite/g++.dg/reflect/p2996-12.C | 3 +- gcc/testsuite/g++.dg/reflect/splice5.C | 10 ++-- 21 files changed, 241 insertions(+), 114 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 984113170640..a0683110eb3d 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 (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 c184846066e0..e64da242152e 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -3976,6 +3976,42 @@ 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 (tree t) +{ + const location_t loc = location_of (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 (DECL_DECOMPOSITION_P (t) && !DECL_DECOMP_IS_BASE (t)) + inform (loc, "but %qE is a structured binding", 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); +} + /* 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 97f2ddd62b31..a40e913893ad 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)) @@ -6183,7 +6185,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 @@ -6252,7 +6256,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 (type); + } type = NULL_TREE; } @@ -6313,63 +6321,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 (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 @@ -6471,13 +6458,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 (tree (scope)); scope = error_mark_node; } @@ -7235,7 +7218,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 825f68e179f1..367905f5c0bb 100644 --- a/gcc/cp/reflect.cc +++ b/gcc/cp/reflect.cc @@ -8338,8 +8338,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 (t); if (start_loc != UNKNOWN_LOCATION) { rich_location richloc (line_table, start_loc); @@ -8352,8 +8352,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 (t); + } } return false; } diff --git a/gcc/testsuite/g++.dg/reflect/crash10.C b/gcc/testsuite/g++.dg/reflect/crash10.C index 05845846e235..dddf1e625441 100644 --- a/gcc/testsuite/g++.dg/reflect/crash10.C +++ b/gcc/testsuite/g++.dg/reflect/crash10.C @@ -4,8 +4,9 @@ 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 *-*-* } 4 } +template <auto V> constexpr int e2 = [:V:]; // { dg-error "expected a reflection of an expression" } 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 83927fbdc7c0..879c2145b973 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 *-*-* } 4 } 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 51cf3d8b7279..f2934fe98fc9 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 50905acc7a09..c122ba2066cb 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 *-*-* } 6 } } void diff --git a/gcc/testsuite/g++.dg/reflect/crash9.C b/gcc/testsuite/g++.dg/reflect/crash9.C index 1f8aff6a715e..eaf3214ec1eb 100644 --- a/gcc/testsuite/g++.dg/reflect/crash9.C +++ b/gcc/testsuite/g++.dg/reflect/crash9.C @@ -3,8 +3,9 @@ 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 *-*-* } 4 } +template <auto V> constexpr int e2 = [:V:]; // { dg-error "expected a reflection of an expression" } 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 4a118de1b70d..3a04cbd58dd6 100644 --- a/gcc/testsuite/g++.dg/reflect/dep5.C +++ b/gcc/testsuite/g++.dg/reflect/dep5.C @@ -18,8 +18,9 @@ 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 *-*-* } 4 } + auto x = [: ^^T :]::template var<([: ^^T :])>; // { dg-error "expected a reflection of an expression" } } void diff --git a/gcc/testsuite/g++.dg/reflect/diag1.C b/gcc/testsuite/g++.dg/reflect/diag1.C index 2d34623a8ac4..537929decb75 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 000000000000..d276a7d22f45 --- /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 000000000000..b2c9bade3316 --- /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 2ca2b18a1fa4..891a643c1a0a 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 *-*-* } 0 } { } 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 *-*-* } 4 } { } 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 *-*-* } 13 } { } 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 *-*-* } 25 } { } 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 *-*-* } 30 } { } @@ -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 *-*-* } 39 } +{ +} + +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 *-*-* } 48 } { } diff --git a/gcc/testsuite/g++.dg/reflect/error12.C b/gcc/testsuite/g++.dg/reflect/error12.C index 7eb787f010d6..8f39b7f74a77 100644 --- a/gcc/testsuite/g++.dg/reflect/error12.C +++ b/gcc/testsuite/g++.dg/reflect/error12.C @@ -7,16 +7,17 @@ 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 *-*-* } 5 } +constexpr bool b4 = template [:r:] > 41; // { dg-error "expected a reflection of a function template" } +constexpr bool b5 = template [:r:] >= 41; // { dg-error "expected a reflection of a function template" } +constexpr bool b6 = template [:r:] == 42; // { dg-error "expected a reflection of a function template" } +constexpr bool b7 = template [:r:] != 41; // { dg-error "expected a reflection of a function template" } 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" } +S<(template [:r:] > 41)> s3; // { dg-error "expected a reflection|invalid" } +S<template [:r:] >= 41> s4; // { dg-error "expected a reflection|invalid" } +S<template [:r:] == 42> s5; // { dg-error "expected a reflection|invalid" } +S<template[:r:] != 41> s6; // { dg-error "expected a reflection|invalid" } diff --git a/gcc/testsuite/g++.dg/reflect/error5.C b/gcc/testsuite/g++.dg/reflect/error5.C index 2b125fffc1a9..e27bf8df6c4a 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 *-*-* } 6 } } void diff --git a/gcc/testsuite/g++.dg/reflect/expr3.C b/gcc/testsuite/g++.dg/reflect/expr3.C index de7cffe1a562..09b970e56e13 100644 --- a/gcc/testsuite/g++.dg/reflect/expr3.C +++ b/gcc/testsuite/g++.dg/reflect/expr3.C @@ -24,28 +24,34 @@ 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 *-*-* } 4 } 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 *-*-* } 6 } + 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 *-*-* } 9 } + 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 *-*-* } 16 } typename [: ^^ST :]<int> c2; template [: ^^ST :]<int> c3; // { dg-error "expected a reflection of an expression" } [: ^^S :]<int> c4; // { dg-error "expected a reflection of an expression|expected primary-expression" } + // { dg-message "but .S. is a type" "" { target *-*-* } 13 } + // { 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" } auto x2 = template [: ^^ST :]<int>{}; // { dg-error "expected a reflection of an expression" } auto x3 = typename [: ^^ST :]<int>{}; } diff --git a/gcc/testsuite/g++.dg/reflect/member1.C b/gcc/testsuite/g++.dg/reflect/member1.C index e9d9a64d0eb3..cecb4a4204d9 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 *-*-* } 20 } 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 *-*-* } 22 } } diff --git a/gcc/testsuite/g++.dg/reflect/ns2.C b/gcc/testsuite/g++.dg/reflect/ns2.C index 482b87547136..feff62406eab 100644 --- a/gcc/testsuite/g++.dg/reflect/ns2.C +++ b/gcc/testsuite/g++.dg/reflect/ns2.C @@ -3,19 +3,43 @@ // Test reflections on namespaces. Invalid stuff. void foo (int); +int i; +enum E { EE }; +template<typename> +struct S { int i, j, k; }; +template<typename> +void bar (); namespace N { } void -f1 () +f1 (int p) { constexpr auto r = ^^::; - [: r :] foo (0); // { dg-error "expected" } + [: r :] foo (0); // { dg-error "expected a reflection of an expression" } + // { dg-message "but .::. is a namespace" "" { target *-*-* } 0 } 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 *-*-* } 5 } + [: ^^EE :]::Y; // { dg-error "expected a reflection of a class, namespace, or enumeration" } + // { dg-message "but .EE. is an enumerator" "" { target *-*-* } 7 } + [: ^^S :]::Z; // { dg-error "expected a reflection of a class, namespace, or enumeration" } + // { dg-message "but .S. is a class template" "" { target *-*-* } 9 } + [: ^^bar :]::W; // { dg-error "expected a reflection of a class, namespace, or enumeration" } + // { dg-message "but .bar. is a function template" "" { target *-*-* } 11 } + [: ^^i :]::U; // { dg-error "expected a reflection of a class, namespace, or enumeration" } + // { dg-message "but .i. is a variable" "" { target *-*-* } 6 } + [: ^^p :]::V; // { dg-error "expected a reflection of a class, namespace, or enumeration" } + // { dg-message "but .p. is a parameter" "" { target *-*-* } 17 } + auto [a, b, c] = S<int>{1, 2, 3}; + [: ^^a :]::G; // { dg-error "expected a reflection of a class, namespace, or enumeration" } + // { dg-message "but .a. is a structured binding" "" { target *-*-* } 38 } + [: ^^S<int>::i :]::H; // { dg-error "expected a reflection of a class, namespace, or enumeration" } + // { dg-message "but .S<int>::i. is a data member" "" { target *-*-* } 9 } 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 58a145693f41..f3aa3a1bd1c5 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 *-*-* } 8 } // 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 781448633376..4f0d2fe61341 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 *-*-* } 4 } + 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 *-*-* } 8 } + s.template [: ^^S::bar :] (0); } template <int N>
