diff options
Diffstat (limited to 'gcc/gimplify.c')
-rw-r--r-- | gcc/gimplify.c | 72 |
1 files changed, 71 insertions, 1 deletions
diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 347e946..7ef88b5 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -660,7 +660,7 @@ copy_if_shared_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, /* Special-case BIND_EXPR. We should never be copying these, therefore we can omit examining BIND_EXPR_VARS. Which also avoids problems with double processing of the DECL_INITIAL, which could be seen via both - the BIND_EXPR_VARS and a DECL_STMT. */ + the BIND_EXPR_VARS and a DECL_EXPR. */ else if (code == BIND_EXPR) { if (TREE_VISITED (t)) @@ -1004,6 +1004,72 @@ gimplify_return_expr (tree stmt, tree *pre_p) return GS_ALL_DONE; } +/* Gimplifies a DECL_EXPR node *STMT_P by making any necessary allocation + and initialization explicit. */ + +static enum gimplify_status +gimplify_decl_expr (tree *stmt_p) +{ + tree stmt = *stmt_p; + tree decl = DECL_EXPR_DECL (stmt); + + *stmt_p = NULL_TREE; + + if (TREE_TYPE (decl) == error_mark_node) + return GS_ERROR; + + else if (TREE_CODE (decl) == TYPE_DECL) + gimplify_type_sizes (TREE_TYPE (decl), stmt_p); + + else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl)) + { + tree init = DECL_INITIAL (decl); + + if (!TREE_CONSTANT (DECL_SIZE (decl))) + { + /* 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(). */ + tree t, args; + + gimplify_type_sizes (TREE_TYPE (decl), stmt_p); + gimplify_one_sizepos (&DECL_SIZE (decl), stmt_p); + gimplify_one_sizepos (&DECL_SIZE_UNIT (decl), stmt_p); + + args = tree_cons (NULL, DECL_SIZE_UNIT (decl), NULL); + t = build_fold_addr_expr (decl); + args = tree_cons (NULL, t, args); + t = implicit_built_in_decls[BUILT_IN_STACK_ALLOC]; + t = build_function_call_expr (t, args); + + gimplify_and_add (t, stmt_p); + DECL_DEFER_OUTPUT (decl) = 1; + } + + if (init && init != error_mark_node) + { + if (!TREE_STATIC (decl)) + { + DECL_INITIAL (decl) = NULL_TREE; + init = build (MODIFY_EXPR, void_type_node, decl, init); + gimplify_and_add (init, stmt_p); + } + 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); + } + + return GS_ALL_DONE; +} + /* Gimplify a LOOP_EXPR. Normally this just involves gimplifying the body and replacing the LOOP_EXPR with goto, but if the loop contains an EXIT_EXPR, we need to append a label for it to jump to. */ @@ -3521,6 +3587,10 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p, *expr_p = DECL_INITIAL (*expr_p); break; + case DECL_EXPR: + ret = gimplify_decl_expr (expr_p); + break; + case EXC_PTR_EXPR: /* FIXME make this a decl. */ ret = GS_ALL_DONE; |