aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorJason Merrill <jason@casey.soma.redhat.com>2000-05-26 21:05:05 +0000
committerJason Merrill <jason@gcc.gnu.org>2000-05-26 17:05:05 -0400
commit6625cdb595e9fa7c320e94c229c5e272893d0206 (patch)
tree9959d4042ddd7272bf7d0408e17421eae99253b4 /gcc/cp
parent0137be2dcab07fad0774f03e17086de8620dc3c5 (diff)
downloadgcc-6625cdb595e9fa7c320e94c229c5e272893d0206.zip
gcc-6625cdb595e9fa7c320e94c229c5e272893d0206.tar.gz
gcc-6625cdb595e9fa7c320e94c229c5e272893d0206.tar.bz2
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
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog28
-rw-r--r--gcc/cp/cp-tree.h6
-rw-r--r--gcc/cp/decl.c515
-rw-r--r--gcc/cp/semantics.c16
4 files changed, 377 insertions, 188 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 656ce2a..0b087f8 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,31 @@
+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>
* class.c (build_vtable_entry_ref): Correct usage of
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 4f255a4..810d174 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -841,7 +841,6 @@ extern struct saved_scope *scope_chain;
struct language_function
{
- tree x_named_labels;
tree x_ctor_label;
tree x_dtor_label;
tree x_base_init_list;
@@ -867,7 +866,8 @@ struct language_function
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;
const char *cannot_inline;
@@ -3892,6 +3892,7 @@ extern void set_class_shadows PARAMS ((tree));
extern void begin_scope PARAMS ((scope_kind));
extern void finish_scope 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 delete_block PARAMS ((tree));
extern void insert_block PARAMS ((tree));
@@ -3930,6 +3931,7 @@ extern tree implicitly_declare PARAMS ((tree));
extern tree lookup_label PARAMS ((tree));
extern tree declare_local_label PARAMS ((tree));
extern tree define_label PARAMS ((const char *, int, tree));
+extern void check_goto PARAMS ((tree));
extern void push_switch PARAMS ((void));
extern void pop_switch PARAMS ((void));
extern void define_case_label PARAMS ((void));
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index dc95473..eecf36d 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -105,6 +105,7 @@ static void resume_binding_level PARAMS ((struct binding_level *));
static struct binding_level *make_binding_level PARAMS ((void));
static void declare_namespace_level PARAMS ((void));
static void signal_catch PARAMS ((int)) ATTRIBUTE_NORETURN;
+static int decl_jump_unsafe PARAMS ((tree));
static void storedecls PARAMS ((tree));
static void require_complete_types_for_parms PARAMS ((tree));
static int ambi_op_p PARAMS ((tree));
@@ -151,7 +152,13 @@ static int walk_namespaces_r PARAMS ((tree, walk_namespaces_fn, void *));
static int walk_globals_r PARAMS ((tree, void *));
static void add_decl_to_level PARAMS ((tree, struct binding_level *));
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 maybe_deduce_size_from_array_init PARAMS ((tree, tree));
static void layout_var_decl PARAMS ((tree));
@@ -268,19 +275,19 @@ static int only_namespace_names;
#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;
tree names_in_scope;
tree label_decl;
const char *filename_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
/* A list of objects which have constructors or destructors
@@ -304,10 +311,20 @@ static tree last_function_parm_tags;
tree last_function_parms;
static tree current_function_parm_tags;
-/* 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. The TREE_VALUE is a LABEL_DECL; the
- TREE_PURPOSE is the previous binding of the label. */
+/* A list 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, and so we can check the validity of jumps to these labels. */
+
+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
@@ -481,7 +498,9 @@ struct binding_level
worry about ambiguous (ARM or ISO) scope rules. */
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;
/* Four bits left for this word. */
@@ -548,11 +567,6 @@ push_binding_level (newlevel, tag_transparent, keep)
newlevel->tag_transparent = tag_transparent;
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;
#if defined(DEBUG_CP_BINDING_LEVELS)
newlevel->binding_depth = binding_depth;
@@ -927,6 +941,14 @@ note_level_for_for ()
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,
this is the `struct binding_level' for the block. */
#define BINDING_LEVEL(NODE) \
@@ -1180,11 +1202,10 @@ pop_binding (id, decl)
in a valid manner, and issue any appropriate warnings or errors. */
static void
-pop_label (link)
- tree link;
+pop_label (label, old_value)
+ tree label;
+ tree old_value;
{
- tree label = TREE_VALUE (link);
-
if (!processing_template_decl && doing_semantic_analysis_p ())
{
if (DECL_INITIAL (label) == NULL_TREE)
@@ -1197,7 +1218,7 @@ pop_label (link)
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
@@ -1208,20 +1229,20 @@ static void
pop_labels (block)
tree block;
{
- tree link;
+ struct named_label_list *link;
/* Clear out the definitions of all label names, since their scopes
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,
so debugger can see them. */
- TREE_CHAIN (TREE_VALUE (link)) = BLOCK_VARS (block);
- BLOCK_VARS (block) = TREE_VALUE (link);
+ TREE_CHAIN (link->label_decl) = BLOCK_VARS (block);
+ BLOCK_VARS (block) = link->label_decl;
}
- named_labels = NULL_TREE;
+ named_labels = NULL;
}
/* Exit a binding level.
@@ -1285,6 +1306,40 @@ poplevel (keep, reverse, functionbody)
if (current_binding_level->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.
Usually current_binding_level->names is in reverse order.
But parameter decls were previously put in forward order. */
@@ -1468,7 +1523,7 @@ poplevel (keep, reverse, functionbody)
for (link = current_binding_level->shadowed_labels;
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
list if a `using' declaration put them there. The debugging
@@ -1500,24 +1555,6 @@ poplevel (keep, reverse, functionbody)
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;
pop_binding_level ();
@@ -1951,7 +1988,7 @@ mark_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->tags);
@@ -1965,9 +2002,28 @@ mark_binding_level (arg)
ggc_mark_tree (lvl->this_class);
ggc_mark_tree (lvl->incomplete);
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. */
@@ -4708,17 +4764,25 @@ make_label_decl (id, local_p)
/* Record the fact that this identifier is bound to this label. */
SET_IDENTIFIER_LABEL_VALUE (id, decl);
- /* Record this label on the list of used labels so that we can check
- 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)
- && (named_label_uses == NULL
- || named_label_uses->names_in_scope != current_binding_level->names
- || named_label_uses->label_decl != decl))
- {
- struct named_label_list *new_ent;
- new_ent
- = (struct named_label_list*)oballoc (sizeof (struct named_label_list));
+ return decl;
+}
+
+/* Record this label on the list of used labels so that we can check
+ at the end of the function to see whether or not the label was
+ actually defined, and so we can check when the label is defined whether
+ this use is valid. */
+
+static void
+use_label (decl)
+ 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->names_in_scope = current_binding_level->names;
new_ent->binding_level = current_binding_level;
@@ -4727,8 +4791,6 @@ make_label_decl (id, local_p)
new_ent->next = named_label_uses;
named_label_uses = new_ent;
}
-
- return decl;
}
/* Look for a label named ID in the current function. If one cannot
@@ -4740,6 +4802,7 @@ lookup_label (id)
tree id;
{
tree decl;
+ struct named_label_list *ent;
/* You can't use labels at global scope. */
if (current_function_decl == NULL_TREE)
@@ -4757,12 +4820,17 @@ lookup_label (id)
/* 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
IDENTIFIER_LABEL_VALUE before the new label is declared. */
- named_labels = tree_cons (IDENTIFIER_LABEL_VALUE (id), NULL_TREE,
- named_labels);
+ ent = ((struct named_label_list *)
+ 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. */
decl = make_label_decl (id, /*local_p=*/0);
+
/* Now fill in the information we didn't have before. */
- TREE_VALUE (named_labels) = decl;
+ ent->label_decl = decl;
return decl;
}
@@ -4789,6 +4857,193 @@ declare_local_label (id)
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.
Return the LABEL_DECL node for the label, if the definition is valid.
Otherwise return 0. */
@@ -4800,6 +5055,11 @@ define_label (filename, line, name)
tree 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
own new (temporary) binding contour. */
@@ -4815,104 +5075,17 @@ define_label (filename, line, name)
}
else
{
- struct named_label_list *uses, *prev;
- int identified = 0;
- int saw_eh = 0;
-
/* Mark label as having been defined. */
DECL_INITIAL (decl) = error_mark_node;
/* Say where in the source. */
DECL_SOURCE_FILE (decl) = filename;
DECL_SOURCE_LINE (decl) = line;
-
- prev = NULL;
- uses = named_label_uses;
- while (uses != NULL)
- if (uses->label_decl == 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;
- }
+ if (ent)
+ {
+ ent->names_in_scope = current_binding_level->names;
+ ent->binding_level = current_binding_level;
+ }
+ check_previous_gotos (decl);
current_function_return_value = NULL_TREE;
return decl;
}
@@ -4953,8 +5126,6 @@ void
define_case_label ()
{
tree cleanup = last_cleanup_this_contour ();
- struct binding_level *b = current_binding_level;
- int identified = 0;
if (! switch_stack)
/* Don't crash; we'll complain in do_case. */
@@ -4973,29 +5144,7 @@ define_case_label ()
}
}
- for (; b && b != switch_stack->level; b = b->level_chain)
- {
- 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);
- }
- }
- }
+ check_switch_goto (switch_stack->level);
/* After labels, make any new cleanups go into their
own new (temporary) binding contour. */
@@ -14660,7 +14809,6 @@ mark_lang_function (p)
if (!p)
return;
- ggc_mark_tree (p->x_named_labels);
ggc_mark_tree (p->x_ctor_label);
ggc_mark_tree (p->x_dtor_label);
ggc_mark_tree (p->x_base_init_list);
@@ -14672,6 +14820,7 @@ mark_lang_function (p)
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_binding_level (&p->bindings);
}
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 77728ba..505c487 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -703,6 +703,8 @@ finish_goto_stmt (destination)
addresses, or some such. */
DECL_UNINLINABLE (current_function_decl) = 1;
+ check_goto (destination);
+
add_tree (build_min_nt (GOTO_STMT, destination));
}
else
@@ -965,10 +967,15 @@ begin_compound_stmt (has_no_scope)
int has_no_scope;
{
tree r;
+ int is_try = 0;
if (building_stmt_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);
if (has_no_scope)
COMPOUND_STMT_NO_SCOPE (r) = 1;
@@ -979,7 +986,11 @@ begin_compound_stmt (has_no_scope)
last_expr_type = NULL_TREE;
if (!has_no_scope)
- do_pushlevel ();
+ {
+ do_pushlevel ();
+ if (is_try)
+ note_level_for_eh ();
+ }
else
/* Normally, we try hard to keep the BLOCK for a
statement-expression. But, if it's a statement-expression with
@@ -2581,8 +2592,7 @@ expand_stmt (t)
expand_start_bindings_and_block (2 * SCOPE_NULLIFIED_P (t),
SCOPE_STMT_BLOCK (t));
else if (SCOPE_END_P (t))
- expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t),
- SCOPE_PARTIAL_P (t));
+ expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0);
}
else if (!SCOPE_NULLIFIED_P (t))
{