X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-nested.c;h=b1ab217340b24b3507fa5113a91f8ee8c1aa9556;hb=9508132a0f3d625ed0b5e8fc2f4f65faa18d2160;hp=1a00ff30f864fed5dc11740f1db38d4fac81ed71;hpb=88bce6369d989a3f87112ad26b981d2415147783;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index 1a00ff30f86..b1ab217340b 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -1,5 +1,5 @@ /* Nested function decomposition for trees. - Copyright (C) 2004 Free Software Foundation, Inc. + Copyright (C) 2004, 2005 Free Software Foundation, Inc. This file is part of GCC. @@ -55,7 +55,7 @@ The implementation here is much more direct. Everything that can be referenced by an inner function is a member of an explicitly created - structure herein called the "nonlocal frame struct". The incomming + structure herein called the "nonlocal frame struct". The incoming static chain for a nested function is a pointer to this struct in the parent. In this way, we settle on known offsets from a known base, and so are decoupled from the logic that places objects in the @@ -132,20 +132,17 @@ create_tmp_var_for (struct nesting_info *info, tree type, const char *prefix) { tree tmp_var; -#if defined ENABLE_CHECKING - /* If the type is an array or a type which must be created by the + /* If the type is of variable size or a type which must be created by the frontend, something is wrong. Note that we explicitly allow incomplete types here, since we create them ourselves here. */ - if (TREE_CODE (type) == ARRAY_TYPE || TREE_ADDRESSABLE (type)) - abort (); - if (TYPE_SIZE_UNIT (type) - && TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST) - abort (); -#endif + gcc_assert (!TREE_ADDRESSABLE (type)); + gcc_assert (!TYPE_SIZE_UNIT (type) + || TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST); tmp_var = create_tmp_var_raw (type, prefix); DECL_CONTEXT (tmp_var) = info->context; TREE_CHAIN (tmp_var) = info->new_local_var_chain; + DECL_SEEN_IN_BIND_EXPR_P (tmp_var) = 1; info->new_local_var_chain = tmp_var; return tmp_var; @@ -153,12 +150,14 @@ create_tmp_var_for (struct nesting_info *info, tree type, const char *prefix) /* Take the address of EXP. Mark it for addressability as necessary. */ -static tree +tree build_addr (tree exp) { tree base = exp; - while (TREE_CODE (base) == COMPONENT_REF || TREE_CODE (base) == ARRAY_REF) + + while (handled_component_p (base)) base = TREE_OPERAND (base, 0); + if (DECL_P (base)) TREE_ADDRESSABLE (base) = 1; @@ -246,8 +245,7 @@ lookup_field_for_decl (struct nesting_info *info, tree decl, slot = htab_find_slot (info->var_map, &dummy, insert); if (!slot) { - if (insert == INSERT) - abort (); + gcc_assert (insert != INSERT); return NULL; } elt = *slot; @@ -306,15 +304,16 @@ get_chain_decl (struct nesting_info *info) /* Note that this variable is *not* entered into any BIND_EXPR; the construction of this variable is handled specially in - expand_function_start and initialize_inlined_parameters. */ - decl = create_tmp_var_raw (type, "CHAIN"); + expand_function_start and initialize_inlined_parameters. + Note also that it's represented as a parameter. This is more + close to the truth, since the initial value does come from + the caller. */ + decl = build_decl (PARM_DECL, create_tmp_var_name ("CHAIN"), type); + DECL_ARTIFICIAL (decl) = 1; + DECL_IGNORED_P (decl) = 1; + TREE_USED (decl) = 1; DECL_CONTEXT (decl) = info->context; - decl->decl.seen_in_bind_expr = 1; - - /* The initialization of CHAIN is not visible to the tree-ssa - analyzers and optimizers. Thus we do not want to issue - warnings for CHAIN. */ - TREE_NO_WARNING (decl) = 1; + DECL_ARG_TYPE (decl) = type; /* Tell tree-inline.c that we never write to this variable, so it can copy-prop the replacement value immediately. */ @@ -369,7 +368,7 @@ init_tmp_var (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi) /* Similarly, but only do so to force EXP to satisfy is_gimple_val. */ static tree -gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi) +tsi_gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi) { if (is_gimple_val (exp)) return exp; @@ -377,6 +376,23 @@ gimplify_val (struct nesting_info *info, tree exp, tree_stmt_iterator *tsi) return init_tmp_var (info, exp, tsi); } +/* Similarly, but copy from the temporary and insert the statement + after the iterator. */ + +static tree +save_tmp_var (struct nesting_info *info, tree exp, + tree_stmt_iterator *tsi) +{ + tree t, stmt; + + t = create_tmp_var_for (info, TREE_TYPE (exp), NULL); + stmt = build (MODIFY_EXPR, TREE_TYPE (t), exp, t); + SET_EXPR_LOCUS (stmt, EXPR_LOCUS (tsi_stmt (*tsi))); + tsi_link_after (tsi, stmt, TSI_SAME_STMT); + + return t; +} + /* Build or return the type used to represent a nested function trampoline. */ static GTY(()) tree trampoline_type; @@ -401,7 +417,7 @@ get_trampoline_type (void) align = STACK_BOUNDARY; } - t = build_index_type (build_int_2 (size - 1, 0)); + t = build_index_type (build_int_cst (NULL_TREE, size - 1)); t = build_array_type (char_type_node, t); t = build_decl (FIELD_DECL, get_identifier ("__data"), t); DECL_ALIGN (t) = align; @@ -430,8 +446,7 @@ lookup_tramp_for_decl (struct nesting_info *info, tree decl, slot = htab_find_slot (info->var_map, &dummy, insert); if (!slot) { - if (insert == INSERT) - abort (); + gcc_assert (insert != INSERT); return NULL; } elt = *slot; @@ -473,7 +488,7 @@ get_nl_goto_field (struct nesting_info *info) /* For __builtin_nonlocal_goto, we need N words. The first is the frame pointer, the rest is for the target's stack pointer save - area. The number of words is controled by STACK_SAVEAREA_MODE; + area. The number of words is controlled by STACK_SAVEAREA_MODE; not the best interface, but it'll do for now. */ if (Pmode == ptr_mode) type = ptr_type_node; @@ -484,7 +499,8 @@ get_nl_goto_field (struct nesting_info *info) size = size / GET_MODE_SIZE (Pmode); size = size + 1; - type = build_array_type (type, build_index_type (build_int_2 (size, 0))); + type = build_array_type + (type, build_index_type (build_int_cst (NULL_TREE, size))); field = make_node (FIELD_DECL); DECL_NAME (field) = get_identifier ("__nl_goto_buf"); @@ -518,6 +534,8 @@ struct walk_stmt_info tree_stmt_iterator tsi; struct nesting_info *info; bool val_only; + bool is_lhs; + bool changed; }; /* A subroutine of walk_function. Iterate over all sub-statements of *TP. */ @@ -549,6 +567,7 @@ walk_stmts (struct walk_stmt_info *wi, tree *tp) break; case CATCH_EXPR: walk_stmts (wi, &CATCH_BODY (t)); + break; case EH_FILTER_EXPR: walk_stmts (wi, &EH_FILTER_FAILURE (t)); break; @@ -566,12 +585,18 @@ walk_stmts (struct walk_stmt_info *wi, tree *tp) break; case MODIFY_EXPR: - /* The immediate arguments of a MODIFY_EXPR may use COMPONENT_REF. */ - wi->val_only = false; - walk_tree (&TREE_OPERAND (t, 0), wi->callback, wi, NULL); - wi->val_only = false; + /* A formal temporary lhs may use a COMPONENT_REF rhs. */ + wi->val_only = !is_gimple_formal_tmp_var (TREE_OPERAND (t, 0)); walk_tree (&TREE_OPERAND (t, 1), wi->callback, wi, NULL); + + /* If the rhs is appropriate for a memory, we may use a + COMPONENT_REF on the lhs. */ + wi->val_only = !is_gimple_mem_rhs (TREE_OPERAND (t, 1)); + wi->is_lhs = true; + walk_tree (&TREE_OPERAND (t, 0), wi->callback, wi, NULL); + wi->val_only = true; + wi->is_lhs = false; break; default: @@ -610,8 +635,49 @@ walk_all_functions (walk_tree_fn callback, struct nesting_info *root) } while (root); } - +/* We have to check for a fairly pathological case. The operands of function + nested function are to be interpreted in the context of the enclosing + function. So if any are variably-sized, they will get remapped when the + enclosing function is inlined. But that remapping would also have to be + done in the types of the PARM_DECLs of the nested function, meaning the + argument types of that function will disagree with the arguments in the + calls to that function. So we'd either have to make a copy of the nested + function corresponding to each time the enclosing function was inlined or + add a VIEW_CONVERT_EXPR to each such operand for each call to the nested + function. The former is not practical. The latter would still require + detecting this case to know when to add the conversions. So, for now at + least, we don't inline such an enclosing function. + + We have to do that check recursively, so here return indicating whether + FNDECL has such a nested function. ORIG_FN is the function we were + trying to inline to use for checking whether any argument is variably + modified by anything in it. + + It would be better to do this in tree-inline.c so that we could give + the appropriate warning for why a function can't be inlined, but that's + too late since the nesting structure has already been flattened and + adding a flag just to record this fact seems a waste of a flag. */ + +static bool +check_for_nested_with_variably_modified (tree fndecl, tree orig_fndecl) +{ + struct cgraph_node *cgn = cgraph_node (fndecl); + tree arg; + + for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) + { + for (arg = DECL_ARGUMENTS (cgn->decl); arg; arg = TREE_CHAIN (arg)) + if (variably_modified_type_p (TREE_TYPE (arg), 0), orig_fndecl) + return true; + + if (check_for_nested_with_variably_modified (cgn->decl, orig_fndecl)) + return true; + } + + return false; +} + /* Construct our local datastructure describing the function nesting tree rooted by CGN. */ @@ -630,6 +696,11 @@ create_nesting_tree (struct cgraph_node *cgn) info->inner = sub; } + /* See discussion at check_for_nested_with_variably_modified for a + discussion of why this has to be here. */ + if (check_for_nested_with_variably_modified (info->context, info->context)) + DECL_UNINLINABLE (info->context) = true; + return info; } @@ -656,7 +727,7 @@ get_static_chain (struct nesting_info *info, tree target_context, tree field = get_chain_field (i); x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x); - x = build (COMPONENT_REF, TREE_TYPE (field), x, field); + x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE); x = init_tmp_var (info, x, tsi); } } @@ -690,14 +761,14 @@ get_frame_field (struct nesting_info *info, tree target_context, tree field = get_chain_field (i); x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x); - x = build (COMPONENT_REF, TREE_TYPE (field), x, field); + x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE); x = init_tmp_var (info, x, tsi); } x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x); } - x = build (COMPONENT_REF, TREE_TYPE (field), x, field); + x = build (COMPONENT_REF, TREE_TYPE (field), x, field, NULL_TREE); return x; } @@ -731,6 +802,7 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) tree target_context = decl_function_context (t); struct nesting_info *i; tree x; + wi->changed = true; for (i = info->outer; i->context != target_context; i = i->outer) continue; @@ -741,8 +813,14 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) x = init_tmp_var (info, x, &wi->tsi); x = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (x)), x); } + if (wi->val_only) - x = init_tmp_var (info, x, &wi->tsi); + { + if (wi->is_lhs) + x = save_tmp_var (info, x, &wi->tsi); + else + x = init_tmp_var (info, x, &wi->tsi); + } *tp = x; } @@ -754,6 +832,7 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) { *walk_subtrees = 1; wi->val_only = true; + wi->is_lhs = false; } break; @@ -769,55 +848,72 @@ convert_nonlocal_reference (tree *tp, int *walk_subtrees, void *data) case ADDR_EXPR: { bool save_val_only = wi->val_only; - tree save_sub = TREE_OPERAND (t, 0); wi->val_only = false; + wi->is_lhs = false; + wi->changed = false; walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL); wi->val_only = true; - if (save_sub != TREE_OPERAND (t, 0)) + if (wi->changed) { /* If we changed anything, then TREE_INVARIANT is be wrong, since we're no longer directly referencing a decl. */ - TREE_INVARIANT (t) = 0; + recompute_tree_invarant_for_addr_expr (t); /* If the callback converted the address argument in a context where we only accept variables (and min_invariant, presumably), then compute the address into a temporary. */ if (save_val_only) - *tp = gimplify_val (wi->info, t, &wi->tsi); + *tp = tsi_gimplify_val (wi->info, t, &wi->tsi); } } break; - case COMPONENT_REF: case REALPART_EXPR: case IMAGPART_EXPR: - wi->val_only = false; - walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL); - wi->val_only = true; - break; - + case COMPONENT_REF: case ARRAY_REF: - wi->val_only = false; - walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL); - wi->val_only = true; - walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi, NULL); - break; - + case ARRAY_RANGE_REF: case BIT_FIELD_REF: - wi->val_only = false; - walk_tree (&TREE_OPERAND (t, 0), convert_nonlocal_reference, wi, NULL); + /* Go down this entire nest and just look at the final prefix and + anything that describes the references. Otherwise, we lose track + of whether a NOP_EXPR or VIEW_CONVERT_EXPR needs a simple value. */ wi->val_only = true; - walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi, NULL); - walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi, NULL); + wi->is_lhs = false; + for (; handled_component_p (t); tp = &TREE_OPERAND (t, 0), t = *tp) + { + if (TREE_CODE (t) == COMPONENT_REF) + walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi, + NULL); + else if (TREE_CODE (t) == ARRAY_REF + || TREE_CODE (t) == ARRAY_RANGE_REF) + { + walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi, + NULL); + walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi, + NULL); + walk_tree (&TREE_OPERAND (t, 3), convert_nonlocal_reference, wi, + NULL); + } + else if (TREE_CODE (t) == BIT_FIELD_REF) + { + walk_tree (&TREE_OPERAND (t, 1), convert_nonlocal_reference, wi, + NULL); + walk_tree (&TREE_OPERAND (t, 2), convert_nonlocal_reference, wi, + NULL); + } + } + wi->val_only = false; + walk_tree (tp, convert_nonlocal_reference, wi, NULL); break; default: - if (!DECL_P (t) && !TYPE_P (t)) + if (!IS_TYPE_OR_DECL_P (t)) { *walk_subtrees = 1; wi->val_only = true; + wi->is_lhs = false; } break; } @@ -834,7 +930,7 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data) { struct walk_stmt_info *wi = data; struct nesting_info *info = wi->info; - tree t = *tp, field, x, y; + tree t = *tp, field, x; switch (TREE_CODE (t)) { @@ -857,10 +953,18 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data) field = lookup_field_for_decl (info, t, NO_INSERT); if (!field) break; + wi->changed = true; x = get_frame_field (info, info->context, field, &wi->tsi); + if (wi->val_only) - x = init_tmp_var (info, x, &wi->tsi); + { + if (wi->is_lhs) + x = save_tmp_var (info, x, &wi->tsi); + else + x = init_tmp_var (info, x, &wi->tsi); + } + *tp = x; } break; @@ -868,88 +972,73 @@ convert_local_reference (tree *tp, int *walk_subtrees, void *data) case ADDR_EXPR: { bool save_val_only = wi->val_only; - tree save_sub = TREE_OPERAND (t, 0); wi->val_only = false; + wi->is_lhs = false; + wi->changed = false; walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL); wi->val_only = save_val_only; /* If we converted anything ... */ - if (TREE_OPERAND (t, 0) != save_sub) + if (wi->changed) { /* Then the frame decl is now addressable. */ TREE_ADDRESSABLE (info->frame_decl) = 1; + + recompute_tree_invarant_for_addr_expr (t); /* If we are in a context where we only accept values, then compute the address into a temporary. */ if (save_val_only) - *tp = gimplify_val (wi->info, t, &wi->tsi); + *tp = tsi_gimplify_val (wi->info, t, &wi->tsi); } } break; - case CALL_EXPR: - *walk_subtrees = 1; - - /* Ready for some fun? We need to recognize - __builtin_stack_alloc (&x, n) - and insert - FRAME.x = &x - after that. X should have use_pointer_in_frame set. We can't - do this any earlier, since we can't meaningfully evaluate &x. */ - - x = get_callee_fndecl (t); - if (!x || DECL_BUILT_IN_CLASS (x) != BUILT_IN_NORMAL) - break; - if (DECL_FUNCTION_CODE (x) != BUILT_IN_STACK_ALLOC) - break; - t = TREE_VALUE (TREE_OPERAND (t, 1)); - if (TREE_CODE (t) != ADDR_EXPR) - abort (); - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) != VAR_DECL) - abort (); - field = lookup_field_for_decl (info, t, NO_INSERT); - if (!field) - break; - if (!use_pointer_in_frame (t)) - abort (); - - x = build_addr (t); - y = get_frame_field (info, info->context, field, &wi->tsi); - x = build (MODIFY_EXPR, void_type_node, y, x); - SET_EXPR_LOCUS (x, EXPR_LOCUS (tsi_stmt (wi->tsi))); - tsi_link_after (&wi->tsi, x, TSI_SAME_STMT); - break; - - case COMPONENT_REF: case REALPART_EXPR: case IMAGPART_EXPR: - wi->val_only = false; - walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL); - wi->val_only = true; - break; - + case COMPONENT_REF: case ARRAY_REF: - wi->val_only = false; - walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL); - wi->val_only = true; - walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi, NULL); - break; - + case ARRAY_RANGE_REF: case BIT_FIELD_REF: - wi->val_only = false; - walk_tree (&TREE_OPERAND (t, 0), convert_local_reference, wi, NULL); + /* Go down this entire nest and just look at the final prefix and + anything that describes the references. Otherwise, we lose track + of whether a NOP_EXPR or VIEW_CONVERT_EXPR needs a simple value. */ wi->val_only = true; - walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi, NULL); - walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi, NULL); + wi->is_lhs = false; + for (; handled_component_p (t); tp = &TREE_OPERAND (t, 0), t = *tp) + { + if (TREE_CODE (t) == COMPONENT_REF) + walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi, + NULL); + else if (TREE_CODE (t) == ARRAY_REF + || TREE_CODE (t) == ARRAY_RANGE_REF) + { + walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi, + NULL); + walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi, + NULL); + walk_tree (&TREE_OPERAND (t, 3), convert_local_reference, wi, + NULL); + } + else if (TREE_CODE (t) == BIT_FIELD_REF) + { + walk_tree (&TREE_OPERAND (t, 1), convert_local_reference, wi, + NULL); + walk_tree (&TREE_OPERAND (t, 2), convert_local_reference, wi, + NULL); + } + } + wi->val_only = false; + walk_tree (tp, convert_local_reference, wi, NULL); break; default: - if (!DECL_P (t) && !TYPE_P (t)) + if (!IS_TYPE_OR_DECL_P (t)) { *walk_subtrees = 1; wi->val_only = true; + wi->is_lhs = false; } break; } @@ -986,7 +1075,7 @@ convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data) /* The original user label may also be use for a normal goto, therefore we must create a new label that will actually receive the abnormal control transfer. This new label will be marked LABEL_NONLOCAL; this - mark will trigger proper behaviour in the cfg, as well as cause the + mark will trigger proper behavior in the cfg, as well as cause the (hairy target-specific) non-local goto receiver code to be generated when we expand rtl. */ new_label = create_artificial_label (); @@ -1004,7 +1093,7 @@ convert_nl_goto_reference (tree *tp, int *walk_subtrees, void *data) field = get_nl_goto_field (i); x = get_frame_field (info, target_context, field, &wi->tsi); x = build_addr (x); - x = gimplify_val (info, x, &wi->tsi); + x = tsi_gimplify_val (info, x, &wi->tsi); arg = tree_cons (NULL, x, NULL); x = build_addr (new_label); arg = tree_cons (NULL, x, arg); @@ -1102,7 +1191,7 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data) /* Compute the address of the field holding the trampoline. */ x = get_frame_field (info, target_context, x, &wi->tsi); x = build_addr (x); - x = gimplify_val (info, x, &wi->tsi); + x = tsi_gimplify_val (info, x, &wi->tsi); arg = tree_cons (NULL, x, NULL); /* Do machine-specific ugliness. Normally this will involve @@ -1125,7 +1214,7 @@ convert_tramp_reference (tree *tp, int *walk_subtrees, void *data) break; default: - if (!DECL_P (t) && !TYPE_P (t)) + if (!IS_TYPE_OR_DECL_P (t)) *walk_subtrees = 1; break; } @@ -1159,7 +1248,8 @@ convert_call_expr (tree *tp, int *walk_subtrees, void *data) case RETURN_EXPR: case MODIFY_EXPR: - /* Only return and modify may contain calls. */ + case WITH_SIZE_EXPR: + /* Only return modify and with_size_expr may contain calls. */ *walk_subtrees = 1; break; @@ -1189,12 +1279,7 @@ convert_all_function_calls (struct nesting_info *root) if (root->outer && !root->chain_decl && !root->chain_field) DECL_NO_STATIC_CHAIN (root->context) = 1; else - { -#ifdef ENABLE_CHECKING - if (DECL_NO_STATIC_CHAIN (root->context)) - abort (); -#endif - } + gcc_assert (!DECL_NO_STATIC_CHAIN (root->context)); root = root->next; } @@ -1212,6 +1297,7 @@ finalize_nesting_tree_1 (struct nesting_info *root) tree stmt_list = NULL; tree context = root->context; struct function *sf; + struct cgraph_node *node; /* If we created a non-local frame type or decl, we need to lay them out at this time. */ @@ -1241,7 +1327,7 @@ finalize_nesting_tree_1 (struct nesting_info *root) x = p; y = build (COMPONENT_REF, TREE_TYPE (field), - root->frame_decl, field); + root->frame_decl, field, NULL_TREE); x = build (MODIFY_EXPR, TREE_TYPE (field), y, x); append_to_statement_list (x, &stmt_list); } @@ -1251,9 +1337,8 @@ finalize_nesting_tree_1 (struct nesting_info *root) from chain_decl. */ if (root->chain_field) { - tree x; - x = build (COMPONENT_REF, TREE_TYPE (root->chain_field), - root->frame_decl, root->chain_field); + tree x = build (COMPONENT_REF, TREE_TYPE (root->chain_field), + root->frame_decl, root->chain_field, NULL_TREE); x = build (MODIFY_EXPR, TREE_TYPE (x), x, get_chain_decl (root)); append_to_statement_list (x, &stmt_list); } @@ -1280,7 +1365,7 @@ finalize_nesting_tree_1 (struct nesting_info *root) arg = tree_cons (NULL, x, arg); x = build (COMPONENT_REF, TREE_TYPE (field), - root->frame_decl, field); + root->frame_decl, field, NULL_TREE); x = build_addr (x); arg = tree_cons (NULL, x, arg); @@ -1315,7 +1400,7 @@ finalize_nesting_tree_1 (struct nesting_info *root) sf->has_nonlocal_label = 1; } - /* Make sure all new local variables get insertted into the + /* Make sure all new local variables get inserted into the proper BIND_EXPR. */ if (root->new_local_var_chain) declare_tmp_vars (root->new_local_var_chain, @@ -1323,6 +1408,15 @@ finalize_nesting_tree_1 (struct nesting_info *root) /* Dump the translated tree function. */ dump_function (TDI_nested, root->context); + node = cgraph_node (root->context); + + /* For nested functions update the cgraph to reflect unnesting. + We also delay finalizing of these functions up to this point. */ + if (node->origin) + { + cgraph_unnest_node (cgraph_node (root->context)); + cgraph_finalize_function (root->context, true); + } } static void