c-common.c (verify_sequence_points): Export.

* c-common.c (verify_sequence_points): Export.
        (c_expand_expr_stmt): Move to c-typeck.c.
        * c-common.h (c_expand_expr_stmt): Remove.
        (verify_sequence_points): Declare.
        * c-mudflap.c (mflang_flush_calls): Use c_finish_expr_stmt.
        * c-parse.in (for_init_stmt, stmt): Likewise.
        * c-tree.h (c_finish_expr_stmt): Declare.
        (c_tree_expr_nonnegative_p): Remove.
        * c-typeck.c (c_tree_expr_nonnegative_p): Remove.
        (build_conditional_expr, build_binary_op): Use tree_expr_nonnegative_p.
        (emit_side_effect_warnings): New.
        (c_finish_expr_stmt): Rename from c_expand_expr_stmt.  Use it.
        (c_finish_stmt_expr): Work without EXPR_STMT.  Handle eh regions.
        Use emit_side_effect_warnings.
        (push_cleanup): Copy STATEMENT_LIST_STMT_EXPR.
        * fold-const.c (tree_expr_nonnegative_p): Handle TARGET_EXPR.
        * gimplify.c (gimplify_modify_expr): Don't discard TARGET_EXPR
        with void initializer.
        (gimplify_target_expr): Handle void BIND_EXPR initializer.
        * tree-inline.c (estimate_num_insns_1): Fix type lookup for
        INIT_EXPR and MODIFY_EXPR.
        * objc/objc-act.c (build_module_descriptor): Use add_stmt
        instead of c_expand_expr_stmt.
cp/
        * semantics.c (finish_expr_stmt): Call verify_sequence_points.
testsuite/
        * gcc.dg/tree-ssa/20030714-1.c: Rename variables to avoid
        merging && to BIT_FIELD_REF.

From-SVN: r83429
This commit is contained in:
Richard Henderson 2004-06-21 02:15:29 -07:00 committed by Richard Henderson
parent 2c486ea78c
commit 3a5b9284da
15 changed files with 238 additions and 114 deletions

View file

@ -1,3 +1,29 @@
2004-06-21 Richard Henderson <rth@redhat.com>
* c-common.c (verify_sequence_points): Export.
(c_expand_expr_stmt): Move to c-typeck.c.
* c-common.h (c_expand_expr_stmt): Remove.
(verify_sequence_points): Declare.
* c-mudflap.c (mflang_flush_calls): Use c_finish_expr_stmt.
* c-parse.in (for_init_stmt, stmt): Likewise.
* c-tree.h (c_finish_expr_stmt): Declare.
(c_tree_expr_nonnegative_p): Remove.
* c-typeck.c (c_tree_expr_nonnegative_p): Remove.
(build_conditional_expr, build_binary_op): Use tree_expr_nonnegative_p.
(emit_side_effect_warnings): New.
(c_finish_expr_stmt): Rename from c_expand_expr_stmt. Use it.
(c_finish_stmt_expr): Work without EXPR_STMT. Handle eh regions.
Use emit_side_effect_warnings.
(push_cleanup): Copy STATEMENT_LIST_STMT_EXPR.
* fold-const.c (tree_expr_nonnegative_p): Handle TARGET_EXPR.
* gimplify.c (gimplify_modify_expr): Don't discard TARGET_EXPR
with void initializer.
(gimplify_target_expr): Handle void BIND_EXPR initializer.
* tree-inline.c (estimate_num_insns_1): Fix type lookup for
INIT_EXPR and MODIFY_EXPR.
* objc/objc-act.c (build_module_descriptor): Use add_stmt
instead of c_expand_expr_stmt.
2004-06-21 Paolo Bonzini <bonzini@gnu.org>
* fold-const.c (fold_cond_expr_with_comparison):

View file

