aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog86
-rw-r--r--gcc/c-decl.c644
-rw-r--r--gcc/c-opts.c8
-rw-r--r--gcc/c-tree.h74
-rw-r--r--gcc/c-typeck.c236
-rw-r--r--gcc/c.opt4
-rw-r--r--gcc/cp/ChangeLog5
-rw-r--r--gcc/cp/parser.c326
-rw-r--r--gcc/df-problems.c24
-rw-r--r--gcc/doc/invoke.texi16
-rw-r--r--gcc/gcov.c40
-rw-r--r--gcc/objc/ChangeLog5
-rw-r--r--gcc/objc/objc-act.c13
-rw-r--r--gcc/testsuite/ChangeLog17
-rw-r--r--gcc/testsuite/gcc.dg/Wjump-misses-init-1.c156
-rw-r--r--gcc/testsuite/gcc.dg/Wjump-misses-init-2.c52
-rw-r--r--gcc/testsuite/gcc.dg/c99-vla-jump-1.c14
-rw-r--r--gcc/testsuite/gcc.dg/c99-vla-jump-2.c4
-rw-r--r--gcc/testsuite/gcc.dg/c99-vla-jump-3.c4
-rw-r--r--gcc/testsuite/gcc.dg/c99-vla-jump-4.c4
-rw-r--r--gcc/testsuite/gcc.dg/c99-vla-jump-5.c8
-rw-r--r--gcc/testsuite/gcc.dg/stmt-expr-label-1.c3
-rw-r--r--gcc/testsuite/gcc.dg/stmt-expr-label-2.c6
-rw-r--r--gcc/testsuite/gcc.dg/stmt-expr-label-3.c3
-rw-r--r--gcc/testsuite/gcc.dg/vla-8.c8
25 files changed, 1190 insertions, 570 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 47e4e6c..fd13b18 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 03d6dbd..c2c2a89 100644
--- a/gcc/c-decl.c
+++ b/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)))
{
diff --git a/gcc/c-opts.c b/gcc/c-opts.c
index 0050ab5..4574bb2 100644
--- a/gcc/c-opts.c
+++ b/gcc/c-opts.c
@@ -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
diff --git a/gcc/c-tree.h b/gcc/c-tree.h
index d606217..f565df5 100644
--- a/gcc/c-tree.h
+++ b/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);
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index 978e95c..0dd97d3 100644
--- a/gcc/c-typeck.c
+++ b/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 (low_value)
- error_at (loc, "case label in statement expression not containing "
- "enclosing switch statement");
- else
- error_at (loc, "%<default%> label in statement expression not containing "
- "enclosing switch statement");
- }
- else if (c_switch_stack && c_switch_stack->blocked_vm)
+ if (c_switch_stack == NULL)
{
if (low_value)
- error_at (loc, "case label in scope of identifier with variably "
- "modified type not containing enclosing switch statement");
+ error_at (loc, "case label not within a switch statement");
else
- error_at (loc, "%<default%> label in scope of identifier with "
- "variably modified type not containing enclosing switch "
- "statement");
+ error_at (loc, "%<default%> label not within a switch statement");
+ return NULL_TREE;
}
- 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. */
diff --git a/gcc/c.opt b/gcc/c.opt
index da1de00..e8a9a31 100644
--- a/gcc/c.opt
+++ b/gcc/c.opt
@@ -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
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 1a0e9351..911081a 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 07f0375..0314bb3 100644
--- a/gcc/cp/parser.c
+++ b/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;
-
- /* Parse a declarator-id */
- abstract_ok = (dcl_kind == CP_PARSER_DECLARATOR_EITHER);
- if (abstract_ok)
- {
- cp_parser_parse_tentatively (parser);
+ {
+ 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);
- /* 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;
-
- 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);
-
- 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;
- }
- }
+ 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)
- 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 && 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);
- 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;
-
- 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;
+ 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;
+ }
+ }
- /* 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;
- }
+ 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;
+ }
- sfk = sfk_none;
+ 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;
+
+ 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;
+
+ /* 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;
+ }
- if (unqualified_name)
- {
- tree class_type;
+ sfk = sfk_none;
- if (qualifying_scope
- && CLASS_TYPE_P (qualifying_scope))
- class_type = qualifying_scope;
- else
- class_type = current_class_type;
+ if (unqualified_name)
+ {
+ tree 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
- 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 (qualifying_scope
+ && CLASS_TYPE_P (qualifying_scope))
+ class_type = qualifying_scope;
+ else
+ class_type = current_class_type;
- 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 (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 (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 (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 (pack_expansion_p)
- maybe_warn_variadic_templates ();
+ 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 ();
+ }
handle_declarator:;
scope = get_scope_of_declarator (declarator);
diff --git a/gcc/df-problems.c b/gcc/df-problems.c
index f48da9b..1d1dc9c 100644
--- a/gcc/df-problems.c
+++ b/gcc/df-problems.c
@@ -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;
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 8d133d0..f75a6a8 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -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
diff --git a/gcc/gcov.c b/gcc/gcov.c
index 61ac7ed..4f5c3d4 100644
--- a/gcc/gcov.c
+++ b/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)
;
diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog
index 5aaa3b7..2fe4b25 100644
--- a/gcc/objc/ChangeLog
+++ b/gcc/objc/ChangeLog
@@ -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.
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index 0c91faa..f114b65 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -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;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 62874a7..c961525 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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.
diff --git a/gcc/testsuite/gcc.dg/Wjump-misses-init-1.c b/gcc/testsuite/gcc.dg/Wjump-misses-init-1.c
new file mode 100644
index 0000000..86117f1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wjump-misses-init-1.c
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/Wjump-misses-init-2.c b/gcc/testsuite/gcc.dg/Wjump-misses-init-2.c
new file mode 100644
index 0000000..042c02a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wjump-misses-init-2.c
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/c99-vla-jump-1.c b/gcc/testsuite/gcc.dg/c99-vla-jump-1.c
index 3cfa384..8e34b10 100644
--- a/gcc/testsuite/gcc.dg/c99-vla-jump-1.c
+++ b/gcc/testsuite/gcc.dg/c99-vla-jump-1.c
@@ -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 } */
diff --git a/gcc/testsuite/gcc.dg/c99-vla-jump-2.c b/gcc/testsuite/gcc.dg/c99-vla-jump-2.c
index 27cecaa..2b4d4d5 100644
--- a/gcc/testsuite/gcc.dg/c99-vla-jump-2.c
+++ b/gcc/testsuite/gcc.dg/c99-vla-jump-2.c
@@ -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 } */
diff --git a/gcc/testsuite/gcc.dg/c99-vla-jump-3.c b/gcc/testsuite/gcc.dg/c99-vla-jump-3.c
index 0aff362..ac1ae96 100644
--- a/gcc/testsuite/gcc.dg/c99-vla-jump-3.c
+++ b/gcc/testsuite/gcc.dg/c99-vla-jump-3.c
@@ -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 } */
diff --git a/gcc/testsuite/gcc.dg/c99-vla-jump-4.c b/gcc/testsuite/gcc.dg/c99-vla-jump-4.c
index e77a142..848dfba 100644
--- a/gcc/testsuite/gcc.dg/c99-vla-jump-4.c
+++ b/gcc/testsuite/gcc.dg/c99-vla-jump-4.c
@@ -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 } */
diff --git a/gcc/testsuite/gcc.dg/c99-vla-jump-5.c b/gcc/testsuite/gcc.dg/c99-vla-jump-5.c
index ca3f85f..683bcf2 100644
--- a/gcc/testsuite/gcc.dg/c99-vla-jump-5.c
+++ b/gcc/testsuite/gcc.dg/c99-vla-jump-5.c
@@ -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 } */
diff --git a/gcc/testsuite/gcc.dg/stmt-expr-label-1.c b/gcc/testsuite/gcc.dg/stmt-expr-label-1.c
index 57ab34e..a9dd466 100644
--- a/gcc/testsuite/gcc.dg/stmt-expr-label-1.c
+++ b/gcc/testsuite/gcc.dg/stmt-expr-label-1.c
@@ -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 } */
diff --git a/gcc/testsuite/gcc.dg/stmt-expr-label-2.c b/gcc/testsuite/gcc.dg/stmt-expr-label-2.c
index 35b96e8..be7aa52 100644
--- a/gcc/testsuite/gcc.dg/stmt-expr-label-2.c
+++ b/gcc/testsuite/gcc.dg/stmt-expr-label-2.c
@@ -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:
diff --git a/gcc/testsuite/gcc.dg/stmt-expr-label-3.c b/gcc/testsuite/gcc.dg/stmt-expr-label-3.c
index 7b1515f..0a67222 100644
--- a/gcc/testsuite/gcc.dg/stmt-expr-label-3.c
+++ b/gcc/testsuite/gcc.dg/stmt-expr-label-3.c
@@ -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 } */
diff --git a/gcc/testsuite/gcc.dg/vla-8.c b/gcc/testsuite/gcc.dg/vla-8.c
index 1d31876..6e14a06 100644
--- a/gcc/testsuite/gcc.dg/vla-8.c
+++ b/gcc/testsuite/gcc.dg/vla-8.c
@@ -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 } */