This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
(C++) patch to fix goto checking
- To: gcc-patches at gcc dot gnu dot org
- Subject: (C++) patch to fix goto checking
- From: Jason Merrill <jason at cygnus dot com>
- Date: Fri, 26 May 2000 14:03:05 -0700
I started out adding code to define_label to notice jumps into catch
blocks, and it got a bit out of hand...fixes g++.other/goto3.C.
Along with that and some factorization, we now check jumps to
previously defined labels in the frontend rather than the backend; the
old code was checking the wrong thing (jumping after a variable with a
cleanup, which is not what we care about), and language semantics
should be checked in the frontend anyway.
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.
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.462
diff -c -p -r1.462 cp-tree.h
*** cp-tree.h 2000/05/26 08:50:46 1.462
--- cp-tree.h 2000/05/26 20:50:45
*************** extern struct saved_scope *scope_chain;
*** 841,847 ****
struct language_function
{
- tree x_named_labels;
tree x_ctor_label;
tree x_dtor_label;
tree x_base_init_list;
--- 841,846 ----
*************** struct language_function
*** 867,873 ****
struct stmt_tree x_stmt_tree;
! struct named_label_list *x_named_label_uses;
struct binding_level *bindings;
const char *cannot_inline;
--- 866,873 ----
struct stmt_tree x_stmt_tree;
! struct named_label_use_list *x_named_label_uses;
! struct named_label_list *x_named_labels;
struct binding_level *bindings;
const char *cannot_inline;
*************** extern void set_class_shadows PARAMS (
*** 3892,3897 ****
--- 3892,3898 ----
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));
*************** extern tree implicitly_declare PARAMS
*** 3930,3935 ****
--- 3931,3937 ----
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));
Index: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.613
diff -c -p -r1.613 decl.c
*** decl.c 2000/05/26 08:50:46 1.613
--- decl.c 2000/05/26 20:50:55
*************** static void resume_binding_level PARAMS
*** 105,110 ****
--- 105,111 ----
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));
*************** static int walk_namespaces_r PARAMS ((tr
*** 151,157 ****
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 pop_labels PARAMS ((tree));
static void maybe_deduce_size_from_array_init PARAMS ((tree, tree));
static void layout_var_decl PARAMS ((tree));
--- 152,164 ----
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 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));
*************** static int only_namespace_names;
*** 268,286 ****
#define original_result_rtx cp_function_chain->x_result_rtx
! struct named_label_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;
};
- /* 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
--- 275,293 ----
#define original_result_rtx cp_function_chain->x_result_rtx
! /* 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_use_list *next;
};
#define named_label_uses cp_function_chain->x_named_label_uses
/* A list of objects which have constructors or destructors
*************** static tree last_function_parm_tags;
*** 303,313 ****
/* Similar, for 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. */
#define named_labels cp_function_chain->x_named_labels
--- 310,330 ----
/* Similar, for last_function_parm_tags. */
tree last_function_parms;
static tree current_function_parm_tags;
+
+ /* 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
*************** struct binding_level
*** 481,487 ****
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. */
unsigned eh_region : 1;
/* Four bits left for this word. */
--- 498,506 ----
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.
! Currently this information is only available while building the
! tree structure. */
unsigned eh_region : 1;
/* Four bits left for this word. */
*************** push_binding_level (newlevel, tag_transp
*** 548,558 ****
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;
--- 567,572 ----
*************** note_level_for_for ()
*** 927,932 ****
--- 941,954 ----
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) \
*************** pop_binding (id, decl)
*** 1180,1190 ****
in a valid manner, and issue any appropriate warnings or errors. */
static void
! pop_label (link)
! tree link;
{
- tree label = TREE_VALUE (link);
-
if (!processing_template_decl && doing_semantic_analysis_p ())
{
if (DECL_INITIAL (label) == NULL_TREE)
--- 1202,1211 ----
in a valid manner, and issue any appropriate warnings or errors. */
static void
! pop_label (label, old_value)
! tree label;
! tree old_value;
{
if (!processing_template_decl && doing_semantic_analysis_p ())
{
if (DECL_INITIAL (label) == NULL_TREE)
*************** pop_label (link)
*** 1197,1203 ****
cp_warning_at ("label `%D' defined but not used", label);
}
! SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), TREE_PURPOSE (link));
}
/* At the end of a function, all labels declared within the fucntion
--- 1218,1224 ----
cp_warning_at ("label `%D' defined but not used", label);
}
! SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), old_value);
}
/* At the end of a function, all labels declared within the fucntion
*************** static void
*** 1208,1227 ****
pop_labels (block)
tree block;
{
! tree link;
/* Clear out the definitions of all label names, since their scopes
end here. */
! for (link = named_labels; link; link = TREE_CHAIN (link))
{
! pop_label (link);
/* 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);
}
! named_labels = NULL_TREE;
}
/* Exit a binding level.
--- 1229,1248 ----
pop_labels (block)
tree block;
{
! struct named_label_list *link;
/* Clear out the definitions of all label names, since their scopes
end here. */
! for (link = named_labels; link; link = link->next)
{
! 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 (link->label_decl) = BLOCK_VARS (block);
! BLOCK_VARS (block) = link->label_decl;
}
! named_labels = NULL;
}
/* Exit a binding level.
*************** poplevel (keep, reverse, functionbody)
*** 1285,1290 ****
--- 1306,1345 ----
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. */
*************** poplevel (keep, reverse, functionbody)
*** 1468,1474 ****
for (link = current_binding_level->shadowed_labels;
link;
link = TREE_CHAIN (link))
! pop_label (link);
/* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs
list if a `using' declaration put them there. The debugging
--- 1523,1529 ----
for (link = current_binding_level->shadowed_labels;
link;
link = TREE_CHAIN (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
*************** poplevel (keep, reverse, functionbody)
*** 1500,1523 ****
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 ();
--- 1555,1560 ----
*************** mark_binding_level (arg)
*** 1951,1957 ****
{
struct binding_level *lvl = *(struct binding_level **)arg;
! while (lvl)
{
ggc_mark_tree (lvl->names);
ggc_mark_tree (lvl->tags);
--- 1988,1994 ----
{
struct binding_level *lvl = *(struct binding_level **)arg;
! for (; lvl; lvl = lvl->level_chain)
{
ggc_mark_tree (lvl->names);
ggc_mark_tree (lvl->tags);
*************** mark_binding_level (arg)
*** 1965,1973 ****
ggc_mark_tree (lvl->this_class);
ggc_mark_tree (lvl->incomplete);
ggc_mark_tree (lvl->dead_vars_from_for);
! lvl = lvl->level_chain;
}
}
/* For debugging. */
--- 2002,2029 ----
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;
! 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. */
*************** make_label_decl (id, local_p)
*** 4707,4724 ****
/* 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));
new_ent->label_decl = decl;
new_ent->names_in_scope = current_binding_level->names;
new_ent->binding_level = current_binding_level;
--- 4763,4788 ----
/* Record the fact that this identifier is bound to this label. */
SET_IDENTIFIER_LABEL_VALUE (id, decl);
+
+ 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;
*************** make_label_decl (id, local_p)
*** 4727,4734 ****
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
--- 4791,4796 ----
*************** lookup_label (id)
*** 4740,4745 ****
--- 4802,4808 ----
tree id;
{
tree decl;
+ struct named_label_list *ent;
/* You can't use labels at global scope. */
if (current_function_decl == NULL_TREE)
*************** lookup_label (id)
*** 4757,4768 ****
/* 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);
/* 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;
return decl;
}
--- 4820,4836 ----
/* 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. */
! 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. */
! ent->label_decl = decl;
return decl;
}
*************** declare_local_label (id)
*** 4789,4794 ****
--- 4857,5049 ----
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. */
*************** define_label (filename, line, name)
*** 4800,4806 ****
--- 5055,5066 ----
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. */
current_binding_level->more_cleanups_ok = 0;
*************** define_label (filename, line, name)
*** 4815,4918 ****
}
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;
! }
current_function_return_value = NULL_TREE;
return decl;
}
--- 5075,5091 ----
}
else
{
/* 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;
! 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;
}
*************** void
*** 4953,4960 ****
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. */
--- 5126,5131 ----
*************** define_case_label ()
*** 4973,5001 ****
}
}
! 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);
! }
! }
! }
/* After labels, make any new cleanups go into their
own new (temporary) binding contour. */
--- 5144,5150 ----
}
}
! check_switch_goto (switch_stack->level);
/* After labels, make any new cleanups go into their
own new (temporary) binding contour. */
*************** mark_lang_function (p)
*** 14660,14666 ****
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);
--- 14809,14814 ----
*************** mark_lang_function (p)
*** 14672,14677 ****
--- 14820,14826 ----
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);
}
Index: semantics.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/semantics.c,v
retrieving revision 1.145
diff -c -p -r1.145 semantics.c
*** semantics.c 2000/05/25 23:27:18 1.145
--- semantics.c 2000/05/26 20:50:56
*************** finish_goto_stmt (destination)
*** 703,708 ****
--- 703,710 ----
addresses, or some such. */
DECL_UNINLINABLE (current_function_decl) = 1;
+ check_goto (destination);
+
add_tree (build_min_nt (GOTO_STMT, destination));
}
else
*************** begin_compound_stmt (has_no_scope)
*** 965,974 ****
--- 967,981 ----
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;
*************** begin_compound_stmt (has_no_scope)
*** 979,985 ****
last_expr_type = NULL_TREE;
if (!has_no_scope)
! do_pushlevel ();
else
/* Normally, we try hard to keep the BLOCK for a
statement-expression. But, if it's a statement-expression with
--- 986,996 ----
last_expr_type = NULL_TREE;
if (!has_no_scope)
! {
! 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
*************** expand_stmt (t)
*** 2581,2588 ****
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));
}
else if (!SCOPE_NULLIFIED_P (t))
{
--- 2592,2598 ----
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), 0);
}
else if (!SCOPE_NULLIFIED_P (t))
{