Commit 6625cdb5 by Jason Merrill Committed by Jason Merrill

Fix goto checking.

        * cp-tree.h (struct language_function): x_named_labels is now
        a struct named_label_list*.
        * decl.c (struct named_label_use_list): Renamed from...
        (struct named_label_list): ...this.  New struct.
        (push_binding_level): Don't set eh_region.
        (note_level_for_eh): New fn.
        (pop_label): Take label and old value directly.
        (pop_labels): Adjust for new named_labels format.
        (lookup_label): Likewise.
        (poplevel): Note characteristics of a binding level containing a
        named label.  Mess with named label lists earlier.
        (mark_named_label_lists): New fn.
        (mark_lang_function): Call it.
        (use_label): New fn, split out from...
        (make_label_decl): ...here.  Don't call it.
        (decl_jump_unsafe, check_previous_goto, check_previous_goto_1,
        check_previous_gotos): New fns, split out from...
        (define_label): ...here.
        (check_switch_goto): New fn.
        (define_case_label): Call it.
        (check_goto): New fn.
        * semantics.c (finish_goto_stmt): Call it and use_label.
        (begin_compound_stmt): If we're a try block, call note_level_for_eh.
        (expand_stmt): Never pass 1 as DONT_JUMP_IN to expand_end_bindings.

