On Tue, Oct 07, 2025 at 10:50:50PM +0100, Jason Merrill wrote: > Tested x86_64-pc-linux-gnu. Jakub, does this make sense to you?
It makes sense, I'm just worried about if consteval having high cost (mce_unknown evaluations being non-constant, so either then repeated as mce_true or failing to be optimized if it is just an optimization). I was thinking about something like (untested) where in your patch then you'd set IF_STMT_CONSTEVAL_INTERNAL_P flag instead of IF_STMT_CONSTEVAL_P (and perhaps put the internal into the name of the fn too). But up to you... 2025-10-08 Jakub Jelinek <[email protected]> * cp-tree.h (IF_STMT_CONSTEVAL_INTERNAL_P): Define. * constexpr.cc (cxx_eval_conditional_expression): Handle IF_STMT_CONSTEVAL_INTERNAL_P. (potential_constant_expression_1): Likewise. * pt.cc (tsubst_stmt): Copy over IF_STMT_CONSTEVAL_INTERNAL_P flag. * cp-gimplify.cc (genericize_if_stmt, cp_fold_immediate_r, cp_fold_r): Handle IF_STMT_CONSTEVAL_INTERNAL_P. --- gcc/cp/cp-tree.h.jj 2025-10-04 09:49:59.962565960 +0200 +++ gcc/cp/cp-tree.h 2025-10-08 10:20:22.334841983 +0200 @@ -522,6 +522,7 @@ extern GTY(()) tree cp_global_trees[CPTI LOOKUP_FOUND_P (in RECORD_TYPE, UNION_TYPE, ENUMERAL_TYPE, NAMESPACE_DECL) FNDECL_MANIFESTLY_CONST_EVALUATED (in FUNCTION_DECL) TARGET_EXPR_INTERNAL_P (in TARGET_EXPR) + IF_STMT_CONSTEVAL_INTERNAL_P (in IF_STMT) 5: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE) CALL_EXPR_REVERSE_ARGS (in CALL_EXPR, AGGR_INIT_EXPR) @@ -5691,6 +5692,13 @@ decl_template_parm_check (const_tree t, /* True on artificial if (0) around .DEFERRED_INIT calls added for !!flag_auto_var_init. */ #define IF_STMT_VACUOUS_INIT_P(NODE) TREE_LANG_FLAG_3 (IF_STMT_CHECK (NODE)) +/* This is similar to IF_STMT_CONSTEVAL_P, except it evaluates condition + to true when both mce_true and mce_unknown instead of just for mce_true + and being non-constant for mce_unknown. This is solely for internally + emitted IL where some form is preferrable for constant evaluation and + different for gimplification purposes. */ +#define IF_STMT_CONSTEVAL_INTERNAL_P(NODE) \ + TREE_LANG_FLAG_4 (IF_STMT_CHECK (NODE)) /* Like PACK_EXPANSION_EXTRA_ARGS, for constexpr if. IF_SCOPE is used while building an IF_STMT; IF_STMT_EXTRA_ARGS is used after it is complete. */ --- gcc/cp/constexpr.cc.jj 2025-10-04 09:49:59.991565551 +0200 +++ gcc/cp/constexpr.cc 2025-10-08 10:24:27.990449168 +0200 @@ -4985,6 +4985,12 @@ cxx_eval_conditional_expression (const c val = constant_boolean_node (ctx->manifestly_const_eval == mce_true, boolean_type_node); } + else if (TREE_CODE (t) == IF_STMT && IF_STMT_CONSTEVAL_INTERNAL_P (t)) + /* Internal variant of if consteval {} else {}. Uses the THEN block + for constant evaluation and ELSE block for genericization. */ + val = constant_boolean_node (ctx->manifestly_const_eval != mce_true, + boolean_type_node); + /* Don't VERIFY_CONSTANT the other operands. */ const bool zero_p = integer_zerop (val); if (zero_p) @@ -12416,6 +12422,8 @@ potential_constant_expression_1 (tree t, return false; if (!processing_template_decl) tmp = cxx_eval_outermost_constant_expr (tmp, true); + if (TREE_CODE (t) == IF_STMT && IF_STMT_CONSTEVAL_INTERNAL_P (t)) + 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 --- gcc/cp/pt.cc.jj 2025-10-08 09:23:48.670696822 +0200 +++ gcc/cp/pt.cc 2025-10-08 10:25:03.551958015 +0200 @@ -19453,6 +19453,7 @@ tsubst_stmt (tree t, tree args, tsubst_f stmt = begin_if_stmt (); IF_STMT_CONSTEXPR_P (stmt) = IF_STMT_CONSTEXPR_P (t); IF_STMT_CONSTEVAL_P (stmt) = IF_STMT_CONSTEVAL_P (t); + IF_STMT_CONSTEVAL_INTERNAL_P (stmt) = IF_STMT_CONSTEVAL_INTERNAL_P (t); if (IF_STMT_CONSTEXPR_P (t)) args = add_extra_args (IF_STMT_EXTRA_ARGS (t), args, complain, in_decl); { --- gcc/cp/cp-gimplify.cc.jj 2025-10-04 09:50:00.028565029 +0200 +++ gcc/cp/cp-gimplify.cc 2025-10-08 10:26:34.356703887 +0200 @@ -236,7 +236,7 @@ genericize_if_stmt (tree *stmt_p) entered by gotos/case labels from elsewhere, and as then_ block can contain unfolded immediate function calls, we have to discard the then_ block regardless of whether else_ has side-effects or not. */ - if (IF_STMT_CONSTEVAL_P (stmt)) + if (IF_STMT_CONSTEVAL_P (stmt) || IF_STMT_CONSTEVAL_INTERNAL_P (stmt)) { if (block_may_fallthru (then_)) stmt = build3 (COND_EXPR, void_type_node, boolean_false_node, @@ -1332,7 +1332,7 @@ cp_fold_immediate_r (tree *stmt_p, int * decl = TREE_OPERAND (stmt, 0); break; case IF_STMT: - if (IF_STMT_CONSTEVAL_P (stmt)) + if (IF_STMT_CONSTEVAL_P (stmt) || IF_STMT_CONSTEVAL_INTERNAL_P (stmt)) { if (!data->pset.add (stmt)) cp_walk_tree (&ELSE_CLAUSE (stmt), cp_fold_immediate_r, data_, @@ -1530,7 +1530,7 @@ cp_fold_r (tree *stmt_p, int *walk_subtr return NULL_TREE; case IF_STMT: - if (IF_STMT_CONSTEVAL_P (stmt)) + if (IF_STMT_CONSTEVAL_P (stmt) || IF_STMT_CONSTEVAL_INTERNAL_P (stmt)) { /* Don't walk THEN_CLAUSE (stmt) for consteval if. IF_COND is always boolean_false_node. */ Jakub
