On 2/18/19 12:45 PM, Jakub Jelinek wrote:
Hi!
As mentioned in the PR, we've regressed on the trunk in diagnostics of some
invalid constexpr evaluations. The problem is that the constexpr evaluation
is effectively done on post-cp_fold_function bodies/arguments and cp_fold
optimizes away some important trees for constexpr diagnostics, either
itself, or through using GENERIC match.pd (on the testcase in particular
diagnostics about reinterpret_cast).
While we save on constexpr call hash table bodies of the functions
pre-cp_fold_function, due to sharing and cp_fold_r the STATEMENT_LIST
statements etc. are modified directly and genericization modifies it as
well.
The following patch uses copy_fn which we have been using before the the
recursive constexpr cases also to make a copy of the constexpr function
before cp_fold_function clobbers it.
I had to implement cxx_eval_conditional_expression handling of various
C++ FE statements that are replaced during genericization.
Bootstrapped/regtested on x86_64-linux and i686-linux (98,11,14,17,2a), ok
for trunk?
2019-02-18 Jakub Jelinek <ja...@redhat.com>
PR c++/89285
* constexpr.c (struct constexpr_fundef): Add parms and result members.
(retrieve_constexpr_fundef): Adjust for the above change.
(register_constexpr_fundef): Save constexpr body with copy_fn,
temporarily set DECL_CONTEXT on DECL_RESULT before that.
(get_fundef_copy): Change FUN argument to FUNDEF with
constexpr_fundef * type, grab body and parms/result out of
constexpr_fundef struct and temporarily change it for copy_fn calls
too.
(cxx_eval_builtin_function_call): For __builtin_FUNCTION temporarily
adjust current_function_decl from ctx->call context. For arith
overflow builtins, don't test is_constant_expression on the result,
instead test if arguments are suitable constant expressions.
(cxx_bind_parameters_in_call): Grab parameters from new_call. Undo
convert_for_arg_passing changes for TREE_ADDRESSABLE type passing.
(cxx_eval_call_expression): Adjust get_fundef_copy caller.
(cxx_eval_conditional_expression): For IF_STMT, allow then or else
operands to be NULL.
(label_matches): Handle BREAK_STMT and CONTINUE_STMT.
(cxx_eval_loop_expr): Add support for FOR_STMT, WHILE_STMT and DO_STMT.
(cxx_eval_switch_expr): Add support for SWITCH_STMT.
(cxx_eval_constant_expression): Handle IF_STMT, FOR_STMT, WHILE_STMT,
DO_STMT, CONTINUE_STMT, SWITCH_STMT, BREAK_STMT and CONTINUE_STMT.
For SIZEOF_EXPR, recurse on the result of fold_sizeof_expr. Ignore
DECL_EXPR with USING_DECL operand.
* lambda.c (maybe_add_lambda_conv_op): Build thisarg using
build_int_cst to make it a valid constant expression.
* g++.dg/ubsan/vptr-4.C: Expect reinterpret_cast errors.
* g++.dg/cpp1y/constexpr-84192.C (f2): Adjust expected diagnostics.
* g++.dg/cpp1y/constexpr-70265-2.C (foo): Adjust expected line of
diagnostics.
* g++.dg/cpp1y/constexpr-89285.C: New test.
--- gcc/cp/constexpr.c.jj 2019-02-17 17:09:47.113351897 +0100
+++ gcc/cp/constexpr.c 2019-02-18 19:34:57.995136395 +0100
@@ -1269,6 +1301,49 @@ cxx_eval_builtin_function_call (const co
return t;
}
+ if (fndecl_built_in_p (fun, BUILT_IN_NORMAL))
+ switch (DECL_FUNCTION_CODE (fun))
+ {
+ case BUILT_IN_ADD_OVERFLOW:
+ case BUILT_IN_SADD_OVERFLOW:
+ case BUILT_IN_SADDL_OVERFLOW:
+ case BUILT_IN_SADDLL_OVERFLOW:
+ case BUILT_IN_UADD_OVERFLOW:
+ case BUILT_IN_UADDL_OVERFLOW:
+ case BUILT_IN_UADDLL_OVERFLOW:
+ case BUILT_IN_SUB_OVERFLOW:
+ case BUILT_IN_SSUB_OVERFLOW:
+ case BUILT_IN_SSUBL_OVERFLOW:
+ case BUILT_IN_SSUBLL_OVERFLOW:
+ case BUILT_IN_USUB_OVERFLOW:
+ case BUILT_IN_USUBL_OVERFLOW:
+ case BUILT_IN_USUBLL_OVERFLOW:
+ case BUILT_IN_MUL_OVERFLOW:
+ case BUILT_IN_SMUL_OVERFLOW:
+ case BUILT_IN_SMULL_OVERFLOW:
+ case BUILT_IN_SMULLL_OVERFLOW:
+ case BUILT_IN_UMUL_OVERFLOW:
+ case BUILT_IN_UMULL_OVERFLOW:
+ case BUILT_IN_UMULLL_OVERFLOW:
+ /* These builtins will fold into
+ (cast)
+ ((something = __real__ SAVE_EXPR <.???_OVERFLOW (cst1, cst2)>),
+ __imag__ SAVE_EXPR <.???_OVERFLOW (cst1, cst2)>)
+ which fails is_constant_expression. */
+ if (TREE_CODE (args[0]) != INTEGER_CST
+ || TREE_CODE (args[1]) != INTEGER_CST
+ || !potential_constant_expression (args[2]))
+ {
+ if (!*non_constant_p && !ctx->quiet)
+ error ("%q+E is not a constant expression", new_call);
+ *non_constant_p = true;
+ return t;
+ }
+ return cxx_eval_constant_expression (&new_ctx, new_call, lval,
+ non_constant_p, overflow_p);
+ default:
+ break;
+ }
What is this for? Won't this recursive cxx_eval_constant_expression
come back to this function again? If the expression is constant,
shouldn't it have been folded by fold_builtin_call_array?
@@ -1358,6 +1433,9 @@ cxx_bind_parameters_in_call (const const
x = ctx->object;
x = build_address (x);
}
+ if (TREE_ADDRESSABLE (type) && TYPE_REF_P (TREE_TYPE (x)))
+ /* Undo convert_for_arg_passing work here. */
+ x = build_fold_indirect_ref_loc (EXPR_LOCATION (x), x);
Not convert_from_reference?
@@ -4036,6 +4113,10 @@ label_matches (const constexpr_ctx *ctx,
}
break;
+ case BREAK_STMT:
+ case CONTINUE_STMT:
+ break;
+
Let's add a comment that these are handled directly in cxx_eval_loop_expr.
Jason