@ -1247,7 +1247,6 @@ static int warning_candidate_p (tree);
static void warn_for_collisions (struct tlist *);
static void warn_for_collisions_1 (tree, tree, struct tlist *, int);
static struct tlist *new_tlist (struct tlist *, tree, tree);
static void verify_sequence_points (tree);
/* Create a new struct tlist and fill in its fields. */
static struct tlist *
@ -1586,7 +1585,7 @@ verify_tree (tree x, struct tlist **pbefore_sp, struct tlist **pno_sp,
/* Try to warn for undefined behavior in EXPR due to missing sequence
points. */
static void
void
verify_sequence_points (tree expr)
{
struct tlist *before_sp = 0, *after_sp = 0;
@ -1603,32 +1602,6 @@ verify_sequence_points (tree expr)
warn_for_collisions (after_sp);
obstack_free (&tlist_obstack, tlist_firstobj);
}
tree
c_expand_expr_stmt (tree expr)
{
/* Do default conversion if safe and possibly important,
in case within ({...}). */
if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
&& (flag_isoc99 || lvalue_p (expr)))
|| TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
expr = default_conversion (expr);
if (warn_sequence_point)
verify_sequence_points (expr);
if (TREE_TYPE (expr) != error_mark_node
&& !COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (expr))
&& TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE)
error ("expression statement has incomplete type");
/* As tempting as it might be, we can't diagnose statement with no
effect yet. We have to wait until after statement expressions
have been parsed, and that process modifies the trees we are
creating here. */
return add_stmt (build_stmt (EXPR_STMT, expr));
}
/* Validate the expression after `case' and apply default promotions. */

View file

@ -859,7 +859,6 @@ extern void binary_op_error (enum tree_code);
#define my_friendly_assert(EXP, N) (void) \
(((EXP) == 0) ? (fancy_abort (__FILE__, __LINE__, __FUNCTION__), 0) : 0)
extern tree c_expand_expr_stmt (tree);
/* Validate the expression after `case' and apply default promotions. */
extern tree check_case_value (tree);
extern tree fix_string_type (tree);
@ -1097,6 +1096,8 @@ extern tree c_walk_subtrees (tree*, int*, walk_tree_fn, void*, void*);
extern void c_warn_unused_result (tree *);
extern void verify_sequence_points (tree);
/* In c-gimplify.c */
extern void c_genericize (tree);
extern int c_gimplify_expr (tree *, tree *, tree *);

View file

@ -85,7 +85,7 @@ mflang_flush_calls (tree enqueued_call_stmt_chain)
mf_mark (current_function_decl);
cs = c_begin_compound_stmt (true);
c_expand_expr_stmt (enqueued_call_stmt_chain);
c_finish_expr_stmt (enqueued_call_stmt_chain);
add_stmt (c_end_compound_stmt (cs, true));
finish_function ();

View file

@ -2210,7 +2210,7 @@ select_or_iter_stmt:
for_init_stmt:
xexpr ';'
{ add_stmt (build_stmt (EXPR_STMT, $1)); }
{ c_finish_expr_stmt ($1); }
| decl
{ check_for_loop_decls (); }
;
@ -2226,7 +2226,7 @@ stmt:
compstmt
{ stmt_count++; add_stmt ($1); }
| expr ';'
{ stmt_count++; c_expand_expr_stmt ($1); }
{ stmt_count++; c_finish_expr_stmt ($1); }
| c99_block_start select_or_iter_stmt
{ add_stmt (c_end_compound_stmt ($1, flag_isoc99)); }
| BREAK ';'

View file

