+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):
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 *
/* 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;
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));
-}
\f
/* Validate the expression after `case' and apply default promotions. */
#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);
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 *);
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 ();
for_init_stmt:
xexpr ';'
- { add_stmt (build_stmt (EXPR_STMT, $1)); }
+ { c_finish_expr_stmt ($1); }
| decl
{ check_for_loop_decls (); }
;
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 ';'
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);
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
#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"
return result;
}
\f
-
-/* 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. */
/* 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");
FOR_BODY (for_stmt) = body;
}
\f
-/* 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)
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;
- return ret;
+ /* 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;
+
+ /* 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);
}
\f
/* Begin and end compound statements. This is as simple as pushing
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;
}
\f
/* Build a binary-operation expression without default conversions.
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
+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.
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");
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);
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
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. */
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 ();
+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.
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);
/* There should be three loads of ->code. */
/* { dg-final { scan-tree-dump-times "->code" 3 "dom3"} } */
-
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;