📄 decl.c
字号:
/* Nonzero if this is a namespace scope. */static intnamespace_bindings_p (){ return current_binding_level->namespace_p;}voidkeep_next_level (){ keep_next_level_flag = 1;}/* Nonzero if the current level needs to have a BLOCK made. */intkept_level_p (){ return (current_binding_level->blocks != NULL_TREE || current_binding_level->keep || current_binding_level->names != NULL_TREE || (current_binding_level->tags != NULL_TREE && !current_binding_level->tag_transparent));}/* Identify this binding level as a level of parameters. */voiddeclare_parm_level (){ current_binding_level->parm_flag = 1;}voiddeclare_pseudo_global_level (){ current_binding_level->pseudo_global = 1;}static voiddeclare_namespace_level (){ current_binding_level->namespace_p = 1;}intpseudo_global_level_p (){ return current_binding_level->pseudo_global;}voidset_class_shadows (shadows) tree shadows;{ class_binding_level->class_shadowed = shadows;}/* Enter a new binding level. If TAG_TRANSPARENT is nonzero, do so only for the name space of variables, not for that of tags. */voidpushlevel (tag_transparent) int tag_transparent;{ register struct binding_level *newlevel = NULL_BINDING_LEVEL; /* If this is the top level of a function, just make sure that NAMED_LABELS is 0. They should have been set to 0 at the end of the previous function. */ if (current_binding_level == global_binding_level) my_friendly_assert (named_labels == NULL_TREE, 134); /* 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 (); } push_binding_level (newlevel, tag_transparent, keep_next_level_flag); GNU_xref_start_scope ((HOST_WIDE_INT) newlevel); keep_next_level_flag = 0;}voidnote_level_for_for (){ current_binding_level->is_for_scope = 1;}voidpushlevel_temporary (tag_transparent) int tag_transparent;{ pushlevel (tag_transparent); current_binding_level->keep = 2; clear_last_expr (); /* Note we don't call push_momentary() here. Otherwise, it would cause cleanups to be allocated on the momentary obstack, and they will be overwritten by the next statement. */ expand_start_bindings (0);}/* 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 KEEP == 2, this level's subblocks go to the front, not the back of the current binding level. This happens, for instance, when code for constructors and destructors need to generate code at the end of a function which must be moved up to the front of the function. 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; 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; /* Clear out the meanings of the local variables of this level. */ if (current_binding_level->is_for_scope && flag_new_for_scope == 1) { struct binding_level *outer = current_binding_level->level_chain; for (link = decls; link; link = TREE_CHAIN (link)) { if (TREE_CODE (link) == VAR_DECL) DECL_DEAD_FOR_LOCAL (link) = 1; else IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = NULL_TREE; } /* Save declarations made in a 'for' statement so we can support pre-ANSI 'for' scoping semantics. */ for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link)) { tree id = TREE_PURPOSE (link); tree decl = IDENTIFIER_LOCAL_VALUE (id); if (decl && DECL_DEAD_FOR_LOCAL (decl)) { /* In this case keep the dead for-decl visible, but remember what (if anything) it shadowed. */ DECL_SHADOWED_FOR_VAR (decl) = TREE_VALUE (link); TREE_CHAIN (decl) = outer->dead_vars_from_for; outer->dead_vars_from_for = decl; } else IDENTIFIER_LOCAL_VALUE (id) = TREE_VALUE (link); } } else /* Not special for scope. */ { for (link = decls; link; link = TREE_CHAIN (link)) { if (DECL_NAME (link) != NULL_TREE) { /* If the ident. was used or addressed via a local extern decl, don't forget that fact. */ if (DECL_EXTERNAL (link)) { if (TREE_USED (link)) TREE_USED (DECL_ASSEMBLER_NAME (link)) = 1; if (TREE_ADDRESSABLE (link)) TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (link)) = 1; } IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = NULL_TREE; } } /* Restore all name-meanings of the outer levels that were shadowed by this level. */ for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link)) IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); /* We first restore the regular decls and *then* the dead_vars_from_for to handle this case: int i; // i#1 { for (int i; ; ) { ...} // i#2 int i; // i#3 } // we are here In this case, we want remove the binding for i#3, restoring that of i#2. Then we want to remove the binding for i#2, and restore that of i#1. */ link = current_binding_level->dead_vars_from_for; for (; link != NULL_TREE; link = TREE_CHAIN (link)) { tree id = DECL_NAME (link); if (IDENTIFIER_LOCAL_VALUE (id) == link) IDENTIFIER_LOCAL_VALUE (id) = DECL_SHADOWED_FOR_VAR (link); } for (link = current_binding_level->class_shadowed; link; link = TREE_CHAIN (link)) IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); for (link = current_binding_level->type_shadowed; link; link = TREE_CHAIN (link)) IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); } /* 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) { if (keep == 2) current_binding_level->blocks = chainon (subblocks, current_binding_level->blocks); else 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;}/* Resume a binding level for a namespace. */voidresume_level (b) struct binding_level *b;{ tree decls, link; resume_binding_level (b);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -