df-problems.c (df_simulate_one_insn_forwards): Fix braces in switch.

./:	* df-problems.c (df_simulate_one_insn_forwards): Fix braces in
	switch.
	* gcov.c (read_count_file): Add braces around variables declared
	before label.

	* c.opt (Wjump-misses-init): New warning.
	* c-opts.c (c_common_handle_option): Set warn_jump_misses_init for
	-Wall and -Wc++-compat if not already set.
	(c_common_post_options): Clear warn_jump_misses_init if it was not
	set.
	* c-decl.c (struct c_binding): Change type field to a union with
	new label field.  Make it the first field in the struct.  Update
	references to type to use u.type instead.
	(struct c_spot_bindings): Define.
	(struct c_goto_bindings): Define.
	(c_goto_bindings_p): Define, along with VECs.
	(struct c_label_vars): Define.
	(struct c_scope): Add has_label_bindings field.
	(bind_label, set_spot_bindings): New static functions.
	(decl_jump_unsafe, update_spot_bindings): New static functions.
	(update_label_decls): New static function.
	(pop_scope): Call update_label_decls.  Don't call c_end_vm_scope.
	Update binding u.label field to shadowed field.
	(c_binding_start_stmt_expr): New function.
	(c_binding_end_stmt_expr): New function.
	(pushdecl): Don't call c_begin_vm_scope.
	(make_label): Add defining and p_label_vars parameters.  Change
	all callers.
	(lookup_label): Correct test for whether a label has not yet been
	defined.  Call bind_label rather than bind.
	(warn_about_goto): New static function.
	(lookup_label_for_goto): New function.
	(declare_label): Call bind_label rather than bind.
	(check_earlier_gotos): New static function.
	(define_label): Don't give errors about jumping into statement
	expressions or scopes of variably modified types.  Call
	set_spot_bindings and check_earlier_gotos.  Call bind_label
	instead of bind.  Don't set label_context_stack_se or
	label_context_stack_vm.
	(c_get_switch_bindings): New function.
	(c_release_switch_bindings): New function.
	(c_check_switch_jump_warnings): New function.
	(start_function): Don't set label_context_stack_se or
	label_context_stack_vm.
	(finish_function): Likewise.
	* c-typeck.c (label_context_stack_se): Don't define.
	(label_context_stack_vm): Don't define.
	(c_finish_goto_label): Call lookup_label_for_goto rather than
	lookup_label.  Don't give errors about jumping into a statement
	expression or the scope of a variably modified type.  Don't set
	label_context_stack_se or label_context_stack_vm.
	(struct c_switch): Remove blocked_stmt_expr and blocked_vm
	fields.  Add bindings field.
	(c_start_case): Don't set deleted fields.  Set bindings field.
	(do_case): Rework order of tests.  Don't check blocked_stmt_expr
	or blocked_vm.  Call c_check_switch_jump_warnings.
	(c_finish_case): Don't test blocked_stmt_expr field.  Call
	c_release_switch_bindings.
	(c_begin_stmt_expr): Don't increment blocked_stmt_expr in
	c_switch_stack.  Don't walk label_context_stack_se labels.  Don't
	set label_context_stack_se.  Call c_bindings_start_stmt_expr.
	(c_finish_stmt_expr): Don't decrement blocked_stmt_expr in
	c_switch_stack.  Don't walk label_context_stack_se labels.  Don't
	set label_context_stack_se.  Call c_bindings_end_stmt_expr.
	(c_begin_vm_scope, c_end_vm_scope): Don't define.
	* c-tree.h (C_DECL_UNJUMPABLE_STMT_EXPR): Don't define.
	(C_DECL_UNDEFINABLE_STMT_EXPR): Don't define.
	(C_DECL_UNJUMPABLE_VM): Don't define.
	(C_DECL_UNDEFINABLE_VM): Don't define.
	(struct c_label_list): Don't define.
	(struct c_label_context_se): Don't define.
	(struct c_label_context_vm): Don't define.
	(struct c_spot_bindings): Declare.
	(c_bindings_start_stmt_expr): Declare.
	(c_bindings_end_stmt_expr): Declare.
	(lookup_label_for_goto): Declare.
	(c_get_switch_bindings, c_release_switch_bindings): Declare.
	(c_check_switch_jump_warnings): Declare.
	(label_context_stack_se, label_context_stack_vm): Don't declare.
	(c_finish_goto_label): Update declaration.
	(c_begin_vm_scope, c_end_vm_scope): Don't declare.
	* doc/invoke.texi (Option Summary): Mention -Wjump-misses-init.
	(Warning Options): Document -Wjump-misses-init.
cp/:
	* parser.c (cp_parser_direct_declarator): Add braces around
	variables declared before label.
objc/:
	* objc-act.c (objc_start_function): Don't set
	label_context_stack_se or label_context_stack_vm.
testsuite/:
	* gcc.dg/Wjump-misses-init-1.c: New testcase.
	* gcc.dg/Wjump-misses-init-2.c: New testcase.
	* gcc.dg/c99-vla-jump-5.c: Adjust expected error messages.
	Recognize new notes.
	* gcc.dg/stmt-expr-label-2.c: Likewise.
	* gcc.dg/c99-vla-jump-1.c: Recognize new notes.  Fix column
	numbers.
	* gcc.dg/c99-vla-jump-2.c: Recognize new notes.
	* gcc.dg/c99-vla-jump-3.c: Recognize new notes.
	* gcc.dg/c99-vla-jump-4.c: Likewise.
	* gcc.dg/stmt-expr-label-1.c: Likewise.
	* gcc.dg/stmt-expr-label-3.c: Likewise.
	* gcc.dg/vla-8.c: Likewise.  Move error message to different
	line.

From-SVN: r148512
This commit is contained in:
Ian Lance Taylor 2009-06-16 05:12:15 +00:00 committed by Ian Lance Taylor
parent dee6f57529
commit e1b7793c8e
25 changed files with 1182 additions and 562 deletions

View File

@ -1,3 +1,89 @@
2009-06-15 Ian Lance Taylor <iant@google.com>
* df-problems.c (df_simulate_one_insn_forwards): Fix braces in
switch.
* gcov.c (read_count_file): Add braces around variables declared
before label.
* c.opt (Wjump-misses-init): New warning.
* c-opts.c (c_common_handle_option): Set warn_jump_misses_init for
-Wall and -Wc++-compat if not already set.
(c_common_post_options): Clear warn_jump_misses_init if it was not
set.
* c-decl.c (struct c_binding): Change type field to a union with
new label field. Make it the first field in the struct. Update
references to type to use u.type instead.
(struct c_spot_bindings): Define.
(struct c_goto_bindings): Define.
(c_goto_bindings_p): Define, along with VECs.
(struct c_label_vars): Define.
(struct c_scope): Add has_label_bindings field.
(bind_label, set_spot_bindings): New static functions.
(decl_jump_unsafe, update_spot_bindings): New static functions.
(update_label_decls): New static function.
(pop_scope): Call update_label_decls. Don't call c_end_vm_scope.
Update binding u.label field to shadowed field.
(c_binding_start_stmt_expr): New function.
(c_binding_end_stmt_expr): New function.
(pushdecl): Don't call c_begin_vm_scope.
(make_label): Add defining and p_label_vars parameters. Change
all callers.
(lookup_label): Correct test for whether a label has not yet been
defined. Call bind_label rather than bind.
(warn_about_goto): New static function.
(lookup_label_for_goto): New function.
(declare_label): Call bind_label rather than bind.
(check_earlier_gotos): New static function.
(define_label): Don't give errors about jumping into statement
expressions or scopes of variably modified types. Call
set_spot_bindings and check_earlier_gotos. Call bind_label
instead of bind. Don't set label_context_stack_se or
label_context_stack_vm.
(c_get_switch_bindings): New function.
(c_release_switch_bindings): New function.
(c_check_switch_jump_warnings): New function.
(start_function): Don't set label_context_stack_se or
label_context_stack_vm.
(finish_function): Likewise.
* c-typeck.c (label_context_stack_se): Don't define.
(label_context_stack_vm): Don't define.
(c_finish_goto_label): Call lookup_label_for_goto rather than
lookup_label. Don't give errors about jumping into a statement
expression or the scope of a variably modified type. Don't set
label_context_stack_se or label_context_stack_vm.
(struct c_switch): Remove blocked_stmt_expr and blocked_vm
fields. Add bindings field.
(c_start_case): Don't set deleted fields. Set bindings field.
(do_case): Rework order of tests. Don't check blocked_stmt_expr
or blocked_vm. Call c_check_switch_jump_warnings.
(c_finish_case): Don't test blocked_stmt_expr field. Call
c_release_switch_bindings.
(c_begin_stmt_expr): Don't increment blocked_stmt_expr in
c_switch_stack. Don't walk label_context_stack_se labels. Don't
set label_context_stack_se. Call c_bindings_start_stmt_expr.
(c_finish_stmt_expr): Don't decrement blocked_stmt_expr in
c_switch_stack. Don't walk label_context_stack_se labels. Don't
set label_context_stack_se. Call c_bindings_end_stmt_expr.
(c_begin_vm_scope, c_end_vm_scope): Don't define.
* c-tree.h (C_DECL_UNJUMPABLE_STMT_EXPR): Don't define.
(C_DECL_UNDEFINABLE_STMT_EXPR): Don't define.
(C_DECL_UNJUMPABLE_VM): Don't define.
(C_DECL_UNDEFINABLE_VM): Don't define.
(struct c_label_list): Don't define.
(struct c_label_context_se): Don't define.
(struct c_label_context_vm): Don't define.
(struct c_spot_bindings): Declare.
(c_bindings_start_stmt_expr): Declare.
(c_bindings_end_stmt_expr): Declare.
(lookup_label_for_goto): Declare.
(c_get_switch_bindings, c_release_switch_bindings): Declare.
(c_check_switch_jump_warnings): Declare.
(label_context_stack_se, label_context_stack_vm): Don't declare.
(c_finish_goto_label): Update declaration.
(c_begin_vm_scope, c_end_vm_scope): Don't declare.
* doc/invoke.texi (Option Summary): Mention -Wjump-misses-init.
(Warning Options): Document -Wjump-misses-init.
2009-06-15 Jakub Jelinek <jakub@redhat.com>
* tree-object-size.c (addr_object_size): Fix a pasto in the last

View File