From-SVN: r34198
parent 0137be2d
2000-05-26 Jason Merrill <jason@casey.soma.redhat.com>
Fix goto checking.
* cp-tree.h (struct language_function): x_named_labels is now
a struct named_label_list*.
* decl.c (struct named_label_use_list): Renamed from...
(struct named_label_list): ...this. New struct.
(push_binding_level): Don't set eh_region.
(note_level_for_eh): New fn.
(pop_label): Take label and old value directly.
(pop_labels): Adjust for new named_labels format.
(lookup_label): Likewise.
(poplevel): Note characteristics of a binding level containing a
named label. Mess with named label lists earlier.
(mark_named_label_lists): New fn.
(mark_lang_function): Call it.
(use_label): New fn, split out from...
(make_label_decl): ...here. Don't call it.
(decl_jump_unsafe, check_previous_goto, check_previous_goto_1,
check_previous_gotos): New fns, split out from...
(define_label): ...here.
(check_switch_goto): New fn.
(define_case_label): Call it.
(check_goto): New fn.
* semantics.c (finish_goto_stmt): Call it and use_label.
(begin_compound_stmt): If we're a try block, call note_level_for_eh.
(expand_stmt): Never pass 1 as DONT_JUMP_IN to expand_end_bindings.
2000-05-26 Mark Mitchell <mark@codesourcery.com> 2000-05-26 Mark Mitchell <mark@codesourcery.com>
* class.c (build_vtable_entry_ref): Correct usage of * class.c (build_vtable_entry_ref): Correct usage of
......
...@@ -841,7 +841,6 @@ extern struct saved_scope *scope_chain; ...@@ -841,7 +841,6 @@ extern struct saved_scope *scope_chain;
struct language_function struct language_function
{ {
tree x_named_labels;
tree x_ctor_label; tree x_ctor_label;
tree x_dtor_label; tree x_dtor_label;
tree x_base_init_list; tree x_base_init_list;
...@@ -867,7 +866,8 @@ struct language_function ...@@ -867,7 +866,8 @@ struct language_function
struct stmt_tree x_stmt_tree; struct stmt_tree x_stmt_tree;
struct named_label_list *x_named_label_uses; struct named_label_use_list *x_named_label_uses;
struct named_label_list *x_named_labels;
struct binding_level *bindings; struct binding_level *bindings;
const char *cannot_inline; const char *cannot_inline;
...@@ -3892,6 +3892,7 @@ extern void set_class_shadows PARAMS ((tree)); ...@@ -3892,6 +3892,7 @@ extern void set_class_shadows PARAMS ((tree));
extern void begin_scope PARAMS ((scope_kind)); extern void begin_scope PARAMS ((scope_kind));
extern void finish_scope PARAMS ((void)); extern void finish_scope PARAMS ((void));
extern void note_level_for_for PARAMS ((void)); extern void note_level_for_for PARAMS ((void));
extern void note_level_for_eh PARAMS ((void));
extern void resume_level PARAMS ((struct binding_level *)); extern void resume_level PARAMS ((struct binding_level *));
extern void delete_block PARAMS ((tree)); extern void delete_block PARAMS ((tree));
extern void insert_block PARAMS ((tree)); extern void insert_block PARAMS ((tree));
...@@ -3930,6 +3931,7 @@ extern tree implicitly_declare PARAMS ((tree)); ...@@ -3930,6 +3931,7 @@ extern tree implicitly_declare PARAMS ((tree));
extern tree lookup_label PARAMS ((tree)); extern tree lookup_label PARAMS ((tree));
extern tree declare_local_label PARAMS ((tree)); extern tree declare_local_label PARAMS ((tree));
extern tree define_label PARAMS ((const char *, int, tree)); extern tree define_label PARAMS ((const char *, int, tree));
extern void check_goto PARAMS ((tree));
extern void push_switch PARAMS ((void)); extern void push_switch PARAMS ((void));
extern void pop_switch PARAMS ((void)); extern void pop_switch PARAMS ((void));
extern void define_case_label PARAMS ((void)); extern void define_case_label PARAMS ((void));
......
...@@ -105,6 +105,7 @@ static void resume_binding_level PARAMS ((struct binding_level *)); ...@@ -105,6 +105,7 @@ static void resume_binding_level PARAMS ((struct binding_level *));
static struct binding_level *make_binding_level PARAMS ((void)); static struct binding_level *make_binding_level PARAMS ((void));
static void declare_namespace_level PARAMS ((void)); static void declare_namespace_level PARAMS ((void));
static void signal_catch PARAMS ((int)) ATTRIBUTE_NORETURN; static void signal_catch PARAMS ((int)) ATTRIBUTE_NORETURN;
static int decl_jump_unsafe PARAMS ((tree));
static void storedecls PARAMS ((tree)); static void storedecls PARAMS ((tree));
static void require_complete_types_for_parms PARAMS ((tree)); static void require_complete_types_for_parms PARAMS ((tree));
static int ambi_op_p PARAMS ((tree)); static int ambi_op_p PARAMS ((tree));
...@@ -151,7 +152,13 @@ static int walk_namespaces_r PARAMS ((tree, walk_namespaces_fn, void *)); ...@@ -151,7 +152,13 @@ static int walk_namespaces_r PARAMS ((tree, walk_namespaces_fn, void *));
static int walk_globals_r PARAMS ((tree, void *)); static int walk_globals_r PARAMS ((tree, void *));
static void add_decl_to_level PARAMS ((tree, struct binding_level *)); static void add_decl_to_level PARAMS ((tree, struct binding_level *));
static tree make_label_decl PARAMS ((tree, int)); static tree make_label_decl PARAMS ((tree, int));
static void pop_label PARAMS ((tree)); static void use_label PARAMS ((tree));
static void check_previous_goto_1 PARAMS ((tree, struct binding_level *, tree,
const char *, int));
static void check_previous_goto PARAMS ((struct named_label_use_list *));
static void check_switch_goto PARAMS ((struct binding_level *));
static void check_previous_gotos PARAMS ((tree));
static void pop_label PARAMS ((tree, tree));
static void pop_labels PARAMS ((tree)); static void pop_labels PARAMS ((tree));
static void maybe_deduce_size_from_array_init PARAMS ((tree, tree)); static void maybe_deduce_size_from_array_init PARAMS ((tree, tree));
static void layout_var_decl PARAMS ((tree)); static void layout_var_decl PARAMS ((tree));
...@@ -268,19 +275,19 @@ static int only_namespace_names; ...@@ -268,19 +275,19 @@ static int only_namespace_names;
#define original_result_rtx cp_function_chain->x_result_rtx #define original_result_rtx cp_function_chain->x_result_rtx
struct named_label_list /* Used only for jumps to as-yet undefined labels, since jumps to
defined labels can have their validity checked immediately. */
struct named_label_use_list
{ {
struct binding_level *binding_level; struct binding_level *binding_level;
tree names_in_scope; tree names_in_scope;
tree label_decl; tree label_decl;
const char *filename_o_goto; const char *filename_o_goto;
int lineno_o_goto; int lineno_o_goto;
struct named_label_list *next; struct named_label_use_list *next;
}; };
/* Used only for jumps to as-yet undefined labels, since jumps to
defined labels can have their validity checked by stmt.c. */
#define named_label_uses cp_function_chain->x_named_label_uses #define named_label_uses cp_function_chain->x_named_label_uses
/* A list of objects which have constructors or destructors /* A list of objects which have constructors or destructors
...@@ -304,10 +311,20 @@ static tree last_function_parm_tags; ...@@ -304,10 +311,20 @@ static tree last_function_parm_tags;
tree last_function_parms; tree last_function_parms;
static tree current_function_parm_tags; static tree current_function_parm_tags;
/* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function /* A list of all LABEL_DECLs in the function that have names. Here so
that have names. Here so we can clear out their names' definitions we can clear out their names' definitions at the end of the
at the end of the function. The TREE_VALUE is a LABEL_DECL; the function, and so we can check the validity of jumps to these labels. */
TREE_PURPOSE is the previous binding of the label. */
struct named_label_list
{
struct binding_level *binding_level;
tree names_in_scope;
tree old_value;
tree label_decl;
tree bad_decls;
int eh_region;
struct named_label_list *next;
};
#define named_labels cp_function_chain->x_named_labels #define named_labels cp_function_chain->x_named_labels
...@@ -481,7 +498,9 @@ struct binding_level ...@@ -481,7 +498,9 @@ struct binding_level
worry about ambiguous (ARM or ISO) scope rules. */ worry about ambiguous (ARM or ISO) scope rules. */
unsigned is_for_scope : 1; unsigned is_for_scope : 1;
/* True if this level corresponds to an EH region, as for a try block. */ /* True if this level corresponds to an EH region, as for a try block.
Currently this information is only available while building the
tree structure. */
unsigned eh_region : 1; unsigned eh_region : 1;
/* Four bits left for this word. */ /* Four bits left for this word. */
...@@ -548,11 +567,6 @@ push_binding_level (newlevel, tag_transparent, keep) ...@@ -548,11 +567,6 @@ push_binding_level (newlevel, tag_transparent, keep)
newlevel->tag_transparent = tag_transparent; newlevel->tag_transparent = tag_transparent;
newlevel->more_cleanups_ok = 1; newlevel->more_cleanups_ok = 1;
/* We are called before expand_start_bindings, but after
expand_eh_region_start for a try block; so we check this now,
before the EH block is covered up. */
newlevel->eh_region = is_eh_region ();
newlevel->keep = keep; newlevel->keep = keep;
#if defined(DEBUG_CP_BINDING_LEVELS) #if defined(DEBUG_CP_BINDING_LEVELS)
newlevel->binding_depth = binding_depth; newlevel->binding_depth = binding_depth;
...@@ -927,6 +941,14 @@ note_level_for_for () ...@@ -927,6 +941,14 @@ note_level_for_for ()
current_binding_level->is_for_scope = 1; current_binding_level->is_for_scope = 1;
} }
/* Record that the current binding level represents a try block. */
void
note_level_for_eh ()
{
current_binding_level->eh_region = 1;
}
/* For a binding between a name and an entity at a block scope, /* For a binding between a name and an entity at a block scope,
this is the `struct binding_level' for the block. */ this is the `struct binding_level' for the block. */
#define BINDING_LEVEL(NODE) \ #define BINDING_LEVEL(NODE) \
...@@ -1180,11 +1202,10 @@ pop_binding (id, decl) ...@@ -1180,11 +1202,10 @@ pop_binding (id, decl)
in a valid manner, and issue any appropriate warnings or errors. */ in a valid manner, and issue any appropriate warnings or errors. */
static void static void
pop_label (link) pop_label (label, old_value)
tree link; tree label;
tree old_value;
{ {
tree label = TREE_VALUE (link);
if (!processing_template_decl && doing_semantic_analysis_p ()) if (!processing_template_decl && doing_semantic_analysis_p ())
{ {
if (DECL_INITIAL (label) == NULL_TREE) if (DECL_INITIAL (label) == NULL_TREE)
...@@ -1197,7 +1218,7 @@ pop_label (link) ...@@ -1197,7 +1218,7 @@ pop_label (link)
cp_warning_at ("label `%D' defined but not used", label); cp_warning_at ("label `%D' defined but not used", label);
} }
SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), TREE_PURPOSE (link)); SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), old_value);
} }
/* At the end of a function, all labels declared within the fucntion /* At the end of a function, all labels declared within the fucntion
...@@ -1208,20 +1229,20 @@ static void ...@@ -1208,20 +1229,20 @@ static void
pop_labels (block) pop_labels (block)
tree block; tree block;
{ {
tree link; struct named_label_list *link;
/* Clear out the definitions of all label names, since their scopes /* Clear out the definitions of all label names, since their scopes
end here. */ end here. */
for (link = named_labels; link; link = TREE_CHAIN (link)) for (link = named_labels; link; link = link->next)
{ {
pop_label (link); pop_label (link->label_decl, link->old_value);
/* Put the labels into the "variables" of the top-level block, /* Put the labels into the "variables" of the top-level block,
so debugger can see them. */ so debugger can see them. */
TREE_CHAIN (TREE_VALUE (link)) = BLOCK_VARS (block); TREE_CHAIN (link->label_decl) = BLOCK_VARS (block);
BLOCK_VARS (block) = TREE_VALUE (link); BLOCK_VARS (block) = link->label_decl;
} }
named_labels = NULL_TREE; named_labels = NULL;
} }
/* Exit a binding level. /* Exit a binding level.
...@@ -1285,6 +1306,40 @@ poplevel (keep, reverse, functionbody) ...@@ -1285,6 +1306,40 @@ poplevel (keep, reverse, functionbody)
if (current_binding_level->keep == 1) if (current_binding_level->keep == 1)
keep = 1; keep = 1;
/* Any uses of undefined labels, and any defined labels, now operate
under constraints of next binding contour. */
if (cfun && !functionbody)
{
struct binding_level *level_chain;
level_chain = current_binding_level->level_chain;
if (level_chain)
{
struct named_label_use_list *uses;
struct named_label_list *labels;
for (labels = named_labels; labels; labels = labels->next)
if (labels->binding_level == current_binding_level)
{
tree decl;
if (current_binding_level->eh_region)
labels->eh_region = 1;
for (decl = labels->names_in_scope; decl;
decl = TREE_CHAIN (decl))
if (decl_jump_unsafe (decl))
labels->bad_decls = tree_cons (NULL_TREE, decl,
labels->bad_decls);
labels->binding_level = level_chain;
labels->names_in_scope = level_chain->names;
}
for (uses = named_label_uses; uses; uses = uses->next)
if (uses->binding_level == current_binding_level)
{
uses->binding_level = level_chain;
uses->names_in_scope = level_chain->names;
}
}
}
/* Get the decls in the order they were written. /* Get the decls in the order they were written.
Usually current_binding_level->names is in reverse order. Usually current_binding_level->names is in reverse order.
But parameter decls were previously put in forward order. */ But parameter decls were previously put in forward order. */
...@@ -1468,7 +1523,7 @@ poplevel (keep, reverse, functionbody) ...@@ -1468,7 +1523,7 @@ poplevel (keep, reverse, functionbody)
for (link = current_binding_level->shadowed_labels; for (link = current_binding_level->shadowed_labels;
link; link;
link = TREE_CHAIN (link)) link = TREE_CHAIN (link))
pop_label (link); pop_label (TREE_VALUE (link), TREE_PURPOSE (link));
/* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs /* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs
list if a `using' declaration put them there. The debugging list if a `using' declaration put them there. The debugging
...@@ -1500,24 +1555,6 @@ poplevel (keep, reverse, functionbody) ...@@ -1500,24 +1555,6 @@ poplevel (keep, reverse, functionbody)
pop_labels (block); pop_labels (block);
} }
/* Any uses of undefined labels now operate under constraints
of next binding contour. */
if (cfun)
{
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; tmp = current_binding_level->keep;
pop_binding_level (); pop_binding_level ();
...@@ -1951,7 +1988,7 @@ mark_binding_level (arg) ...@@ -1951,7 +1988,7 @@ mark_binding_level (arg)
{ {
struct binding_level *lvl = *(struct binding_level **)arg; struct binding_level *lvl = *(struct binding_level **)arg;
while (lvl) for (; lvl; lvl = lvl->level_chain)
{ {
ggc_mark_tree (lvl->names); ggc_mark_tree (lvl->names);
ggc_mark_tree (lvl->tags); ggc_mark_tree (lvl->tags);
...@@ -1965,9 +2002,28 @@ mark_binding_level (arg) ...@@ -1965,9 +2002,28 @@ mark_binding_level (arg)
ggc_mark_tree (lvl->this_class); ggc_mark_tree (lvl->this_class);
ggc_mark_tree (lvl->incomplete); ggc_mark_tree (lvl->incomplete);
ggc_mark_tree (lvl->dead_vars_from_for); ggc_mark_tree (lvl->dead_vars_from_for);
}
}
static void
mark_named_label_lists (labs, uses)
void *labs;
void *uses;
{
struct named_label_list *l = *(struct named_label_list **)labs;
struct named_label_use_list *u = *(struct named_label_use_list **)uses;
lvl = lvl->level_chain; for (; l; l = l->next)
{
ggc_mark (l);
mark_binding_level (l->binding_level);
ggc_mark_tree (l->old_value);
ggc_mark_tree (l->label_decl);
ggc_mark_tree (l->bad_decls);
} }
for (; u; u = u->next)
ggc_mark (u);
} }
/* For debugging. */ /* For debugging. */
...@@ -4708,17 +4764,25 @@ make_label_decl (id, local_p) ...@@ -4708,17 +4764,25 @@ make_label_decl (id, local_p)
/* Record the fact that this identifier is bound to this label. */ /* Record the fact that this identifier is bound to this label. */
SET_IDENTIFIER_LABEL_VALUE (id, decl); SET_IDENTIFIER_LABEL_VALUE (id, decl);
/* Record this label on the list of used labels so that we can check return decl;
at the end of the function to see whether or not the label was }
actually defined. */
if ((named_label_uses == NULL || named_label_uses->label_decl != decl) /* Record this label on the list of used labels so that we can check
&& (named_label_uses == NULL at the end of the function to see whether or not the label was
|| named_label_uses->names_in_scope != current_binding_level->names actually defined, and so we can check when the label is defined whether
|| named_label_uses->label_decl != decl)) this use is valid. */
{
struct named_label_list *new_ent; static void
new_ent use_label (decl)
= (struct named_label_list*)oballoc (sizeof (struct named_label_list)); tree decl;
{
if (named_label_uses == NULL
|| named_label_uses->names_in_scope != current_binding_level->names
|| named_label_uses->label_decl != decl)
{
struct named_label_use_list *new_ent;
new_ent = ((struct named_label_use_list *)
ggc_alloc (sizeof (struct named_label_use_list)));
new_ent->label_decl = decl; new_ent->label_decl = decl;
new_ent->names_in_scope = current_binding_level->names; new_ent->names_in_scope = current_binding_level->names;
new_ent->binding_level = current_binding_level; new_ent->binding_level = current_binding_level;
...@@ -4727,8 +4791,6 @@ make_label_decl (id, local_p) ...@@ -4727,8 +4791,6 @@ make_label_decl (id, local_p)
new_ent->next = named_label_uses; new_ent->next = named_label_uses;
named_label_uses = new_ent; named_label_uses = new_ent;
} }
return decl;
} }
/* Look for a label named ID in the current function. If one cannot /* Look for a label named ID in the current function. If one cannot
...@@ -4740,6 +4802,7 @@ lookup_label (id) ...@@ -4740,6 +4802,7 @@ lookup_label (id)
tree id; tree id;
{ {
tree decl; tree decl;
struct named_label_list *ent;
/* You can't use labels at global scope. */ /* You can't use labels at global scope. */
if (current_function_decl == NULL_TREE) if (current_function_decl == NULL_TREE)
...@@ -4757,12 +4820,17 @@ lookup_label (id) ...@@ -4757,12 +4820,17 @@ lookup_label (id)
/* Record this label on the list of labels used in this function. /* Record this label on the list of labels used in this function.
We do this before calling make_label_decl so that we get the We do this before calling make_label_decl so that we get the
IDENTIFIER_LABEL_VALUE before the new label is declared. */ IDENTIFIER_LABEL_VALUE before the new label is declared. */
named_labels = tree_cons (IDENTIFIER_LABEL_VALUE (id), NULL_TREE, ent = ((struct named_label_list *)
named_labels); ggc_alloc_obj (sizeof (struct named_label_list), 1));
ent->old_value = IDENTIFIER_LABEL_VALUE (id);
ent->next = named_labels;
named_labels = ent;
/* We need a new label. */ /* We need a new label. */
decl = make_label_decl (id, /*local_p=*/0); decl = make_label_decl (id, /*local_p=*/0);
/* Now fill in the information we didn't have before. */ /* Now fill in the information we didn't have before. */
TREE_VALUE (named_labels) = decl; ent->label_decl = decl;
return decl; return decl;
} }
...@@ -4789,6 +4857,193 @@ declare_local_label (id) ...@@ -4789,6 +4857,193 @@ declare_local_label (id)
return decl; return decl;
} }
/* Returns nonzero if it is ill-formed to jump past the declaration of
DECL. Returns 2 if it's also a real problem. */
static int
decl_jump_unsafe (decl)
tree decl;
{
if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl))
return 0;
if (DECL_INITIAL (decl) == NULL_TREE
&& pod_type_p (TREE_TYPE (decl)))
return 0;
/* This is really only important if we're crossing an initialization.
The POD stuff is just pedantry; why should it matter if the class
contains a field of pointer to member type? */
if (DECL_INITIAL (decl)
|| (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))))
return 2;
return 1;
}
/* Check that a single previously seen jump to a newly defined label
is OK. DECL is the LABEL_DECL or 0; LEVEL is the binding_level for
the jump context; NAMES are the names in scope in LEVEL at the jump
context; FILE and LINE are the source position of the jump or 0. */
static void
check_previous_goto_1 (decl, level, names, file, line)
tree decl;
struct binding_level *level;
tree names;
const char *file;
int line;
{
int identified = 0;
int saw_eh = 0;
struct binding_level *b = current_binding_level;
for (; b; b = b->level_chain)
{
tree new_decls = b->names;
tree old_decls = (b == level ? names : NULL_TREE);
for (; new_decls != old_decls;
new_decls = TREE_CHAIN (new_decls))
{
int problem = decl_jump_unsafe (new_decls);
if (! problem)
continue;
if (! identified)
{
if (decl)
cp_pedwarn ("jump to label `%D'", decl);
else
pedwarn ("jump to case label");
if (file)
pedwarn_with_file_and_line (file, line, " from here");
identified = 1;
}
if (problem > 1 && DECL_ARTIFICIAL (new_decls))
/* Can't skip init of __exception_info. */
cp_error_at (" enters catch block", new_decls);
else if (problem > 1)
cp_error_at (" crosses initialization of `%#D'",
new_decls);
else
cp_pedwarn_at (" enters scope of non-POD `%#D'",
new_decls);
}
if (b == level)
break;
if (b->eh_region && ! saw_eh)
{
if (! identified)
{
if (decl)
cp_pedwarn ("jump to label `%D'", decl);
else
pedwarn ("jump to case label");
if (file)
pedwarn_with_file_and_line (file, line, " from here");
identified = 1;
}
error (" enters try block");
saw_eh = 1;
}
}
}
static void
check_previous_goto (use)
struct named_label_use_list *use;
{
check_previous_goto_1 (use->label_decl, use->binding_level,
use->names_in_scope, use->filename_o_goto,
use->lineno_o_goto);
}
static void
check_switch_goto (level)
struct binding_level *level;
{
check_previous_goto_1 (NULL_TREE, level, level->names, NULL, 0);
}
/* Check that any previously seen jumps to a newly defined label DECL
are OK. Called by define_label. */
static void
check_previous_gotos (decl)
tree decl;
{
struct named_label_use_list **usep;
if (! TREE_USED (decl))
return;
for (usep = &named_label_uses; *usep; )
{
struct named_label_use_list *use = *usep;
if (use->label_decl == decl)
{
check_previous_goto (use);
*usep = use->next;
}
else
usep = &(use->next);
}
}
/* Check that a new jump to a label DECL is OK. Called by
finish_goto_stmt. */
void
check_goto (decl)
tree decl;
{
int identified = 0;
tree bad;
struct named_label_list *lab;
/* If the label hasn't been defined yet, defer checking. */
if (! DECL_INITIAL (decl))
{
use_label (decl);
return;
}
for (lab = named_labels; lab; lab = lab->next)
if (decl == lab->label_decl)
break;
/* If the label is not on named_labels it's a gcc local label, so
it must be in an outer scope, so jumping to it is always OK. */
if (lab == 0)
return;
if ((lab->eh_region || lab->bad_decls) && !identified)
{
cp_pedwarn_at ("jump to label `%D'", decl);
pedwarn (" from here");
identified = 1;
}
for (bad = lab->bad_decls; bad; bad = TREE_CHAIN (bad))
{
tree b = TREE_VALUE (bad);
int u = decl_jump_unsafe (b);
if (u > 1 && DECL_ARTIFICIAL (b))
/* Can't skip init of __exception_info. */
cp_error_at (" enters catch block", b);
else if (u > 1)
cp_error_at (" skips initialization of `%#D'", b);
else
cp_pedwarn_at (" enters scope of non-POD `%#D'", b);
}
if (lab->eh_region)
error (" enters try block");
}
/* Define a label, specifying the location in the source file. /* Define a label, specifying the location in the source file.
Return the LABEL_DECL node for the label, if the definition is valid. Return the LABEL_DECL node for the label, if the definition is valid.
Otherwise return 0. */ Otherwise return 0. */
...@@ -4800,6 +5055,11 @@ define_label (filename, line, name) ...@@ -4800,6 +5055,11 @@ define_label (filename, line, name)
tree name; tree name;
{ {
tree decl = lookup_label (name); tree decl = lookup_label (name);
struct named_label_list *ent;
for (ent = named_labels; ent; ent = ent->next)
if (ent->label_decl == decl)
break;
/* After labels, make any new cleanups go into their /* After labels, make any new cleanups go into their
own new (temporary) binding contour. */ own new (temporary) binding contour. */
...@@ -4815,104 +5075,17 @@ define_label (filename, line, name) ...@@ -4815,104 +5075,17 @@ define_label (filename, line, name)
} }
else else
{ {
struct named_label_list *uses, *prev;
int identified = 0;
int saw_eh = 0;
/* Mark label as having been defined. */ /* Mark label as having been defined. */
DECL_INITIAL (decl) = error_mark_node; DECL_INITIAL (decl) = error_mark_node;
/* Say where in the source. */ /* Say where in the source. */
DECL_SOURCE_FILE (decl) = filename; DECL_SOURCE_FILE (decl) = filename;
DECL_SOURCE_LINE (decl) = line; DECL_SOURCE_LINE (decl) = line;
if (ent)
prev = NULL; {
uses = named_label_uses; ent->names_in_scope = current_binding_level->names;
while (uses != NULL) ent->binding_level = current_binding_level;
if (uses->label_decl == decl) }
{ check_previous_gotos (decl);
struct binding_level *b = current_binding_level;
while (b)
{
tree new_decls = b->names;
tree old_decls = (b == uses->binding_level)
? uses->names_in_scope : NULL_TREE;
while (new_decls != old_decls)
{
if (TREE_CODE (new_decls) == VAR_DECL
/* Don't complain about crossing initialization
of internal entities. They can't be accessed,
and they should be cleaned up
by the time we get to the label. */
&& ! DECL_ARTIFICIAL (new_decls)
&& !(DECL_INITIAL (new_decls) == NULL_TREE
&& pod_type_p (TREE_TYPE (new_decls))))
{
/* This is really only important if we're crossing
an initialization. The POD stuff is just
pedantry; why should it matter if the class
contains a field of pointer to member type? */
int problem = (DECL_INITIAL (new_decls)
|| (TYPE_NEEDS_CONSTRUCTING
(TREE_TYPE (new_decls))));
if (! identified)
{
if (problem)
{
cp_error ("jump to label `%D'", decl);
error_with_file_and_line
(uses->filename_o_goto,
uses->lineno_o_goto, " from here");
}
else
{
cp_pedwarn ("jump to label `%D'", decl);
pedwarn_with_file_and_line
(uses->filename_o_goto,
uses->lineno_o_goto, " from here");
}
identified = 1;
}
if (problem)
cp_error_at (" crosses initialization of `%#D'",
new_decls);
else
cp_pedwarn_at (" enters scope of non-POD `%#D'",
new_decls);
}
new_decls = TREE_CHAIN (new_decls);
}
if (b == uses->binding_level)
break;
if (b->eh_region && ! saw_eh)
{
if (! identified)
{
cp_error ("jump to label `%D'", decl);
error_with_file_and_line
(uses->filename_o_goto,
uses->lineno_o_goto, " from here");
identified = 1;
}
error (" enters exception handling block");
saw_eh = 1;
}
b = b->level_chain;
}
if (prev != NULL)
prev->next = uses->next;
else
named_label_uses = uses->next;
uses = uses->next;
}
else
{
prev = uses;
uses = uses->next;
}
current_function_return_value = NULL_TREE; current_function_return_value = NULL_TREE;
return decl; return decl;
} }
...@@ -4953,8 +5126,6 @@ void ...@@ -4953,8 +5126,6 @@ void
define_case_label () define_case_label ()
{ {
tree cleanup = last_cleanup_this_contour (); tree cleanup = last_cleanup_this_contour ();
struct binding_level *b = current_binding_level;
int identified = 0;
if (! switch_stack) if (! switch_stack)
/* Don't crash; we'll complain in do_case. */ /* Don't crash; we'll complain in do_case. */
...@@ -4973,29 +5144,7 @@ define_case_label () ...@@ -4973,29 +5144,7 @@ define_case_label ()
} }
} }
for (; b && b != switch_stack->level; b = b->level_chain) check_switch_goto (switch_stack->level);
{
tree new_decls = b->names;
for (; new_decls; new_decls = TREE_CHAIN (new_decls))
{
if (TREE_CODE (new_decls) == VAR_DECL
/* Don't complain about crossing initialization
of internal entities. They can't be accessed,
and they should be cleaned up
by the time we get to the label. */
&& ! DECL_ARTIFICIAL (new_decls)
&& ((DECL_INITIAL (new_decls) != NULL_TREE
&& DECL_INITIAL (new_decls) != error_mark_node)
|| TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (new_decls))))
{
if (! identified)
error ("jump to case label");
identified = 1;
cp_error_at (" crosses initialization of `%#D'",
new_decls);
}
}
}
/* After labels, make any new cleanups go into their /* After labels, make any new cleanups go into their
own new (temporary) binding contour. */ own new (temporary) binding contour. */
...@@ -14660,7 +14809,6 @@ mark_lang_function (p) ...@@ -14660,7 +14809,6 @@ mark_lang_function (p)
if (!p) if (!p)
return; return;
ggc_mark_tree (p->x_named_labels);
ggc_mark_tree (p->x_ctor_label); ggc_mark_tree (p->x_ctor_label);
ggc_mark_tree (p->x_dtor_label); ggc_mark_tree (p->x_dtor_label);
ggc_mark_tree (p->x_base_init_list); ggc_mark_tree (p->x_base_init_list);
...@@ -14672,6 +14820,7 @@ mark_lang_function (p) ...@@ -14672,6 +14820,7 @@ mark_lang_function (p)
ggc_mark_rtx (p->x_result_rtx); ggc_mark_rtx (p->x_result_rtx);
mark_named_label_lists (&p->x_named_labels, &p->x_named_label_uses);
mark_stmt_tree (&p->x_stmt_tree); mark_stmt_tree (&p->x_stmt_tree);
mark_binding_level (&p->bindings); mark_binding_level (&p->bindings);
} }
......
...@@ -703,6 +703,8 @@ finish_goto_stmt (destination) ...@@ -703,6 +703,8 @@ finish_goto_stmt (destination)
addresses, or some such. */ addresses, or some such. */
DECL_UNINLINABLE (current_function_decl) = 1; DECL_UNINLINABLE (current_function_decl) = 1;
check_goto (destination);
add_tree (build_min_nt (GOTO_STMT, destination)); add_tree (build_min_nt (GOTO_STMT, destination));
} }
else else
...@@ -965,10 +967,15 @@ begin_compound_stmt (has_no_scope) ...@@ -965,10 +967,15 @@ begin_compound_stmt (has_no_scope)
int has_no_scope; int has_no_scope;
{ {
tree r; tree r;
int is_try = 0;
if (building_stmt_tree ()) if (building_stmt_tree ())
{ {
r = build_min_nt (COMPOUND_STMT, NULL_TREE); r = build_min_nt (COMPOUND_STMT, NULL_TREE);
/* Mark that this block is for a try so that we can yell at
people trying to jump in. */
if (last_tree && TREE_CODE (last_tree) == TRY_BLOCK)
is_try = 1;
add_tree (r); add_tree (r);
if (has_no_scope) if (has_no_scope)
COMPOUND_STMT_NO_SCOPE (r) = 1; COMPOUND_STMT_NO_SCOPE (r) = 1;
...@@ -979,7 +986,11 @@ begin_compound_stmt (has_no_scope) ...@@ -979,7 +986,11 @@ begin_compound_stmt (has_no_scope)
last_expr_type = NULL_TREE; last_expr_type = NULL_TREE;
if (!has_no_scope) if (!has_no_scope)
do_pushlevel (); {
do_pushlevel ();
if (is_try)
note_level_for_eh ();
}
else else
/* Normally, we try hard to keep the BLOCK for a /* Normally, we try hard to keep the BLOCK for a
statement-expression. But, if it's a statement-expression with statement-expression. But, if it's a statement-expression with
...@@ -2581,8 +2592,7 @@ expand_stmt (t) ...@@ -2581,8 +2592,7 @@ expand_stmt (t)
expand_start_bindings_and_block (2 * SCOPE_NULLIFIED_P (t), expand_start_bindings_and_block (2 * SCOPE_NULLIFIED_P (t),
SCOPE_STMT_BLOCK (t)); SCOPE_STMT_BLOCK (t));
else if (SCOPE_END_P (t)) else if (SCOPE_END_P (t))
expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0);
SCOPE_PARTIAL_P (t));
} }
else if (!SCOPE_NULLIFIED_P (t)) else if (!SCOPE_NULLIFIED_P (t))
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment