The problem in this testcase was that the initializer looked constant to is_nondependent_constant_expression, but instantiating it found the conversion error, but because fold_non_dependent_expr passed tf_none to the instantiation, we didn't give an error. store_init_value then happily stuck the error_mark_node in DECL_INITIAL, leading to an abort later on when we find it without seen_error().
Basically, if we're going to keep around the result of the instantiation, we need to pass in the appropriate complain argument. So this patch adds a complain parameter to fold_non_dependent_expr. It also changes the default to tf_warning_or_error, like it was in older releases. This change meant that the use in build_cxx_call would start to diagnose conversion problems without the relevant information about which parameter the conversion was for, so I've disabled that folding when we're in a template. In store_init_value, I also think we want to go back to the original uninstantiated initializer if folding doesn't actually produce a constant value: we want something that's OK to re-tsubst later. I considered switching store_init_value back to using instantiate_non_dependent_expr; the switch to fold_non_dependent_expr was motivated by a problem with force_paren_expr making an expression dependent that wasn't previously. To address that, since we're using VIEW_CONVERT_EXPR for location wrappers now, let's try using it here as well. But I ended up staying with fold_non_dependent_expr anyway. Tested x86_64-pc-linux-gnu, applying to trunk. For GCC 8 I'm applying a much more localized patch, that just switches to tf_warning_or_error for store_init_value.
commit d78857c84e5daf8b8f4cfa9db0833748e23f76b1 Author: Jason Merrill <ja...@redhat.com> Date: Thu Jun 21 14:54:59 2018 -0400 PR c++/86219 - ICE with erroneous initializer in template. * constexpr.c (fold_non_dependent_expr): Add complain parm. * call.c, expr.c, init.c, pt.c, semantics.c, typeck.c, typeck2.c: Pass it. * call.c (build_cxx_call): Don't mess with builtins in a template. * typeck2.c (store_init_value): If fold_non_dependent_expr didn't produce a constant value, go back to the uninstantiated form. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index e417590e97d..aa0e696972a 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -544,7 +544,7 @@ null_ptr_cst_p (tree t) } else if (CP_INTEGRAL_TYPE_P (type)) { - t = fold_non_dependent_expr (t); + t = fold_non_dependent_expr (t, tf_none); STRIP_NOPS (t); if (integer_zerop (t) && !TREE_OVERFLOW (t)) return true; @@ -8796,6 +8796,7 @@ build_cxx_call (tree fn, int nargs, tree *argarray, /* Check that arguments to builtin functions match the expectations. */ if (fndecl + && !processing_template_decl && DECL_BUILT_IN (fndecl) && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) { @@ -8804,7 +8805,7 @@ build_cxx_call (tree fn, int nargs, tree *argarray, /* We need to take care that values to BUILT_IN_NORMAL are reduced. */ for (i = 0; i < nargs; i++) - argarray[i] = fold_non_dependent_expr (argarray[i]); + argarray[i] = maybe_constant_value (argarray[i]); if (!check_builtin_function_arguments (EXPR_LOCATION (fn), vNULL, fndecl, nargs, argarray)) diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index dea2a4e57b3..365296d6e3b 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -5179,12 +5179,20 @@ clear_cv_and_fold_caches (void) /* Like maybe_constant_value but first fully instantiate the argument. Note: this is equivalent to instantiate_non_dependent_expr_sfinae - (t, tf_none) followed by maybe_constant_value but is more efficient, - because calls instantiation_dependent_expression_p and - potential_constant_expression at most once. */ + (t, complain) followed by maybe_constant_value but is more efficient, + because it calls instantiation_dependent_expression_p and + potential_constant_expression at most once. + + Callers should generally pass their active complain, or if they are in a + non-template, diagnosing context, they can use the default of + tf_warning_or_error. Callers that might be within a template context, don't + have a complain parameter, and aren't going to remember the result for long + (e.g. null_ptr_cst_p), can pass tf_none and deal with error_mark_node + appropriately. */ tree -fold_non_dependent_expr (tree t) +fold_non_dependent_expr (tree t, + tsubst_flags_t complain /* = tf_warning_or_error */) { if (t == NULL_TREE) return NULL_TREE; @@ -5201,7 +5209,7 @@ fold_non_dependent_expr (tree t) if (is_nondependent_constant_expression (t)) { processing_template_decl_sentinel s; - t = instantiate_non_dependent_expr_internal (t, tf_none); + t = instantiate_non_dependent_expr_internal (t, complain); if (type_unknown_p (t) || BRACE_ENCLOSED_INITIALIZER_P (t)) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 264bba53f0d..89b6555c09f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7536,7 +7536,7 @@ extern tree cxx_constant_value (tree, tree = NULL_TREE); extern tree cxx_constant_init (tree, tree = NULL_TREE); extern tree maybe_constant_value (tree, tree = NULL_TREE); extern tree maybe_constant_init (tree, tree = NULL_TREE); -extern tree fold_non_dependent_expr (tree); +extern tree fold_non_dependent_expr (tree, tsubst_flags_t = tf_warning_or_error); extern tree fold_simple (tree); extern bool is_sub_constant_expr (tree); extern bool reduced_constant_expression_p (tree); diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c index 133a01b8a51..93477bcd12f 100644 --- a/gcc/cp/expr.c +++ b/gcc/cp/expr.c @@ -353,7 +353,13 @@ fold_for_warn (tree x) /* It's not generally safe to fully fold inside of a template, so call fold_non_dependent_expr instead. */ if (processing_template_decl) - return fold_non_dependent_expr (x); + { + tree f = fold_non_dependent_expr (x, tf_none); + if (f == error_mark_node) + return x; + else + return f; + } return c_fully_fold (x, /*for_init*/false, /*maybe_constp*/NULL); } diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 810a776a3c8..76ce0b829dd 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2931,7 +2931,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, /* Lots of logic below depends on whether we have a constant number of elements, so go ahead and fold it now. */ - const_tree cst_outer_nelts = fold_non_dependent_expr (outer_nelts); + const_tree cst_outer_nelts = fold_non_dependent_expr (outer_nelts, complain); /* If our base type is an array, then make sure we know how many elements it has. */ @@ -3731,7 +3731,7 @@ build_new (vec<tree, va_gc> **placement, tree type, tree nelts, /* Try to determine the constant value only for the purposes of the diagnostic below but continue to use the original value and handle const folding later. */ - const_tree cst_nelts = fold_non_dependent_expr (nelts); + const_tree cst_nelts = fold_non_dependent_expr (nelts, complain); /* The expression in a noptr-new-declarator is erroneous if it's of non-class type and its value before converting to std::size_t is diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d6410d71555..ed74c27c230 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -16881,7 +16881,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, /* Don't instantiate the THEN_CLAUSE. */; else { - bool inhibit = integer_zerop (fold_non_dependent_expr (tmp)); + tree folded = fold_non_dependent_expr (tmp, complain); + bool inhibit = integer_zerop (folded); if (inhibit) ++c_inhibit_evaluation_warnings; RECUR (THEN_CLAUSE (t)); @@ -16894,7 +16895,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, /* Don't instantiate the ELSE_CLAUSE. */; else if (ELSE_CLAUSE (t)) { - bool inhibit = integer_nonzerop (fold_non_dependent_expr (tmp)); + tree folded = fold_non_dependent_expr (tmp, complain); + bool inhibit = integer_nonzerop (folded); begin_else_clause (stmt); if (inhibit) ++c_inhibit_evaluation_warnings; @@ -18535,7 +18537,7 @@ tsubst_copy_and_build (tree t, { tree cond = RECUR (TREE_OPERAND (t, 0)); cond = mark_rvalue_use (cond); - tree folded_cond = fold_non_dependent_expr (cond); + tree folded_cond = fold_non_dependent_expr (cond, complain); tree exp1, exp2; if (TREE_CODE (folded_cond) == INTEGER_CST) @@ -22100,7 +22102,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict, corresponding parameter is type-dependent. Make any necessary adjustments based on whether arg is a reference. */ if (CONSTANT_CLASS_P (arg)) - parm = fold_non_dependent_expr (parm); + parm = fold_non_dependent_expr (parm, complain); else if (REFERENCE_REF_P (arg)) { tree sub = TREE_OPERAND (arg, 0); @@ -25873,7 +25875,7 @@ build_non_dependent_expr (tree expr) /* Don't do this during concept expansion either and for the same reason. */ && !expanding_concept ()) - fold_non_dependent_expr (expr); + fold_non_dependent_expr (expr, tf_none); STRIP_ANY_LOCATION_WRAPPER (expr); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index da75f30885f..c779137da45 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -8676,7 +8676,7 @@ finish_static_assert (tree condition, tree message, location_t location, /* Fold the expression and convert it to a boolean value. */ condition = perform_implicit_conversion_flags (boolean_type_node, condition, complain, LOOKUP_NORMAL); - condition = fold_non_dependent_expr (condition); + condition = fold_non_dependent_expr (condition, complain); if (TREE_CODE (condition) == INTEGER_CST && !integer_zerop (condition)) /* Do nothing; the condition is satisfied. */ diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 936de9fe5c6..3a4f1cdf479 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -4163,7 +4163,7 @@ warn_for_null_address (location_t location, tree op, tsubst_flags_t complain) || TREE_NO_WARNING (op)) return; - tree cop = fold_non_dependent_expr (op); + tree cop = fold_non_dependent_expr (op, complain); if (TREE_CODE (cop) == ADDR_EXPR && decl_with_nonnull_addr_p (TREE_OPERAND (cop, 0)) @@ -4480,7 +4480,7 @@ cp_build_binary_op (location_t location, || code1 == COMPLEX_TYPE || code1 == VECTOR_TYPE)) { enum tree_code tcode0 = code0, tcode1 = code1; - tree cop1 = fold_non_dependent_expr (op1); + tree cop1 = fold_non_dependent_expr (op1, complain); doing_div_or_mod = true; warn_for_div_by_zero (location, cop1); @@ -4519,7 +4519,7 @@ cp_build_binary_op (location_t location, case TRUNC_MOD_EXPR: case FLOOR_MOD_EXPR: { - tree cop1 = fold_non_dependent_expr (op1); + tree cop1 = fold_non_dependent_expr (op1, complain); doing_div_or_mod = true; warn_for_div_by_zero (location, cop1); } @@ -4614,7 +4614,7 @@ cp_build_binary_op (location_t location, } else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) { - tree const_op1 = fold_non_dependent_expr (op1); + tree const_op1 = fold_non_dependent_expr (op1, complain); if (TREE_CODE (const_op1) != INTEGER_CST) const_op1 = op1; result_type = type0; @@ -4660,10 +4660,10 @@ cp_build_binary_op (location_t location, } else if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE) { - tree const_op0 = fold_non_dependent_expr (op0); + tree const_op0 = fold_non_dependent_expr (op0, complain); if (TREE_CODE (const_op0) != INTEGER_CST) const_op0 = op0; - tree const_op1 = fold_non_dependent_expr (op1); + tree const_op1 = fold_non_dependent_expr (op1, complain); if (TREE_CODE (const_op1) != INTEGER_CST) const_op1 = op1; result_type = type0; @@ -5370,8 +5370,8 @@ cp_build_binary_op (location_t location, /* OP0 and/or OP1 might have side-effects. */ op0 = cp_save_expr (op0); op1 = cp_save_expr (op1); - op0 = fold_non_dependent_expr (op0); - op1 = fold_non_dependent_expr (op1); + op0 = fold_non_dependent_expr (op0, complain); + op1 = fold_non_dependent_expr (op1, complain); if (doing_div_or_mod && sanitize_flags_p (SANITIZE_DIVIDE | SANITIZE_FLOAT_DIVIDE)) { diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index ca87b438bd3..43e236de41c 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -822,6 +822,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags) if (decl_maybe_constant_var_p (decl) || TREE_STATIC (decl)) { bool const_init; + tree oldval = value; value = fold_non_dependent_expr (value); if (DECL_DECLARED_CONSTEXPR_P (decl) || (DECL_IN_AGGR_P (decl) @@ -847,6 +848,8 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags) /* FIXME setting TREE_CONSTANT on refs breaks the back end. */ if (!TYPE_REF_P (type)) TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl); + if (!const_init) + value = oldval; } value = cp_fully_fold (value); @@ -899,7 +902,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain) return ok; } - init = fold_non_dependent_expr (init); + init = fold_non_dependent_expr (init, complain); if (TREE_CODE (type) == INTEGER_TYPE && TREE_CODE (ftype) == REAL_TYPE) @@ -1254,7 +1257,7 @@ massage_init_elt (tree type, tree init, int nested, tsubst_flags_t complain) init = TARGET_EXPR_INITIAL (init); /* When we defer constant folding within a statement, we may want to defer this folding as well. */ - tree t = fold_non_dependent_expr (init); + tree t = fold_non_dependent_expr (init, complain); t = maybe_constant_init (t); if (TREE_CONSTANT (t)) init = t; diff --git a/gcc/testsuite/g++.dg/template/conv15.C b/gcc/testsuite/g++.dg/template/conv15.C new file mode 100644 index 00000000000..2f61c113564 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/conv15.C @@ -0,0 +1,10 @@ +// PR c++/86219 + +template <int a> struct t; +template <int a> +void f () +{ + const int b = ""; // { dg-error "conversion" } + t<b>::c; // { dg-error "constant" } + // { dg-prune-output "template argument 1 is invalid" } +}
commit 05e980d2b38d2405448632a92d767eea1eaaa2df Author: Jason Merrill <ja...@redhat.com> Date: Fri Jun 22 12:44:43 2018 -0400 Avoid taking the address of something just because it's in parens. * constexpr.c (same_type_ignoring_tlq_and_bounds_p): New. (cxx_fold_indirect_ref): Use it. (cxx_eval_constant_expression) [VIEW_CONVERT_EXPR]: Use it. * cp-tree.h (REF_PARENTHESIZED_P): Allow VIEW_CONVERT_EXPR. * semantics.c (force_paren_expr): Use VIEW_CONVERT_EXPR instead of static_cast to reference type. (maybe_undo_parenthesized_ref): Handle VIEW_CONVERT_EXPR. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 44f3093ab47..dea2a4e57b3 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3076,6 +3076,23 @@ cxx_eval_vec_init (const constexpr_ctx *ctx, tree t, return r; } +/* Like same_type_ignoring_top_level_qualifiers_p, but also handle the case + where the desired type is an array of unknown bounds because the variable + has had its bounds deduced since the wrapping expression was created. */ + +static bool +same_type_ignoring_tlq_and_bounds_p (tree type1, tree type2) +{ + while (TREE_CODE (type1) == ARRAY_TYPE + && TREE_CODE (type2) == ARRAY_TYPE + && (!TYPE_DOMAIN (type1) || !TYPE_DOMAIN (type2))) + { + type1 = TREE_TYPE (type1); + type2 = TREE_TYPE (type2); + } + return same_type_ignoring_top_level_qualifiers_p (type1, type2); +} + /* A less strict version of fold_indirect_ref_1, which requires cv-quals to match. We want to be less strict for simple *& folding; if we have a non-const temporary that we access through a const pointer, that should @@ -3108,15 +3125,7 @@ cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) if (TREE_CODE (op) == CONST_DECL) return DECL_INITIAL (op); /* *&p => p; make sure to handle *&"str"[cst] here. */ - if (same_type_ignoring_top_level_qualifiers_p (optype, type) - /* Also handle the case where the desired type is an array of unknown - bounds because the variable has had its bounds deduced since the - ADDR_EXPR was created. */ - || (TREE_CODE (type) == ARRAY_TYPE - && TREE_CODE (optype) == ARRAY_TYPE - && TYPE_DOMAIN (type) == NULL_TREE - && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (optype), - TREE_TYPE (type)))) + if (same_type_ignoring_tlq_and_bounds_p (optype, type)) { tree fop = fold_read_from_constant_string (op); if (fop) @@ -4676,7 +4685,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, conversion. */ return fold (t); - if (tcode == UNARY_PLUS_EXPR) + /* Handle an array's bounds having been deduced after we built + the wrapping expression. */ + if (same_type_ignoring_tlq_and_bounds_p (type, TREE_TYPE (op))) + r = op; + else if (tcode == UNARY_PLUS_EXPR) r = fold_convert (TREE_TYPE (t), op); else r = fold_build1 (tcode, type, op); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e1465a915f1..264bba53f0d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -399,7 +399,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR) FNDECL_USED_AUTO (in FUNCTION_DECL) DECLTYPE_FOR_LAMBDA_PROXY (in DECLTYPE_TYPE) - REF_PARENTHESIZED_P (in COMPONENT_REF, INDIRECT_REF, SCOPE_REF) + REF_PARENTHESIZED_P (in COMPONENT_REF, INDIRECT_REF, SCOPE_REF, VIEW_CONVERT_EXPR) AGGR_INIT_ZERO_FIRST (in AGGR_INIT_EXPR) CONSTRUCTOR_MUTABLE_POISON (in CONSTRUCTOR) OVL_HIDDEN_P (in OVERLOAD) @@ -3676,7 +3676,7 @@ struct GTY(()) lang_decl { of the time in C++14 mode. */ #define REF_PARENTHESIZED_P(NODE) \ - TREE_LANG_FLAG_2 (TREE_CHECK3 ((NODE), COMPONENT_REF, INDIRECT_REF, SCOPE_REF)) + TREE_LANG_FLAG_2 (TREE_CHECK4 ((NODE), COMPONENT_REF, INDIRECT_REF, SCOPE_REF, VIEW_CONVERT_EXPR)) /* Nonzero if this AGGR_INIT_EXPR provides for initialization via a constructor call, rather than an ordinary function call. */ diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index bad712ee6e8..da75f30885f 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1720,23 +1720,10 @@ force_paren_expr (tree expr) REF_PARENTHESIZED_P (expr) = true; else if (processing_template_decl) expr = build1 (PAREN_EXPR, TREE_TYPE (expr), expr); - else if (VAR_P (expr) && DECL_HARD_REGISTER (expr)) - /* We can't bind a hard register variable to a reference. */; else { - cp_lvalue_kind kind = lvalue_kind (expr); - if ((kind & ~clk_class) != clk_none) - { - tree type = unlowered_expr_type (expr); - bool rval = !!(kind & clk_rvalueref); - type = cp_build_reference_type (type, rval); - /* This inhibits warnings in, eg, cxx_mark_addressable - (c++/60955). */ - warning_sentinel s (extra_warnings); - expr = build_static_cast (type, expr, tf_error); - if (expr != error_mark_node) - REF_PARENTHESIZED_P (expr) = true; - } + expr = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (expr), expr); + REF_PARENTHESIZED_P (expr) = true; } return expr; @@ -1765,6 +1752,9 @@ maybe_undo_parenthesized_ref (tree t) } else if (TREE_CODE (t) == PAREN_EXPR) t = TREE_OPERAND (t, 0); + else if (TREE_CODE (t) == VIEW_CONVERT_EXPR + && REF_PARENTHESIZED_P (t)) + t = TREE_OPERAND (t, 0); return t; }
commit 097a94cc7ae57759e5a52ac30b2d60ea1d306477 Author: Jason Merrill <ja...@redhat.com> Date: Thu Jun 21 14:54:59 2018 -0400 PR c++/86219 - ICE with erroneous initializer in template. * constexpr.c (fold_non_dependent_expr): Add complain parm. * typeck2.c (store_init_value): Pass tf_warning_or_error. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index b4bcc6a567d..178026512b4 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -5107,12 +5107,12 @@ clear_cv_and_fold_caches (void) /* Like maybe_constant_value but first fully instantiate the argument. Note: this is equivalent to instantiate_non_dependent_expr_sfinae - (t, tf_none) followed by maybe_constant_value but is more efficient, + (t, complain) followed by maybe_constant_value but is more efficient, because calls instantiation_dependent_expression_p and potential_constant_expression at most once. */ tree -fold_non_dependent_expr (tree t) +fold_non_dependent_expr (tree t, tsubst_flags_t complain /* = tf_none */) { if (t == NULL_TREE) return NULL_TREE; @@ -5129,7 +5129,7 @@ fold_non_dependent_expr (tree t) if (is_nondependent_constant_expression (t)) { processing_template_decl_sentinel s; - t = instantiate_non_dependent_expr_internal (t, tf_none); + t = instantiate_non_dependent_expr_internal (t, complain); if (type_unknown_p (t) || BRACE_ENCLOSED_INITIALIZER_P (t)) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7603786576c..85ba5b87e3b 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7546,7 +7546,7 @@ extern tree cxx_constant_value (tree, tree = NULL_TREE); extern tree cxx_constant_init (tree, tree = NULL_TREE); extern tree maybe_constant_value (tree, tree = NULL_TREE); extern tree maybe_constant_init (tree, tree = NULL_TREE); -extern tree fold_non_dependent_expr (tree); +extern tree fold_non_dependent_expr (tree, tsubst_flags_t = tf_none); extern tree fold_simple (tree); extern bool is_sub_constant_expr (tree); extern bool reduced_constant_expression_p (tree); diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 444ebfdcb37..105d128899a 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -822,7 +822,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags) if (decl_maybe_constant_var_p (decl) || TREE_STATIC (decl)) { bool const_init; - value = fold_non_dependent_expr (value); + value = fold_non_dependent_expr (value, tf_warning_or_error); if (DECL_DECLARED_CONSTEXPR_P (decl) || (DECL_IN_AGGR_P (decl) && DECL_INITIALIZED_IN_CLASS_P (decl) diff --git a/gcc/testsuite/g++.dg/template/conv15.C b/gcc/testsuite/g++.dg/template/conv15.C new file mode 100644 index 00000000000..2f61c113564 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/conv15.C @@ -0,0 +1,10 @@ +// PR c++/86219 + +template <int a> struct t; +template <int a> +void f () +{ + const int b = ""; // { dg-error "conversion" } + t<b>::c; // { dg-error "constant" } + // { dg-prune-output "template argument 1 is invalid" } +}