gcc - GNU Compiler Collection (original) (raw)
| author | Marek Polacek polacek@redhat.com | 2026-03-20 12:34:31 -0400 |
|---|---|---|
| committer | Marek Polacek polacek@redhat.com | 2026-04-09 14:22:13 -0400 |
| commit | c684613dea0b00d222ebbae8439ea8fd8c1f1865 (patch) | |
| tree | da7d4c8f95e4072d59c40dbd7e93cd2971c775b5 | |
| parent | fortran: Diagnose invalid array initializer after parameter substitution [PR1... (diff) |
c++/reflection: reject invalid template splice [PR123998]HEADtrunkmaster
When we have "template [:R:]" without template arguments, the splice has to designate a function template. E.g., void foo (int); template [: ^^foo :] (0); // invalid We check this in cp_parser_splice_expression. But when the splice is dependent, we don't check it when instantiating, thus missing the error in template [: N == 0 ? ^^foo : ^^:: :] (0); This patch introduces SPLICE_EXPR_TEMPLATE_P and SPLICE_EXPR_TARGS_P, and moves the checking into check_splice_expr. It also adds a missing check for DECL_TYPE_TEMPLATE_P in case we have a splice-expression of the form template splice-specialization-specifier. PR c++/123998 gcc/cp/ChangeLog: * cp-tree.h (SPLICE_EXPR_TEMPLATE_P): Define. (SET_SPLICE_EXPR_TEMPLATE_P): Define. (SPLICE_EXPR_TARGS_P): Define. (SET_SPLICE_EXPR_TARGS_P): Define. (check_splice_expr): Adjust. * parser.cc (cp_parser_splice_expression): Do SET_SPLICE_EXPR_TEMPLATE_P and SET_SPLICE_EXPR_TARGS_P. Adjust the call to check_splice_expr. Move the template_p checking into check_splice_expr. * pt.cc (tsubst_splice_expr): Do SET_SPLICE_EXPR_TEMPLATE_P and SET_SPLICE_EXPR_TARGS_P. Adjust the call to check_splice_expr. * reflect.cc (eval_constant_of): Adjust the call to check_splice_expr. (check_splice_expr): Two new bool parameters. Add the template_p checking from cp_parser_splice_expression. Allow variable_template_p in the assert. Add a check for DECL_TYPE_TEMPLATE_P. gcc/testsuite/ChangeLog: * g++.dg/reflect/crash11.C: Adjust dg-error. * g++.dg/reflect/splice5.C: Likewise. Reviewed-by: Jason Merrill jason@redhat.com
| -rw-r--r-- | gcc/cp/cp-tree.h | 24 |
|---|---|---|
| -rw-r--r-- | gcc/cp/parser.cc | 41 |
| -rw-r--r-- | gcc/cp/pt.cc | 6 |
| -rw-r--r-- | gcc/cp/reflect.cc | 53 |
| -rw-r--r-- | gcc/testsuite/g++.dg/reflect/crash11.C | 4 |
| -rw-r--r-- | gcc/testsuite/g++.dg/reflect/splice5.C | 7 |
6 files changed, 93 insertions, 42 deletions
| diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.hindex 1ea3319c37b8..1080203ac8a4 100644--- a/gcc/cp/cp-tree.h+++ b/gcc/cp/cp-tree.h | |||
|---|---|---|---|
| @@ -522,6 +522,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; | |||
| 522 | TARGET_EXPR_ELIDING_P (in TARGET_EXPR) | 522 | TARGET_EXPR_ELIDING_P (in TARGET_EXPR) |
| 523 | IF_STMT_VACUOUS_INIT_P (IF_STMT) | 523 | IF_STMT_VACUOUS_INIT_P (IF_STMT) |
| 524 | TYPENAME_IS_RESOLVING_P (in TYPENAME_TYPE) | 524 | TYPENAME_IS_RESOLVING_P (in TYPENAME_TYPE) |
| 525 | SPLICE_EXPR_TEMPLATE_P (in SPLICE_EXPR) | ||
| 525 | 4: IDENTIFIER_MARKED (IDENTIFIER_NODEs) | 526 | 4: IDENTIFIER_MARKED (IDENTIFIER_NODEs) |
| 526 | TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR, | 527 | TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR, |
| 527 | CALL_EXPR, or FIELD_DECL). | 528 | CALL_EXPR, or FIELD_DECL). |
| @@ -533,6 +534,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; | |||
| 533 | TARGET_EXPR_INTERNAL_P (in TARGET_EXPR) | 534 | TARGET_EXPR_INTERNAL_P (in TARGET_EXPR) |
| 534 | CONTRACT_CONST (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT) | 535 | CONTRACT_CONST (in ASSERTION_, PRECONDITION_, POSTCONDITION_STMT) |
| 535 | DECL_HAS_DEFAULT_ARGUMENT_P (in PARM_DECL) | 536 | DECL_HAS_DEFAULT_ARGUMENT_P (in PARM_DECL) |
| 537 | SPLICE_EXPR_TARGS_P (in SPLICE_EXPR) | ||
| 536 | 5: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) | 538 | 5: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) |
| 537 | FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE) | 539 | FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE) |
| 538 | CALL_EXPR_REVERSE_ARGS (in CALL_EXPR, AGGR_INIT_EXPR) | 540 | CALL_EXPR_REVERSE_ARGS (in CALL_EXPR, AGGR_INIT_EXPR) |
| @@ -1979,6 +1981,24 @@ enum reflect_kind : addr_space_t { | |||
| 1979 | (SPLICE_EXPR_ADDRESS_P (TREE_CODE (NODE) == SPLICE_EXPR \ | 1981 | (SPLICE_EXPR_ADDRESS_P (TREE_CODE (NODE) == SPLICE_EXPR \ |
| 1980 | ? NODE : TREE_OPERAND (NODE, 0)) = (VAL)) | 1982 | ? NODE : TREE_OPERAND (NODE, 0)) = (VAL)) |
| 1981 | 1983 | ||
| 1984 | /* True if this SPLICE_EXPR was decorated with 'template'. */ | ||
| 1985 | #define SPLICE_EXPR_TEMPLATE_P(NODE) \ | ||
| 1986 | TREE_LANG_FLAG_3 (SPLICE_EXPR_CHECK (NODE)) | ||
| 1987 | |||
| 1988 | /* Helper macro to set SPLICE_EXPR_TEMPLATE_P. */ | ||
| 1989 | #define SET_SPLICE_EXPR_TEMPLATE_P(NODE, VAL) \ | ||
| 1990 | (SPLICE_EXPR_TEMPLATE_P (TREE_CODE (NODE) == SPLICE_EXPR \ | ||
| 1991 | ? NODE : TREE_OPERAND (NODE, 0)) = (VAL)) | ||
| 1992 | |||
| 1993 | /* True if this SPLICE_EXPR has template arguments. */ | ||
| 1994 | #define SPLICE_EXPR_TARGS_P(NODE) \ | ||
| 1995 | TREE_LANG_FLAG_4 (SPLICE_EXPR_CHECK (NODE)) | ||
| 1996 | |||
| 1997 | /* Helper macro to set SPLICE_EXPR_TARGS_P. */ | ||
| 1998 | #define SET_SPLICE_EXPR_TARGS_P(NODE, VAL) \ | ||
| 1999 | (SPLICE_EXPR_TARGS_P (TREE_CODE (NODE) == SPLICE_EXPR \ | ||
| 2000 | ? NODE : TREE_OPERAND (NODE, 0)) = (VAL)) | ||
| 2001 | |||
| 1982 | /* The expression in question for a SPLICE_SCOPE. */ | 2002 | /* The expression in question for a SPLICE_SCOPE. */ |
| 1983 | #define SPLICE_SCOPE_EXPR(NODE) \ | 2003 | #define SPLICE_SCOPE_EXPR(NODE) \ |
| 1984 | (TYPE_VALUES_RAW (SPLICE_SCOPE_CHECK (NODE))) | 2004 | (TYPE_VALUES_RAW (SPLICE_SCOPE_CHECK (NODE))) |
| @@ -9416,8 +9436,8 @@ extern bool consteval_only_p (tree) ATTRIBUTE_PURE; | |||
| 9416 | extern bool compare_reflections (tree, tree) ATTRIBUTE_PURE; | 9436 | extern bool compare_reflections (tree, tree) ATTRIBUTE_PURE; |
| 9417 | extern bool valid_splice_type_p (const_tree) ATTRIBUTE_PURE; | 9437 | extern bool valid_splice_type_p (const_tree) ATTRIBUTE_PURE; |
| 9418 | extern bool valid_splice_scope_p (const_tree) ATTRIBUTE_PURE; | 9438 | extern bool valid_splice_scope_p (const_tree) ATTRIBUTE_PURE; |
| 9419 | extern bool check_splice_expr (location_t, location_t, tree, bool, bool, bool) | 9439 | extern bool check_splice_expr (location_t, location_t, tree, bool, bool, bool, |
| 9420 | ATTRIBUTE_PURE; | 9440 | bool, bool) ATTRIBUTE_PURE; |
| 9421 | extern tree make_splice_scope (tree, bool); | 9441 | extern tree make_splice_scope (tree, bool); |
| 9422 | extern bool dependent_splice_p (const_tree) ATTRIBUTE_PURE; | 9442 | extern bool dependent_splice_p (const_tree) ATTRIBUTE_PURE; |
| 9423 | extern tree reflection_mangle_prefix (tree, char [3]); | 9443 | extern tree reflection_mangle_prefix (tree, char [3]); |
| diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.ccindex bbebc1257656..fe27a15a2835 100644--- a/gcc/cp/parser.cc+++ b/gcc/cp/parser.cc | |||
| @@ -6318,6 +6318,8 @@ cp_parser_splice_expression (cp_parser *parser, bool template_p, | |||
| 6318 | SET_SPLICE_EXPR_EXPRESSION_P (t); | 6318 | SET_SPLICE_EXPR_EXPRESSION_P (t); |
| 6319 | SET_SPLICE_EXPR_MEMBER_ACCESS_P (t, member_access_p); | 6319 | SET_SPLICE_EXPR_MEMBER_ACCESS_P (t, member_access_p); |
| 6320 | SET_SPLICE_EXPR_ADDRESS_P (t, address_p); | 6320 | SET_SPLICE_EXPR_ADDRESS_P (t, address_p); |
| 6321 | SET_SPLICE_EXPR_TEMPLATE_P (t, template_p); | ||
| 6322 | SET_SPLICE_EXPR_TARGS_P (t, targs_p); | ||
| 6321 | return t; | 6323 | return t; |
| 6322 | } | 6324 | } |
| 6323 | 6325 | ||
| @@ -6330,38 +6332,17 @@ cp_parser_splice_expression (cp_parser *parser, bool template_p, | |||
| 6330 | 6332 | ||
| 6331 | /* Make sure this splice-expression produces an expression. */ | 6333 | /* Make sure this splice-expression produces an expression. */ |
| 6332 | if (!check_splice_expr (loc, expr.get_start (), t, address_p, | 6334 | if (!check_splice_expr (loc, expr.get_start (), t, address_p, |
| 6333 | member_access_p, /*complain=*/true)) | 6335 | member_access_p, template_p, targs_p, |
| 6336 | /*complain=*/true)) | ||
| 6334 | return error_mark_node; | 6337 | return error_mark_node; |
| 6335 | 6338 | ||
| 6336 | if (template_p) | 6339 | if (!template_p |
| 6337 | { | 6340 | /* No 'template' but there were template arguments? */ |
| 6338 | /* [expr.prim.splice] For a splice-expression of the form template | 6341 | && (targs_p |
| 6339 | splice-specifier, the splice-specifier shall designate a function | 6342 | /* No 'template' but the splice-specifier designates a function |
| 6340 | template. */ | 6343 | template? */ |
| 6341 | if (!targs_p | 6344 | | |
| 6342 | && !really_overloaded_fn (t) | 6345 | && warning_enabled_at (loc, OPT_Wmissing_template_keyword)) |
| 6343 | && !dependent_splice_p (t)) | ||
| 6344 | { | ||
| 6345 | auto_diagnostic_group d; | ||
| 6346 | error_at (loc, "expected a reflection of a function template"); | ||
| 6347 | inform_tree_category (t); | ||
| 6348 | return error_mark_node; | ||
| 6349 | } | ||
| 6350 | /* [expr.prim.splice] For a splice-expression of the form | ||
| 6351 | template splice-specialization-specifier, the splice-specifier of the | ||
| 6352 | splice-specialization-specifier shall designate a template. Since | ||
| 6353 | we would have already complained, just check that we have a template. */ | ||
| 6354 | gcc_checking_assert (really_overloaded_fn (t) | ||
| 6355 | | | get_template_info (t) | |
| 6356 | | | TREE_CODE (t) == TEMPLATE_ID_EXPR | |
| 6357 | | | dependent_splice_p (t)); | |
| 6358 | } | ||
| 6359 | else if (/* No 'template' but there were template arguments? */ | ||
| 6360 | (targs_p | ||
| 6361 | /* No 'template' but the splice-specifier designates a function | ||
| 6362 | template? */ | ||
| 6363 | | | really_overloaded_fn (t)) | |
| 6364 | && warning_enabled_at (loc, OPT_Wmissing_template_keyword)) | ||
| 6365 | /* Were 'template' present, this would be valid code, so keep going. */ | 6346 | /* Were 'template' present, this would be valid code, so keep going. */ |
| 6366 | missing_template_diag (loc, diagnostics::kind::pedwarn); | 6347 | missing_template_diag (loc, diagnostics::kind::pedwarn); |
| 6367 | 6348 | ||
| diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.ccindex c10ca09cdb16..18aec7ebb561 100644--- a/gcc/cp/pt.cc+++ b/gcc/cp/pt.cc | |||
| @@ -16833,12 +16833,18 @@ tsubst_splice_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) | |||
| 16833 | SET_SPLICE_EXPR_MEMBER_ACCESS_P (op, true); | 16833 | SET_SPLICE_EXPR_MEMBER_ACCESS_P (op, true); |
| 16834 | if (SPLICE_EXPR_ADDRESS_P (t)) | 16834 | if (SPLICE_EXPR_ADDRESS_P (t)) |
| 16835 | SET_SPLICE_EXPR_ADDRESS_P (op, true); | 16835 | SET_SPLICE_EXPR_ADDRESS_P (op, true); |
| 16836 | if (SPLICE_EXPR_TEMPLATE_P (t)) | ||
| 16837 | SET_SPLICE_EXPR_TEMPLATE_P (op, true); | ||
| 16838 | if (SPLICE_EXPR_TARGS_P (t)) | ||
| 16839 | SET_SPLICE_EXPR_TARGS_P (op, true); | ||
| 16836 | return op; | 16840 | return op; |
| 16837 | } | 16841 | } |
| 16838 | if (SPLICE_EXPR_EXPRESSION_P (t) | 16842 | if (SPLICE_EXPR_EXPRESSION_P (t) |
| 16839 | && !check_splice_expr (input_location, UNKNOWN_LOCATION, op, | 16843 | && !check_splice_expr (input_location, UNKNOWN_LOCATION, op, |
| 16840 | SPLICE_EXPR_ADDRESS_P (t), | 16844 | SPLICE_EXPR_ADDRESS_P (t), |
| 16841 | SPLICE_EXPR_MEMBER_ACCESS_P (t), | 16845 | SPLICE_EXPR_MEMBER_ACCESS_P (t), |
| 16846 | SPLICE_EXPR_TEMPLATE_P (t), | ||
| 16847 | SPLICE_EXPR_TARGS_P (t), | ||
| 16842 | (complain & tf_error))) | 16848 | (complain & tf_error))) |
| 16843 | return error_mark_node; | 16849 | return error_mark_node; |
| 16844 | 16850 | ||
| diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.ccindex 78d48db29ba2..8925bf49465d 100644--- a/gcc/cp/reflect.cc+++ b/gcc/cp/reflect.cc | |||
| @@ -2752,6 +2752,8 @@ eval_constant_of (location_t loc, const constexpr_ctx *ctx, tree r, | |||
| 2752 | else if (!check_splice_expr (loc, UNKNOWN_LOCATION, r, | 2752 | else if (!check_splice_expr (loc, UNKNOWN_LOCATION, r, |
| 2753 | /*address_p=*/false, | 2753 | /*address_p=*/false, |
| 2754 | /*member_access_p=*/false, | 2754 | /*member_access_p=*/false, |
| 2755 | /*template_p=*/false, | ||
| 2756 | /*targs_p=*/false, | ||
| 2755 | /*complain_p=*/false) | 2757 | /*complain_p=*/false) |
| 2756 | /* One cannot query the value of a function template. | 2758 | /* One cannot query the value of a function template. |
| 2757 | ??? But if [:^^X:] where X is a template is OK, should we | 2759 | ??? But if [:^^X:] where X is a template is OK, should we |
| @@ -8812,13 +8814,15 @@ check_consteval_only_fn (tree decl) | |||
| 8812 | 8814 | ||
| 8813 | /* Check if T is a valid result of splice-expression. ADDRESS_P is true if | 8815 | /* Check if T is a valid result of splice-expression. ADDRESS_P is true if |
| 8814 | we are taking the address of the splice. MEMBER_ACCESS_P is true if this | 8816 | we are taking the address of the splice. MEMBER_ACCESS_P is true if this |
| 8815 | splice is used in foo.[: bar :] or foo->[: bar :] context. COMPLAIN_P is | 8817 | splice is used in foo.[: bar :] or foo->[: bar :] context. TEMPLATE_P is |
| 8816 | true if any errors should be emitted. Returns true is no problems are | 8818 | true if the splice-expression was preceded by 'template'. TARGS_P is true |
| 8817 | found, false otherwise. */ | 8819 | if there were template arguments. COMPLAIN_P is true if any errors should |
| 8820 | be emitted. Returns true is no problems are found, false otherwise. */ | ||
| 8818 | 8821 | ||
| 8819 | bool | 8822 | bool |
| 8820 | check_splice_expr (location_t loc, location_t start_loc, tree t, | 8823 | check_splice_expr (location_t loc, location_t start_loc, tree t, |
| 8821 | bool address_p, bool member_access_p, bool complain_p) | 8824 | bool address_p, bool member_access_p, bool template_p, |
| 8825 | bool targs_p, bool complain_p) | ||
| 8822 | { | 8826 | { |
| 8823 | /* We may not have gotten an expression. */ | 8827 | /* We may not have gotten an expression. */ |
| 8824 | if (TREE_CODE (t) == TYPE_DECL | 8828 | if (TREE_CODE (t) == TYPE_DECL |
| @@ -8949,6 +8953,47 @@ check_splice_expr (location_t loc, location_t start_loc, tree t, | |||
| 8949 | return false; | 8953 | return false; |
| 8950 | } | 8954 | } |
| 8951 | 8955 | ||
| 8956 | if (template_p) | ||
| 8957 | { | ||
| 8958 | /* [expr.prim.splice] For a splice-expression of the form template | ||
| 8959 | splice-specifier, the splice-specifier shall designate a function | ||
| 8960 | template. */ | ||
| 8961 | if (!targs_p) | ||
| 8962 | { | ||
| 8963 | if (!really_overloaded_fn (t) && !dependent_splice_p (t)) | ||
| 8964 | { | ||
| 8965 | if (complain_p) | ||
| 8966 | { | ||
| 8967 | auto_diagnostic_group d; | ||
| 8968 | error_at (loc, "expected a reflection of a function " | ||
| 8969 | "template"); | ||
| 8970 | inform_tree_category (t); | ||
| 8971 | } | ||
| 8972 | return false; | ||
| 8973 | } | ||
| 8974 | } | ||
| 8975 | /* [expr.prim.splice] For a splice-expression of the form | ||
| 8976 | template splice-specialization-specifier, the splice-specifier of the | ||
| 8977 | splice-specialization-specifier shall designate a template. The | ||
| 8978 | template should be a function template or a variable template. */ | ||
| 8979 | else if (DECL_TYPE_TEMPLATE_P (t)) | ||
| 8980 | { | ||
| 8981 | if (complain_p) | ||
| 8982 | { | ||
| 8983 | auto_diagnostic_group d; | ||
| 8984 | error_at (loc, "expected a reflection of a function or variable " | ||
| 8985 | "template"); | ||
| 8986 | inform_tree_category (t); | ||
| 8987 | } | ||
| 8988 | return false; | ||
| 8989 | } | ||
| 8990 | gcc_checking_assert (really_overloaded_fn (t) | ||
| 8991 | | | get_template_info (t) | |
| 8992 | | | TREE_CODE (t) == TEMPLATE_ID_EXPR | |
| 8993 | | | variable_template_p (t) | |
| 8994 | | | dependent_splice_p (t)); | |
| 8995 | } | ||
| 8996 | |||
| 8952 | return true; | 8997 | return true; |
| 8953 | } | 8998 | } |
| 8954 | 8999 | ||
| diff --git a/gcc/testsuite/g++.dg/reflect/crash11.C b/gcc/testsuite/g++.dg/reflect/crash11.Cindex 3aef5d0b2fe5..1d8e78994c24 100644--- a/gcc/testsuite/g++.dg/reflect/crash11.C+++ b/gcc/testsuite/g++.dg/reflect/crash11.C | |||
| @@ -12,8 +12,8 @@ template<typename T, auto R> | |||
| 12 | void | 12 | void |
| 13 | g () | 13 | g () |
| 14 | { | 14 | { |
| 15 | template [: R :] c0; // { dg-error "not a function template|expected" } | 15 | template [: R :] c0; // { dg-error "function or variable template|expected" } |
| 16 | template [: T::r :] c1; // { dg-error "not a function template|expected" } | 16 | template [: T::r :] c1; // { dg-error "function or variable template|expected" } |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | void | 19 | void |
| diff --git a/gcc/testsuite/g++.dg/reflect/splice5.C b/gcc/testsuite/g++.dg/reflect/splice5.Cindex 4f0d2fe61341..96d3192eb55f 100644--- a/gcc/testsuite/g++.dg/reflect/splice5.C+++ b/gcc/testsuite/g++.dg/reflect/splice5.C | |||
| @@ -25,10 +25,9 @@ template | |||
| 25 | void | 25 | void |
| 26 | qux (S &s) | 26 | qux (S &s) |
| 27 | { | 27 | { |
| 28 | // TODO: We don't reject this one. | 28 | template [: N == 0 ? ^^foo : ^^:: :] (0); // { dg-error "expected a reflection of a function template" } |
| 29 | template [: N == 0 ? ^^foo : ^^:: :] (0); // { dg-error "reflection 'foo' not usable in a template splice" "" { xfail *-*-* } } | 29 | template [: N == 0 ? ^^bar : ^^:: :] (0); |
| 30 | template [: N == 0 ? ^^bar : ^^:: :] (0); // { dg-message "only function templates are allowed here" "" { xfail *-*-* } .-1 } | 30 | s.template [: N == 0 ? ^^S::foo : ^^:: :] (0); // { dg-error "expected a reflection of a function template" } |
| 31 | s.template [: N == 0 ? ^^S::foo : ^^:: :] (0); // { dg-error "reflection 'foo' not usable in a template splice" "" { xfail *-*-* } } | ||
| 32 | s.template [: N == 0 ? ^^S::bar : ^^:: :] (0); | 31 | s.template [: N == 0 ? ^^S::bar : ^^:: :] (0); |
| 33 | } | 32 | } |
| 34 | 33 |