by the C-based front ends. The structure of gimplified, or
language-independent, trees is dictated by the grammar described in this
file.
- Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
Lowering of expressions contributed by Sebastian Pop <s.pop@laposte.net>
Re-written to support lowering of whole function trees, documentation
and miscellaneous cleanups by Diego Novillo <dnovillo@redhat.com>
/* Local declarations. */
-static void gimplify_cleanup_stmts (tree);
-
enum bc_t { bc_break = 0, bc_continue = 1 };
static struct c_gimplify_ctx
/* Go ahead and gimplify for now. */
push_context ();
- gimplify_cleanup_stmts (fndecl);
gimplify_function_tree (fndecl);
pop_context ();
c_genericize (cgn->decl);
}
-/* Genericize a CLEANUP_STMT. This just turns into a TRY_FINALLY or
- TRY_CATCH depending on whether it's EH-only. */
-
-static tree
-gimplify_cleanup_stmt (tree *stmt_p, int *walk_subtrees,
- void *data ATTRIBUTE_UNUSED)
-{
- tree stmt = *stmt_p;
-
- if (DECL_P (stmt) || TYPE_P (stmt))
- *walk_subtrees = 0;
- else if (TREE_CODE (stmt) == CLEANUP_STMT)
- *stmt_p = build (CLEANUP_EH_ONLY (stmt) ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR,
- void_type_node, CLEANUP_BODY (stmt), CLEANUP_EXPR (stmt));
-
- return NULL;
-}
-
-static void
-gimplify_cleanup_stmts (tree fndecl)
-{
- walk_tree (&DECL_SAVED_TREE (fndecl), gimplify_cleanup_stmt, NULL, NULL);
-}
-
static void
add_block_to_enclosing (tree block)
{
warning ("statement with no effect");
}
else if (warn_unused_value)
- {
- /* Kludge for 20020220-2.c. warn_if_unused_value shouldn't use
- the stmt file location info. */
- set_file_and_line_for_stmt (input_location);
- warn_if_unused_value (stmt);
- }
+ warn_if_unused_value (stmt, input_location);
}
if (stmt == NULL_TREE)
- stmt = build_empty_stmt ();
- else if (stmts_are_full_exprs_p ())
- stmt = build1 (CLEANUP_POINT_EXPR, void_type_node, stmt);
+ stmt = alloc_stmt_list ();
*stmt_p = stmt;
cont_block = begin_bc_block (bc_continue);
gimplify_stmt (&body);
- if (incr && stmts_are_full_exprs_p ())
- incr = fold (build1 (CLEANUP_POINT_EXPR, void_type_node, incr));
gimplify_stmt (&incr);
body = finish_bc_block (cont_block, body);
tree stmt = *stmt_p;
if (FOR_INIT_STMT (stmt))
- {
- gimplify_stmt (&FOR_INIT_STMT (stmt));
- append_to_statement_list (FOR_INIT_STMT (stmt), pre_p);
- }
+ gimplify_and_add (FOR_INIT_STMT (stmt), pre_p);
+
*stmt_p = gimplify_c_loop (FOR_COND (stmt), FOR_BODY (stmt),
FOR_EXPR (stmt), 1);
return GS_ALL_DONE;
}
-/* Genericize an IF_STMT by turning it into a COND_EXPR. */
-
-static enum gimplify_status
-gimplify_if_stmt (tree *stmt_p)
-{
- tree stmt, then_, else_;
-
- stmt = *stmt_p;
- then_ = THEN_CLAUSE (stmt);
- else_ = ELSE_CLAUSE (stmt);
-
- if (!then_)
- then_ = build_empty_stmt ();
- if (!else_)
- else_ = build_empty_stmt ();
-
- stmt = build (COND_EXPR, void_type_node, IF_COND (stmt), then_, else_);
- *stmt_p = stmt;
-
- return GS_OK;
-}
-
/* Genericize a SWITCH_STMT by turning it into a SWITCH_EXPR. */
static enum gimplify_status
*stmt_p = build (SWITCH_EXPR, SWITCH_TYPE (stmt), SWITCH_COND (stmt),
body, NULL_TREE);
- annotate_with_locus (*stmt_p, stmt_locus);
+ SET_EXPR_LOCATION (*stmt_p, stmt_locus);
gimplify_stmt (stmt_p);
*stmt_p = finish_bc_block (break_block, *stmt_p);
return GS_ALL_DONE;
}
-/* Genericize a RETURN_STMT by turning it into a RETURN_EXPR. */
-
-static enum gimplify_status
-gimplify_return_stmt (tree *stmt_p)
-{
- tree expr = RETURN_STMT_EXPR (*stmt_p);
- expr = build1 (RETURN_EXPR, void_type_node, expr);
- if (stmts_are_full_exprs_p ())
- expr = build1 (CLEANUP_POINT_EXPR, void_type_node, expr);
- *stmt_p = expr;
- return GS_OK;
-}
-
-/* Gimplifies a DECL_STMT node *STMT_P by making any necessary allocation
- and initialization explicit. */
-
-static enum gimplify_status
-gimplify_decl_stmt (tree *stmt_p)
-{
- tree stmt = *stmt_p;
- tree decl = DECL_STMT_DECL (stmt);
- tree pre = NULL_TREE;
- tree post = NULL_TREE;
-
- if (TREE_TYPE (decl) == error_mark_node)
- {
- *stmt_p = NULL;
- return GS_ERROR;
- }
-
- if (TREE_CODE (decl) == TYPE_DECL)
- {
- tree type = TREE_TYPE (decl);
- if (TYPE_SIZE_UNIT (type)
- && !TREE_CONSTANT (TYPE_SIZE_UNIT (type)))
- {
- /* This is a variable-sized array type. Simplify its size. */
- tree temp = TYPE_SIZE_UNIT (type);
- gimplify_expr (&temp, &pre, &post, is_gimple_val, fb_rvalue);
- }
- }
-
- if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
- {
- tree init = DECL_INITIAL (decl);
-
- if (!TREE_CONSTANT (DECL_SIZE (decl)))
- {
- tree pt_type = build_pointer_type (TREE_TYPE (decl));
- tree alloc, size;
-
- /* This is a variable-sized decl. Simplify its size and mark it
- for deferred expansion. Note that mudflap depends on the format
- of the emitted code: see mx_register_decls(). */
-
- size = get_initialized_tmp_var (DECL_SIZE_UNIT (decl), &pre, &post);
- DECL_DEFER_OUTPUT (decl) = 1;
- alloc = build_function_call_expr
- (implicit_built_in_decls[BUILT_IN_STACK_ALLOC],
- tree_cons (NULL_TREE,
- build1 (ADDR_EXPR, pt_type, decl),
- tree_cons (NULL_TREE, size, NULL_TREE)));
- append_to_compound_expr (alloc, &pre);
- }
-
- if (init && init != error_mark_node)
- {
- if (!TREE_STATIC (decl))
- {
- /* Do not warn about int x = x; as it is a GCC extension
- to turn off this warning but only if warn_init_self
- is zero. */
- if (init == decl && !warn_init_self)
- TREE_NO_WARNING (decl) = 1;
-
- DECL_INITIAL (decl) = NULL_TREE;
- init = build (MODIFY_EXPR, void_type_node, decl, init);
- if (stmts_are_full_exprs_p ())
- init = build1 (CLEANUP_POINT_EXPR, void_type_node, init);
- append_to_compound_expr (init, &pre);
- }
- else
- {
- /* We must still examine initializers for static variables
- as they may contain a label address. */
- walk_tree (&init, force_labels_r, NULL, NULL);
- }
- }
-
- /* This decl isn't mentioned in the enclosing block, so add it to the
- list of temps. FIXME it seems a bit of a kludge to say that
- anonymous artificial vars aren't pushed, but everything else is. */
- if (DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE)
- gimple_add_tmp_var (decl);
- }
-
- append_to_compound_expr (post, &pre);
- *stmt_p = pre;
- return GS_OK;
-}
-
/* Gimplification of expression trees. */
/* Gimplify a C99 compound literal expression. This just means adding the
- DECL_STMT before the current EXPR_STMT and using its anonymous decl
+ DECL_EXPR before the current EXPR_STMT and using its anonymous decl
instead. */
static enum gimplify_status
-gimplify_compound_literal_expr (tree *expr_p)
+gimplify_compound_literal_expr (tree *expr_p, tree *pre_p)
{
tree decl_s = COMPOUND_LITERAL_EXPR_DECL_STMT (*expr_p);
- tree decl = DECL_STMT_DECL (decl_s);
+ tree decl = DECL_EXPR_DECL (decl_s);
/* This decl isn't mentioned in the enclosing block, so add it to the
list of temps. FIXME it seems a bit of a kludge to say that
if (DECL_NAME (decl) == NULL_TREE)
gimple_add_tmp_var (decl);
- gimplify_decl_stmt (&decl_s);
- *expr_p = decl_s ? decl_s : decl;
+ gimplify_and_add (decl_s, pre_p);
+ *expr_p = decl;
return GS_OK;
}
switch (code)
{
+ case DECL_EXPR:
+ /* This is handled mostly by gimplify.c, but we have to deal with
+ not warning about int x = x; as it is a GCC extension to turn off
+ this warning but only if warn_init_self is zero. */
+ if (TREE_CODE (DECL_EXPR_DECL (*expr_p)) == VAR_DECL
+ && !DECL_EXTERNAL (DECL_EXPR_DECL (*expr_p))
+ && !TREE_STATIC (DECL_EXPR_DECL (*expr_p))
+ && (DECL_INITIAL (DECL_EXPR_DECL (*expr_p))
+ == DECL_EXPR_DECL (*expr_p))
+ && !warn_init_self)
+ TREE_NO_WARNING (DECL_EXPR_DECL (*expr_p)) = 1;
+ return GS_UNHANDLED;
+
case COMPOUND_LITERAL_EXPR:
- return gimplify_compound_literal_expr (expr_p);
+ return gimplify_compound_literal_expr (expr_p, pre_p);
case FOR_STMT:
return gimplify_for_stmt (expr_p, pre_p);
case DO_STMT:
return gimplify_do_stmt (expr_p);
- case IF_STMT:
- return gimplify_if_stmt (expr_p);
-
case SWITCH_STMT:
return gimplify_switch_stmt (expr_p);
case EXPR_STMT:
return gimplify_expr_stmt (expr_p);
- case RETURN_STMT:
- return gimplify_return_stmt (expr_p);
-
- case DECL_STMT:
- return gimplify_decl_stmt (expr_p);
-
case CONTINUE_STMT:
*expr_p = build_bc_goto (bc_continue);
return GS_ALL_DONE;