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