@ -227,7 +227,6 @@ extern tree build_indirect_ref (tree, const char *);
extern tree build_array_ref (tree, tree);
extern tree build_external_ref (tree, int);
extern tree parser_build_binary_op (enum tree_code, tree, tree);
extern int c_tree_expr_nonnegative_p (tree);
extern void readonly_error (tree, const char *);
extern tree build_conditional_expr (tree, tree, tree);
extern tree build_compound_expr (tree);
@ -272,6 +271,7 @@ extern void c_finish_for_stmt_incr (tree, tree);
extern void c_finish_for_stmt (tree, tree);
extern tree c_begin_stmt_expr (void);
extern tree c_finish_stmt_expr (tree);
extern void c_finish_expr_stmt (tree);
extern tree build_offsetof (tree, tree);
/* Set to 0 at beginning of a function definition, set to 1 if

View file

@ -46,6 +46,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "ggc.h"
#include "target.h"
#include "tree-iterator.h"
#include "tree-gimple.h"
/* Nonzero if we've already printed a "missing braces around initializer"
@ -2201,17 +2202,6 @@ parser_build_binary_op (enum tree_code code, tree arg1, tree arg2)
return result;
}
/* Return true if `t' is known to be non-negative. */
int
c_tree_expr_nonnegative_p (tree t)
{
if (TREE_CODE (t) == STMT_EXPR)
t = expr_last (STMT_EXPR_STMT (t));
return tree_expr_nonnegative_p (t);
}
/* Return a tree for the difference of pointers OP0 and OP1.
The resulting tree has type int. */
@ -2810,8 +2800,8 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
/* Do not warn if the signed quantity is an unsuffixed
integer literal (or some static constant expression
involving such literals) and it is non-negative. */
else if ((unsigned_op2 && c_tree_expr_nonnegative_p (op1))
|| (unsigned_op1 && c_tree_expr_nonnegative_p (op2)))
else if ((unsigned_op2 && tree_expr_nonnegative_p (op1))
|| (unsigned_op1 && tree_expr_nonnegative_p (op2)))
/* OK */;
else
warning ("signed and unsigned type in conditional expression");
@ -6657,7 +6647,61 @@ c_finish_for_stmt (tree body, tree for_stmt)
FOR_BODY (for_stmt) = body;
}
/* Create a statement expression. */
/* A helper routine for c_finish_expr_stmt and c_finish_stmt_expr. */
static void
emit_side_effect_warnings (tree expr)
{
if (!TREE_SIDE_EFFECTS (expr))
{
if (!VOID_TYPE_P (TREE_TYPE (expr)) && !TREE_NO_WARNING (expr))
warning ("%Hstatement with no effect",
EXPR_LOCUS (expr) ? EXPR_LOCUS (expr) : &input_location);
}
else if (warn_unused_value)
warn_if_unused_value (expr, input_location);
}
/* Emit an expression as a statement. */
void
c_finish_expr_stmt (tree expr)
{
if (!expr)
return;
/* Do default conversion if safe and possibly important,
in case within ({...}). */
if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
&& (flag_isoc99 || lvalue_p (expr)))
|| TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
expr = default_conversion (expr);
if (warn_sequence_point)
verify_sequence_points (expr);
if (TREE_TYPE (expr) != error_mark_node
&& !COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (expr))
&& TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE)
error ("expression statement has incomplete type");
/* If we're not processing a statement expression, warn about unused values.
Warnings for statement expressions will be emitted later, once we figure
out which is the result. */
if (!STATEMENT_LIST_STMT_EXPR (cur_stmt_list)
&& (extra_warnings || warn_unused_value))
emit_side_effect_warnings (expr);
/* If the expression is not of a type to which we cannot assign a line
number, wrap the thing in a no-op NOP_EXPR. */
if (DECL_P (expr) || TREE_CODE_CLASS (TREE_CODE (expr)) == 'c')
expr = build1 (NOP_EXPR, TREE_TYPE (expr), expr);
add_stmt (expr);
}
/* Do the opposite and emit a statement as an expression. To begin,
create a new binding level and return it. */
tree
c_begin_stmt_expr (void)
@ -6679,63 +6723,77 @@ c_begin_stmt_expr (void)
tree
c_finish_stmt_expr (tree body)
{
tree ret, last, type;
tree last, type, tmp, val;
tree *last_p;
body = c_end_compound_stmt (body, true);
/* Locate the last statement in BODY. */
last = body, last_p = &body;
if (TREE_CODE (last) == BIND_EXPR)
{
last_p = &BIND_EXPR_BODY (last);
last = BIND_EXPR_BODY (last);
}
/* Locate the last statement in BODY. See c_end_compound_stmt
about always returning a BIND_EXPR. */
last_p = &BIND_EXPR_BODY (body);
last = BIND_EXPR_BODY (body);
continue_searching:
if (TREE_CODE (last) == STATEMENT_LIST)
{
tree_stmt_iterator i = tsi_last (last);
if (tsi_end_p (i))
tree_stmt_iterator i;
/* This can happen with degenerate cases like ({ }). No value. */
if (!TREE_SIDE_EFFECTS (last))
return body;
/* If we're supposed to generate side effects warnings, process
all of the statements except the last. */
if (extra_warnings || warn_unused_value)
{
type = void_type_node;
/* ??? Warn */
goto no_expr;
for (i = tsi_start (last); !tsi_one_before_end_p (i); tsi_next (&i))
emit_side_effect_warnings (tsi_stmt (i));
}
else
{
last_p = tsi_stmt_ptr (i);
last = *last_p;
}
i = tsi_last (last);
last_p = tsi_stmt_ptr (i);
last = *last_p;
}
/* If the last statement is an EXPR_STMT, then unwrap it. Otherwise
voidify_wrapper_expr will stuff it inside a MODIFY_EXPR and we'll
fail gimplification. */
/* ??? Should we go ahead and perform voidify_wrapper_expr here?
We've got about all the information we need here. All we'd have
to do even for proper type safety is to create, in effect,
( ({ ...; tmp = last; }), tmp )
I.e. a COMPOUND_EXPR with the rhs being the compiler temporary.
Not going to try this now, since it's not clear what should
happen (wrt bindings) with new temporaries at this stage. It's
easier once we begin gimplification. */
if (TREE_CODE (last) == EXPR_STMT)
*last_p = last = EXPR_STMT_EXPR (last);
/* If the end of the list is exception related, then the list was split
by a call to push_cleanup. Continue searching. */
if (TREE_CODE (last) == TRY_FINALLY_EXPR
|| TREE_CODE (last) == TRY_CATCH_EXPR)
{
last_p = &TREE_OPERAND (last, 0);
last = *last_p;
goto continue_searching;
}
/* In the case that the BIND_EXPR is not necessary, return the
expression out from inside it. */
if (last == BIND_EXPR_BODY (body) && BIND_EXPR_VARS (body) == NULL)
return last;
/* Extract the type of said expression. */
type = TREE_TYPE (last);
if (!type)
type = void_type_node;
no_expr:
/* If what's left is compound, make sure we've got a BIND_EXPR, and
that it has the proper type. */
ret = body;
if (TREE_CODE (ret) == STATEMENT_LIST)
ret = build (BIND_EXPR, type, NULL, ret, NULL);
else if (TREE_CODE (ret) == BIND_EXPR)
TREE_TYPE (ret) = type;
/* If we're not returning a value at all, then the BIND_EXPR that
we already have is a fine expression to return. */
if (!type || VOID_TYPE_P (type))
return body;
return ret;
/* Now that we've located the expression containing the value, it seems
silly to make voidify_wrapper_expr repeat the process. Create a
temporary of the appropriate type and stick it in a TARGET_EXPR. */
tmp = create_tmp_var_raw (type, NULL);
/* Unwrap a no-op NOP_EXPR as added by c_finish_expr_stmt. This avoids
tree_expr_nonnegative_p giving up immediately. */
val = last;
if (TREE_CODE (val) == NOP_EXPR
&& TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0)))
val = TREE_OPERAND (val, 0);
*last_p = build (MODIFY_EXPR, void_type_node, tmp, val);
SET_EXPR_LOCUS (*last_p, EXPR_LOCUS (last));
return build (TARGET_EXPR, type, tmp, body, NULL_TREE, NULL_TREE);
}
/* Begin and end compound statements. This is as simple as pushing
@ -6791,10 +6849,17 @@ c_end_compound_stmt (tree stmt, bool do_scope)
void
push_cleanup (tree decl ATTRIBUTE_UNUSED, tree cleanup, bool eh_only)
{
enum tree_code code = eh_only ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR;
tree stmt = build_stmt (code, NULL, cleanup);
enum tree_code code;
tree stmt, list;
bool stmt_expr;
code = eh_only ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR;
stmt = build_stmt (code, NULL, cleanup);
add_stmt (stmt);
TREE_OPERAND (stmt, 0) = push_stmt_list ();
stmt_expr = STATEMENT_LIST_STMT_EXPR (cur_stmt_list);
list = push_stmt_list ();
TREE_OPERAND (stmt, 0) = list;
STATEMENT_LIST_STMT_EXPR (list) = stmt_expr;
}
/* Build a binary-operation expression without default conversions.
@ -7412,7 +7477,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
constant expression involving such literals or a
conditional expression involving such literals)
and it is non-negative. */
if (c_tree_expr_nonnegative_p (sop))
if (tree_expr_nonnegative_p (sop))
/* OK */;
/* Do not warn if the comparison is an equality operation,
the unsigned quantity is an integral constant, and it

View file

@ -1,3 +1,7 @@
2004-06-21 Richard Henderson <rth@redhat.com>
* semantics.c (finish_expr_stmt): Call verify_sequence_points.
2004-06-20 Richard Henderson <rth@redhat.com>
* cp-tree.h (add_decl_stmt): Declare.

View file

@ -493,7 +493,11 @@ finish_expr_stmt (tree expr)
if (expr != NULL_TREE)
{
if (!processing_template_decl)
expr = convert_to_void (expr, "statement");
{
if (warn_sequence_point)
verify_sequence_points (expr);
expr = convert_to_void (expr, "statement");
}
else if (!type_dependent_expression_p (expr))
convert_to_void (build_non_dependent_expr (expr), "statement");

View file

@ -9267,6 +9267,37 @@ tree_expr_nonnegative_p (tree t)
case RTL_EXPR:
return rtl_expr_nonnegative_p (RTL_EXPR_RTL (t));
case TARGET_EXPR:
{
tree temp = TARGET_EXPR_SLOT (t);
t = TARGET_EXPR_INITIAL (t);
/* If the initializer is non-void, then it's a normal expression
that will be assigned to the slot. */
if (!VOID_TYPE_P (t))
return tree_expr_nonnegative_p (t);
/* Otherwise, the initializer sets the slot in some way. One common
way is an assignment statement at the end of the initializer. */
while (1)
{
if (TREE_CODE (t) == BIND_EXPR)
t = expr_last (BIND_EXPR_BODY (t));
else if (TREE_CODE (t) == TRY_FINALLY_EXPR
|| TREE_CODE (t) == TRY_CATCH_EXPR)
t = expr_last (TREE_OPERAND (t, 0));
else if (TREE_CODE (t) == STATEMENT_LIST)
t = expr_last (t);
else
break;
}
if (TREE_CODE (t) == MODIFY_EXPR
&& TREE_OPERAND (t, 0) == temp)
return tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
return 0;
}
case CALL_EXPR:
{
tree fndecl = get_callee_fndecl (t);

View file

@ -2472,13 +2472,19 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
return ret;
/* If we are initializing something from a TARGET_EXPR, strip the
TARGET_EXPR and initialize it directly. */
TARGET_EXPR and initialize it directly, if possible. This can't
be done if the initializer is void, since that implies that the
temporary is set in some non-trivial way. */
/* What about code that pulls out the temp and uses it elsewhere? I
think that such code never uses the TARGET_EXPR as an initializer. If
I'm wrong, we'll abort because the temp won't have any RTL. In that
case, I guess we'll need to replace references somehow. */
if (TREE_CODE (*from_p) == TARGET_EXPR)
*from_p = TARGET_EXPR_INITIAL (*from_p);
{
tree init = TARGET_EXPR_INITIAL (*from_p);
if (!VOID_TYPE_P (TREE_TYPE (init)))
*from_p = init;
}
/* If we're assigning from a ?: expression with ADDRESSABLE type, push
the assignment down into the branches, since we can't generate a
@ -3021,22 +3027,29 @@ gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p)
if (init)
{
/* TARGET_EXPR temps aren't part of the enclosing block, so add it to the
temps list. */
/* TARGET_EXPR temps aren't part of the enclosing block, so add it
to the temps list. */
gimple_add_tmp_var (temp);
/* Build up the initialization and add it to pre_p. Special handling
for BIND_EXPR can result in fewer temporaries created. */
if (TREE_CODE (init) == BIND_EXPR)
gimplify_bind_expr (&init, temp, pre_p);
if (init != temp)
/* If TARGET_EXPR_INITIAL is void, then the mere evaluation of the
expression is supposed to initialize the slot. */
if (VOID_TYPE_P (TREE_TYPE (init)))
ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt, fb_none);
else
{
if (! VOID_TYPE_P (TREE_TYPE (init)))
init = build (MODIFY_EXPR, void_type_node, temp, init);
ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt, fb_none);
if (ret == GS_ERROR)
return GS_ERROR;
/* Special handling for BIND_EXPR can result in fewer temps. */
ret = GS_OK;
if (TREE_CODE (init) == BIND_EXPR)
gimplify_bind_expr (&init, temp, pre_p);
if (init != temp)
{
init = build (MODIFY_EXPR, void_type_node, temp, init);
ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt,
fb_none);
}
}
if (ret == GS_ERROR)
return GS_ERROR;
append_to_statement_list (init, pre_p);
/* If needed, push the cleanup for the temp. */