@ -188,7 +188,7 @@ bool c_override_global_bindings_to_false;
suppress further errors about that identifier in the current
function.
The ->type field stores the type of the declaration in this scope;
The ->u.type field stores the type of the declaration in this scope;
if NULL, the type is the type of the ->decl field. This is only of
relevance for objects with external or internal linkage which may
be redeclared in inner scopes, forming composite types that only
@ -198,6 +198,9 @@ bool c_override_global_bindings_to_false;
scope) stores whether an incomplete array type at file scope was
completed at an inner scope to an array size other than 1.
The ->u.label field is used for labels. It points to a structure
which stores additional information used for warnings.
The depth field is copied from the scope structure that holds this
decl. It is used to preserve the proper ordering of the ->shadowed
field (see bind()) and also for a handful of special-case checks.
@ -208,8 +211,11 @@ bool c_override_global_bindings_to_false;
invisible bit true. */
struct GTY((chain_next ("%h.prev"))) c_binding {
union GTY(()) { /* first so GTY desc can use decl */
tree GTY((tag ("0"))) type; /* the type in this scope */
struct c_label_vars * GTY((tag ("1"))) label; /* for warnings */
} GTY((desc ("TREE_CODE (%0.decl) == LABEL_DECL"))) u;
tree decl; /* the decl bound */
tree type; /* the type in this scope */
tree id; /* the identifier it's bound to */
struct c_binding *prev; /* the previous decl in this scope */
struct c_binding *shadowed; /* the innermost decl shadowed by this one */
@ -266,6 +272,67 @@ union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
struct lang_identifier GTY ((tag ("1"))) identifier;
};
/* Track bindings and other things that matter for goto warnings. For
efficiency, we do not gather all the decls at the point of
definition. Instead, we point into the bindings structure. As
scopes are popped, we update these structures and gather the decls
that matter at that time. */
struct GTY(()) c_spot_bindings {
/* The currently open scope which holds bindings defined when the
label was defined or the goto statement was found. */
struct c_scope *scope;
/* The bindings in the scope field which were defined at the point
of the label or goto. This lets us look at older or newer
bindings in the scope, as appropriate. */
struct c_binding *bindings_in_scope;
/* The number of statement expressions that have started since this
label or goto statement was defined. This is zero if we are at
the same statement expression level. It is positive if we are in
a statement expression started since this spot. It is negative
if this spot was in a statement expression and we have left
it. */
int stmt_exprs;
/* Whether we started in a statement expression but are no longer in
it. This is set to true if stmt_exprs ever goes negative. */
bool left_stmt_expr;
};
/* This structure is used to keep track of bindings seen when a goto
statement is defined. This is only used if we see the goto
statement before we see the label. */
struct GTY(()) c_goto_bindings {
/* The location of the goto statement. */
location_t loc;
/* The bindings of the goto statement. */
struct c_spot_bindings goto_bindings;
};
typedef struct c_goto_bindings *c_goto_bindings_p;
DEF_VEC_P(c_goto_bindings_p);
DEF_VEC_ALLOC_P(c_goto_bindings_p,gc);
/* The additional information we keep track of for a label binding.
These fields are updated as scopes are popped. */
struct GTY(()) c_label_vars {
/* The shadowed c_label_vars, when one label shadows another (which
can only happen using a __label__ declaration). */
struct c_label_vars *shadowed;
/* The bindings when the label was defined. */
struct c_spot_bindings label_bindings;
/* A list of decls that we care about: decls about which we should
warn if a goto branches to this label from later in the function.
Decls are added to this list as scopes are popped. We only add
the decls that matter. */
VEC(tree,gc) *decls_in_scope;
/* A list of goto statements to this label. This is only used for
goto statements seen before the label was defined, so that we can
issue appropriate warnings for them. */
VEC(c_goto_bindings_p,gc) *gotos;
};
/* Each c_scope structure describes the complete contents of one
scope. Four scopes are distinguished specially: the innermost or
current scope, the innermost function scope, the file scope (always
@ -354,6 +421,11 @@ struct GTY((chain_next ("%h.outer"))) c_scope {
/* True means that an unsuffixed float constant is _Decimal64. */
BOOL_BITFIELD float_const_decimal64 : 1;
/* True if this scope has any label bindings. This is used to speed
up searching for labels when popping scopes, particularly since
labels are normally only found at function scope. */
BOOL_BITFIELD has_label_bindings : 1;
};
/* The scope currently in effect. */
@ -518,7 +590,7 @@ bind (tree name, tree decl, struct c_scope *scope, bool invisible,
b->inner_comp = 0;
b->locus = locus;
b->type = 0;
b->u.type = NULL;
b->prev = scope->bindings;
scope->bindings = b;
@ -569,6 +641,24 @@ free_binding_and_advance (struct c_binding *b)
return prev;
}
/* Bind a label. Like bind, but skip fields which aren't used for
labels, and add the LABEL_VARS value. */
static void
bind_label (tree name, tree label, struct c_scope *scope,
struct c_label_vars *label_vars)
{
struct c_binding *b;
bind (name, label, scope, /*invisible=*/false, /*nested=*/false,
UNKNOWN_LOCATION);
scope->has_label_bindings = true;
b = scope->bindings;
gcc_assert (b->decl == label);
label_vars->shadowed = b->u.label;
b->u.label = label_vars;
}
/* Hook called at end of compilation to assume 1 elt
for a file-scope tentative array defn that wasn't complete before. */
@ -641,6 +731,73 @@ check_inline_statics (void)
c_inline_statics = NULL;
}
/* Fill in a c_spot_bindings structure. If DEFINING is true, set it
for the current state, otherwise set it to uninitialized. */
static void
set_spot_bindings (struct c_spot_bindings *p, bool defining)
{
if (defining)
{
p->scope = current_scope;
p->bindings_in_scope = current_scope->bindings;
}
else
{
p->scope = NULL;
p->bindings_in_scope = NULL;
}
p->stmt_exprs = 0;
p->left_stmt_expr = false;
}
/* Return true if we will want to say something if a goto statement
crosses DECL. */
static bool
decl_jump_unsafe (tree decl)
{
if (decl == error_mark_node || TREE_TYPE (decl) == error_mark_node)
return false;
/* Always warn about crossing variably modified types. */
if ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == TYPE_DECL)
&& variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
return true;
/* Otherwise, only warn if -Wgoto-misses-init and this is an
initialized automatic decl. */
if (warn_jump_misses_init
&& TREE_CODE (decl) == VAR_DECL
&& !TREE_STATIC (decl)
&& DECL_INITIAL (decl) != NULL_TREE)
return true;
return false;
}
/* Update spot bindings P as we pop out of SCOPE. Return true if we
should push decls for a label. */
static bool
update_spot_bindings (struct c_scope *scope, struct c_spot_bindings *p)
{
if (p->scope != scope)
{
/* This label or goto is defined in some other scope, or it is a
label which is not yet defined. There is nothing to
update. */
return false;
}
/* Adjust the spot bindings to refer to the bindings already defined
in the enclosing scope. */
p->scope = scope->outer;
p->bindings_in_scope = p->scope->bindings;
return true;
}
/* The Objective-C front-end often needs to determine the current scope. */
void *
@ -784,6 +941,67 @@ push_scope (void)
}
}
/* This is called when we are leaving SCOPE. For each label defined
in SCOPE, add any appropriate decls to its decls_in_scope fields.
These are the decls whose initialization will be skipped by a goto
later in the function. */
static void
update_label_decls (struct c_scope *scope)
{
struct c_scope *s;
s = scope;
while (s != NULL)
{
if (s->has_label_bindings)
{
struct c_binding *b;
for (b = s->bindings; b != NULL; b = b->prev)
{
struct c_label_vars *label_vars;
struct c_binding *b1;
unsigned int ix;
struct c_goto_bindings *g;
if (TREE_CODE (b->decl) != LABEL_DECL)
continue;
label_vars = b->u.label;
b1 = label_vars->label_bindings.bindings_in_scope;
if (update_spot_bindings (scope, &label_vars->label_bindings))
{
/* This label is defined in this scope. */
for (; b1 != NULL; b1 = b1->prev)
{
/* A goto from later in the function to this
label will never see the initialization of
B1, if any. Save it to issue a warning if
needed. */
if (decl_jump_unsafe (b1->decl))
VEC_safe_push (tree, gc, label_vars->decls_in_scope,
b1->decl);
}
}
/* Update the bindings of any goto statements associated
with this label. */
for (ix = 0;
VEC_iterate (c_goto_bindings_p, label_vars->gotos, ix, g);
++ix)
update_spot_bindings (scope, &g->goto_bindings);
}
}
/* Don't search beyond the current function. */
if (s == current_function_scope)
break;
s = s->outer;
}
}
/* Set the TYPE_CONTEXT of all of TYPE's variants to CONTEXT. */
static void
@ -809,7 +1027,7 @@ pop_scope (void)
bool functionbody = scope->function_body;
bool keep = functionbody || scope->keep || scope->bindings;
c_end_vm_scope (scope->depth);
update_label_decls (scope);
/* If appropriate, create a BLOCK to record the decls for the life
of this function. */
@ -874,6 +1092,10 @@ pop_scope (void)
BLOCK_VARS (block) = p;
gcc_assert (I_LABEL_BINDING (b->id) == b);
I_LABEL_BINDING (b->id) = b->shadowed;
/* Also pop back to the shadowed label_vars. */
release_tree_vector (b->u.label->decls_in_scope);
b->u.label = b->u.label->shadowed;
break;
case ENUMERAL_TYPE:
@ -999,8 +1221,8 @@ pop_scope (void)
{
gcc_assert (I_SYMBOL_BINDING (b->id) == b);
I_SYMBOL_BINDING (b->id) = b->shadowed;
if (b->shadowed && b->shadowed->type)
TREE_TYPE (b->shadowed->decl) = b->shadowed->type;
if (b->shadowed && b->shadowed->u.type)
TREE_TYPE (b->shadowed->decl) = b->shadowed->u.type;
}
break;
@ -1087,7 +1309,91 @@ pop_file_scope (void)
maybe_apply_pending_pragma_weaks ();
cgraph_finalize_compilation_unit ();
}
/* Adjust the bindings for the start of a statement expression. */
void
c_bindings_start_stmt_expr (struct c_spot_bindings* switch_bindings)
{
struct c_scope *scope;
for (scope = current_scope; scope != NULL; scope = scope->outer)
{
struct c_binding *b;
if (!scope->has_label_bindings)
continue;
for (b = scope->bindings; b != NULL; b = b->prev)
{
struct c_label_vars *label_vars;
unsigned int ix;
struct c_goto_bindings *g;
if (TREE_CODE (b->decl) != LABEL_DECL)
continue;
label_vars = b->u.label;
++label_vars->label_bindings.stmt_exprs;
for (ix = 0;
VEC_iterate (c_goto_bindings_p, label_vars->gotos, ix, g);
++ix)
++g->goto_bindings.stmt_exprs;
}
}
if (switch_bindings != NULL)
++switch_bindings->stmt_exprs;
}
/* Adjust the bindings for the end of a statement expression. */
void
c_bindings_end_stmt_expr (struct c_spot_bindings *switch_bindings)
{
struct c_scope *scope;
for (scope = current_scope; scope != NULL; scope = scope->outer)
{
struct c_binding *b;
if (!scope->has_label_bindings)
continue;
for (b = scope->bindings; b != NULL; b = b->prev)
{
struct c_label_vars *label_vars;
unsigned int ix;
struct c_goto_bindings *g;
if (TREE_CODE (b->decl) != LABEL_DECL)
continue;
label_vars = b->u.label;
--label_vars->label_bindings.stmt_exprs;
if (label_vars->label_bindings.stmt_exprs < 0)
{
label_vars->label_bindings.left_stmt_expr = true;
label_vars->label_bindings.stmt_exprs = 0;
}
for (ix = 0;
VEC_iterate (c_goto_bindings_p, label_vars->gotos, ix, g);
++ix)
{
--g->goto_bindings.stmt_exprs;
if (g->goto_bindings.stmt_exprs < 0)
{
g->goto_bindings.left_stmt_expr = true;
g->goto_bindings.stmt_exprs = 0;
}
}
}
}
if (switch_bindings != NULL)
{
--switch_bindings->stmt_exprs;
gcc_assert (switch_bindings->stmt_exprs >= 0);
}
}
/* Push a definition or a declaration of struct, union or enum tag "name".
"type" should be the type node.
@ -2182,12 +2488,6 @@ pushdecl (tree x)
|| DECL_INITIAL (x) || !DECL_EXTERNAL (x)))
DECL_CONTEXT (x) = current_function_decl;
/* If this is of variably modified type, prevent jumping into its
scope. */
if ((TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == TYPE_DECL)
&& variably_modified_type_p (TREE_TYPE (x), NULL_TREE))
c_begin_vm_scope (scope->depth);
/* Anonymous decls are just inserted in the scope. */
if (!name)
{
@ -2226,8 +2526,8 @@ pushdecl (tree x)
if (b_ext)
{
b_use = b_ext;
if (b_use->type)
TREE_TYPE (b_use->decl) = b_use->type;
if (b_use->u.type)
TREE_TYPE (b_use->decl) = b_use->u.type;
}
}
if (duplicate_decls (x, b_use->decl))
@ -2241,13 +2541,13 @@ pushdecl (tree x)
thistype = composite_type (vistype, type);
else
thistype = TREE_TYPE (b_use->decl);
b_use->type = TREE_TYPE (b_use->decl);
b_use->u.type = TREE_TYPE (b_use->decl);
if (TREE_CODE (b_use->decl) == FUNCTION_DECL
&& DECL_BUILT_IN (b_use->decl))
thistype
= build_type_attribute_variant (thistype,
TYPE_ATTRIBUTES
(b_use->type));
(b_use->u.type));
TREE_TYPE (b_use->decl) = thistype;
}
return b_use->decl;
@ -2298,7 +2598,7 @@ pushdecl (tree x)
their scopes will not have been re-entered. */
if (DECL_P (b->decl) && DECL_FILE_SCOPE_P (b->decl) && !type_saved)
{
b->type = TREE_TYPE (b->decl);
b->u.type = TREE_TYPE (b->decl);
type_saved = true;
}
if (B_IN_FILE_SCOPE (b)
@ -2324,8 +2624,8 @@ pushdecl (tree x)
After the consistency checks, it will be reset to the
composite of the visible types only. */
if (b && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl))
&& b->type)
TREE_TYPE (b->decl) = b->type;
&& b->u.type)
TREE_TYPE (b->decl) = b->u.type;
/* The point of the same_translation_unit_p check here is,
we want to detect a duplicate decl for a construct like
@ -2346,11 +2646,11 @@ pushdecl (tree x)
}
else
thistype = type;
b->type = TREE_TYPE (b->decl);
b->u.type = TREE_TYPE (b->decl);
if (TREE_CODE (b->decl) == FUNCTION_DECL && DECL_BUILT_IN (b->decl))
thistype
= build_type_attribute_variant (thistype,
TYPE_ATTRIBUTES (b->type));
TYPE_ATTRIBUTES (b->u.type));
TREE_TYPE (b->decl) = thistype;
bind (name, b->decl, scope, /*invisible=*/false, /*nested=*/true,
locus);
@ -2500,8 +2800,8 @@ implicitly_declare (location_t loc, tree functionid)
else
{
tree newtype = default_function_type;
if (b->type)
TREE_TYPE (decl) = b->type;
if (b->u.type)
TREE_TYPE (decl) = b->u.type;
/* Implicit declaration of a function already declared
(somehow) in a different scope, or as a built-in.
If this is the first time this has happened, warn;
@ -2531,7 +2831,7 @@ implicitly_declare (location_t loc, tree functionid)
locate_old_decl (decl);
}
}
b->type = TREE_TYPE (decl);
b->u.type = TREE_TYPE (decl);
TREE_TYPE (decl) = newtype;
bind (functionid, decl, current_scope,
/*invisible=*/false, /*nested=*/true,
@ -2603,16 +2903,26 @@ undeclared_variable (location_t loc, tree id)
}
/* Subroutine of lookup_label, declare_label, define_label: construct a
LABEL_DECL with all the proper frills. */
LABEL_DECL with all the proper frills. Also create a struct
c_label_vars initialized for the current scope. */
static tree
make_label (location_t location, tree name)
make_label (location_t location, tree name, bool defining,
struct c_label_vars **p_label_vars)
{
tree label = build_decl (location, LABEL_DECL, name, void_type_node);
struct c_label_vars *label_vars;
DECL_CONTEXT (label) = current_function_decl;
DECL_MODE (label) = VOIDmode;
label_vars = GGC_NEW (struct c_label_vars);
label_vars->shadowed = NULL;
set_spot_bindings (&label_vars->label_bindings, defining);
label_vars->decls_in_scope = make_tree_vector ();
label_vars->gotos = VEC_alloc (c_goto_bindings_p, gc, 0);
*p_label_vars = label_vars;
return label;
}
@ -2625,6 +2935,7 @@ tree
lookup_label (tree name)
{
tree label;
struct c_label_vars *label_vars;
if (current_function_decl == 0)
{
@ -2642,17 +2953,91 @@ lookup_label (tree name)
/* If the label has only been declared, update its apparent
location to point here, for better diagnostics if it
turns out not to have been defined. */
if (!TREE_USED (label))
if (DECL_INITIAL (label) == NULL_TREE)
DECL_SOURCE_LOCATION (label) = input_location;
return label;
}
/* No label binding for that identifier; make one. */
label = make_label (input_location, name);
label = make_label (input_location, name, false, &label_vars);
/* Ordinary labels go in the current function scope. */
bind (name, label, current_function_scope,
/*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
bind_label (name, label, current_function_scope, label_vars);
return label;
}
/* Issue a warning about DECL for a goto statement at GOTO_LOC going
to LABEL. */
static void
warn_about_goto (location_t goto_loc, tree label, tree decl)
{
if (variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
error_at (goto_loc,
"jump into scope of identifier with variably modified type");
else
warning_at (goto_loc, OPT_Wjump_misses_init,
"jump skips variable initialization");
inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", label);
inform (DECL_SOURCE_LOCATION (decl), "%qD declared here", decl);
}
/* Look up a label because of a goto statement. This is like
lookup_label, but also issues any appropriate warnings. */
tree
lookup_label_for_goto (location_t loc, tree name)
{
tree label;
struct c_label_vars *label_vars;
unsigned int ix;
tree decl;
label = lookup_label (name);
if (label == NULL_TREE)
return NULL_TREE;
/* If we are jumping to a different function, we can't issue any
useful warnings. */
if (DECL_CONTEXT (label) != current_function_decl)
{
gcc_assert (C_DECLARED_LABEL_FLAG (label));
return label;
}
label_vars = I_LABEL_BINDING (name)->u.label;
/* If the label has not yet been defined, then push this goto on a
list for possible later warnings. */
if (label_vars->label_bindings.scope == NULL)
{
struct c_goto_bindings *g;
g = GGC_NEW (struct c_goto_bindings);
g->loc = loc;
set_spot_bindings (&g->goto_bindings, true);
VEC_safe_push (c_goto_bindings_p, gc, label_vars->gotos, g);
return label;
}
/* If there are any decls in label_vars->decls_in_scope, then this
goto has missed the declaration of the decl. This happens for a
case like
int i = 1;
lab:
...
goto lab;
Issue a warning or error. */
for (ix = 0; VEC_iterate (tree, label_vars->decls_in_scope, ix, decl); ++ix)
warn_about_goto (loc, label, decl);
if (label_vars->label_bindings.left_stmt_expr)
{
error_at (loc, "jump into statement expression");
inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", label);
}
return label;
}
@ -2665,6 +3050,7 @@ declare_label (tree name)
{
struct c_binding *b = I_LABEL_BINDING (name);
tree label;
struct c_label_vars *label_vars;
/* Check to make sure that the label hasn't already been declared
at this scope */
@ -2677,15 +3063,74 @@ declare_label (tree name)
return b->decl;
}
label = make_label (input_location, name);
label = make_label (input_location, name, false, &label_vars);
C_DECLARED_LABEL_FLAG (label) = 1;
/* Declared labels go in the current scope. */
bind (name, label, current_scope,
/*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
bind_label (name, label, current_scope, label_vars);
return label;
}
/* When we define a label, issue any appropriate warnings if there are
any gotos earlier in the function which jump to this label. */
static void
check_earlier_gotos (tree label, struct c_label_vars* label_vars)
{
unsigned int ix;
struct c_goto_bindings *g;
for (ix = 0;
VEC_iterate (c_goto_bindings_p, label_vars->gotos, ix, g);
++ix)
{
struct c_binding *b;
struct c_scope *scope;
/* We have a goto to this label. The goto is going forward. In
g->scope, the goto is going to skip any binding which was
defined after g->bindings_in_scope. */
for (b = g->goto_bindings.scope->bindings;
b != g->goto_bindings.bindings_in_scope;
b = b->prev)
{
if (decl_jump_unsafe (b->decl))
warn_about_goto (g->loc, label, b->decl);
}
/* We also need to warn about decls defined in any scopes
between the scope of the label and the scope of the goto. */
for (scope = label_vars->label_bindings.scope;
scope != g->goto_bindings.scope;
scope = scope->outer)
{
gcc_assert (scope != NULL);
if (scope == label_vars->label_bindings.scope)
b = label_vars->label_bindings.bindings_in_scope;
else
b = scope->bindings;
for (; b != NULL; b = b->prev)
{
if (decl_jump_unsafe (b->decl))
warn_about_goto (g->loc, label, b->decl);
}
}
if (g->goto_bindings.stmt_exprs > 0)
{
error_at (g->loc, "jump into statement expression");
inform (DECL_SOURCE_LOCATION (label), "label %qD defined here",
label);
}
}
/* Now that the label is defined, we will issue warnings about
subsequent gotos to this label when we see them. */
VEC_truncate (c_goto_bindings_p, label_vars->gotos, 0);
label_vars->gotos = NULL;
}
/* 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. */
@ -2698,7 +3143,6 @@ define_label (location_t location, tree name)
if there is a containing function with a declared label with
the same name. */
tree label = I_LABEL_DECL (name);
struct c_label_list *nlist_se, *nlist_vm;
if (label
&& ((DECL_CONTEXT (label) == current_function_decl
@ -2712,24 +3156,27 @@ define_label (location_t location, tree name)
}
else if (label && DECL_CONTEXT (label) == current_function_decl)
{
struct c_label_vars *label_vars = I_LABEL_BINDING (name)->u.label;
/* The label has been used or declared already in this function,
but not defined. Update its location to point to this
definition. */
if (C_DECL_UNDEFINABLE_STMT_EXPR (label))
error_at (location, "jump into statement expression");
if (C_DECL_UNDEFINABLE_VM (label))
error_at (location,
"jump into scope of identifier with variably modified type");
DECL_SOURCE_LOCATION (label) = location;
set_spot_bindings (&label_vars->label_bindings, true);
/* Issue warnings as required about any goto statements from
earlier in the function. */
check_earlier_gotos (label, label_vars);
}
else
{
struct c_label_vars *label_vars;
/* No label binding for that identifier; make one. */
label = make_label (location, name);
label = make_label (location, name, true, &label_vars);
/* Ordinary labels go in the current function scope. */
bind (name, label, current_function_scope,
/*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
bind_label (name, label, current_function_scope, label_vars);
}
if (!in_system_header && lookup_name (name))
@ -2737,21 +3184,82 @@ define_label (location_t location, tree name)
"traditional C lacks a separate namespace "
"for labels, identifier %qE conflicts", name);
nlist_se = XOBNEW (&parser_obstack, struct c_label_list);
nlist_se->next = label_context_stack_se->labels_def;
nlist_se->label = label;
label_context_stack_se->labels_def = nlist_se;
nlist_vm = XOBNEW (&parser_obstack, struct c_label_list);
nlist_vm->next = label_context_stack_vm->labels_def;
nlist_vm->label = label;
label_context_stack_vm->labels_def = nlist_vm;
/* Mark label as having been defined. */
DECL_INITIAL (label) = error_mark_node;
return label;
}
/* Get the bindings for a new switch statement. This is used to issue
warnings as appropriate for jumps from the switch to case or
default labels. */
struct c_spot_bindings *
c_get_switch_bindings (void)
{
struct c_spot_bindings *switch_bindings;
switch_bindings = XNEW (struct c_spot_bindings);
set_spot_bindings (switch_bindings, true);
return switch_bindings;
}
void
c_release_switch_bindings (struct c_spot_bindings *bindings)
{
gcc_assert (bindings->stmt_exprs == 0 && !bindings->left_stmt_expr);
XDELETE (bindings);
}
/* This is called at the point of a case or default label to issue
warnings about decls as needed. It returns true if it found an
error, not just a warning. */
bool
c_check_switch_jump_warnings (struct c_spot_bindings *switch_bindings,
location_t switch_loc, location_t case_loc)
{
bool saw_error;
struct c_scope *scope;
saw_error = false;
for (scope = current_scope;
scope != switch_bindings->scope;
scope = scope->outer)
{
struct c_binding *b;
gcc_assert (scope != NULL);
for (b = scope->bindings; b != NULL; b = b->prev)
{
if (decl_jump_unsafe (b->decl))
{
if (variably_modified_type_p (TREE_TYPE (b->decl), NULL_TREE))
{
saw_error = true;
error_at (case_loc,
("switch jumps into scope of identifier with "
"variably modified type"));
}
else
warning_at (case_loc, OPT_Wjump_misses_init,
"switch jumps over variable initialization");
inform (switch_loc, "switch starts here");
inform (DECL_SOURCE_LOCATION (b->decl), "%qD declared here",
b->decl);
}
}
}
if (switch_bindings->stmt_exprs > 0)
{
saw_error = true;
error_at (case_loc, "switch jumps into statement expression");
inform (switch_loc, "switch starts here");
}
return saw_error;
}
/* Given NAME, an IDENTIFIER_NODE,
return the structure (or union or enum) definition for that name.
If THISLEVEL_ONLY is nonzero, searches only the current_scope.
@ -3610,10 +4118,10 @@ finish_decl (tree decl, location_t init_loc, tree init,
b_ext = b_ext->shadowed;
if (b_ext)
{
if (b_ext->type)
b_ext->type = composite_type (b_ext->type, type);
if (b_ext->u.type)
b_ext->u.type = composite_type (b_ext->u.type, type);
else
b_ext->type = type;
b_ext->u.type = type;
}
}
break;
@ -6610,8 +7118,6 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
{
tree decl1, old_decl;
tree restype, resdecl;
struct c_label_context_se *nstack_se;
struct c_label_context_vm *nstack_vm;
location_t loc;
current_function_returns_value = 0; /* Assume, until we see it does. */
@ -6620,19 +7126,6 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
warn_about_return_type = 0;
c_switch_stack = NULL;
nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se);
nstack_se->labels_def = NULL;
nstack_se->labels_used = NULL;
nstack_se->next = label_context_stack_se;
label_context_stack_se = nstack_se;
nstack_vm = XOBNEW (&parser_obstack, struct c_label_context_vm);
nstack_vm->labels_def = NULL;
nstack_vm->labels_used = NULL;
nstack_vm->scope = 0;
nstack_vm->next = label_context_stack_vm;
label_context_stack_vm = nstack_vm;
/* Indicate no valid break/continue context by setting these variables
to some non-null, non-label value. We'll notice and emit the proper
error message in c_finish_bc_stmt. */
@ -6644,11 +7137,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
/* If the declarator is not suitable for a function definition,
cause a syntax error. */
if (decl1 == 0)
{
label_context_stack_se = label_context_stack_se->next;
label_context_stack_vm = label_context_stack_vm->next;
return 0;
}
return 0;
loc = DECL_SOURCE_LOCATION (decl1);
@ -6730,7 +7219,7 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
{
tree ext_decl, ext_type;
ext_decl = b->decl;
ext_type = b->type ? b->type : TREE_TYPE (ext_decl);
ext_type = b->u.type ? b->u.type : TREE_TYPE (ext_decl);
if (TREE_CODE (ext_type) == FUNCTION_TYPE
&& comptypes (TREE_TYPE (TREE_TYPE (decl1)),
TREE_TYPE (ext_type)))
@ -7282,9 +7771,6 @@ finish_function (void)
{
tree fndecl = current_function_decl;
label_context_stack_se = label_context_stack_se->next;
label_context_stack_vm = label_context_stack_vm->next;
if (TREE_CODE (fndecl) == FUNCTION_DECL
&& targetm.calls.promote_prototypes (TREE_TYPE (fndecl)))
{

View File

@ -395,6 +395,8 @@ c_common_handle_option (size_t scode, const char *arg, int value)
warn_strict_overflow = value;
warn_array_bounds = value;
warn_volatile_register_var = value;
if (warn_jump_misses_init == -1)
warn_jump_misses_init = value;
/* Only warn about unknown pragmas that are not in system
headers. */
@ -445,6 +447,10 @@ c_common_handle_option (size_t scode, const char *arg, int value)
implies -Wenum-compare. */
if (warn_enum_compare == -1 && value)
warn_enum_compare = value;
/* Because C++ always warns about a goto which misses an
initialization, -Wc++-compat turns on -Wgoto-misses-init. */
if (warn_jump_misses_init == -1 && value)
warn_jump_misses_init = value;
cpp_opts->warn_cxx_operator_names = value;
break;
@ -1084,6 +1090,8 @@ c_common_post_options (const char **pfilename)
warn_strict_aliasing = 0;
if (warn_strict_overflow == -1)
warn_strict_overflow = 0;
if (warn_jump_misses_init == -1)
warn_jump_misses_init = 0;
/* -Woverlength-strings is off by default, but is enabled by -pedantic.
It is never enabled in C++, as the minimum limit is not normative

View File

@ -108,29 +108,6 @@ struct GTY(()) lang_type {
sizeof and typeof it is set for other function decls as well. */
#define C_DECL_USED(EXP) DECL_LANG_FLAG_5 (FUNCTION_DECL_CHECK (EXP))
/* Record whether a label was defined in a statement expression which
has finished and so can no longer be jumped to. */
#define C_DECL_UNJUMPABLE_STMT_EXPR(EXP) \
DECL_LANG_FLAG_6 (LABEL_DECL_CHECK (EXP))
/* Record whether a label was the subject of a goto from outside the
current level of statement expression nesting and so cannot be
defined right now. */
#define C_DECL_UNDEFINABLE_STMT_EXPR(EXP) \
DECL_LANG_FLAG_7 (LABEL_DECL_CHECK (EXP))
/* Record whether a label was defined in the scope of an identifier
with variably modified type which has finished and so can no longer
be jumped to. */
#define C_DECL_UNJUMPABLE_VM(EXP) \
DECL_LANG_FLAG_3 (LABEL_DECL_CHECK (EXP))
/* Record whether a label was the subject of a goto from outside the
current level of scopes of identifiers with variably modified type
and so cannot be defined right now. */
#define C_DECL_UNDEFINABLE_VM(EXP) \
DECL_LANG_FLAG_5 (LABEL_DECL_CHECK (EXP))
/* Record whether a variable has been declared threadprivate by
#pragma omp threadprivate. */
#define C_DECL_THREADPRIVATE_P(DECL) DECL_LANG_FLAG_3 (VAR_DECL_CHECK (DECL))
@ -421,45 +398,6 @@ struct GTY(()) language_function {
int warn_about_return_type;
};
/* Save lists of labels used or defined in particular contexts.
Allocated on the parser obstack. */
struct c_label_list
{
/* The label at the head of the list. */
tree label;
/* The rest of the list. */
struct c_label_list *next;
};
/* Statement expression context. */
struct c_label_context_se
{
/* The labels defined at this level of nesting. */
struct c_label_list *labels_def;
/* The labels used at this level of nesting. */
struct c_label_list *labels_used;
/* The next outermost context. */
struct c_label_context_se *next;
};
/* Context of variably modified declarations. */
struct c_label_context_vm
{
/* The labels defined at this level of nesting. */
struct c_label_list *labels_def;
/* The labels used at this level of nesting. */
struct c_label_list *labels_used;
/* The scope of this context. Multiple contexts may be at the same
numbered scope, since each variably modified declaration starts a
new context. */
unsigned scope;
/* The next outermost context. */
struct c_label_context_vm *next;
};
/* Used when parsing an enum. Initialized by start_enum. */
struct c_enum_contents
{
@ -491,6 +429,7 @@ extern void c_parse_init (void);
extern void gen_aux_info_record (tree, int, int, int);
/* in c-decl.c */
struct c_spot_bindings;
extern struct obstack parser_obstack;
extern tree c_break_label;
extern tree c_cont_label;
@ -498,6 +437,8 @@ extern tree c_cont_label;
extern int global_bindings_p (void);
extern void push_scope (void);
extern tree pop_scope (void);
extern void c_bindings_start_stmt_expr (struct c_spot_bindings *);
extern void c_bindings_end_stmt_expr (struct c_spot_bindings *);
extern void record_inline_static (location_t, tree, tree,
enum c_inline_static_type);
@ -513,8 +454,13 @@ extern tree check_for_loop_decls (location_t);
extern void mark_forward_parm_decls (void);
extern void declare_parm_level (void);
extern void undeclared_variable (location_t, tree);
extern tree lookup_label_for_goto (location_t, tree);
extern tree declare_label (tree);
extern tree define_label (location_t, tree);
extern struct c_spot_bindings *c_get_switch_bindings (void);
extern void c_release_switch_bindings (struct c_spot_bindings *);
extern bool c_check_switch_jump_warnings (struct c_spot_bindings *,
location_t, location_t);
extern void c_maybe_initialize_eh (void);
extern void finish_decl (tree, location_t, tree, tree, tree);
extern tree finish_enum (tree, tree, tree);
@ -583,8 +529,6 @@ extern int in_sizeof;
extern int in_typeof;
extern struct c_switch *c_switch_stack;
extern struct c_label_context_se *label_context_stack_se;
extern struct c_label_context_vm *label_context_stack_vm;
extern tree c_objc_common_truthvalue_conversion (location_t, tree);
extern tree require_complete_type (tree);
@ -643,8 +587,6 @@ extern tree c_finish_return (location_t, tree, tree);
extern tree c_finish_bc_stmt (location_t, tree *, bool);
extern tree c_finish_goto_label (location_t, tree);
extern tree c_finish_goto_ptr (location_t, tree);
extern void c_begin_vm_scope (unsigned int);
extern void c_end_vm_scope (unsigned int);
extern tree c_expr_to_decl (tree, bool *, bool *);
extern tree c_begin_omp_parallel (void);
extern tree c_finish_omp_parallel (location_t, tree, tree);

View File

@ -70,9 +70,6 @@ int in_sizeof;
/* The level of nesting inside "typeof". */
int in_typeof;
struct c_label_context_se *label_context_stack_se;
struct c_label_context_vm *label_context_stack_vm;
/* Nonzero if we've already printed a "missing braces around initializer"
message within this initializer. */
static int missing_braces_mentioned;
@ -7979,46 +7976,9 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs,
tree
c_finish_goto_label (location_t loc, tree label)
{
tree decl = lookup_label (label);
tree decl = lookup_label_for_goto (loc, label);
if (!decl)
return NULL_TREE;
if (C_DECL_UNJUMPABLE_STMT_EXPR (decl))
{
error_at (loc, "jump into statement expression");
return NULL_TREE;
}
if (C_DECL_UNJUMPABLE_VM (decl))
{
error_at (loc,
"jump into scope of identifier with variably modified type");
return NULL_TREE;
}
if (!C_DECL_UNDEFINABLE_STMT_EXPR (decl))
{
/* No jump from outside this statement expression context, so
record that there is a jump from within this context. */
struct c_label_list *nlist;
nlist = XOBNEW (&parser_obstack, struct c_label_list);
nlist->next = label_context_stack_se->labels_used;
nlist->label = decl;
label_context_stack_se->labels_used = nlist;
}
if (!C_DECL_UNDEFINABLE_VM (decl))
{
/* No jump from outside this context context of identifiers with
variably modified type, so record that there is a jump from
within this context. */
struct c_label_list *nlist;
nlist = XOBNEW (&parser_obstack, struct c_label_list);
nlist->next = label_context_stack_vm->labels_used;
nlist->label = decl;
label_context_stack_vm->labels_used = nlist;
}
TREE_USED (decl) = 1;
{
tree t = build1 (GOTO_EXPR, void_type_node, decl);
@ -8189,15 +8149,9 @@ struct c_switch {
of the GNU case range extension. */
splay_tree cases;
/* Number of nested statement expressions within this switch
statement; if nonzero, case and default labels may not
appear. */
unsigned int blocked_stmt_expr;
/* Scope of outermost declarations of identifiers with variably
modified type within this switch statement; if nonzero, case and
default labels may not appear. */
unsigned int blocked_vm;
/* The bindings at the point of the switch. This is used for
warnings crossing decls when branching to a case label. */
struct c_spot_bindings *bindings;
/* The next node on the stack. */
struct c_switch *next;
@ -8261,8 +8215,7 @@ c_start_case (location_t switch_loc,
SET_EXPR_LOCATION (cs->switch_expr, switch_loc);
cs->orig_type = orig_type;
cs->cases = splay_tree_new (case_compare, NULL, NULL);
cs->blocked_stmt_expr = 0;
cs->blocked_vm = 0;
cs->bindings = c_get_switch_bindings ();
cs->next = c_switch_stack;
c_switch_stack = cs;
@ -8292,40 +8245,26 @@ do_case (location_t loc, tree low_value, tree high_value)
"case label is not an integer constant expression");
}
if (c_switch_stack && !c_switch_stack->blocked_stmt_expr
&& !c_switch_stack->blocked_vm)
{
label = c_add_case_label (loc, c_switch_stack->cases,
SWITCH_COND (c_switch_stack->switch_expr),
c_switch_stack->orig_type,
low_value, high_value);
if (label == error_mark_node)
label = NULL_TREE;
}
else if (c_switch_stack && c_switch_stack->blocked_stmt_expr)
if (c_switch_stack == NULL)
{
if (low_value)
error_at (loc, "case label in statement expression not containing "
"enclosing switch statement");
error_at (loc, "case label not within a switch statement");
else
error_at (loc, "%<default%> label in statement expression not containing "
"enclosing switch statement");
error_at (loc, "%<default%> label not within a switch statement");
return NULL_TREE;
}
else if (c_switch_stack && c_switch_stack->blocked_vm)
{
if (low_value)
error_at (loc, "case label in scope of identifier with variably "
"modified type not containing enclosing switch statement");
else
error_at (loc, "%<default%> label in scope of identifier with "
"variably modified type not containing enclosing switch "
"statement");
}
else if (low_value)
error_at (loc, "case label not within a switch statement");
else
error_at (loc, "%<default%> label not within a switch statement");
if (c_check_switch_jump_warnings (c_switch_stack->bindings,
EXPR_LOCATION (c_switch_stack->switch_expr),
loc))
return NULL_TREE;
label = c_add_case_label (loc, c_switch_stack->cases,
SWITCH_COND (c_switch_stack->switch_expr),
c_switch_stack->orig_type,
low_value, high_value);
if (label == error_mark_node)
label = NULL_TREE;
return label;
}
@ -8339,11 +8278,6 @@ c_finish_case (tree body)
SWITCH_BODY (cs->switch_expr) = body;
/* We must not be within a statement expression nested in the switch
at this point; we might, however, be within the scope of an
identifier with variably modified type nested in the switch. */
gcc_assert (!cs->blocked_stmt_expr);
/* Emit warnings as needed. */
switch_location = EXPR_LOCATION (cs->switch_expr);
c_do_switch_warnings (cs->cases, switch_location,
@ -8353,6 +8287,7 @@ c_finish_case (tree body)
/* Pop the stack. */
c_switch_stack = cs->next;
splay_tree_delete (cs->cases);
c_release_switch_bindings (cs->bindings);
XDELETE (cs);
}
@ -8603,30 +8538,16 @@ tree
c_begin_stmt_expr (void)
{
tree ret;
struct c_label_context_se *nstack;
struct c_label_list *glist;
/* We must force a BLOCK for this level so that, if it is not expanded
later, there is a way to turn off the entire subtree of blocks that
are contained in it. */
keep_next_level ();
ret = c_begin_compound_stmt (true);
if (c_switch_stack)
{
c_switch_stack->blocked_stmt_expr++;
gcc_assert (c_switch_stack->blocked_stmt_expr != 0);
}
for (glist = label_context_stack_se->labels_used;
glist != NULL;
glist = glist->next)
{
C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 1;
}
nstack = XOBNEW (&parser_obstack, struct c_label_context_se);
nstack->labels_def = NULL;
nstack->labels_used = NULL;
nstack->next = label_context_stack_se;
label_context_stack_se = nstack;
c_bindings_start_stmt_expr (c_switch_stack == NULL
? NULL
: c_switch_stack->bindings);
/* Mark the current statement list as belonging to a statement list. */
STATEMENT_LIST_STMT_EXPR (ret) = 1;
@ -8642,37 +8563,12 @@ c_finish_stmt_expr (location_t loc, tree body)
{
tree last, type, tmp, val;
tree *last_p;
struct c_label_list *dlist, *glist, *glist_prev = NULL;
body = c_end_compound_stmt (loc, body, true);
if (c_switch_stack)
{
gcc_assert (c_switch_stack->blocked_stmt_expr != 0);
c_switch_stack->blocked_stmt_expr--;
}
/* It is no longer possible to jump to labels defined within this
statement expression. */
for (dlist = label_context_stack_se->labels_def;
dlist != NULL;
dlist = dlist->next)
{
C_DECL_UNJUMPABLE_STMT_EXPR (dlist->label) = 1;
}
/* It is again possible to define labels with a goto just outside
this statement expression. */
for (glist = label_context_stack_se->next->labels_used;
glist != NULL;
glist = glist->next)
{
C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 0;
glist_prev = glist;
}
if (glist_prev != NULL)
glist_prev->next = label_context_stack_se->labels_used;
else
label_context_stack_se->next->labels_used
= label_context_stack_se->labels_used;
label_context_stack_se = label_context_stack_se->next;
c_bindings_end_stmt_expr (c_switch_stack == NULL
? NULL
: c_switch_stack->bindings);
/* Locate the last statement in BODY. See c_end_compound_stmt
about always returning a BIND_EXPR. */
@ -8762,80 +8658,6 @@ c_finish_stmt_expr (location_t loc, tree body)
return t;
}
}
/* Begin the scope of an identifier of variably modified type, scope
number SCOPE. Jumping from outside this scope to inside it is not
permitted. */
void
c_begin_vm_scope (unsigned int scope)
{
struct c_label_context_vm *nstack;
struct c_label_list *glist;
gcc_assert (scope > 0);
/* At file_scope, we don't have to do any processing. */
if (label_context_stack_vm == NULL)
return;
if (c_switch_stack && !c_switch_stack->blocked_vm)
c_switch_stack->blocked_vm = scope;
for (glist = label_context_stack_vm->labels_used;
glist != NULL;
glist = glist->next)
{
C_DECL_UNDEFINABLE_VM (glist->label) = 1;
}
nstack = XOBNEW (&parser_obstack, struct c_label_context_vm);
nstack->labels_def = NULL;
nstack->labels_used = NULL;
nstack->scope = scope;
nstack->next = label_context_stack_vm;
label_context_stack_vm = nstack;
}
/* End a scope which may contain identifiers of variably modified
type, scope number SCOPE. */
void
c_end_vm_scope (unsigned int scope)
{
if (label_context_stack_vm == NULL)
return;
if (c_switch_stack && c_switch_stack->blocked_vm == scope)
c_switch_stack->blocked_vm = 0;
/* We may have a number of nested scopes of identifiers with
variably modified type, all at this depth. Pop each in turn. */
while (label_context_stack_vm->scope == scope)
{
struct c_label_list *dlist, *glist, *glist_prev = NULL;
/* It is no longer possible to jump to labels defined within this
scope. */
for (dlist = label_context_stack_vm->labels_def;
dlist != NULL;
dlist = dlist->next)
{
C_DECL_UNJUMPABLE_VM (dlist->label) = 1;
}
/* It is again possible to define labels with a goto just outside
this scope. */
for (glist = label_context_stack_vm->next->labels_used;
glist != NULL;
glist = glist->next)
{
C_DECL_UNDEFINABLE_VM (glist->label) = 0;
glist_prev = glist;
}
if (glist_prev != NULL)
glist_prev->next = label_context_stack_vm->labels_used;
else
label_context_stack_vm->next->labels_used
= label_context_stack_vm->labels_used;
label_context_stack_vm = label_context_stack_vm->next;
}
}
/* Begin and end compound statements. This is as simple as pushing
and popping new statement lists from the tree. */

View File

@ -284,6 +284,10 @@ Winvalid-pch
C ObjC C++ ObjC++ Warning
Warn about PCH files that are found but not used
Wjump-misses-init
C Objc Var(warn_jump_misses_init) Init(-1) Warning
Warn when a jump misses a variable initialization
Wlogical-op
C ObjC C++ ObjC++ Var(warn_logical_op) Init(0) Warning
Warn when a logical operator is suspiciously always evaluating to true or false

View File

@ -1,3 +1,8 @@
2009-06-15 Ian Lance Taylor <iant@google.com>
* parser.c (cp_parser_direct_declarator): Add braces around
variables declared before label.
2009-06-15 Rafael Avila de Espindola <espindola@google.com>
* cp-objcp-common.h (LANG_HOOKS_COMDAT_GROUP): Remove.

View File

@ -13371,181 +13371,183 @@ cp_parser_direct_declarator (cp_parser* parser,
}
else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT)
{
tree qualifying_scope;
tree unqualified_name;
special_function_kind sfk;
bool abstract_ok;
bool pack_expansion_p = false;
cp_token *declarator_id_start_token;
{
tree qualifying_scope;
tree unqualified_name;
special_function_kind sfk;
bool abstract_ok;
bool pack_expansion_p = false;
cp_token *declarator_id_start_token;
/* Parse a declarator-id */
abstract_ok = (dcl_kind == CP_PARSER_DECLARATOR_EITHER);
if (abstract_ok)
{
cp_parser_parse_tentatively (parser);
/* Parse a declarator-id */
abstract_ok = (dcl_kind == CP_PARSER_DECLARATOR_EITHER);
if (abstract_ok)
{
cp_parser_parse_tentatively (parser);
/* If we see an ellipsis, we should be looking at a
parameter pack. */
if (token->type == CPP_ELLIPSIS)
{
/* Consume the `...' */
cp_lexer_consume_token (parser->lexer);
/* If we see an ellipsis, we should be looking at a
parameter pack. */
if (token->type == CPP_ELLIPSIS)
{
/* Consume the `...' */
cp_lexer_consume_token (parser->lexer);
pack_expansion_p = true;
}
}
pack_expansion_p = true;
}
}
declarator_id_start_token = cp_lexer_peek_token (parser->lexer);
unqualified_name
= cp_parser_declarator_id (parser, /*optional_p=*/abstract_ok);
qualifying_scope = parser->scope;
if (abstract_ok)
{
bool okay = false;
declarator_id_start_token = cp_lexer_peek_token (parser->lexer);
unqualified_name
= cp_parser_declarator_id (parser, /*optional_p=*/abstract_ok);
qualifying_scope = parser->scope;
if (abstract_ok)
{
bool okay = false;
if (!unqualified_name && pack_expansion_p)
{
/* Check whether an error occurred. */
okay = !cp_parser_error_occurred (parser);
if (!unqualified_name && pack_expansion_p)
{
/* Check whether an error occurred. */
okay = !cp_parser_error_occurred (parser);
/* We already consumed the ellipsis to mark a
parameter pack, but we have no way to report it,
so abort the tentative parse. We will be exiting
immediately anyway. */
cp_parser_abort_tentative_parse (parser);
}
else
okay = cp_parser_parse_definitely (parser);
/* We already consumed the ellipsis to mark a
parameter pack, but we have no way to report it,
so abort the tentative parse. We will be exiting
immediately anyway. */
cp_parser_abort_tentative_parse (parser);
}
else
okay = cp_parser_parse_definitely (parser);
if (!okay)
unqualified_name = error_mark_node;
else if (unqualified_name
&& (qualifying_scope
|| (TREE_CODE (unqualified_name)
!= IDENTIFIER_NODE)))
{
cp_parser_error (parser, "expected unqualified-id");
if (!okay)
unqualified_name = error_mark_node;
}
}
else if (unqualified_name
&& (qualifying_scope
|| (TREE_CODE (unqualified_name)
!= IDENTIFIER_NODE)))
{
cp_parser_error (parser, "expected unqualified-id");
unqualified_name = error_mark_node;
}
}
if (!unqualified_name)
return NULL;
if (unqualified_name == error_mark_node)
{
declarator = cp_error_declarator;
pack_expansion_p = false;
declarator->parameter_pack_p = false;
break;
}
if (!unqualified_name)
return NULL;
if (unqualified_name == error_mark_node)
{
declarator = cp_error_declarator;
pack_expansion_p = false;
declarator->parameter_pack_p = false;
break;
}
if (qualifying_scope && at_namespace_scope_p ()
&& TREE_CODE (qualifying_scope) == TYPENAME_TYPE)
{
/* In the declaration of a member of a template class
outside of the class itself, the SCOPE will sometimes
be a TYPENAME_TYPE. For example, given:
if (qualifying_scope && at_namespace_scope_p ()
&& TREE_CODE (qualifying_scope) == TYPENAME_TYPE)
{
/* In the declaration of a member of a template class
outside of the class itself, the SCOPE will sometimes
be a TYPENAME_TYPE. For example, given:
template <typename T>
int S<T>::R::i = 3;
template <typename T>
int S<T>::R::i = 3;
the SCOPE will be a TYPENAME_TYPE for `S<T>::R'. In
this context, we must resolve S<T>::R to an ordinary
type, rather than a typename type.
the SCOPE will be a TYPENAME_TYPE for `S<T>::R'. In
this context, we must resolve S<T>::R to an ordinary
type, rather than a typename type.
The reason we normally avoid resolving TYPENAME_TYPEs
is that a specialization of `S' might render
`S<T>::R' not a type. However, if `S' is
specialized, then this `i' will not be used, so there
is no harm in resolving the types here. */
tree type;
The reason we normally avoid resolving TYPENAME_TYPEs
is that a specialization of `S' might render
`S<T>::R' not a type. However, if `S' is
specialized, then this `i' will not be used, so there
is no harm in resolving the types here. */
tree type;
/* Resolve the TYPENAME_TYPE. */
type = resolve_typename_type (qualifying_scope,
/*only_current_p=*/false);
/* If that failed, the declarator is invalid. */
if (TREE_CODE (type) == TYPENAME_TYPE)
error ("%H%<%T::%E%> is not a type",
&declarator_id_start_token->location,
TYPE_CONTEXT (qualifying_scope),
TYPE_IDENTIFIER (qualifying_scope));
qualifying_scope = type;
}
/* Resolve the TYPENAME_TYPE. */
type = resolve_typename_type (qualifying_scope,
/*only_current_p=*/false);
/* If that failed, the declarator is invalid. */
if (TREE_CODE (type) == TYPENAME_TYPE)
error ("%H%<%T::%E%> is not a type",
&declarator_id_start_token->location,
TYPE_CONTEXT (qualifying_scope),
TYPE_IDENTIFIER (qualifying_scope));
qualifying_scope = type;
}
sfk = sfk_none;
sfk = sfk_none;
if (unqualified_name)
{
tree class_type;
if (unqualified_name)
{
tree class_type;
if (qualifying_scope
&& CLASS_TYPE_P (qualifying_scope))
class_type = qualifying_scope;
else
class_type = current_class_type;
if (qualifying_scope
&& CLASS_TYPE_P (qualifying_scope))
class_type = qualifying_scope;
else
class_type = current_class_type;
if (TREE_CODE (unqualified_name) == TYPE_DECL)
{
tree name_type = TREE_TYPE (unqualified_name);
if (class_type && same_type_p (name_type, class_type))
{
if (qualifying_scope
&& CLASSTYPE_USE_TEMPLATE (name_type))
{
error ("%Hinvalid use of constructor as a template",
&declarator_id_start_token->location);
inform (input_location, "use %<%T::%D%> instead of %<%T::%D%> to "
"name the constructor in a qualified name",
class_type,
DECL_NAME (TYPE_TI_TEMPLATE (class_type)),
class_type, name_type);
declarator = cp_error_declarator;
break;
}
else
if (TREE_CODE (unqualified_name) == TYPE_DECL)
{
tree name_type = TREE_TYPE (unqualified_name);
if (class_type && same_type_p (name_type, class_type))
{
if (qualifying_scope
&& CLASSTYPE_USE_TEMPLATE (name_type))
{
error ("%Hinvalid use of constructor as a template",
&declarator_id_start_token->location);
inform (input_location, "use %<%T::%D%> instead of %<%T::%D%> to "
"name the constructor in a qualified name",
class_type,
DECL_NAME (TYPE_TI_TEMPLATE (class_type)),
class_type, name_type);
declarator = cp_error_declarator;
break;
}
else
unqualified_name = constructor_name (class_type);
}
else
{
/* We do not attempt to print the declarator
here because we do not have enough
information about its original syntactic
form. */
cp_parser_error (parser, "invalid declarator");
declarator = cp_error_declarator;
break;
}
}
if (class_type)
{
if (TREE_CODE (unqualified_name) == BIT_NOT_EXPR)
sfk = sfk_destructor;
else if (IDENTIFIER_TYPENAME_P (unqualified_name))
sfk = sfk_conversion;
else if (/* There's no way to declare a constructor
for an anonymous type, even if the type
got a name for linkage purposes. */
!TYPE_WAS_ANONYMOUS (class_type)
&& constructor_name_p (unqualified_name,
class_type))
{
unqualified_name = constructor_name (class_type);
}
else
{
/* We do not attempt to print the declarator
here because we do not have enough
information about its original syntactic
form. */
cp_parser_error (parser, "invalid declarator");
declarator = cp_error_declarator;
break;
}
}
sfk = sfk_constructor;
}
if (class_type)
{
if (TREE_CODE (unqualified_name) == BIT_NOT_EXPR)
sfk = sfk_destructor;
else if (IDENTIFIER_TYPENAME_P (unqualified_name))
sfk = sfk_conversion;
else if (/* There's no way to declare a constructor
for an anonymous type, even if the type
got a name for linkage purposes. */
!TYPE_WAS_ANONYMOUS (class_type)
&& constructor_name_p (unqualified_name,
class_type))
{
unqualified_name = constructor_name (class_type);
sfk = sfk_constructor;
}
if (ctor_dtor_or_conv_p && sfk != sfk_none)
*ctor_dtor_or_conv_p = -1;
}
}
declarator = make_id_declarator (qualifying_scope,
unqualified_name,
sfk);
declarator->id_loc = token->location;
declarator->parameter_pack_p = pack_expansion_p;
if (ctor_dtor_or_conv_p && sfk != sfk_none)
*ctor_dtor_or_conv_p = -1;
}
}
declarator = make_id_declarator (qualifying_scope,
unqualified_name,
sfk);
declarator->id_loc = token->location;
declarator->parameter_pack_p = pack_expansion_p;
if (pack_expansion_p)
maybe_warn_variadic_templates ();
if (pack_expansion_p)
maybe_warn_variadic_templates ();
}
handle_declarator:;
scope = get_scope_of_declarator (declarator);

View File

@ -3912,19 +3912,21 @@ df_simulate_one_insn_forwards (basic_block bb, rtx insn, bitmap live)
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
{
switch (REG_NOTE_KIND (link))
{
case REG_DEAD:
case REG_UNUSED:
{
rtx reg = XEXP (link, 0);
int regno = REGNO (reg);
if (regno < FIRST_PSEUDO_REGISTER)
{
int n = hard_regno_nregs[regno][GET_MODE (reg)];
while (--n >= 0)
bitmap_clear_bit (live, regno + n);
}
else
bitmap_clear_bit (live, regno);
{
rtx reg = XEXP (link, 0);
int regno = REGNO (reg);
if (regno < FIRST_PSEUDO_REGISTER)
{
int n = hard_regno_nregs[regno][GET_MODE (reg)];
while (--n >= 0)
bitmap_clear_bit (live, regno + n);
}
else
bitmap_clear_bit (live, regno);
}
break;
default:
break;

View File

@ -238,7 +238,7 @@ Objective-C and Objective-C++ Dialects}.
-Wfatal-errors -Wfloat-equal -Wformat -Wformat=2 @gol
-Wno-format-contains-nul -Wno-format-extra-args -Wformat-nonliteral @gol
-Wformat-security -Wformat-y2k @gol
-Wframe-larger-than=@var{len} -Wignored-qualifiers @gol
-Wframe-larger-than=@var{len} -Wjump-misses-init -Wignored-qualifiers @gol
-Wimplicit -Wimplicit-function-declaration -Wimplicit-int @gol
-Winit-self -Winline @gol
-Wno-int-to-pointer-cast -Wno-invalid-offsetof @gol
@ -2973,6 +2973,20 @@ requiring a non-null value by the @code{nonnull} function attribute.
@option{-Wnonnull} is included in @option{-Wall} and @option{-Wformat}. It
can be disabled with the @option{-Wno-nonnull} option.
@item -Wjump-misses-init @r{(C, Objective-C only)}
@opindex Wjump-misses-init
@opindex Wno-jump-misses-init
Warn if a @code{goto} statement or a @code{switch} statement jumps
forward across the initialization of a variable, or jumps backward to a
label after the variable has been initialized. This only warns about
variables which are initialized when they are declared. This warning is
only supported for C and Objective C; in C++ this sort of branch is an
error in any case.
@option{-Wjump-misses-init} is included in @option{-Wall} and
@option{-Wc++-compat}. It can be disabled with the
@option{-Wno-jump-misses-init} option.
@item -Winit-self @r{(C, C++, Objective-C and Objective-C++ only)}
@opindex Winit-self
@opindex Wno-init-self

View File

@ -1065,27 +1065,29 @@ read_count_file (void)
program_count++;
else if (tag == GCOV_TAG_FUNCTION)
{
unsigned ident = gcov_read_unsigned ();
struct function_info *fn_n = functions;
{
unsigned ident = gcov_read_unsigned ();
struct function_info *fn_n = functions;
/* Try to find the function in the list.
To speed up the search, first start from the last function
found. */
for (fn = fn ? fn->next : NULL; ; fn = fn->next)
{
if (fn)
;
else if ((fn = fn_n))
fn_n = NULL;
else
{
fnotice (stderr, "%s:unknown function '%u'\n",
da_file_name, ident);
/* Try to find the function in the list.
To speed up the search, first start from the last function
found. */
for (fn = fn ? fn->next : NULL; ; fn = fn->next)
{
if (fn)
;
else if ((fn = fn_n))
fn_n = NULL;
else
{
fnotice (stderr, "%s:unknown function '%u'\n",
da_file_name, ident);
break;
}
if (fn->ident == ident)
break;
}
if (fn->ident == ident)
break;
}
}
}
if (!fn)
;

View File

@ -1,3 +1,8 @@
2009-06-15 Ian Lance Taylor <iant@google.com>
* objc-act.c (objc_start_function): Don't set
label_context_stack_se or label_context_stack_vm.
2009-06-12 Aldy Hernandez <aldyh@redhat.com>
* objc-act.c (finish_var_decl): Pass location to finish_decl.

View File

@ -8632,19 +8632,6 @@ objc_start_function (tree name, tree type, tree attrs,
cplus_decl_attributes (&fndecl, attrs, 0);
start_preparsed_function (fndecl, attrs, /*flags=*/SF_DEFAULT);
#else
struct c_label_context_se *nstack_se;
struct c_label_context_vm *nstack_vm;
nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se);
nstack_se->labels_def = NULL;
nstack_se->labels_used = NULL;
nstack_se->next = label_context_stack_se;
label_context_stack_se = nstack_se;
nstack_vm = XOBNEW (&parser_obstack, struct c_label_context_vm);
nstack_vm->labels_def = NULL;
nstack_vm->labels_used = NULL;
nstack_vm->scope = 0;
nstack_vm->next = label_context_stack_vm;
label_context_stack_vm = nstack_vm;
current_function_returns_value = 0; /* Assume, until we see it does. */
current_function_returns_null = 0;

View File

@ -1,3 +1,20 @@
2009-06-15 Ian Lance Taylor <iant@google.com>
* gcc.dg/Wjump-misses-init-1.c: New testcase.
* gcc.dg/Wjump-misses-init-2.c: New testcase.
* gcc.dg/c99-vla-jump-5.c: Adjust expected error messages.
Recognize new notes.
* gcc.dg/stmt-expr-label-2.c: Likewise.
* gcc.dg/c99-vla-jump-1.c: Recognize new notes. Fix column
numbers.
* gcc.dg/c99-vla-jump-2.c: Recognize new notes.
* gcc.dg/c99-vla-jump-3.c: Recognize new notes.
* gcc.dg/c99-vla-jump-4.c: Likewise.
* gcc.dg/stmt-expr-label-1.c: Likewise.
* gcc.dg/stmt-expr-label-3.c: Likewise.
* gcc.dg/vla-8.c: Likewise. Move error message to different
line.
2009-06-16 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* gcc.dg/torture/builtin-math-6.c: Robustify and fix clog cases.

View File

@ -0,0 +1,156 @@
/* { dg-do compile } */
/* { dg-options "-Wjump-misses-init" } */
int
f1 (int a)
{
if (a > 0)
{
int i = 7; /* { dg-message "here" } */
lab: /* { dg-message "here" } */
return a;
}
else
{
if (a < 0)
goto lab; /* { dg-warning "jump" } */
return 1;
}
}
int
f2 (int a)
{
if (a > 0)
{
if (a < 0)
goto lab; /* { dg-warning "jump" } */
return 1;
}
else
{
int i = 7; /* { dg-message "here" } */
lab: /* { dg-message "here" } */
return a;
}
}
int
f3 (int a)
{
if (a > 0)
{
static int i = 7;
lab:
return a;
}
else
{
if (a < 0)
goto lab;
return 1;
}
}
int
f4 (int a)
{
if (a > 0)
{
if (a < 0)
goto lab;
return 1;
}
else
{
static int i = 7;
lab:
return a;
}
}
int
f5 (int a)
{
if (a > 0)
{
int b = 1;
if (a < 0)
goto lab;
}
lab:
return a;
}
int
f6 (int a)
{
if (a > 0)
{
lab:
return a;
}
else
{
int b = 1;
goto lab;
}
}
int
f7 (int a)
{
switch (a) /* { dg-message "switch" } */
{
int b = 1; /* { dg-message "here" } */
case 1: /* { dg-warning "jump" } */
return a;
}
}
int
f8 (int a)
{
switch (a) /* { dg-message "switch" } */
{
int b = 1; /* { dg-message "here" } */
case 1: /* { dg-warning "jump" } */
goto lab;
}
lab:
return a;
}
int
f9 (int a)
{
switch (a)
{
case 0:
{
int b = 1;
return b;
}
case 1:
return a;
}
}
int
f10 (int a)
{
switch (a)
{
case 0:
{
int b = 1;
goto lab;
}
case 1:
goto lab;
}
lab:
return a;
}

View File

@ -0,0 +1,52 @@
/* { dg-do compile } */
/* { dg-options "-Wjump-misses-init -std=c99" } */
extern void f1 ();
int
f2 (int a)
{
switch (a) /* { dg-message "switch" } */
{
case 1:
f1 ();
int v2 = 3; /* { dg-message "here" } */
case 2: /* { dg-warning "jump" } */
if (v2 == 7)
f1 ();
}
return 0;
}
int
f3 (int i)
{
if (i)
goto bad; /* { dg-warning "jump" } */
int a = f2 (i); /* { dg-message "here" } */
bad: /* { dg-message "here" } */
return a;
}
int
f4 (int a)
{
switch (a)
{
case 1:
f1 ();
static int v2 = 3;
case 2:
if (v2 == 7)
f1 ();
}
return 0;
}
int
f5 (int i)
{
if (i)
goto bad;
static int a = 6;
bad:
return a;
}

View File

@ -15,11 +15,11 @@
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
void fa0 (int n) { goto a; a:{ int b[n]; { int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; }
void fa1 (int n) { goto a; { int b[n]; a:{ int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "41:jump into scope of identifier with variably modified type" } */
void fa2 (int n) { goto a; { int b[n]; { int c[n]; a:0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "53:jump into scope of identifier with variably modified type" } */
void fa3 (int n) { goto a; { int b[n]; { int c[n]; 0;} a:{ int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "57:jump into scope of identifier with variably modified type" } */
void fa4 (int n) { goto a; { int b[n]; { int c[n]; 0;} { int d[n]; a:0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "69:jump into scope of identifier with variably modified type" } */
void fa5 (int n) { goto a; { int b[n]; { int c[n]; 0;} { int d[n]; 0;} a:; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "73:jump into scope of identifier with variably modified type" } */
void fa1 (int n) { goto a; { int b[n]; a:{ int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "21:jump into scope of identifier with variably modified type" } */
void fa2 (int n) { goto a; { int b[n]; { int c[n]; a:0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "21:jump into scope of identifier with variably modified type" } */
void fa3 (int n) { goto a; { int b[n]; { int c[n]; 0;} a:{ int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "21:jump into scope of identifier with variably modified type" } */
void fa4 (int n) { goto a; { int b[n]; { int c[n]; 0;} { int d[n]; a:0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "21:jump into scope of identifier with variably modified type" } */
void fa5 (int n) { goto a; { int b[n]; { int c[n]; 0;} { int d[n]; 0;} a:; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "21:jump into scope of identifier with variably modified type" } */
void fa6 (int n) { goto a; { int b[n]; { int c[n]; 0;} { int d[n]; 0;} ; int e[n]; a:0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "jump into scope of identifier with variably modified type" } */
void fa7 (int n) { goto a; { int b[n]; { int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}; a:{ int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; }
void fa8 (int n) { goto a; { int b[n]; { int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; a:{ int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0; } /* { dg-error "jump into scope of identifier with variably modified type" } */
@ -303,3 +303,7 @@ void fa285 (int n) { { int b[n]; { int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}
void fa286 (int n) { { int b[n]; { int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; a:; int j[n]; 0; goto a; }
void fa287 (int n) { { int b[n]; { int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; a:0; goto a; }
void fa288 (int n) { { int b[n]; { int c[n]; 0;} { int d[n]; 0;} ; int e[n]; 0;}; { int f[n]; { int g[n]; 0;}; { int h[n]; 0;}; ; int i[n]; 0;}; ; int j[n]; 0;a: goto a; }
/* Match extra informative notes. */
/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */
/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */

View File

@ -303,3 +303,7 @@ void fb285 (int n) { P0A:goto P0A;{ int b[n]; P01A:goto P01A;{ int c[n]; P012A:g
void fb286 (int n) { P0A:goto P0A;{ int b[n]; P01A:goto P01A;{ int c[n]; P012A:goto P012A;0;} P01B:goto P01B;{ int d[n]; P013A:goto P013A;0;} P01C:goto P01C;; int e[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ int f[n]; P02A:goto P02A;{ int g[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ int h[n]; P025A:goto P025A;0;}; P02C:goto P02C;; int i[n]; P026A:goto P026A;0;}; a:; int j[n]; P03A:goto P03A;0;p03B:goto p03B; goto a; P03B:goto P03B; }
void fb287 (int n) { P0A:goto P0A;{ int b[n]; P01A:goto P01A;{ int c[n]; P012A:goto P012A;0;} P01B:goto P01B;{ int d[n]; P013A:goto P013A;0;} P01C:goto P01C;; int e[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ int f[n]; P02A:goto P02A;{ int g[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ int h[n]; P025A:goto P025A;0;}; P02C:goto P02C;; int i[n]; P026A:goto P026A;0;}; P0C:goto P0C;; int j[n]; a:0;p03B:goto p03B; goto a; P03B:goto P03B; }
void fb288 (int n) { P0A:goto P0A;{ int b[n]; P01A:goto P01A;{ int c[n]; P012A:goto P012A;0;} P01B:goto P01B;{ int d[n]; P013A:goto P013A;0;} P01C:goto P01C;; int e[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ int f[n]; P02A:goto P02A;{ int g[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ int h[n]; P025A:goto P025A;0;}; P02C:goto P02C;; int i[n]; P026A:goto P026A;0;}; P0C:goto P0C;; int j[n]; P03A:goto P03A;0;a: goto a; P03B:goto P03B; }
/* Match extra informative notes. */
/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */
/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */

View File

@ -303,3 +303,7 @@ void fc285 (int n) { { typedef int (*b)[n]; { typedef int (*c)[n]; 0;} { typedef
void fc286 (int n) { { typedef int (*b)[n]; { typedef int (*c)[n]; 0;} { typedef int (*d)[n]; 0;} ; typedef int (*e)[n]; 0;}; { typedef int (*f)[n]; { typedef int (*g)[n]; 0;}; { typedef int (*h)[n]; 0;}; ; typedef int (*i)[n]; 0;}; a:; typedef int (*j)[n]; 0; goto a; }
void fc287 (int n) { { typedef int (*b)[n]; { typedef int (*c)[n]; 0;} { typedef int (*d)[n]; 0;} ; typedef int (*e)[n]; 0;}; { typedef int (*f)[n]; { typedef int (*g)[n]; 0;}; { typedef int (*h)[n]; 0;}; ; typedef int (*i)[n]; 0;}; ; typedef int (*j)[n]; a:0; goto a; }
void fc288 (int n) { { typedef int (*b)[n]; { typedef int (*c)[n]; 0;} { typedef int (*d)[n]; 0;} ; typedef int (*e)[n]; 0;}; { typedef int (*f)[n]; { typedef int (*g)[n]; 0;}; { typedef int (*h)[n]; 0;}; ; typedef int (*i)[n]; 0;}; ; typedef int (*j)[n]; 0;a: goto a; }
/* Match extra informative notes. */
/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */
/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */

View File

@ -303,3 +303,7 @@ void fd285 (int n) { P0A:goto P0A;{ typedef int (*b)[n]; P01A:goto P01A;{ typede
void fd286 (int n) { P0A:goto P0A;{ typedef int (*b)[n]; P01A:goto P01A;{ typedef int (*c)[n]; P012A:goto P012A;0;} P01B:goto P01B;{ typedef int (*d)[n]; P013A:goto P013A;0;} P01C:goto P01C;; typedef int (*e)[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ typedef int (*f)[n]; P02A:goto P02A;{ typedef int (*g)[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ typedef int (*h)[n]; P025A:goto P025A;0;}; P02C:goto P02C;; typedef int (*i)[n]; P026A:goto P026A;0;}; a:; typedef int (*j)[n]; P03A:goto P03A;0;p03B:goto p03B; goto a; P03B:goto P03B; }
void fd287 (int n) { P0A:goto P0A;{ typedef int (*b)[n]; P01A:goto P01A;{ typedef int (*c)[n]; P012A:goto P012A;0;} P01B:goto P01B;{ typedef int (*d)[n]; P013A:goto P013A;0;} P01C:goto P01C;; typedef int (*e)[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ typedef int (*f)[n]; P02A:goto P02A;{ typedef int (*g)[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ typedef int (*h)[n]; P025A:goto P025A;0;}; P02C:goto P02C;; typedef int (*i)[n]; P026A:goto P026A;0;}; P0C:goto P0C;; typedef int (*j)[n]; a:0;p03B:goto p03B; goto a; P03B:goto P03B; }
void fd288 (int n) { P0A:goto P0A;{ typedef int (*b)[n]; P01A:goto P01A;{ typedef int (*c)[n]; P012A:goto P012A;0;} P01B:goto P01B;{ typedef int (*d)[n]; P013A:goto P013A;0;} P01C:goto P01C;; typedef int (*e)[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ typedef int (*f)[n]; P02A:goto P02A;{ typedef int (*g)[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ typedef int (*h)[n]; P025A:goto P025A;0;}; P02C:goto P02C;; typedef int (*i)[n]; P026A:goto P026A;0;}; P0C:goto P0C;; typedef int (*j)[n]; P03A:goto P03A;0;a: goto a; P03B:goto P03B; }
/* Match extra informative notes. */
/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */
/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */

View File

@ -16,8 +16,8 @@ f (int a, int b)
{
switch (a) {
int v[b];
case 2: /* { dg-error "case label in scope of identifier with variably modified type not containing enclosing switch statement" } */
default: /* { dg-error "'default' label in scope of identifier with variably modified type not containing enclosing switch statement" } */
case 2: /* { dg-error "switch jumps into scope of identifier with variably modified type" } */
default: /* { dg-error "switch jumps into scope of identifier with variably modified type" } */
switch (a)
{
case 4:
@ -28,3 +28,7 @@ f (int a, int b)
}
}
}
/* Match extra informative notes. */
/* { dg-message "note: switch starts here" "note: expected" { target *-*-* } 0 } */
/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */

View File

@ -402,3 +402,6 @@ void f194 (void) { ({ ({0;}); ({0;}); 0;}); ({ ({0;}); ({0;}); 0;}); a:0; goto a
void fa194 (void) { P0A:goto P0A;({ P01A:goto P01A;({P012A:goto P012A;0;}); P01B:goto P01B;({P013A:goto P013A;0;}); P01C:goto P01C;0;}); P0B:goto P0B;({ P02A:goto P02A;({P024A:goto P024A;0;}); P02B:goto P02B;({P025A:goto P025A;0;}); P02C:goto P02C;0;}); a:0;p0D:goto p0D; goto a; P0D:goto P0D; }
void f195 (void) { ({ ({0;}); ({0;}); 0;}); ({ ({0;}); ({0;}); 0;}); 0;a: goto a; }
void fa195 (void) { P0A:goto P0A;({ P01A:goto P01A;({P012A:goto P012A;0;}); P01B:goto P01B;({P013A:goto P013A;0;}); P01C:goto P01C;0;}); P0B:goto P0B;({ P02A:goto P02A;({P024A:goto P024A;0;}); P02B:goto P02B;({P025A:goto P025A;0;}); P02C:goto P02C;0;}); P0C:goto P0C;0;a: goto a; P0D:goto P0D; }
/* Match extra informative notes. */
/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */

View File

@ -8,13 +8,13 @@
void
f (int a)
{
switch (a)
switch (a) /* { dg-message "here" } */
{
case 0:
case 1:
({
case 2: /* { dg-error "case label in statement expression not containing enclosing switch statement" } */
default: /* { dg-error "'default' label in statement expression not containing enclosing switch statement" } */
case 2: /* { dg-error "switch jumps into statement expression" } */
default: /* { dg-error "switch jumps into statement expression" } */
switch (a)
{
case 3:

View File

@ -6,3 +6,6 @@
/* { dg-options "-O2" } */
void f(void) { 1 ? 1 : ({ a : 1; 1; }); goto a; } /* { dg-error "jump into statement expression" } */
/* Match extra informative notes. */
/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */

View File

@ -23,8 +23,12 @@ void foo1(int n) {
}
void foo2(int n) {
goto A;
goto A; /* { dg-error "jump into scope of identifier with variably modified type" } */
int (*(*bar2)(void))[n];
A: /* { dg-error "jump into scope of identifier with variably modified type" } */
A:
;
}
/* Match extra informative notes. */
/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */
/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */