decl = get_callee_fndecl (*expr_p);
if (decl && DECL_BUILT_IN (decl))
{
- tree new = fold_builtin (*expr_p, !want_value);
+ tree fndecl = get_callee_fndecl (*expr_p);
+ tree arglist = TREE_OPERAND (*expr_p, 1);
+ tree new = fold_builtin (fndecl, arglist, !want_value);
if (new && new != *expr_p)
{
if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
&& DECL_FUNCTION_CODE (decl) == BUILT_IN_VA_START)
{
- tree arglist = TREE_OPERAND (*expr_p, 1);
-
if (!arglist || !TREE_CHAIN (arglist))
{
error ("too few arguments to function %<va_start%>");
/* Try this again in case gimplification exposed something. */
if (ret != GS_ERROR && decl && DECL_BUILT_IN (decl))
{
- tree new = fold_builtin (*expr_p, !want_value);
+ tree fndecl = get_callee_fndecl (*expr_p);
+ tree arglist = TREE_OPERAND (*expr_p, 1);
+ tree new = fold_builtin (fndecl, arglist, !want_value);
if (new && new != *expr_p)
{
if (TREE_CODE (type) == BOOLEAN_TYPE)
return expr;
- /* If this is the predicate of a COND_EXPR, it might not even be a
- truthvalue yet. */
- expr = lang_hooks.truthvalue_conversion (expr);
-
switch (TREE_CODE (expr))
{
case TRUTH_AND_EXPR:
*EXPR_P should be stored. */
static enum gimplify_status
-gimplify_cond_expr (tree *expr_p, tree *pre_p, tree *post_p, tree target)
+gimplify_cond_expr (tree *expr_p, tree *pre_p, tree *post_p, tree target,
+ fallback_t fallback)
{
tree expr = *expr_p;
tree tmp, tmp2, type;
the arms. */
else if (! VOID_TYPE_P (type))
{
+ tree result;
+
if (target)
{
ret = gimplify_expr (&target, pre_p, post_p,
is_gimple_min_lval, fb_lvalue);
if (ret != GS_ERROR)
ret = GS_OK;
- tmp = target;
+ result = tmp = target;
tmp2 = unshare_expr (target);
}
+ else if ((fallback & fb_lvalue) == 0)
+ {
+ result = tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
+ ret = GS_ALL_DONE;
+ }
else
{
- tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
+ tree type = build_pointer_type (TREE_TYPE (expr));
+
+ if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
+ TREE_OPERAND (expr, 1) =
+ build_fold_addr_expr (TREE_OPERAND (expr, 1));
+
+ if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
+ TREE_OPERAND (expr, 2) =
+ build_fold_addr_expr (TREE_OPERAND (expr, 2));
+
+ tmp2 = tmp = create_tmp_var (type, "iftmp");
+
+ expr = build (COND_EXPR, void_type_node, TREE_OPERAND (expr, 0),
+ TREE_OPERAND (expr, 1), TREE_OPERAND (expr, 2));
+
+ result = build_fold_indirect_ref (tmp);
ret = GS_ALL_DONE;
}
/* Move the COND_EXPR to the prequeue. */
gimplify_and_add (expr, pre_p);
- *expr_p = tmp;
+ *expr_p = result;
return ret;
}
if (!is_gimple_reg_type (TREE_TYPE (*from_p)))
{
*expr_p = *from_p;
- return gimplify_cond_expr (expr_p, pre_p, post_p, *to_p);
+ return gimplify_cond_expr (expr_p, pre_p, post_p, *to_p,
+ fb_rvalue);
}
else
ret = GS_UNHANDLED;
break;
case COND_EXPR:
- ret = gimplify_cond_expr (expr_p, pre_p, post_p, NULL_TREE);
+ ret = gimplify_cond_expr (expr_p, pre_p, post_p, NULL_TREE,
+ fallback);
+ /* C99 code may assign to an array in a structure value of a
+ conditional expression, and this has undefined behavior
+ only on execution, so create a temporary if an lvalue is
+ required. */
+ if (fallback == fb_lvalue)
+ {
+ *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
+ lang_hooks.mark_addressable (*expr_p);
+ }
break;
case CALL_EXPR:
ret = gimplify_call_expr (expr_p, pre_p, fallback != fb_none);
+ /* C99 code may assign to an array in a structure returned
+ from a function, and this has undefined behavior only on
+ execution, so create a temporary if an lvalue is
+ required. */
+ if (fallback == fb_lvalue)
+ {
+ *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
+ lang_hooks.mark_addressable (*expr_p);
+ }
break;
case TREE_LIST:
case WITH_SIZE_EXPR:
{
- enum gimplify_status r0, r1;
- r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
- post_p == &internal_post ? NULL : post_p,
- gimple_test_f, fallback);
- r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
- is_gimple_val, fb_rvalue);
+ gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
+ post_p == &internal_post ? NULL : post_p,
+ gimple_test_f, fallback);
+ gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
+ is_gimple_val, fb_rvalue);
}
break;
{
/* We don't do anything if the value isn't there, is constant, or contains
A PLACEHOLDER_EXPR. We also don't want to do anything if it's already
- a VAR_DECL. If it's a VAR_DECL from another function, the gimplfier
+ a VAR_DECL. If it's a VAR_DECL from another function, the gimplifier
will want to replace it with a new variable, but that will cause problems
if this type is from outside the function. It's OK to have that here. */
if (*expr_p == NULL_TREE || TREE_CONSTANT (*expr_p)