View file

@ -1918,7 +1918,7 @@ build_module_descriptor (void)
build_unary_op (ADDR_EXPR, UOBJC_MODULES_decl, 0));
decelerator = build_function_call (execclass_decl, parms);
c_expand_expr_stmt (decelerator);
add_stmt (decelerator);
add_stmt (c_end_compound_stmt (compound, true));
finish_function ();

View file

@ -1,3 +1,8 @@
2004-06-21 Richard Henderson <rth@redhat.com>
* gcc.dg/tree-ssa/20030714-1.c: Rename variables to avoid
merging && to BIT_FIELD_REF.
2004-06-21 Richard Sandiford <rsandifo@redhat.com>
* g++.dg/opt/placeholder1.C: New test.

View file

@ -19,12 +19,12 @@ find_base_value (src)
rtx src;
{
rtx temp;
rtx src_0;
rtx src_1;
rtx src_0, src_2;
rtx src_1, src_3;
if ((src_0->code == REG) && (({src_0;})->frame_related))
if ((src_0->code == REG) && (({src_2;})->frame_related))
return find_base_value (src_0);
if ((src_1->code == REG) && (({ src_1;})->frame_related))
if ((src_1->code == REG) && (({ src_3;})->frame_related))
return find_base_value (src_1);
if (src_0->code == REG)
find_base_value (src_0);
@ -41,4 +41,3 @@ find_base_value (src)
/* There should be three loads of ->code. */
/* { dg-final { scan-tree-dump-times "->code" 3 "dom3"} } */

View file

@ -1251,11 +1251,14 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
case STRING_CST:
*walk_subtrees = 0;
return NULL;
/* Recognize assignments of large structures and constructors of
big arrays. */
case INIT_EXPR:
case TARGET_EXPR:
case MODIFY_EXPR:
x = TREE_OPERAND (x, 0);
/* FALLTHRU */
case TARGET_EXPR:
case CONSTRUCTOR:
{
HOST_WIDE_INT size;