* c-decl.c (named_labels, shadowed_labels, label_level_chain)
(push_label_level, pop_label_level): Kill. (struct binding_level): Rename level_chain to outer. Add outer_function field. Change parm_flag, function_body, keep, keep_if_subblocks to 1-bit bitfields of type bool. (current_function_level): New variable. (keep_next_level_flag, keep_next_if_subblocks): Change type to bool. (keep_next_level, declare_parm_level, warn_if_shadowing): Update to match. (struct language_function): Kill named_labels, shadowed_labels fields. (c_init_decl_processing, start_function, c_push__function_context) (c_pop_function_context): No need to muck with named_labels nor shadowed_labels. (make_binding_level): No need to clear the structure here. (pop_binding_level): Always operate on current_binding_level. Update current_function_level if necessary. (pushlevel): Don't clear named_labels. Update current_function_level if necessary. Use "true" and "false" where appropriate. (poplevel): Diagnose labels defined but not used, or vice versa, and clear out label-meanings leaving scope, while walking down the decls list, for all binding levels. Handle LABEL_DECLs appearing in the shadowed list. pop_binding_level takes no arguments. (pushdecl_function_level): Use current_function_level. (make_label, bind_label): New static functions. (declare_label): New exported function. (lookup_label, define_label): Rewritten for new data structure. (shadow_label): Kill. * c-tree.h: Prototype declare_label; don't prototype push_label_level, pop_label_level, nor shadow_label. * c-parse.in: Remove all calls to push_label_level and pop_label_level. Use declare_label for __label__ decls. * doc/extend.texi: Clarify that __label__ can be used to declare labels with local scope in any nested block, not just statement expressions. Cross-reference nested functions section from local labels section. testsuite: * gcc.dg/noncompile/label-1.c: New comprehensive test case for diagnostics of ill-formed constructs involving labels. * gcc.dg/noncompile/label-lineno-1.c: Add error regexp for the new 'previously defined here' message. From-SVN: r69597
This commit is contained in:
parent
1b339d862a
commit
14e33ee856
8 changed files with 472 additions and 296 deletions
|
@ -1,3 +1,46 @@
|
|||
2003-07-19 Zack Weinberg <zack@codesourcery.com>
|
||||
|
||||
* c-decl.c (named_labels, shadowed_labels, label_level_chain)
|
||||
(push_label_level, pop_label_level): Kill.
|
||||
(struct binding_level): Rename level_chain to outer.
|
||||
Add outer_function field. Change parm_flag, function_body,
|
||||
keep, keep_if_subblocks to 1-bit bitfields of type bool.
|
||||
(current_function_level): New variable.
|
||||
(keep_next_level_flag, keep_next_if_subblocks): Change type to bool.
|
||||
(keep_next_level, declare_parm_level, warn_if_shadowing):
|
||||
Update to match.
|
||||
(struct language_function): Kill named_labels, shadowed_labels fields.
|
||||
(c_init_decl_processing, start_function, c_push__function_context)
|
||||
(c_pop_function_context): No need to muck with named_labels nor
|
||||
shadowed_labels.
|
||||
|
||||
(make_binding_level): No need to clear the structure here.
|
||||
(pop_binding_level): Always operate on current_binding_level.
|
||||
Update current_function_level if necessary.
|
||||
(pushlevel): Don't clear named_labels. Update current_function_level
|
||||
if necessary. Use "true" and "false" where appropriate.
|
||||
(poplevel): Diagnose labels defined but not used, or vice
|
||||
versa, and clear out label-meanings leaving scope, while
|
||||
walking down the decls list, for all binding levels.
|
||||
Handle LABEL_DECLs appearing in the shadowed list.
|
||||
pop_binding_level takes no arguments.
|
||||
(pushdecl_function_level): Use current_function_level.
|
||||
|
||||
(make_label, bind_label): New static functions.
|
||||
(declare_label): New exported function.
|
||||
(lookup_label, define_label): Rewritten for new data structure.
|
||||
(shadow_label): Kill.
|
||||
|
||||
* c-tree.h: Prototype declare_label; don't prototype
|
||||
push_label_level, pop_label_level, nor shadow_label.
|
||||
* c-parse.in: Remove all calls to push_label_level and
|
||||
pop_label_level. Use declare_label for __label__ decls.
|
||||
|
||||
* doc/extend.texi: Clarify that __label__ can be used to
|
||||
declare labels with local scope in any nested block, not
|
||||
just statement expressions. Cross-reference nested functions
|
||||
section from local labels section.
|
||||
|
||||
2003-07-19 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
|
||||
|
||||
* sched-rgn.c (find_rgns): Initialize current_edge correctly.
|
||||
|
@ -13,7 +56,7 @@
|
|||
|
||||
2003-07-19 Ulrich Weigand <uweigand@de.ibm.com>
|
||||
|
||||
* config/s390/s390.c (legitimize_pic_address): Access local symbols
|
||||
* config/s390/s390.c (legitimize_pic_address): Access local symbols
|
||||
relative to the GOT instead of relative to the literal pool base.
|
||||
(s390_output_symbolic_const): Handle new GOT-relative accesses.
|
||||
* config/s390/s390.md ("call"): Access local functions and PLT stubs
|
||||
|
@ -21,7 +64,7 @@
|
|||
("call_value"): Likewise.
|
||||
("call_value_tls"): Likewise.
|
||||
|
||||
* config/s390/s390.c (s390_chunkify_start): Remove pool anchor
|
||||
* config/s390/s390.c (s390_chunkify_start): Remove pool anchor
|
||||
reloading. Support LTREL_BASE / LTREL_OFFSET construct.
|
||||
(s390_chunkify_finish): Likewise.
|
||||
(s390_chunkify_cancel): Likewise.
|
||||
|
@ -40,12 +83,12 @@
|
|||
* config/s390/s390.c (s390_split_branches): Use LTREL_BASE/OFFSET.
|
||||
(s390_load_got): New function. Use LTREL_BASE/OFFSET.
|
||||
(s390_emit_prologue): Use it.
|
||||
* config/s390/s390.md ("builtin_longjmp", "builtin_setjmp_setup",
|
||||
"builtin_setjmp_receiver"): Cleanup. Use s390_load_got. Do not
|
||||
* config/s390/s390.md ("builtin_longjmp", "builtin_setjmp_setup",
|
||||
"builtin_setjmp_receiver"): Cleanup. Use s390_load_got. Do not
|
||||
hard-code register 14.
|
||||
* config/s390/s390-protos.h (s390_load_got): Declare.
|
||||
|
||||
* config/s390/s390.c (NR_C_MODES, constant_modes, gen_consttable):
|
||||
* config/s390/s390.c (NR_C_MODES, constant_modes, gen_consttable):
|
||||
Support TImode constants.
|
||||
* config/s390/s390.md ("consttable_ti"): New.
|
||||
("consttable_si", "consttable_di"): Handle TLS symbols correctly.
|
||||
|
@ -61,7 +104,7 @@
|
|||
"pool_start_64", "pool_end_64", "reload_base_31", "reload_base_64",
|
||||
"pool", "literal_pool_31", "literal_pool_64"): Cleanup. Use
|
||||
symbolic UNSPEC values.
|
||||
* config/s390/s390.c (larl_operand, s390_short_displacement,
|
||||
* config/s390/s390.c (larl_operand, s390_short_displacement,
|
||||
bras_sym_operand, s390_cannot_force_const_mem,
|
||||
s390_delegitimize_address, s390_decompose_address,
|
||||
legitimize_pic_address, s390_output_symbolic_const,
|
||||
|
@ -163,7 +206,7 @@
|
|||
|
||||
2003-07-18 Kazu Hirata <kazu@cs.umass.edu>
|
||||
|
||||
* combine.c (simplify_comparison): Don't share rtx when converting
|
||||
* combine.c (simplify_comparison): Don't share rtx when converting
|
||||
(ne (and (not X) 1) 0) to (eq (and X 1) 0).
|
||||
|
||||
2003-07-18 David Edelsohn <edelsohn@gnu.org>
|
||||
|
|
461
gcc/c-decl.c
461
gcc/c-decl.c
|
@ -115,16 +115,6 @@ static GTY(()) struct stmt_tree_s c_stmt_tree;
|
|||
|
||||
static GTY(()) tree c_scope_stmt_stack;
|
||||
|
||||
/* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function
|
||||
that have names. Here so we can clear out their names' definitions
|
||||
at the end of the function. */
|
||||
|
||||
static GTY(()) tree named_labels;
|
||||
|
||||
/* A list of LABEL_DECLs from outer contexts that are currently shadowed. */
|
||||
|
||||
static GTY(()) tree shadowed_labels;
|
||||
|
||||
/* A list of external DECLs that appeared at block scope when there was
|
||||
some other global meaning for that identifier. */
|
||||
static GTY(()) tree truly_local_externals;
|
||||
|
@ -206,23 +196,26 @@ struct binding_level GTY(())
|
|||
that were entered and exited one level down. */
|
||||
tree blocks;
|
||||
|
||||
/* The binding level which this one is contained in (inherits from). */
|
||||
struct binding_level *level_chain;
|
||||
/* The scope containing this one. */
|
||||
struct binding_level *outer;
|
||||
|
||||
/* Nonzero if we are currently filling this level with parameter
|
||||
/* The next outermost function scope. */
|
||||
struct binding_level *outer_function;
|
||||
|
||||
/* True if we are currently filling this level with parameter
|
||||
declarations. */
|
||||
char parm_flag;
|
||||
bool parm_flag : 1;
|
||||
|
||||
/* Nonzero if this is the outermost block scope of a function body.
|
||||
/* True if this is the outermost block scope of a function body.
|
||||
This scope contains both the parameters and the local variables
|
||||
declared in the outermost block. */
|
||||
char function_body;
|
||||
bool function_body : 1;
|
||||
|
||||
/* Nonzero means make a BLOCK for this level regardless of all else. */
|
||||
char keep;
|
||||
/* True means make a BLOCK for this level regardless of all else. */
|
||||
bool keep : 1;
|
||||
|
||||
/* Nonzero means make a BLOCK if this level has any subblocks. */
|
||||
char keep_if_subblocks;
|
||||
/* True means make a BLOCK if this level has any subblocks. */
|
||||
bool keep_if_subblocks : 1;
|
||||
|
||||
/* List of decls in `names' that have incomplete structure or
|
||||
union types. */
|
||||
|
@ -244,28 +237,24 @@ static GTY(()) struct binding_level *current_binding_level;
|
|||
|
||||
static GTY((deletable (""))) struct binding_level *free_binding_level;
|
||||
|
||||
/* The innermost function scope. Ordinary (not explicitly declared)
|
||||
labels, bindings to error_mark_node, and the lazily-created
|
||||
bindings of __func__ and its friends get this scope. */
|
||||
static GTY(()) struct binding_level *current_function_level;
|
||||
|
||||
/* The outermost binding level, for names of file scope.
|
||||
This is created when the compiler is started and exists
|
||||
through the entire run. */
|
||||
|
||||
static GTY(()) struct binding_level *global_binding_level;
|
||||
|
||||
/* Nonzero means unconditionally make a BLOCK for the next level pushed. */
|
||||
/* True means unconditionally make a BLOCK for the next level pushed. */
|
||||
|
||||
static int keep_next_level_flag;
|
||||
static bool keep_next_level_flag;
|
||||
|
||||
/* Nonzero means make a BLOCK for the next level pushed
|
||||
if it has subblocks. */
|
||||
/* True means make a BLOCK for the next level pushed if it has subblocks. */
|
||||
|
||||
static int keep_next_if_subblocks;
|
||||
|
||||
/* The chain of outer levels of label scopes.
|
||||
This uses the same data structure used for binding levels,
|
||||
but it works differently: each link in the chain records
|
||||
saved values of named_labels and shadowed_labels for
|
||||
a label binding level outside the current one. */
|
||||
|
||||
static GTY(()) struct binding_level *label_level_chain;
|
||||
static bool keep_next_if_subblocks;
|
||||
|
||||
/* Functions called automatically at the beginning and end of execution. */
|
||||
|
||||
|
@ -274,9 +263,11 @@ tree static_ctors, static_dtors;
|
|||
/* Forward declarations. */
|
||||
|
||||
static struct binding_level *make_binding_level (void);
|
||||
static void pop_binding_level (struct binding_level **);
|
||||
static void pop_binding_level (void);
|
||||
static int duplicate_decls (tree, tree, int, int);
|
||||
static int redeclaration_error_message (tree, tree);
|
||||
static tree make_label (tree, location_t);
|
||||
static void bind_label (tree, tree, struct binding_level *);
|
||||
static void implicit_decl_warning (tree);
|
||||
static void storedecls (tree);
|
||||
static void storetags (tree);
|
||||
|
@ -356,8 +347,7 @@ make_binding_level (void)
|
|||
if (free_binding_level)
|
||||
{
|
||||
result = free_binding_level;
|
||||
free_binding_level = result->level_chain;
|
||||
memset (result, 0, sizeof(struct binding_level));
|
||||
free_binding_level = result->outer;
|
||||
}
|
||||
else
|
||||
result = ggc_alloc_cleared (sizeof (struct binding_level));
|
||||
|
@ -365,17 +355,21 @@ make_binding_level (void)
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Remove a binding level from a list and add it to the level chain. */
|
||||
/* Remove the topmost binding level from the stack and add it to the
|
||||
free list, updating current_function_level if necessary. */
|
||||
|
||||
static void
|
||||
pop_binding_level (struct binding_level **lp)
|
||||
pop_binding_level (void)
|
||||
{
|
||||
struct binding_level *l = *lp;
|
||||
*lp = l->level_chain;
|
||||
struct binding_level *scope = current_binding_level;
|
||||
|
||||
memset (l, 0, sizeof (struct binding_level));
|
||||
l->level_chain = free_binding_level;
|
||||
free_binding_level = l;
|
||||
current_binding_level = scope->outer;
|
||||
if (scope->function_body)
|
||||
current_function_level = scope->outer_function;
|
||||
|
||||
memset (scope, 0, sizeof (struct binding_level));
|
||||
scope->outer = free_binding_level;
|
||||
free_binding_level = scope;
|
||||
}
|
||||
|
||||
/* Nonzero if we are currently in the global binding level. */
|
||||
|
@ -389,7 +383,7 @@ global_bindings_p (void)
|
|||
void
|
||||
keep_next_level (void)
|
||||
{
|
||||
keep_next_level_flag = 1;
|
||||
keep_next_level_flag = true;
|
||||
}
|
||||
|
||||
/* Identify this binding level as a level of parameters. */
|
||||
|
@ -397,7 +391,7 @@ keep_next_level (void)
|
|||
void
|
||||
declare_parm_level (void)
|
||||
{
|
||||
current_binding_level->parm_flag = 1;
|
||||
current_binding_level->parm_flag = true;
|
||||
}
|
||||
|
||||
/* Nonzero if currently making parm declarations. */
|
||||
|
@ -413,12 +407,6 @@ in_parm_level_p (void)
|
|||
void
|
||||
pushlevel (int dummy ATTRIBUTE_UNUSED)
|
||||
{
|
||||
/* If this is the top level of a function, make sure that
|
||||
NAMED_LABELS is 0. */
|
||||
|
||||
if (current_binding_level == global_binding_level)
|
||||
named_labels = 0;
|
||||
|
||||
if (keep_next_if_subblocks)
|
||||
{
|
||||
/* This is the transition from the parameters to the top level
|
||||
|
@ -429,22 +417,24 @@ pushlevel (int dummy ATTRIBUTE_UNUSED)
|
|||
store_parm_decls, which in turn is called when and only
|
||||
when we are about to encounter the opening curly brace for
|
||||
the function body. */
|
||||
current_binding_level->parm_flag = 0;
|
||||
current_binding_level->function_body = 1;
|
||||
current_binding_level->keep |= keep_next_level_flag;
|
||||
current_binding_level->keep_if_subblocks = 1;
|
||||
current_binding_level->parm_flag = false;
|
||||
current_binding_level->function_body = true;
|
||||
current_binding_level->keep |= keep_next_level_flag;
|
||||
current_binding_level->keep_if_subblocks = true;
|
||||
current_binding_level->outer_function = current_function_level;
|
||||
current_function_level = current_binding_level;
|
||||
|
||||
keep_next_level_flag = 0;
|
||||
keep_next_if_subblocks = 0;
|
||||
keep_next_level_flag = false;
|
||||
keep_next_if_subblocks = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct binding_level *newlevel = make_binding_level ();
|
||||
|
||||
newlevel->keep = keep_next_level_flag;
|
||||
newlevel->level_chain = current_binding_level;
|
||||
newlevel->keep = keep_next_level_flag;
|
||||
newlevel->outer = current_binding_level;
|
||||
current_binding_level = newlevel;
|
||||
keep_next_level_flag = 0;
|
||||
keep_next_level_flag = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -496,7 +486,27 @@ poplevel (int keep, int reverse, int functionbody)
|
|||
containing functions. */
|
||||
for (link = decls; link; link = TREE_CHAIN (link))
|
||||
{
|
||||
if (DECL_NAME (link) != 0)
|
||||
if (TREE_CODE (link) == LABEL_DECL)
|
||||
{
|
||||
if (TREE_USED (link) && DECL_INITIAL (link) == 0)
|
||||
{
|
||||
error ("%Hlabel `%D' used but not defined",
|
||||
&DECL_SOURCE_LOCATION (link), link);
|
||||
/* Avoid crashing later. */
|
||||
DECL_INITIAL (link) = error_mark_node;
|
||||
}
|
||||
else if (!TREE_USED (link) && warn_unused_label)
|
||||
{
|
||||
if (DECL_INITIAL (link) != 0)
|
||||
warning ("%Hlabel `%D' defined but not used",
|
||||
&DECL_SOURCE_LOCATION (link), link);
|
||||
else
|
||||
warning ("%Hlabel `%D' declared but not defined",
|
||||
&DECL_SOURCE_LOCATION (link), link);
|
||||
}
|
||||
IDENTIFIER_LABEL_VALUE (DECL_NAME (link)) = 0;
|
||||
}
|
||||
else if (DECL_NAME (link) != 0)
|
||||
{
|
||||
if (DECL_EXTERNAL (link)
|
||||
&& current_binding_level != global_binding_level)
|
||||
|
@ -521,11 +531,14 @@ poplevel (int keep, int reverse, int functionbody)
|
|||
if (TREE_PURPOSE (link))
|
||||
IDENTIFIER_TAG_VALUE (TREE_PURPOSE (link)) = 0;
|
||||
|
||||
/* Restore all name-meanings of the outer levels
|
||||
/* Restore all name- and label-meanings of the outer levels
|
||||
that were shadowed by this level. */
|
||||
|
||||
for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
|
||||
IDENTIFIER_SYMBOL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
|
||||
if (TREE_VALUE (link) && TREE_CODE (TREE_VALUE (link)) == LABEL_DECL)
|
||||
IDENTIFIER_LABEL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
|
||||
else
|
||||
IDENTIFIER_SYMBOL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
|
||||
|
||||
/* Restore all tag-meanings of the outer levels
|
||||
that were shadowed by this level. */
|
||||
|
@ -599,38 +612,8 @@ poplevel (int keep, int reverse, int functionbody)
|
|||
for (link = tags; link; link = TREE_CHAIN (link))
|
||||
TYPE_CONTEXT (TREE_VALUE (link)) = decl;
|
||||
|
||||
/* If the level being exited is the top level of a function, check
|
||||
over all the labels, and clear out the current (function local)
|
||||
meanings of their names. Then add them to BLOCK_VARS. */
|
||||
|
||||
if (functionbody)
|
||||
{
|
||||
for (link = named_labels; link; link = TREE_CHAIN (link))
|
||||
{
|
||||
tree label = TREE_VALUE (link);
|
||||
|
||||
if (DECL_INITIAL (label) == 0)
|
||||
{
|
||||
error ("%Hlabel '%D' used but not defined",
|
||||
&DECL_SOURCE_LOCATION (label), label);
|
||||
/* Avoid crashing later. */
|
||||
define_label (input_location, DECL_NAME (label));
|
||||
}
|
||||
else if (warn_unused_label && !TREE_USED (label))
|
||||
warning ("%Hlabel '%D' defined but not used",
|
||||
&DECL_SOURCE_LOCATION (label), label);
|
||||
IDENTIFIER_LABEL_VALUE (DECL_NAME (label)) = 0;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pop the current level, and free the structure for reuse. */
|
||||
|
||||
pop_binding_level (¤t_binding_level);
|
||||
pop_binding_level ();
|
||||
|
||||
/* Dispose of the block that we just made inside some higher level. */
|
||||
if (functionbody)
|
||||
|
@ -671,77 +654,6 @@ set_block (tree block ATTRIBUTE_UNUSED)
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
push_label_level (void)
|
||||
{
|
||||
struct binding_level *newlevel;
|
||||
|
||||
newlevel = make_binding_level ();
|
||||
|
||||
/* Add this level to the front of the chain (stack) of label levels. */
|
||||
|
||||
newlevel->level_chain = label_level_chain;
|
||||
label_level_chain = newlevel;
|
||||
|
||||
newlevel->names = named_labels;
|
||||
newlevel->shadowed = shadowed_labels;
|
||||
named_labels = 0;
|
||||
shadowed_labels = 0;
|
||||
}
|
||||
|
||||
void
|
||||
pop_label_level (void)
|
||||
{
|
||||
struct binding_level *level = label_level_chain;
|
||||
tree link, prev;
|
||||
|
||||
/* Clear out the definitions of the declared labels in this level.
|
||||
Leave in the list any ordinary, non-declared labels. */
|
||||
for (link = named_labels, prev = 0; link;)
|
||||
{
|
||||
if (C_DECLARED_LABEL_FLAG (TREE_VALUE (link)))
|
||||
{
|
||||
if (DECL_SOURCE_LINE (TREE_VALUE (link)) == 0)
|
||||
{
|
||||
error ("%Hlabel '%D' used but not defined",
|
||||
&DECL_SOURCE_LOCATION (TREE_VALUE (link)),
|
||||
TREE_VALUE (link));
|
||||
/* Avoid crashing later. */
|
||||
define_label (input_location, DECL_NAME (TREE_VALUE (link)));
|
||||
}
|
||||
else if (warn_unused_label && !TREE_USED (TREE_VALUE (link)))
|
||||
warning ("%Hlabel '%D' defined but not used",
|
||||
&DECL_SOURCE_LOCATION (TREE_VALUE (link)),
|
||||
TREE_VALUE (link));
|
||||
IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link))) = 0;
|
||||
|
||||
/* Delete this element from the list. */
|
||||
link = TREE_CHAIN (link);
|
||||
if (prev)
|
||||
TREE_CHAIN (prev) = link;
|
||||
else
|
||||
named_labels = link;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev = link;
|
||||
link = TREE_CHAIN (link);
|
||||
}
|
||||
}
|
||||
|
||||
/* Bring back all the labels that were shadowed. */
|
||||
for (link = shadowed_labels; link; link = TREE_CHAIN (link))
|
||||
if (DECL_NAME (TREE_VALUE (link)) != 0)
|
||||
IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link)))
|
||||
= TREE_VALUE (link);
|
||||
|
||||
named_labels = chainon (named_labels, level->names);
|
||||
shadowed_labels = level->shadowed;
|
||||
|
||||
/* Pop the current level, and free the structure for reuse. */
|
||||
pop_binding_level (&label_level_chain);
|
||||
}
|
||||
|
||||
/* Push a definition or a declaration of struct, union or enum tag "name".
|
||||
"type" should be the type node.
|
||||
We assume that the tag "name" is not already defined.
|
||||
|
@ -1631,7 +1543,7 @@ warn_if_shadowing (tree x, tree old)
|
|||
declarator in a declaration, as opposed to a definition,
|
||||
but there is no way to tell it's not a definition. */
|
||||
|| (TREE_CODE (x) == PARM_DECL
|
||||
&& current_binding_level->level_chain->parm_flag))
|
||||
&& current_binding_level->outer->parm_flag))
|
||||
return;
|
||||
|
||||
name = IDENTIFIER_POINTER (DECL_NAME (x));
|
||||
|
@ -1864,13 +1776,7 @@ pushdecl_top_level (tree x)
|
|||
static void
|
||||
pushdecl_function_level (tree x, tree name)
|
||||
{
|
||||
struct binding_level *scope;
|
||||
|
||||
scope = current_binding_level;
|
||||
while (scope->function_body == 0)
|
||||
scope = scope->level_chain;
|
||||
if (!scope)
|
||||
abort ();
|
||||
struct binding_level *scope = current_function_level;
|
||||
|
||||
if (x == error_mark_node)
|
||||
scope->shadowed = tree_cons (name, IDENTIFIER_SYMBOL_VALUE (name),
|
||||
|
@ -2051,84 +1957,110 @@ undeclared_variable (tree id)
|
|||
}
|
||||
}
|
||||
|
||||
/* Get the LABEL_DECL corresponding to identifier ID as a label.
|
||||
/* Subroutine of lookup_label, declare_label, define_label: construct a
|
||||
LABEL_DECL with all the proper frills. */
|
||||
|
||||
static tree
|
||||
make_label (tree name, location_t location)
|
||||
{
|
||||
tree label = build_decl (LABEL_DECL, name, void_type_node);
|
||||
|
||||
DECL_CONTEXT (label) = current_function_decl;
|
||||
DECL_MODE (label) = VOIDmode;
|
||||
DECL_SOURCE_LOCATION (label) = location;
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
/* Another subroutine of lookup_label, declare_label, define_label:
|
||||
set up the binding of name to LABEL_DECL in the given SCOPE. */
|
||||
|
||||
static void
|
||||
bind_label (tree name, tree label, struct binding_level *scope)
|
||||
{
|
||||
if (IDENTIFIER_LABEL_VALUE (name))
|
||||
scope->shadowed = tree_cons (name, IDENTIFIER_LABEL_VALUE (name),
|
||||
scope->shadowed);
|
||||
IDENTIFIER_LABEL_VALUE (name) = label;
|
||||
|
||||
TREE_CHAIN (label) = scope->names;
|
||||
scope->names = label;
|
||||
}
|
||||
|
||||
/* Get the LABEL_DECL corresponding to identifier NAME as a label.
|
||||
Create one if none exists so far for the current function.
|
||||
This function is called for both label definitions and label references. */
|
||||
This is called when a label is used in a goto expression or
|
||||
has its address taken. */
|
||||
|
||||
tree
|
||||
lookup_label (tree id)
|
||||
lookup_label (tree name)
|
||||
{
|
||||
tree decl = IDENTIFIER_LABEL_VALUE (id);
|
||||
tree label;
|
||||
|
||||
if (current_function_decl == 0)
|
||||
{
|
||||
error ("label %s referenced outside of any function",
|
||||
IDENTIFIER_POINTER (id));
|
||||
IDENTIFIER_POINTER (name));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use a label already defined or ref'd with this name. */
|
||||
if (decl != 0)
|
||||
/* Use a label already defined or ref'd with this name, but not if
|
||||
it is inherited from a containing function and wasn't declared
|
||||
using __label__. */
|
||||
label = IDENTIFIER_LABEL_VALUE (name);
|
||||
if (label && (DECL_CONTEXT (label) == current_function_decl
|
||||
|| C_DECLARED_LABEL_FLAG (label)))
|
||||
{
|
||||
/* But not if it is inherited and wasn't declared to be inheritable. */
|
||||
if (DECL_CONTEXT (decl) != current_function_decl
|
||||
&& ! C_DECLARED_LABEL_FLAG (decl))
|
||||
return shadow_label (id);
|
||||
return decl;
|
||||
/* If the label has only been declared, update its apparent
|
||||
location to point here, for better diagnostics if it
|
||||
turns out not to have been defined. */
|
||||
if (!TREE_USED (label))
|
||||
DECL_SOURCE_LOCATION (label) = input_location;
|
||||
return label;
|
||||
}
|
||||
|
||||
decl = build_decl (LABEL_DECL, id, void_type_node);
|
||||
/* No label binding for that identifier; make one. */
|
||||
label = make_label (name, input_location);
|
||||
|
||||
/* A label not explicitly declared must be local to where it's ref'd. */
|
||||
DECL_CONTEXT (decl) = current_function_decl;
|
||||
|
||||
DECL_MODE (decl) = VOIDmode;
|
||||
|
||||
/* Say where one reference is to the label,
|
||||
for the sake of the error if it is not defined. */
|
||||
DECL_SOURCE_LOCATION (decl) = input_location;
|
||||
|
||||
IDENTIFIER_LABEL_VALUE (id) = decl;
|
||||
|
||||
named_labels = tree_cons (NULL_TREE, decl, named_labels);
|
||||
|
||||
return decl;
|
||||
/* Ordinary labels go in the current function scope, which is
|
||||
not necessarily the current label scope. */
|
||||
bind_label (name, label, current_function_level);
|
||||
return label;
|
||||
}
|
||||
|
||||
/* Make a label named NAME in the current function,
|
||||
shadowing silently any that may be inherited from containing functions
|
||||
or containing scopes.
|
||||
/* Make a label named NAME in the current function, shadowing silently
|
||||
any that may be inherited from containing functions or containing
|
||||
scopes. This is called for __label__ declarations. */
|
||||
|
||||
Note that valid use, if the label being shadowed
|
||||
comes from another scope in the same function,
|
||||
requires calling declare_nonlocal_label right away. */
|
||||
/* Note that valid use, if the label being shadowed comes from another
|
||||
scope in the same function, requires calling declare_nonlocal_label
|
||||
right away. (Is this still true? -zw 2003-07-17) */
|
||||
|
||||
tree
|
||||
shadow_label (tree name)
|
||||
declare_label (tree name)
|
||||
{
|
||||
tree decl = IDENTIFIER_LABEL_VALUE (name);
|
||||
tree label = IDENTIFIER_LABEL_VALUE (name);
|
||||
tree dup;
|
||||
|
||||
if (decl != 0)
|
||||
{
|
||||
tree dup;
|
||||
/* Check to make sure that the label hasn't already been declared
|
||||
at this scope */
|
||||
for (dup = current_binding_level->names; dup; dup = TREE_CHAIN (dup))
|
||||
if (dup == label)
|
||||
{
|
||||
error ("duplicate label declaration `%s'", IDENTIFIER_POINTER (name));
|
||||
error ("%Hthis is a previous declaration",
|
||||
&DECL_SOURCE_LOCATION (dup));
|
||||
|
||||
/* Check to make sure that the label hasn't already been declared
|
||||
at this label scope */
|
||||
for (dup = named_labels; dup; dup = TREE_CHAIN (dup))
|
||||
if (TREE_VALUE (dup) == decl)
|
||||
{
|
||||
error ("duplicate label declaration '%E'", name);
|
||||
error ("%Hthis is a previous declaration",
|
||||
&DECL_SOURCE_LOCATION (TREE_VALUE (dup)));
|
||||
/* Just use the previous declaration. */
|
||||
return lookup_label (name);
|
||||
}
|
||||
/* Just use the previous declaration. */
|
||||
return dup;
|
||||
}
|
||||
|
||||
shadowed_labels = tree_cons (NULL_TREE, decl, shadowed_labels);
|
||||
IDENTIFIER_LABEL_VALUE (name) = decl = 0;
|
||||
}
|
||||
label = make_label (name, input_location);
|
||||
C_DECLARED_LABEL_FLAG (label) = 1;
|
||||
|
||||
return lookup_label (name);
|
||||
/* Declared labels go in the current scope. */
|
||||
bind_label (name, label, current_binding_level);
|
||||
return label;
|
||||
}
|
||||
|
||||
/* Define a label, specifying the location in the source file.
|
||||
|
@ -2138,33 +2070,54 @@ shadow_label (tree name)
|
|||
tree
|
||||
define_label (location_t location, tree name)
|
||||
{
|
||||
tree decl = lookup_label (name);
|
||||
tree label;
|
||||
|
||||
/* If label with this name is known from an outer context, shadow it. */
|
||||
if (decl != 0 && DECL_CONTEXT (decl) != current_function_decl)
|
||||
/* Find any preexisting label with this name. It is an error
|
||||
if that label has already been defined in this function, or
|
||||
if there is a containing function with a declared label with
|
||||
the same name. */
|
||||
label = IDENTIFIER_LABEL_VALUE (name);
|
||||
|
||||
if (label
|
||||
&& ((DECL_CONTEXT (label) == current_function_decl
|
||||
&& DECL_INITIAL (label) != 0)
|
||||
|| (DECL_CONTEXT (label) != current_function_decl
|
||||
&& C_DECLARED_LABEL_FLAG (label))))
|
||||
{
|
||||
shadowed_labels = tree_cons (NULL_TREE, decl, shadowed_labels);
|
||||
IDENTIFIER_LABEL_VALUE (name) = 0;
|
||||
decl = lookup_label (name);
|
||||
error ("%Hduplicate label `%D'", &location, label);
|
||||
if (DECL_INITIAL (label))
|
||||
error ("%H`%D' previously defined here",
|
||||
&DECL_SOURCE_LOCATION (label), label);
|
||||
else
|
||||
error ("%H`%D' previously declared here",
|
||||
&DECL_SOURCE_LOCATION (label), label);
|
||||
return 0;
|
||||
}
|
||||
else if (label && DECL_CONTEXT (label) == current_function_decl)
|
||||
{
|
||||
/* The label has been used or declared already in this function,
|
||||
but not defined. Update its location to point to this
|
||||
definition. */
|
||||
DECL_SOURCE_LOCATION (label) = location;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No label binding for that identifier; make one. */
|
||||
label = make_label (name, location);
|
||||
|
||||
/* Ordinary labels go in the current function scope, which is
|
||||
not necessarily the current label scope. */
|
||||
bind_label (name, label, current_function_level);
|
||||
}
|
||||
|
||||
if (warn_traditional && !in_system_header && lookup_name (name))
|
||||
warning ("%Htraditional C lacks a separate namespace for labels, "
|
||||
"identifier `%s' conflicts", &location, IDENTIFIER_POINTER (name));
|
||||
"identifier `%s' conflicts", &location,
|
||||
IDENTIFIER_POINTER (name));
|
||||
|
||||
if (DECL_INITIAL (decl) != 0)
|
||||
{
|
||||
error ("%Hduplicate label `%s'", &location, IDENTIFIER_POINTER (name));
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Mark label as having been defined. */
|
||||
DECL_INITIAL (decl) = error_mark_node;
|
||||
/* Say where in the source. */
|
||||
DECL_SOURCE_LOCATION (decl) = location;
|
||||
return decl;
|
||||
}
|
||||
/* Mark label as having been defined. */
|
||||
DECL_INITIAL (label) = error_mark_node;
|
||||
return label;
|
||||
}
|
||||
|
||||
/* Return the list of declarations of the current level.
|
||||
|
@ -2316,7 +2269,6 @@ c_init_decl_processing (void)
|
|||
c_parse_init ();
|
||||
|
||||
current_function_decl = NULL;
|
||||
named_labels = NULL;
|
||||
current_binding_level = NULL_BINDING_LEVEL;
|
||||
free_binding_level = NULL_BINDING_LEVEL;
|
||||
|
||||
|
@ -5571,8 +5523,6 @@ start_function (tree declspecs, tree declarator, tree attributes)
|
|||
current_function_returns_abnormally = 0;
|
||||
warn_about_return_type = 0;
|
||||
current_extern_inline = 0;
|
||||
named_labels = 0;
|
||||
shadowed_labels = 0;
|
||||
|
||||
/* Don't expand any sizes in the return type of the function. */
|
||||
immediate_size_expand = 0;
|
||||
|
@ -6611,8 +6561,6 @@ check_for_loop_decls (void)
|
|||
struct language_function GTY(())
|
||||
{
|
||||
struct c_language_function base;
|
||||
tree named_labels;
|
||||
tree shadowed_labels;
|
||||
int returns_value;
|
||||
int returns_null;
|
||||
int returns_abnormally;
|
||||
|
@ -6633,8 +6581,6 @@ c_push_function_context (struct function *f)
|
|||
|
||||
p->base.x_stmt_tree = c_stmt_tree;
|
||||
p->base.x_scope_stmt_stack = c_scope_stmt_stack;
|
||||
p->named_labels = named_labels;
|
||||
p->shadowed_labels = shadowed_labels;
|
||||
p->returns_value = current_function_returns_value;
|
||||
p->returns_null = current_function_returns_null;
|
||||
p->returns_abnormally = current_function_returns_abnormally;
|
||||
|
@ -6649,13 +6595,6 @@ void
|
|||
c_pop_function_context (struct function *f)
|
||||
{
|
||||
struct language_function *p = f->language;
|
||||
tree link;
|
||||
|
||||
/* Bring back all the labels that were shadowed. */
|
||||
for (link = shadowed_labels; link; link = TREE_CHAIN (link))
|
||||
if (DECL_NAME (TREE_VALUE (link)) != 0)
|
||||
IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link)))
|
||||
= TREE_VALUE (link);
|
||||
|
||||
if (DECL_SAVED_INSNS (current_function_decl) == 0
|
||||
&& DECL_SAVED_TREE (current_function_decl) == NULL_TREE)
|
||||
|
@ -6669,8 +6608,6 @@ c_pop_function_context (struct function *f)
|
|||
|
||||
c_stmt_tree = p->base.x_stmt_tree;
|
||||
c_scope_stmt_stack = p->base.x_scope_stmt_stack;
|
||||
named_labels = p->named_labels;
|
||||
shadowed_labels = p->shadowed_labels;
|
||||
current_function_returns_value = p->returns_value;
|
||||
current_function_returns_null = p->returns_null;
|
||||
current_function_returns_abnormally = p->returns_abnormally;
|
||||
|
|
|
@ -664,8 +664,6 @@ primary:
|
|||
|
||||
if (pedantic)
|
||||
pedwarn ("ISO C forbids braced-groups within expressions");
|
||||
pop_label_level ();
|
||||
|
||||
saved_last_tree = COMPOUND_BODY ($1);
|
||||
RECHAIN_STMTS ($1, COMPOUND_BODY ($1));
|
||||
last_tree = saved_last_tree;
|
||||
|
@ -677,7 +675,6 @@ primary:
|
|||
}
|
||||
| compstmt_primary_start error ')'
|
||||
{
|
||||
pop_label_level ();
|
||||
last_tree = COMPOUND_BODY ($1);
|
||||
TREE_CHAIN (last_tree) = NULL_TREE;
|
||||
$$ = error_mark_node;
|
||||
|
@ -2113,7 +2110,7 @@ label_decl:
|
|||
{ tree link;
|
||||
for (link = $2; link; link = TREE_CHAIN (link))
|
||||
{
|
||||
tree label = shadow_label (TREE_VALUE (link));
|
||||
tree label = declare_label (TREE_VALUE (link));
|
||||
C_DECLARED_LABEL_FLAG (label) = 1;
|
||||
add_decl_stmt (label);
|
||||
}
|
||||
|
@ -2158,7 +2155,6 @@ compstmt_primary_start:
|
|||
there is a way to turn off the entire subtree of blocks
|
||||
that are contained in it. */
|
||||
keep_next_level ();
|
||||
push_label_level ();
|
||||
compstmt_count++;
|
||||
$$ = add_stmt (build_stmt (COMPOUND_STMT, last_tree));
|
||||
}
|
||||
|
|
|
@ -197,6 +197,7 @@ extern void clear_parm_order (void);
|
|||
extern int complete_array_type (tree, tree, int);
|
||||
extern void declare_parm_level (void);
|
||||
extern void undeclared_variable (tree);
|
||||
extern tree declare_label (tree);
|
||||
extern tree define_label (location_t, tree);
|
||||
extern void finish_decl (tree, tree, tree);
|
||||
extern tree finish_enum (tree, tree, tree);
|
||||
|
@ -214,13 +215,10 @@ extern void parmlist_tags_warning (void);
|
|||
extern void pending_xref_error (void);
|
||||
extern void c_push_function_context (struct function *);
|
||||
extern void c_pop_function_context (struct function *);
|
||||
extern void pop_label_level (void);
|
||||
extern void push_label_level (void);
|
||||
extern void push_parm_decl (tree);
|
||||
extern tree pushdecl_top_level (tree);
|
||||
extern void pushtag (tree, tree);
|
||||
extern tree set_array_declarator_type (tree, tree, int);
|
||||
extern tree shadow_label (tree);
|
||||
extern void shadow_tag (tree);
|
||||
extern void shadow_tag_warned (tree, int);
|
||||
extern tree start_enum (tree);
|
||||
|
|
|
@ -424,7 +424,7 @@ extensions, accepted by GCC in C89 mode and in C++.
|
|||
|
||||
@menu
|
||||
* Statement Exprs:: Putting statements and declarations inside expressions.
|
||||
* Local Labels:: Labels local to a statement-expression.
|
||||
* Local Labels:: Labels local to a block.
|
||||
* Labels as Values:: Getting pointers to labels, and computed gotos.
|
||||
* Nested Functions:: As in Algol and Pascal, lexical scoping of functions.
|
||||
* Constructing Calls:: Dispatching a call to another function.
|
||||
|
@ -577,10 +577,10 @@ bug.)
|
|||
@cindex local labels
|
||||
@cindex macros, local labels
|
||||
|
||||
Each statement expression is a scope in which @dfn{local labels} can be
|
||||
declared. A local label is simply an identifier; you can jump to it
|
||||
with an ordinary @code{goto} statement, but only from within the
|
||||
statement expression it belongs to.
|
||||
GCC allows you to declare @dfn{local labels} in any nested block
|
||||
scope. A local label is just like an ordinary label, but you can
|
||||
only reference it (with a @code{goto} statement, or by taking its
|
||||
address) within the block in which it was declared.
|
||||
|
||||
A local label declaration looks like this:
|
||||
|
||||
|
@ -595,21 +595,38 @@ or
|
|||
__label__ @var{label1}, @var{label2}, /* @r{@dots{}} */;
|
||||
@end example
|
||||
|
||||
Local label declarations must come at the beginning of the statement
|
||||
expression, right after the @samp{(@{}, before any ordinary
|
||||
declarations.
|
||||
Local label declarations must come at the beginning of the block,
|
||||
before any ordinary declarations or statements.
|
||||
|
||||
The label declaration defines the label @emph{name}, but does not define
|
||||
the label itself. You must do this in the usual way, with
|
||||
@code{@var{label}:}, within the statements of the statement expression.
|
||||
|
||||
The local label feature is useful because statement expressions are
|
||||
often used in macros. If the macro contains nested loops, a @code{goto}
|
||||
can be useful for breaking out of them. However, an ordinary label
|
||||
whose scope is the whole function cannot be used: if the macro can be
|
||||
expanded several times in one function, the label will be multiply
|
||||
defined in that function. A local label avoids this problem. For
|
||||
example:
|
||||
The local label feature is useful for complex macros. If a macro
|
||||
contains nested loops, a @code{goto} can be useful for breaking out of
|
||||
them. However, an ordinary label whose scope is the whole function
|
||||
cannot be used: if the macro can be expanded several times in one
|
||||
function, the label will be multiply defined in that function. A
|
||||
local label avoids this problem. For example:
|
||||
|
||||
@example
|
||||
#define SEARCH(value, array, target) \
|
||||
do @{ \
|
||||
__label__ found; \
|
||||
typeof (target) _SEARCH_target = (target); \
|
||||
typeof (*(array)) *_SEARCH_array = (array); \
|
||||
int i, j; \
|
||||
int value; \
|
||||
for (i = 0; i < max; i++) \
|
||||
for (j = 0; j < max; j++) \
|
||||
if (_SEARCH_array[i][j] == _SEARCH_target) \
|
||||
@{ (value) = i; goto found; @} \
|
||||
(value) = -1; \
|
||||
found:; \
|
||||
@} while (0)
|
||||
@end example
|
||||
|
||||
This could also be written using a statement-expression:
|
||||
|
||||
@example
|
||||
#define SEARCH(array, target) \
|
||||
|
@ -629,6 +646,9 @@ example:
|
|||
@})
|
||||
@end example
|
||||
|
||||
Local label declarations also make the labels they declare visible to
|
||||
nested functions, if there are any. @xref{Nested Functions}, for details.
|
||||
|
||||
@node Labels as Values
|
||||
@section Labels as Values
|
||||
@cindex labels as values
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
2003-07-19 Zack Weinberg <zack@codesourcery.com>
|
||||
|
||||
* gcc.dg/noncompile/label-1.c: New comprehensive test case for
|
||||
diagnostics of ill-formed constructs involving labels.
|
||||
* gcc.dg/noncompile/label-lineno-1.c: Add error regexp for
|
||||
the new 'previously defined here' message.
|
||||
|
||||
2003-07-18 Nathan Sidwell <nathan@codesourcery.com>
|
||||
|
||||
* g++.dg/parse/non-dependent2.C: New test.
|
||||
|
||||
2003-07-18 Andrew Pinski <pinskia@physics.uc.edu>
|
||||
|
||||
* g++.dg/init/init-ref4.C: xfail on targets without
|
||||
* g++.dg/init/init-ref4.C: xfail on targets without
|
||||
weak symbols.
|
||||
|
||||
2003-07-17 Jakub Jelinek <jakub@redhat.com>
|
||||
|
@ -278,7 +285,7 @@
|
|||
* g++.dg/opt/emptyunion.C: New testcase.
|
||||
|
||||
2003-07-07 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
|
||||
Eric Botcazou <ebotcazou@libertysurf.fr>
|
||||
Eric Botcazou <ebotcazou@libertysurf.fr>
|
||||
|
||||
* g++.dg/opt/stack1.C: New test.
|
||||
|
||||
|
@ -286,7 +293,7 @@
|
|||
|
||||
* g++.old-deja/g++.jason/typeid1.C: Make it a compile test, not a
|
||||
run test.
|
||||
|
||||
|
||||
PR c++/11431
|
||||
* g++.dg/expr/static_cast3.C: New test.
|
||||
|
||||
|
|
175
gcc/testsuite/gcc.dg/noncompile/label-1.c
Normal file
175
gcc/testsuite/gcc.dg/noncompile/label-1.c
Normal file
|
@ -0,0 +1,175 @@
|
|||
/* Test various diagnostics of ill-formed constructs involving labels. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-Wunused" } */
|
||||
|
||||
extern void dummy(void);
|
||||
|
||||
/* labels must be defined */
|
||||
void a(void)
|
||||
{
|
||||
goto l; /* { dg-error "used but not defined" "no label" } */
|
||||
}
|
||||
|
||||
/* warnings for labels defined but not used, or declared but not defined */
|
||||
void b(void)
|
||||
{
|
||||
__label__ l;
|
||||
l: /* { dg-warning "defined but not used" "no goto 1" } */
|
||||
m: /* { dg-warning "defined but not used" "no goto 2" } */
|
||||
dummy();
|
||||
}
|
||||
|
||||
void c(void)
|
||||
{
|
||||
__label__ l; /* { dg-warning "declared but not defined" "only __label__" } */
|
||||
dummy();
|
||||
}
|
||||
|
||||
/* can't have two labels with the same name in the same function */
|
||||
void d(void)
|
||||
{
|
||||
l: dummy(); /* { dg-error "previously defined" "prev def same scope" } */
|
||||
l: dummy(); /* { dg-error "duplicate label" "dup label same scope" } */
|
||||
goto l;
|
||||
}
|
||||
|
||||
/* even at different scopes */
|
||||
void e(void)
|
||||
{
|
||||
l: dummy(); /* { dg-error "previously defined" "prev def diff scope" } */
|
||||
{
|
||||
l: dummy(); /* { dg-error "duplicate label" "dup label diff scope" } */
|
||||
}
|
||||
goto l;
|
||||
}
|
||||
|
||||
/* but, with __label__, you can */
|
||||
void f(void)
|
||||
{
|
||||
l: dummy();
|
||||
{
|
||||
__label__ l;
|
||||
l: dummy(); /* { dg-warning "defined but not used" "unused shadow 1" } */
|
||||
};
|
||||
goto l; /* this reaches the outer l */
|
||||
}
|
||||
|
||||
/* a __label__ is not visible outside its scope */
|
||||
void g(void)
|
||||
{
|
||||
dummy();
|
||||
{
|
||||
__label__ l;
|
||||
l: dummy();
|
||||
goto l;
|
||||
}
|
||||
goto l; /* { dg-error "used but not defined" "label ref out of scope" } */
|
||||
}
|
||||
|
||||
/* __label__ can appear at top level of a function, too...
|
||||
... but doesn't provide a definition of the label */
|
||||
void h(void)
|
||||
{
|
||||
__label__ l;
|
||||
dummy ();
|
||||
|
||||
goto l; /* { dg-error "used but not defined" "used, only __label__" } */
|
||||
}
|
||||
|
||||
/* A nested function may not goto a label outside itself */
|
||||
void i(void)
|
||||
{
|
||||
auto void nest(void);
|
||||
|
||||
l: nest();
|
||||
|
||||
void nest(void)
|
||||
{
|
||||
goto l; /* { dg-error "used but not defined" "nest use outer label" } */
|
||||
}
|
||||
|
||||
goto l; /* reaches the outer l */
|
||||
}
|
||||
|
||||
/* which means that a nested function may have its own label with the
|
||||
same name as the outer function */
|
||||
void j(void)
|
||||
{
|
||||
auto void nest(void);
|
||||
|
||||
l: nest();
|
||||
|
||||
void nest(void)
|
||||
{
|
||||
l: dummy(); /* { dg-warning "defined but not used" "nest label same name" } */
|
||||
}
|
||||
|
||||
goto l; /* reaches the outer l */
|
||||
}
|
||||
|
||||
/* and, turnabout, an outer function may not goto a label in a nested
|
||||
function */
|
||||
void k(void)
|
||||
{
|
||||
void nest(void)
|
||||
{
|
||||
l: dummy(); /* { dg-warning "defined but not used" "outer use nest label" } */
|
||||
}
|
||||
|
||||
goto l; /* { dg-error "used but not defined" "outer use nest label" } */
|
||||
nest();
|
||||
}
|
||||
|
||||
/* not even with __label__ */
|
||||
void l(void)
|
||||
{
|
||||
void nest(void)
|
||||
{
|
||||
__label__ l;
|
||||
l: dummy(); /* { dg-warning "defined but not used" "outer use nest __label__" } */
|
||||
}
|
||||
|
||||
goto l; /* { dg-error "used but not defined" "outer use nest __label__" } */
|
||||
nest();
|
||||
}
|
||||
|
||||
|
||||
/* but if the outer label is declared with __label__, then a nested
|
||||
function can goto that label (accomplishing a longjmp) */
|
||||
void m(void)
|
||||
{
|
||||
__label__ l;
|
||||
void nest(void) { goto l; }
|
||||
nest();
|
||||
dummy();
|
||||
l:;
|
||||
}
|
||||
|
||||
/* and that means the nested function cannot have its own label with
|
||||
the same name as an outer label declared with __label__ */
|
||||
|
||||
void n(void)
|
||||
{
|
||||
__label__ l; /* { dg-error "previously declared" "outer label decl" } */
|
||||
void nest(void)
|
||||
{
|
||||
l: goto l; /* { dg-error "duplicate label" "inner label defn" } */
|
||||
}
|
||||
|
||||
l:
|
||||
nest();
|
||||
}
|
||||
|
||||
/* unless the nested function uses __label__ too! */
|
||||
void o(void)
|
||||
{
|
||||
__label__ l;
|
||||
void nest(void)
|
||||
{
|
||||
__label__ l;
|
||||
l: goto l;
|
||||
}
|
||||
|
||||
l: goto l;
|
||||
nest();
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
void
|
||||
foo(int i)
|
||||
{
|
||||
my_label:
|
||||
my_label: /* { dg-error "previously defined" "prev label" } */
|
||||
|
||||
i++;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue