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_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));
#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
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
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. */
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;
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) \
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)
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
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.
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. */
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
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 ();
{
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);
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);
}
\f
/* For debugging. */
/* 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;
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
tree id;
{
tree decl;
+ struct named_label_list *ent;
/* You can't use labels at global scope. */
if (current_function_decl == NULL_TREE)
/* 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;
}
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. */
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. */
}
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;
}
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. */
}
}
- 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. */
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);
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);
}