📄 decl.c
字号:
}/* Exit a binding level. Pop the level off, and restore the state of the identifier-decl mappings that were in effect when this level was entered. If KEEP == 1, this level had explicit declarations, so and create a "block" (a BLOCK node) for the level to record its declarations and subblocks for symbol table output. If FUNCTIONBODY is nonzero, this level is the body of a function, so create a block as if KEEP were set and also clear out all label names. If REVERSE is nonzero, reverse the order of decls before putting them into the BLOCK. */treepoplevel (keep, reverse, functionbody) int keep; int reverse; int functionbody;{ register tree link; /* The chain of decls was accumulated in reverse order. Put it into forward order, just for cleanliness. */ tree decls; int tmp = functionbody; int real_functionbody = current_binding_level->keep == 2 ? ((functionbody = 0), tmp) : functionbody; tree tags = functionbody >= 0 ? current_binding_level->tags : 0; tree subblocks = functionbody >= 0 ? current_binding_level->blocks : 0; tree block = NULL_TREE; tree decl; int block_previously_created; int leaving_for_scope; if (current_binding_level->parm_flag == 2) return poplevel_class (); my_friendly_assert (!current_binding_level->class_shadowed, 19990414); /* We used to use KEEP == 2 to indicate that the new block should go at the beginning of the list of blocks at this binding level, rather than the end. This hack is no longer used. */ my_friendly_assert (keep == 0 || keep == 1, 0); GNU_xref_end_scope ((HOST_WIDE_INT) current_binding_level, (HOST_WIDE_INT) current_binding_level->level_chain, current_binding_level->parm_flag, current_binding_level->keep); if (current_binding_level->keep == 1) keep = 1; /* Get the decls in the order they were written. Usually current_binding_level->names is in reverse order. But parameter decls were previously put in forward order. */ if (reverse) current_binding_level->names = decls = nreverse (current_binding_level->names); else decls = current_binding_level->names; /* Output any nested inline functions within this block if they weren't already output. */ for (decl = decls; decl; decl = TREE_CHAIN (decl)) if (TREE_CODE (decl) == FUNCTION_DECL && ! TREE_ASM_WRITTEN (decl) && DECL_INITIAL (decl) != NULL_TREE && TREE_ADDRESSABLE (decl) && decl_function_context (decl) == current_function_decl) { /* If this decl was copied from a file-scope decl on account of a block-scope extern decl, propagate TREE_ADDRESSABLE to the file-scope decl. */ if (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE) TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1; else { push_function_context (); output_inline_function (decl); pop_function_context (); } } /* If there were any declarations or structure tags in that level, or if this level is a function body, create a BLOCK to record them for the life of this function. */ block = NULL_TREE; block_previously_created = (current_binding_level->this_block != NULL_TREE); if (block_previously_created) block = current_binding_level->this_block; else if (keep == 1 || functionbody) block = make_node (BLOCK); if (block != NULL_TREE) { if (block_previously_created) { if (decls || tags || subblocks) { if (BLOCK_VARS (block) || BLOCK_TYPE_TAGS (block)) warning ("internal compiler error: debugging info corrupted"); BLOCK_VARS (block) = decls; BLOCK_TYPE_TAGS (block) = tags; /* We can have previous subblocks and new subblocks when doing fixup_gotos with complex cleanups. We chain the new subblocks onto the end of any pre-existing subblocks. */ BLOCK_SUBBLOCKS (block) = chainon (BLOCK_SUBBLOCKS (block), subblocks); } /* If we created the block earlier on, and we are just diddling it now, then it already should have a proper BLOCK_END_NOTE value associated with it. */ } else { BLOCK_VARS (block) = decls; BLOCK_TYPE_TAGS (block) = tags; BLOCK_SUBBLOCKS (block) = subblocks; /* Otherwise, for a new block, install a new BLOCK_END_NOTE value. */ remember_end_note (block); } } /* In each subblock, record that this is its superior. */ if (keep >= 0) for (link = subblocks; link; link = TREE_CHAIN (link)) BLOCK_SUPERCONTEXT (link) = block; /* We still support the old for-scope rules, whereby the variables in a for-init statement were in scope after the for-statement ended. We only use the new rules in flag_new_for_scope is nonzero. */ leaving_for_scope = current_binding_level->is_for_scope && flag_new_for_scope == 1; /* Remove declarations for all the DECLs in this level. */ for (link = decls; link; link = TREE_CHAIN (link)) { if (leaving_for_scope && TREE_CODE (link) == VAR_DECL) { tree outer_binding = TREE_CHAIN (IDENTIFIER_BINDING (DECL_NAME (link))); tree ns_binding; if (!outer_binding) ns_binding = IDENTIFIER_NAMESPACE_VALUE (DECL_NAME (link)); else ns_binding = NULL_TREE; if (outer_binding && (BINDING_LEVEL (outer_binding) == current_binding_level->level_chain)) /* We have something like: int i; for (int i; ;); and we are leaving the `for' scope. There's no reason to keep the binding of the inner `i' in this case. */ pop_binding (DECL_NAME (link), link); else if ((outer_binding && (TREE_CODE (BINDING_VALUE (outer_binding)) == TYPE_DECL)) || (ns_binding && TREE_CODE (ns_binding) == TYPE_DECL)) /* Here, we have something like: typedef int I; void f () { for (int I; ;); } We must pop the for-scope binding so we know what's a type and what isn't. */ pop_binding (DECL_NAME (link), link); else { /* Mark this VAR_DECL as dead so that we can tell we left it there only for backward compatibility. */ DECL_DEAD_FOR_LOCAL (link) = 1; /* Keep track of what should of have happenned when we popped the binding. */ if (outer_binding && BINDING_VALUE (outer_binding)) DECL_SHADOWED_FOR_VAR (link) = BINDING_VALUE (outer_binding); /* Add it to the list of dead variables in the next outermost binding to that we can remove these when we leave that binding. */ current_binding_level->level_chain->dead_vars_from_for = tree_cons (NULL_TREE, link, current_binding_level->level_chain-> dead_vars_from_for); /* Although we don't pop the CPLUS_BINDING, we do clear its BINDING_LEVEL since the level is going away now. */ BINDING_LEVEL (IDENTIFIER_BINDING (DECL_NAME (link))) = 0; } } else { /* Remove the binding. */ decl = link; if (TREE_CODE (decl) == TREE_LIST) decl = TREE_VALUE (decl); if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd') pop_binding (DECL_NAME (decl), decl); else if (TREE_CODE (decl) == OVERLOAD) pop_binding (DECL_NAME (OVL_FUNCTION (decl)), decl); else my_friendly_abort (0); } } /* Remove declarations for any `for' variables from inner scopes that we kept around. */ for (link = current_binding_level->dead_vars_from_for; link; link = TREE_CHAIN (link)) pop_binding (DECL_NAME (TREE_VALUE (link)), TREE_VALUE (link)); /* Restore the IDENTIFIER_TYPE_VALUEs. */ for (link = current_binding_level->type_shadowed; link; link = TREE_CHAIN (link)) SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link), TREE_VALUE (link)); /* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs list if a `using' declaration put them there. The debugging back-ends won't understand OVERLOAD, so we remove them here. Because the BLOCK_VARS are (temporarily) shared with CURRENT_BINDING_LEVEL->NAMES we must do this fixup after we have popped all the bindings. */ if (block) { tree* d; for (d = &BLOCK_VARS (block); *d; ) { if (TREE_CODE (*d) == TREE_LIST) *d = TREE_CHAIN (*d); else d = &TREE_CHAIN (*d); } } /* If the level being exited is the top level of a function, check over all the labels. */ if (functionbody) { /* If this is the top level block of a function, the vars are the function's parameters. Don't leave them in the BLOCK because they are found in the FUNCTION_DECL instead. */ BLOCK_VARS (block) = 0; /* Clear out the definitions of all label names, since their scopes end here. */ for (link = named_labels; link; link = TREE_CHAIN (link)) { register tree label = TREE_VALUE (link); if (DECL_INITIAL (label) == NULL_TREE) { cp_error_at ("label `%D' used but not defined", label); /* Avoid crashing later. */ define_label (input_filename, 1, DECL_NAME (label)); } else if (warn_unused && !TREE_USED (label)) cp_warning_at ("label `%D' defined but not used", label); SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), NULL_TREE); /* Put the labels into the "variables" of the top-level block, so debugger can see them. */ TREE_CHAIN (label) = BLOCK_VARS (block); BLOCK_VARS (block) = label; } named_labels = NULL_TREE; } /* Any uses of undefined labels now operate under constraints of next binding contour. */ { struct binding_level *level_chain; level_chain = current_binding_level->level_chain; if (level_chain) { struct named_label_list *labels; for (labels = named_label_uses; labels; labels = labels->next) if (labels->binding_level == current_binding_level) { labels->binding_level = level_chain; labels->names_in_scope = level_chain->names; } } } tmp = current_binding_level->keep; pop_binding_level (); if (functionbody) DECL_INITIAL (current_function_decl) = block; else if (block) { if (!block_previously_created) current_binding_level->blocks = chainon (current_binding_level->blocks, block); } /* If we did not make a block for the level just exited, any blocks made for inner levels (since they cannot be recorded as subblocks in that level) must be carried forward so they will later become subblocks of something else. */ else if (subblocks) current_binding_level->blocks = chainon (current_binding_level->blocks, subblocks); /* Take care of compiler's internal binding structures. */ if (tmp == 2) { expand_end_bindings (getdecls (), keep, 1); /* Each and every BLOCK node created here in `poplevel' is important (e.g. for proper debugging information) so if we created one earlier, mark it as "used". */ if (block) TREE_USED (block) = 1; block = poplevel (keep, reverse, real_functionbody); } /* Each and every BLOCK node created here in `poplevel' is important (e.g. for proper debugging information) so if we created one earlier, mark it as "used". */ if (block) TREE_USED (block) = 1; return block;}/* Delete the node BLOCK from the current binding level. This is used for the block inside a stmt expr ({...}) so that the block can be reinserted where appropriate. */voiddelete_block (block) tree block;{ tree t; if (current_binding_level->blocks == block) current_binding_level->blocks = TREE_CHAIN (block); for (t = current_binding_level->blocks; t;) { if (TREE_CHAIN (t) == block) TREE_CHAIN (t) = TREE_CHAIN (block); else t = TREE_CHAIN (t); } TREE_CHAIN (block) = NULL_TREE; /* Clear TREE_USED which is always set by poplevel. The flag is set again if insert_block is called. */ TREE_USED (block) = 0;}/* Insert BLOCK at the end of the list of subblocks of the current binding level. This is used when a BIND_EXPR is expanded, to handle the BLOCK node inside the BIND_EXPR. */voidinsert_block (block) tree block;{ TREE_USED (block) = 1; current_binding_level->blocks = chainon (current_binding_level->blocks, block);}/* Set the BLOCK node for the innermost scope (the one we are currently in). */voidset_block (block) register tree block;{ current_binding_level->this_block = block;}/* Do a pushlevel for class declarations. */voidpushlevel_class (){ register struct binding_level *newlevel; /* Reuse or create a struct for this binding level. */#if defined(DEBUG_CP_BINDING_LEVELS) if (0)#else /* !defined(DEBUG_CP_BINDING_LEVELS) */ if (free_binding_level)#endif /* !defined(DEBUG_CP_BINDING_LEVELS) */ { newlevel = free_binding_level; free_binding_level = free_binding_level->level_chain; } else newlevel = make_binding_level ();#if defined(DEBUG_CP_BINDING_LEVELS) is_class_level = 1;#endif /* defined(DEBUG_CP_BINDING_LEVELS) */ push_binding_level (newlevel, 0, 0); decl_stack = push_decl_level (decl_stack, &decl_obstack); class_binding_level = current_binding_level; class_binding_level->parm_flag = 2;}/* ...and a poplevel for class declarations. */static treepoplevel_class (){ register struct binding_level *level = class_binding_level; tree shadowed; my_friendly_assert (level != 0, 354);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -