+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
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
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.
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 */
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
/* 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. */
b->inner_comp = 0;
b->locus = locus;
- b->type = 0;
+ b->u.type = NULL;
b->prev = scope->bindings;
scope->bindings = 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;
+}
\f
/* Hook called at end of compilation to assume 1 elt
for a file-scope tentative array defn that wasn't complete before. */
c_inline_statics = NULL;
}
\f
+/* 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;
+}
+\f
/* The Objective-C front-end often needs to determine the current 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
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. */
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:
{
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;
maybe_apply_pending_pragma_weaks ();
cgraph_finalize_compilation_unit ();
}
+\f
+/* 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);
+ }
+}
\f
/* Push a definition or a declaration of struct, union or enum tag "name".
"type" should be the type node.
|| 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)
{
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))
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;
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)
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
}
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);
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;
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,
}
\f
/* 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;
}
lookup_label (tree name)
{
tree label;
+ struct c_label_vars *label_vars;
if (current_function_decl == 0)
{
/* 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;
}
{
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 */
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. */
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
}
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))
"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;
}
\f
+/* 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;
+}
+\f
/* 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.
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;
{
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. */
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. */
/* 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);
{
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)))
{
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)))
{
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. */
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;
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
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))
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
{
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;
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);
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);
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);
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);
/* 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;
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);
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;
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;
"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;
}
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,
/* Pop the stack. */
c_switch_stack = cs->next;
splay_tree_delete (cs->cases);
+ c_release_switch_bindings (cs->bindings);
XDELETE (cs);
}
\f
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;
{
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. */
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;
- }
-}
\f
/* Begin and end compound statements. This is as simple as pushing
and popping new statement lists from the tree. */
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
+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.
}
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);
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;
-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
@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
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)
;
+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.
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;
+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.
--- /dev/null
+/* { 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;
+}
--- /dev/null
+/* { 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;
+}
/* { 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" } */
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 } */
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 } */
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 } */
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 } */
{
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:
}
}
}
+
+/* Match extra informative notes. */
+/* { dg-message "note: switch starts here" "note: expected" { target *-*-* } 0 } */
+/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */
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 } */
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:
/* { 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 } */
}
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 } */