diff options
author | Jason Merrill <jason@casey.soma.redhat.com> | 2000-05-26 21:05:05 +0000 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2000-05-26 17:05:05 -0400 |
commit | 6625cdb595e9fa7c320e94c229c5e272893d0206 (patch) | |
tree | 9959d4042ddd7272bf7d0408e17421eae99253b4 /gcc/cp | |
parent | 0137be2dcab07fad0774f03e17086de8620dc3c5 (diff) | |
download | gcc-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/ChangeLog | 28 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 6 | ||||
-rw-r--r-- | gcc/cp/decl.c | 515 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 16 |
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)) { |