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:
parent
dee6f57529
commit
e1b7793c8e
|
@ -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
|
||||
|
|
644
gcc/c-decl.c
644
gcc/c-decl.c
|
@ -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)))
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
74
gcc/c-tree.h
74
gcc/c-tree.h
|
@ -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);
|
||||
|
|
236
gcc/c-typeck.c
236
gcc/c-typeck.c
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
310
gcc/cp/parser.c
310
gcc/cp/parser.c
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
40
gcc/gcov.c
40
gcc/gcov.c
|
@ -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)
|
||||
;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 } */
|
||||
|
|
|
@ -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 } */
|
||||
|
|
|
@ -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 } */
|
||||
|
|
|
@ -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 } */
|
||||
|
|
|
@ -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 } */
|
||||
|
|
|
@ -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 } */
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 } */
|
||||
|
|
|
@ -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 } */
|
||||
|
|
Loading…
Reference in New Issue