diff options
Diffstat (limited to 'gcc/cp/constexpr.c')
-rw-r--r-- | gcc/cp/constexpr.c | 357 |
1 files changed, 267 insertions, 90 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index c946744..0c2498a 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -46,6 +46,7 @@ do { \ static HOST_WIDE_INT find_array_ctor_elt (tree ary, tree dindex, bool insert = false); +static int array_index_cmp (tree key, tree index); /* Returns true iff FUN is an instantiation of a constexpr function template or a defaulted constexpr function. */ @@ -329,12 +330,9 @@ build_data_member_initialization (tree t, vec<constructor_elt, va_gc> **vec) return false; if (TREE_CODE (t) == STATEMENT_LIST) { - tree_stmt_iterator i; - for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) - { - if (! build_data_member_initialization (tsi_stmt (i), vec)) - return false; - } + for (tree stmt : tsi_range (t)) + if (! build_data_member_initialization (stmt, vec)) + return false; return true; } if (TREE_CODE (t) == CLEANUP_STMT) @@ -576,10 +574,9 @@ build_constexpr_constructor_member_initializers (tree type, tree body) break; case STATEMENT_LIST: - for (tree_stmt_iterator i = tsi_start (body); - !tsi_end_p (i); tsi_next (&i)) + for (tree stmt : tsi_range (body)) { - body = tsi_stmt (i); + body = stmt; if (TREE_CODE (body) == BIND_EXPR) break; } @@ -616,10 +613,9 @@ build_constexpr_constructor_member_initializers (tree type, tree body) } else if (TREE_CODE (body) == STATEMENT_LIST) { - tree_stmt_iterator i; - for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i)) + for (tree stmt : tsi_range (body)) { - ok = build_data_member_initialization (tsi_stmt (i), &vec); + ok = build_data_member_initialization (stmt, &vec); if (!ok) break; } @@ -674,11 +670,10 @@ constexpr_fn_retval (tree body) { case STATEMENT_LIST: { - tree_stmt_iterator i; tree expr = NULL_TREE; - for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i)) + for (tree stmt : tsi_range (body)) { - tree s = constexpr_fn_retval (tsi_stmt (i)); + tree s = constexpr_fn_retval (stmt); if (s == error_mark_node) return error_mark_node; else if (s == NULL_TREE) @@ -870,7 +865,7 @@ maybe_save_constexpr_fundef (tree fun) if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun) || cp_function_chain->invalid_constexpr - || DECL_CLONED_FUNCTION_P (fun)) + || (DECL_CLONED_FUNCTION_P (fun) && !DECL_DELETING_DESTRUCTOR_P (fun))) return; if (!is_valid_constexpr_fn (fun, !DECL_GENERATED_P (fun))) @@ -947,7 +942,6 @@ explain_invalid_constexpr_fn (tree fun) { static hash_set<tree> *diagnosed; tree body; - location_t save_loc; /* Only diagnose defaulted functions, lambdas, or instantiations. */ if (!DECL_DEFAULTED_FN (fun) && !LAMBDA_TYPE_P (CP_DECL_CONTEXT (fun)) @@ -962,7 +956,7 @@ explain_invalid_constexpr_fn (tree fun) /* Already explained. */ return; - save_loc = input_location; + iloc_sentinel ils = input_location; if (!lambda_static_thunk_p (fun)) { /* Diagnostics should completely ignore the static thunk, so leave @@ -990,7 +984,6 @@ explain_invalid_constexpr_fn (tree fun) cx_check_missing_mem_inits (DECL_CONTEXT (fun), body, true); } } - input_location = save_loc; } /* Objects of this type represent calls to constexpr functions @@ -1320,7 +1313,10 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, } /* For __builtin_is_constant_evaluated, defer it if not - ctx->manifestly_const_eval, otherwise fold it to true. */ + ctx->manifestly_const_eval (as sometimes we try to constant evaluate + without manifestly_const_eval even expressions or parts thereof which + will later be manifestly const_eval evaluated), otherwise fold it to + true. */ if (fndecl_built_in_p (fun, CP_BUILT_IN_IS_CONSTANT_EVALUATED, BUILT_IN_FRONTEND)) { @@ -1429,8 +1425,32 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, && ctx->call && ctx->call->fundef) current_function_decl = ctx->call->fundef->decl; - new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t), - CALL_EXPR_FN (t), nargs, args); + if (fndecl_built_in_p (fun, + CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS, + BUILT_IN_FRONTEND)) + { + location_t loc = EXPR_LOCATION (t); + if (nargs >= 1) + VERIFY_CONSTANT (args[0]); + new_call + = fold_builtin_is_pointer_inverconvertible_with_class (loc, nargs, + args); + } + else if (fndecl_built_in_p (fun, + CP_BUILT_IN_IS_CORRESPONDING_MEMBER, + BUILT_IN_FRONTEND)) + { + location_t loc = EXPR_LOCATION (t); + if (nargs >= 2) + { + VERIFY_CONSTANT (args[0]); + VERIFY_CONSTANT (args[1]); + } + new_call = fold_builtin_is_corresponding_member (loc, nargs, args); + } + else + new_call = fold_builtin_call_array (EXPR_LOCATION (t), TREE_TYPE (t), + CALL_EXPR_FN (t), nargs, args); current_function_decl = save_cur_fn; force_folding_builtin_constant_p = save_ffbcp; if (new_call == NULL) @@ -1555,6 +1575,32 @@ free_constructor (tree t) } } +/* Helper function of cxx_bind_parameters_in_call. Return non-NULL + if *TP is address of a static variable (or part of it) currently being + constructed or of a heap artificial variable. */ + +static tree +addr_of_non_const_var (tree *tp, int *walk_subtrees, void *data) +{ + if (TREE_CODE (*tp) == ADDR_EXPR) + if (tree var = get_base_address (TREE_OPERAND (*tp, 0))) + if (VAR_P (var) && TREE_STATIC (var)) + { + if (DECL_NAME (var) == heap_uninit_identifier + || DECL_NAME (var) == heap_identifier + || DECL_NAME (var) == heap_vec_uninit_identifier + || DECL_NAME (var) == heap_vec_identifier) + return var; + + constexpr_global_ctx *global = (constexpr_global_ctx *) data; + if (global->values.get (var)) + return var; + } + if (TYPE_P (*tp)) + *walk_subtrees = false; + return NULL_TREE; +} + /* Subroutine of cxx_eval_call_expression. We are processing a call expression (either CALL_EXPR or AGGR_INIT_EXPR) in the context of CTX. Evaluate @@ -1616,6 +1662,15 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t, /* The destructor needs to see any modifications the callee makes to the argument. */ *non_constant_args = true; + /* If arg is or contains address of a heap artificial variable or + of a static variable being constructed, avoid caching the + function call, as those variables might be modified by the + function, or might be modified by the callers in between + the cached function and just read by the function. */ + else if (!*non_constant_args + && cp_walk_tree (&arg, addr_of_non_const_var, ctx->global, + NULL)) + *non_constant_args = true; /* For virtual calls, adjust the this argument, so that it is the object on which the method is called, rather than @@ -2317,7 +2372,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, *non_constant_p = true; return t; } - if (DECL_CLONED_FUNCTION_P (fun)) + if (DECL_CLONED_FUNCTION_P (fun) && !DECL_DELETING_DESTRUCTOR_P (fun)) fun = DECL_CLONED_FUNCTION (fun); if (is_ubsan_builtin_p (fun)) @@ -2515,6 +2570,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, location_t save_loc = input_location; input_location = loc; ++function_depth; + if (ctx->manifestly_const_eval) + FNDECL_MANIFESTLY_CONST_EVALUATED (fun) = true; instantiate_decl (fun, /*defer_ok*/false, /*expl_inst*/false); --function_depth; input_location = save_loc; @@ -2760,9 +2817,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, /* Forget the saved values of the callee's SAVE_EXPRs and TARGET_EXPRs. */ - unsigned int i; - tree save_expr; - FOR_EACH_VEC_ELT (save_exprs, i, save_expr) + for (tree save_expr : save_exprs) ctx->global->values.remove (save_expr); /* Remove the parms/result from the values map. Is it worth @@ -2875,9 +2930,27 @@ reduced_constant_expression_p (tree t) /* An initialized vector would have a VECTOR_CST. */ return false; else if (cxx_dialect >= cxx20 - /* An ARRAY_TYPE doesn't have any TYPE_FIELDS. */ && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) - field = NULL_TREE; + { + /* There must be a valid constant initializer at every array + index. */ + tree min = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (t))); + tree max = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (t))); + tree cursor = min; + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), i, idx, val) + { + if (!reduced_constant_expression_p (val)) + return false; + if (array_index_cmp (cursor, idx) != 0) + return false; + if (TREE_CODE (idx) == RANGE_EXPR) + cursor = TREE_OPERAND (idx, 1); + cursor = int_const_binop (PLUS_EXPR, cursor, size_one_node); + } + if (find_array_ctor_elt (t, max) == -1) + return false; + goto ok; + } else if (cxx_dialect >= cxx20 && TREE_CODE (TREE_TYPE (t)) == UNION_TYPE) { @@ -2911,6 +2984,7 @@ reduced_constant_expression_p (tree t) for (; field; field = next_initializable_field (DECL_CHAIN (field))) if (!is_really_empty_class (TREE_TYPE (field), /*ignore_vptr*/false)) return false; +ok: if (CONSTRUCTOR_NO_CLEARING (t)) /* All the fields are initialized. */ CONSTRUCTOR_NO_CLEARING (t) = false; @@ -3249,6 +3323,22 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t, /*lval*/false, non_constant_p, overflow_p); VERIFY_CONSTANT (val); + if (TREE_CODE (t) == IF_STMT && IF_STMT_CONSTEVAL_P (t)) + { + /* Evaluate the condition as if it was + if (__builtin_is_constant_evaluated ()), i.e. defer it if not + ctx->manifestly_const_eval (as sometimes we try to constant evaluate + without manifestly_const_eval even expressions or parts thereof which + will later be manifestly const_eval evaluated), otherwise fold it to + true. */ + if (ctx->manifestly_const_eval) + val = boolean_true_node; + else + { + *non_constant_p = true; + return t; + } + } /* Don't VERIFY_CONSTANT the other operands. */ if (integer_zerop (val)) val = TREE_OPERAND (t, 2); @@ -3779,20 +3869,29 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, directly for non-aggregates to avoid creating a garbage CONSTRUCTOR. */ tree val; constexpr_ctx new_ctx; - if (CP_AGGREGATE_TYPE_P (elem_type)) + if (is_really_empty_class (elem_type, /*ignore_vptr*/false)) + return build_constructor (elem_type, NULL); + else if (CP_AGGREGATE_TYPE_P (elem_type)) { tree empty_ctor = build_constructor (init_list_type_node, NULL); val = digest_init (elem_type, empty_ctor, tf_warning_or_error); + } + else + val = build_value_init (elem_type, tf_warning_or_error); + + if (!SCALAR_TYPE_P (elem_type)) + { new_ctx = *ctx; - new_ctx.object = t; + if (ctx->object) + /* If there was no object, don't add one: it could confuse us + into thinking we're modifying a const object. */ + new_ctx.object = t; new_ctx.ctor = build_constructor (elem_type, NULL); ctx = &new_ctx; } - else - val = build_value_init (elem_type, tf_warning_or_error); t = cxx_eval_constant_expression (ctx, val, lval, non_constant_p, overflow_p); - if (CP_AGGREGATE_TYPE_P (elem_type) && t != ctx->ctor) + if (!SCALAR_TYPE_P (elem_type) && t != ctx->ctor) free_constructor (ctx->ctor); return t; } @@ -4383,7 +4482,12 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, FOR_EACH_CONSTRUCTOR_ELT (v, i, index, value) { tree orig_value = value; - init_subob_ctx (ctx, new_ctx, index, value); + /* Like in cxx_eval_store_expression, omit entries for empty fields. */ + bool no_slot = TREE_CODE (type) == RECORD_TYPE && is_empty_field (index); + if (no_slot) + new_ctx = *ctx; + else + init_subob_ctx (ctx, new_ctx, index, value); int pos_hint = -1; if (new_ctx.ctor != ctx->ctor) { @@ -4429,6 +4533,8 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t, gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (index)))); changed = true; } + else if (no_slot) + changed = true; else { if (TREE_CODE (type) == UNION_TYPE @@ -4679,28 +4785,17 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, { tree optype = TREE_TYPE (op); unsigned HOST_WIDE_INT const_nunits; - if (off == 0) + if (off == 0 && similar_type_p (optype, type)) + return op; + else if (TREE_CODE (optype) == COMPLEX_TYPE + && similar_type_p (type, TREE_TYPE (optype))) { - if (similar_type_p (optype, type)) - return op; - /* Also handle conversion to an empty base class, which - is represented with a NOP_EXPR. */ /* *(foo *)&complexfoo => __real__ complexfoo */ - else if (TREE_CODE (optype) == COMPLEX_TYPE - && similar_type_p (type, TREE_TYPE (optype))) + if (off == 0) return build1_loc (loc, REALPART_EXPR, type, op); - } - /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */ - else if (TREE_CODE (optype) == COMPLEX_TYPE - && similar_type_p (type, TREE_TYPE (optype)) - && tree_to_uhwi (TYPE_SIZE_UNIT (type)) == off) - return build1_loc (loc, IMAGPART_EXPR, type, op); - if (is_empty_class (type) - && CLASS_TYPE_P (optype) - && DERIVED_FROM_P (type, optype)) - { - *empty_base = true; - return op; + /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */ + else if (tree_to_uhwi (TYPE_SIZE_UNIT (type)) == off) + return build1_loc (loc, IMAGPART_EXPR, type, op); } /* ((foo*)&vectorfoo)[x] => BIT_FIELD_REF<vectorfoo,...> */ else if (VECTOR_TYPE_P (optype) @@ -4779,6 +4874,15 @@ cxx_fold_indirect_ref_1 (const constexpr_ctx *ctx, location_t loc, tree type, return ret; } } + /* Also handle conversion to an empty base class, which + is represented with a NOP_EXPR. */ + if (is_empty_class (type) + && CLASS_TYPE_P (optype) + && DERIVED_FROM_P (type, optype)) + { + *empty_base = true; + return op; + } } return NULL_TREE; @@ -4839,12 +4943,26 @@ cxx_fold_indirect_ref (const constexpr_ctx *ctx, location_t loc, tree type, && tree_fits_uhwi_p (TREE_OPERAND (sub, 1))) { tree op00 = TREE_OPERAND (sub, 0); - tree op01 = TREE_OPERAND (sub, 1); + tree off = TREE_OPERAND (sub, 1); STRIP_NOPS (op00); if (TREE_CODE (op00) == ADDR_EXPR) - return cxx_fold_indirect_ref_1 (ctx, loc, type, TREE_OPERAND (op00, 0), - tree_to_uhwi (op01), empty_base); + { + tree obj = TREE_OPERAND (op00, 0); + while (TREE_CODE (obj) == COMPONENT_REF + && tree_int_cst_sign_bit (off)) + { + /* Canonicalize this object/offset pair by iteratively absorbing + the innermost component into the offset until the offset is + nonnegative, so that cxx_fold_indirect_ref_1 can identify + more folding opportunities. */ + tree field = TREE_OPERAND (obj, 1); + off = int_const_binop (PLUS_EXPR, off, byte_position (field)); + obj = TREE_OPERAND (obj, 0); + } + return cxx_fold_indirect_ref_1 (ctx, loc, type, obj, + tree_to_uhwi (off), empty_base); + } } /* *(foo *)fooarrptr => (*fooarrptr)[0] */ else if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE @@ -5060,6 +5178,16 @@ var_in_constexpr_fn (tree t) && DECL_DECLARED_CONSTEXPR_P (ctx)); } +/* True if a function might be constexpr: either a function that was + declared constexpr, or a C++17 lambda op(). */ + +bool +maybe_constexpr_fn (tree t) +{ + return (DECL_DECLARED_CONSTEXPR_P (t) + || (cxx_dialect >= cxx17 && LAMBDA_FUNCTION_P (t))); +} + /* True if T was declared in a function that might be constexpr: either a function that was declared constexpr, or a C++17 lambda op(). */ @@ -5405,9 +5533,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, semantics are not applied on an object under construction. They come into effect when the constructor for the most derived object ends." */ - tree elt; - unsigned int i; - FOR_EACH_VEC_ELT (*ctors, i, elt) + for (tree elt : *ctors) if (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (const_object_being_modified), TREE_TYPE (elt))) { @@ -5474,8 +5600,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, argument, which has the derived type rather than the base type. In this situation, just evaluate the initializer and return, since there's no actual data to store. */ - gcc_assert (is_empty_class (TREE_TYPE (init)) && !lval); - return init; + gcc_assert (is_empty_class (TREE_TYPE (init))); + return lval ? target : init; } CONSTRUCTOR_ELTS (*valp) = CONSTRUCTOR_ELTS (init); TREE_CONSTANT (*valp) = TREE_CONSTANT (init); @@ -5483,6 +5609,14 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, CONSTRUCTOR_NO_CLEARING (*valp) = CONSTRUCTOR_NO_CLEARING (init); } + else if (TREE_CODE (init) == CONSTRUCTOR + && !same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (init), + type)) + { + /* See above on initialization of empty bases. */ + gcc_assert (is_empty_class (TREE_TYPE (init)) && !lval); + return init; + } else *valp = init; @@ -5507,12 +5641,10 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, /* Update TREE_CONSTANT and TREE_SIDE_EFFECTS on enclosing CONSTRUCTORs, if any. */ - tree elt; - unsigned i; bool c = TREE_CONSTANT (init); bool s = TREE_SIDE_EFFECTS (init); if (!c || s || activated_union_member_p) - FOR_EACH_VEC_ELT (*ctors, i, elt) + for (tree elt : *ctors) { if (!c) TREE_CONSTANT (elt) = false; @@ -5697,7 +5829,6 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t, bool *non_constant_p, bool *overflow_p, tree *jump_target) { - tree_stmt_iterator i; tree local_target; /* In a statement-expression we want to return the last value. For empty statement expression return void_node. */ @@ -5707,9 +5838,8 @@ cxx_eval_statement_list (const constexpr_ctx *ctx, tree t, local_target = NULL_TREE; jump_target = &local_target; } - for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) + for (tree stmt : tsi_range (t)) { - tree stmt = tsi_stmt (i); /* We've found a continue, so skip everything until we reach the label its jumping to. */ if (continues (jump_target)) @@ -5832,9 +5962,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, } /* Forget saved values of SAVE_EXPRs and TARGET_EXPRs. */ - unsigned int i; - tree save_expr; - FOR_EACH_VEC_ELT (save_exprs, i, save_expr) + for (tree save_expr : save_exprs) ctx->global->values.remove (save_expr); save_exprs.truncate (0); @@ -5856,9 +5984,7 @@ cxx_eval_loop_expr (const constexpr_ctx *ctx, tree t, && !*non_constant_p); /* Forget saved values of SAVE_EXPRs and TARGET_EXPRs. */ - unsigned int i; - tree save_expr; - FOR_EACH_VEC_ELT (save_exprs, i, save_expr) + for (tree save_expr : save_exprs) ctx->global->values.remove (save_expr); return NULL_TREE; @@ -5949,6 +6075,37 @@ inline_asm_in_constexpr_error (location_t loc) "%<constexpr%> function in C++20"); } +/* We're getting the constant value of DECL in a manifestly constant-evaluated + context; maybe complain about that. */ + +static void +maybe_warn_about_constant_value (location_t loc, tree decl) +{ + static bool explained = false; + if (cxx_dialect >= cxx17 + && warn_interference_size + && !global_options_set.x_param_destruct_interfere_size + && DECL_CONTEXT (decl) == std_node + && id_equal (DECL_NAME (decl), "hardware_destructive_interference_size") + && (LOCATION_FILE (input_location) != main_input_filename + || module_exporting_p ()) + && warning_at (loc, OPT_Winterference_size, "use of %qD", decl) + && !explained) + { + explained = true; + inform (loc, "its value can vary between compiler versions or " + "with different %<-mtune%> or %<-mcpu%> flags"); + inform (loc, "if this use is part of a public ABI, change it to " + "instead use a constant variable you define"); + inform (loc, "the default value for the current CPU tuning " + "is %d bytes", param_destruct_interfere_size); + inform (loc, "you can stabilize this value with %<--param " + "hardware_destructive_interference_size=%d%>, or disable " + "this warning with %<-Wno-interference-size%>", + param_destruct_interfere_size); + } +} + /* Attempt to reduce the expression T to a constant value. On failure, issue diagnostic and return error_mark_node. */ /* FIXME unify with c_fully_fold */ @@ -6093,6 +6250,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = *p; break; } + if (ctx->manifestly_const_eval) + maybe_warn_about_constant_value (loc, t); if (COMPLETE_TYPE_P (TREE_TYPE (t)) && is_really_empty_class (TREE_TYPE (t), /*ignore_vptr*/false)) { @@ -6656,7 +6815,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (TREE_CODE (t) == CONVERT_EXPR && ARITHMETIC_TYPE_P (type) - && INDIRECT_TYPE_P (TREE_TYPE (op))) + && INDIRECT_TYPE_P (TREE_TYPE (op)) + && ctx->manifestly_const_eval) { if (!ctx->quiet) error_at (loc, @@ -6669,8 +6829,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, /* [expr.const]: a conversion from type cv void* to a pointer-to-object type cannot be part of a core constant expression as a resolution to DR 1312. */ - if (integer_zerop (op) /* FIXME: Remove in GCC 12. */ - && TYPE_PTROB_P (type) + if (TYPE_PTROB_P (type) && TYPE_PTR_P (TREE_TYPE (op)) && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (op))) /* Inside a call to std::construct_at or to @@ -7319,6 +7478,11 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, } } + /* Remember the original location if that wouldn't need a wrapper. */ + if (location_t loc = EXPR_LOCATION (t)) + if (CAN_HAVE_LOCATION_P (r)) + SET_EXPR_LOCATION (r, loc); + return r; } @@ -7332,6 +7496,18 @@ cxx_constant_value (tree t, tree decl) return cxx_eval_outermost_constant_expr (t, false, true, true, false, decl); } +/* As above, but respect SFINAE. */ + +tree +cxx_constant_value_sfinae (tree t, tsubst_flags_t complain) +{ + bool sfinae = !(complain & tf_error); + tree r = cxx_eval_outermost_constant_expr (t, sfinae, true, true); + if (sfinae && !TREE_CONSTANT (r)) + r = error_mark_node; + return r; +} + /* Like cxx_constant_value, but used for evaluation of constexpr destructors of constexpr variables. The actual initializer of DECL is not modified. */ @@ -8207,16 +8383,10 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, } case STATEMENT_LIST: - { - tree_stmt_iterator i; - for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) - { - if (!RECUR (tsi_stmt (i), any)) - return false; - } - return true; - } - break; + for (tree stmt : tsi_range (t)) + if (!RECUR (stmt, any)) + return false; + return true; case MODIFY_EXPR: if (cxx_dialect < cxx14) @@ -8738,10 +8908,17 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, return false; if (!processing_template_decl) tmp = cxx_eval_outermost_constant_expr (tmp, true); - if (integer_zerop (tmp)) - return RECUR (TREE_OPERAND (t, 2), want_rval); - else if (TREE_CODE (tmp) == INTEGER_CST) - return RECUR (TREE_OPERAND (t, 1), want_rval); + /* potential_constant_expression* isn't told if it is called for + manifestly_const_eval or not, so for consteval if always + process both branches as if the condition is not a known + constant. */ + if (TREE_CODE (t) != IF_STMT || !IF_STMT_CONSTEVAL_P (t)) + { + if (integer_zerop (tmp)) + return RECUR (TREE_OPERAND (t, 2), want_rval); + else if (TREE_CODE (tmp) == INTEGER_CST) + return RECUR (TREE_OPERAND (t, 1), want_rval); + } tmp = *jump_target; for (i = 1; i < 3; ++i) { |