OSDN Git Service

./:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 16 Jun 2009 05:12:15 +0000 (05:12 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 16 Jun 2009 05:12:15 +0000 (05:12 +0000)
* df-problems.c (df_simulate_one_insn_forwards): Fix braces in
switch.
* gcov.c (read_count_file): Add braces around variables declared
before label.

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

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@148512 138bc75d-0d04-0410-961f-82ee72b054a4

25 files changed:
gcc/ChangeLog
gcc/c-decl.c
gcc/c-opts.c
gcc/c-tree.h
gcc/c-typeck.c
gcc/c.opt
gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/df-problems.c
gcc/doc/invoke.texi
gcc/gcov.c
gcc/objc/ChangeLog
gcc/objc/objc-act.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/Wjump-misses-init-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wjump-misses-init-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c99-vla-jump-1.c
gcc/testsuite/gcc.dg/c99-vla-jump-2.c
gcc/testsuite/gcc.dg/c99-vla-jump-3.c
gcc/testsuite/gcc.dg/c99-vla-jump-4.c
gcc/testsuite/gcc.dg/c99-vla-jump-5.c
gcc/testsuite/gcc.dg/stmt-expr-label-1.c
gcc/testsuite/gcc.dg/stmt-expr-label-2.c
gcc/testsuite/gcc.dg/stmt-expr-label-3.c
gcc/testsuite/gcc.dg/vla-8.c

index 47e4e6c..fd13b18 100644 (file)
@@ -1,3 +1,89 @@
+2009-06-15  Ian Lance Taylor  <iant@google.com>
+
+       * df-problems.c (df_simulate_one_insn_forwards): Fix braces in
+       switch.
+       * gcov.c (read_count_file): Add braces around variables declared
+       before label.
+
+       * c.opt (Wjump-misses-init): New warning.
+       * c-opts.c (c_common_handle_option): Set warn_jump_misses_init for
+       -Wall and -Wc++-compat if not already set.
+       (c_common_post_options): Clear warn_jump_misses_init if it was not
+       set.
+       * c-decl.c (struct c_binding): Change type field to a union with
+       new label field.  Make it the first field in the struct.  Update
+       references to type to use u.type instead.
+       (struct c_spot_bindings): Define.
+       (struct c_goto_bindings): Define.
+       (c_goto_bindings_p): Define, along with VECs.
+       (struct c_label_vars): Define.
+       (struct c_scope): Add has_label_bindings field.
+       (bind_label, set_spot_bindings): New static functions.
+       (decl_jump_unsafe, update_spot_bindings): New static functions.
+       (update_label_decls): New static function.
+       (pop_scope): Call update_label_decls.  Don't call c_end_vm_scope.
+       Update binding u.label field to shadowed field.
+       (c_binding_start_stmt_expr): New function.
+       (c_binding_end_stmt_expr): New function.
+       (pushdecl): Don't call c_begin_vm_scope.
+       (make_label): Add defining and p_label_vars parameters.  Change
+       all callers.
+       (lookup_label): Correct test for whether a label has not yet been
+       defined.  Call bind_label rather than bind.
+       (warn_about_goto): New static function.
+       (lookup_label_for_goto): New function.
+       (declare_label): Call bind_label rather than bind.
+       (check_earlier_gotos): New static function.
+       (define_label): Don't give errors about jumping into statement
+       expressions or scopes of variably modified types.  Call
+       set_spot_bindings and check_earlier_gotos.  Call bind_label
+       instead of bind.  Don't set label_context_stack_se or
+       label_context_stack_vm.
+       (c_get_switch_bindings): New function.
+       (c_release_switch_bindings): New function.
+       (c_check_switch_jump_warnings): New function.
+       (start_function): Don't set label_context_stack_se or
+       label_context_stack_vm.
+       (finish_function): Likewise.
+       * c-typeck.c (label_context_stack_se): Don't define.
+       (label_context_stack_vm): Don't define.
+       (c_finish_goto_label): Call lookup_label_for_goto rather than
+       lookup_label.  Don't give errors about jumping into a statement
+       expression or the scope of a variably modified type.  Don't set
+       label_context_stack_se or label_context_stack_vm.
+       (struct c_switch): Remove blocked_stmt_expr and blocked_vm
+       fields.  Add bindings field.
+       (c_start_case): Don't set deleted fields.  Set bindings field.
+       (do_case): Rework order of tests.  Don't check blocked_stmt_expr
+       or blocked_vm.  Call c_check_switch_jump_warnings.
+       (c_finish_case): Don't test blocked_stmt_expr field.  Call
+       c_release_switch_bindings.
+       (c_begin_stmt_expr): Don't increment blocked_stmt_expr in
+       c_switch_stack.  Don't walk label_context_stack_se labels.  Don't
+       set label_context_stack_se.  Call c_bindings_start_stmt_expr.
+       (c_finish_stmt_expr): Don't decrement blocked_stmt_expr in
+       c_switch_stack.  Don't walk label_context_stack_se labels.  Don't
+       set label_context_stack_se.  Call c_bindings_end_stmt_expr.
+       (c_begin_vm_scope, c_end_vm_scope): Don't define.
+       * c-tree.h (C_DECL_UNJUMPABLE_STMT_EXPR): Don't define.
+       (C_DECL_UNDEFINABLE_STMT_EXPR): Don't define.
+       (C_DECL_UNJUMPABLE_VM): Don't define.
+       (C_DECL_UNDEFINABLE_VM): Don't define.
+       (struct c_label_list): Don't define.
+       (struct c_label_context_se): Don't define.
+       (struct c_label_context_vm): Don't define.
+       (struct c_spot_bindings): Declare.
+       (c_bindings_start_stmt_expr): Declare.
+       (c_bindings_end_stmt_expr): Declare.
+       (lookup_label_for_goto): Declare.
+       (c_get_switch_bindings, c_release_switch_bindings): Declare.
+       (c_check_switch_jump_warnings): Declare.
+       (label_context_stack_se, label_context_stack_vm): Don't declare.
+       (c_finish_goto_label): Update declaration.
+       (c_begin_vm_scope, c_end_vm_scope): Don't declare.
+       * doc/invoke.texi (Option Summary): Mention -Wjump-misses-init.
+       (Warning Options): Document -Wjump-misses-init.
+
 2009-06-15  Jakub Jelinek  <jakub@redhat.com>
 
        * tree-object-size.c (addr_object_size): Fix a pasto in the last
index 03d6dbd..c2c2a89 100644 (file)
@@ -188,7 +188,7 @@ bool c_override_global_bindings_to_false;
    suppress further errors about that identifier in the current
    function.
 
-   The ->type field stores the type of the declaration in this scope;
+   The ->u.type field stores the type of the declaration in this scope;
    if NULL, the type is the type of the ->decl field.  This is only of
    relevance for objects with external or internal linkage which may
    be redeclared in inner scopes, forming composite types that only
@@ -198,6 +198,9 @@ bool c_override_global_bindings_to_false;
    scope) stores whether an incomplete array type at file scope was
    completed at an inner scope to an array size other than 1.
 
+   The ->u.label field is used for labels.  It points to a structure
+   which stores additional information used for warnings.
+
    The depth field is copied from the scope structure that holds this
    decl.  It is used to preserve the proper ordering of the ->shadowed
    field (see bind()) and also for a handful of special-case checks.
@@ -208,8 +211,11 @@ bool c_override_global_bindings_to_false;
    invisible bit true.  */
 
 struct GTY((chain_next ("%h.prev"))) c_binding {
+  union GTY(()) {              /* first so GTY desc can use decl */
+    tree GTY((tag ("0"))) type; /* the type in this scope */
+    struct c_label_vars * GTY((tag ("1"))) label; /* for warnings */
+  } GTY((desc ("TREE_CODE (%0.decl) == LABEL_DECL"))) u;
   tree decl;                   /* the decl bound */
-  tree type;                   /* the type in this scope */
   tree id;                     /* the identifier it's bound to */
   struct c_binding *prev;      /* the previous decl in this scope */
   struct c_binding *shadowed;  /* the innermost decl shadowed by this one */
@@ -266,6 +272,67 @@ union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
   struct lang_identifier GTY ((tag ("1"))) identifier;
 };
 
+/* Track bindings and other things that matter for goto warnings.  For
+   efficiency, we do not gather all the decls at the point of
+   definition.  Instead, we point into the bindings structure.  As
+   scopes are popped, we update these structures and gather the decls
+   that matter at that time.  */
+
+struct GTY(()) c_spot_bindings {
+  /* The currently open scope which holds bindings defined when the
+     label was defined or the goto statement was found.  */
+  struct c_scope *scope;
+  /* The bindings in the scope field which were defined at the point
+     of the label or goto.  This lets us look at older or newer
+     bindings in the scope, as appropriate.  */
+  struct c_binding *bindings_in_scope;
+  /* The number of statement expressions that have started since this
+     label or goto statement was defined.  This is zero if we are at
+     the same statement expression level.  It is positive if we are in
+     a statement expression started since this spot.  It is negative
+     if this spot was in a statement expression and we have left
+     it.  */
+  int stmt_exprs;
+  /* Whether we started in a statement expression but are no longer in
+     it.  This is set to true if stmt_exprs ever goes negative.  */
+  bool left_stmt_expr;
+};
+
+/* This structure is used to keep track of bindings seen when a goto
+   statement is defined.  This is only used if we see the goto
+   statement before we see the label.  */
+
+struct GTY(()) c_goto_bindings {
+  /* The location of the goto statement.  */
+  location_t loc;
+  /* The bindings of the goto statement.  */
+  struct c_spot_bindings goto_bindings;
+};
+
+typedef struct c_goto_bindings *c_goto_bindings_p;
+DEF_VEC_P(c_goto_bindings_p);
+DEF_VEC_ALLOC_P(c_goto_bindings_p,gc);
+
+/* The additional information we keep track of for a label binding.
+   These fields are updated as scopes are popped.  */
+
+struct GTY(()) c_label_vars {
+  /* The shadowed c_label_vars, when one label shadows another (which
+     can only happen using a __label__ declaration).  */
+  struct c_label_vars *shadowed;
+  /* The bindings when the label was defined.  */
+  struct c_spot_bindings label_bindings;
+  /* A list of decls that we care about: decls about which we should
+     warn if a goto branches to this label from later in the function.
+     Decls are added to this list as scopes are popped.  We only add
+     the decls that matter.  */
+  VEC(tree,gc) *decls_in_scope;
+  /* A list of goto statements to this label.  This is only used for
+     goto statements seen before the label was defined, so that we can
+     issue appropriate warnings for them.  */
+  VEC(c_goto_bindings_p,gc) *gotos;
+};
+
 /* Each c_scope structure describes the complete contents of one
    scope.  Four scopes are distinguished specially: the innermost or
    current scope, the innermost function scope, the file scope (always
@@ -354,6 +421,11 @@ struct GTY((chain_next ("%h.outer"))) c_scope {
 
   /* True means that an unsuffixed float constant is _Decimal64.  */
   BOOL_BITFIELD float_const_decimal64 : 1;
+
+  /* True if this scope has any label bindings.  This is used to speed
+     up searching for labels when popping scopes, particularly since
+     labels are normally only found at function scope.  */
+  BOOL_BITFIELD has_label_bindings : 1;
 };
 
 /* The scope currently in effect.  */
@@ -518,7 +590,7 @@ bind (tree name, tree decl, struct c_scope *scope, bool invisible,
   b->inner_comp = 0;
   b->locus = locus;
 
-  b->type = 0;
+  b->u.type = NULL;
 
   b->prev = scope->bindings;
   scope->bindings = b;
@@ -569,6 +641,24 @@ free_binding_and_advance (struct c_binding *b)
   return prev;
 }
 
+/* Bind a label.  Like bind, but skip fields which aren't used for
+   labels, and add the LABEL_VARS value.  */
+static void
+bind_label (tree name, tree label, struct c_scope *scope,
+           struct c_label_vars *label_vars)
+{
+  struct c_binding *b;
+
+  bind (name, label, scope, /*invisible=*/false, /*nested=*/false,
+       UNKNOWN_LOCATION);
+
+  scope->has_label_bindings = true;
+
+  b = scope->bindings;
+  gcc_assert (b->decl == label);
+  label_vars->shadowed = b->u.label;
+  b->u.label = label_vars;
+}
 \f
 /* 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;
 }
 \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 *
@@ -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 ();
 }
+\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.
@@ -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)
 }
 \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;
 }
 
@@ -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;
 }
 \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.
@@ -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)))
     {
index 0050ab5..4574bb2 100644 (file)
@@ -395,6 +395,8 @@ c_common_handle_option (size_t scode, const char *arg, int value)
        warn_strict_overflow = value;
       warn_array_bounds = value;
       warn_volatile_register_var = value;
+      if (warn_jump_misses_init == -1)
+       warn_jump_misses_init = value;
 
       /* Only warn about unknown pragmas that are not in system
         headers.  */
@@ -445,6 +447,10 @@ c_common_handle_option (size_t scode, const char *arg, int value)
         implies -Wenum-compare.  */
       if (warn_enum_compare == -1 && value)
        warn_enum_compare = value;
+      /* Because C++ always warns about a goto which misses an
+        initialization, -Wc++-compat turns on -Wgoto-misses-init.  */
+      if (warn_jump_misses_init == -1 && value)
+       warn_jump_misses_init = value;
       cpp_opts->warn_cxx_operator_names = value;
       break;
 
@@ -1084,6 +1090,8 @@ c_common_post_options (const char **pfilename)
     warn_strict_aliasing = 0;
   if (warn_strict_overflow == -1)
     warn_strict_overflow = 0;
+  if (warn_jump_misses_init == -1)
+    warn_jump_misses_init = 0;
 
   /* -Woverlength-strings is off by default, but is enabled by -pedantic.
      It is never enabled in C++, as the minimum limit is not normative
index d606217..f565df5 100644 (file)
@@ -108,29 +108,6 @@ struct GTY(()) lang_type {
    sizeof and typeof it is set for other function decls as well.  */
 #define C_DECL_USED(EXP) DECL_LANG_FLAG_5 (FUNCTION_DECL_CHECK (EXP))
 
-/* Record whether a label was defined in a statement expression which
-   has finished and so can no longer be jumped to.  */
-#define C_DECL_UNJUMPABLE_STMT_EXPR(EXP)       \
-  DECL_LANG_FLAG_6 (LABEL_DECL_CHECK (EXP))
-
-/* Record whether a label was the subject of a goto from outside the
-   current level of statement expression nesting and so cannot be
-   defined right now.  */
-#define C_DECL_UNDEFINABLE_STMT_EXPR(EXP)      \
-  DECL_LANG_FLAG_7 (LABEL_DECL_CHECK (EXP))
-
-/* Record whether a label was defined in the scope of an identifier
-   with variably modified type which has finished and so can no longer
-   be jumped to.  */
-#define C_DECL_UNJUMPABLE_VM(EXP)      \
-  DECL_LANG_FLAG_3 (LABEL_DECL_CHECK (EXP))
-
-/* Record whether a label was the subject of a goto from outside the
-   current level of scopes of identifiers with variably modified type
-   and so cannot be defined right now.  */
-#define C_DECL_UNDEFINABLE_VM(EXP)     \
-  DECL_LANG_FLAG_5 (LABEL_DECL_CHECK (EXP))
-
 /* Record whether a variable has been declared threadprivate by
    #pragma omp threadprivate.  */
 #define C_DECL_THREADPRIVATE_P(DECL) DECL_LANG_FLAG_3 (VAR_DECL_CHECK (DECL))
@@ -421,45 +398,6 @@ struct GTY(()) language_function {
   int warn_about_return_type;
 };
 
-/* Save lists of labels used or defined in particular contexts.
-   Allocated on the parser obstack.  */
-
-struct c_label_list
-{
-  /* The label at the head of the list.  */
-  tree label;
-  /* The rest of the list.  */
-  struct c_label_list *next;
-};
-
-/* Statement expression context.  */
-
-struct c_label_context_se
-{
-  /* The labels defined at this level of nesting.  */
-  struct c_label_list *labels_def;
-  /* The labels used at this level of nesting.  */
-  struct c_label_list *labels_used;
-  /* The next outermost context.  */
-  struct c_label_context_se *next;
-};
-
-/* Context of variably modified declarations.  */
-
-struct c_label_context_vm
-{
-  /* The labels defined at this level of nesting.  */
-  struct c_label_list *labels_def;
-  /* The labels used at this level of nesting.  */
-  struct c_label_list *labels_used;
-  /* The scope of this context.  Multiple contexts may be at the same
-     numbered scope, since each variably modified declaration starts a
-     new context.  */
-  unsigned scope;
-  /* The next outermost context.  */
-  struct c_label_context_vm *next;
-};
-
 /* Used when parsing an enum.  Initialized by start_enum.  */
 struct c_enum_contents
 {
@@ -491,6 +429,7 @@ extern void c_parse_init (void);
 extern void gen_aux_info_record (tree, int, int, int);
 
 /* in c-decl.c */
+struct c_spot_bindings;
 extern struct obstack parser_obstack;
 extern tree c_break_label;
 extern tree c_cont_label;
@@ -498,6 +437,8 @@ extern tree c_cont_label;
 extern int global_bindings_p (void);
 extern void push_scope (void);
 extern tree pop_scope (void);
+extern void c_bindings_start_stmt_expr (struct c_spot_bindings *);
+extern void c_bindings_end_stmt_expr (struct c_spot_bindings *);
 
 extern void record_inline_static (location_t, tree, tree,
                                  enum c_inline_static_type);
@@ -513,8 +454,13 @@ extern tree check_for_loop_decls (location_t);
 extern void mark_forward_parm_decls (void);
 extern void declare_parm_level (void);
 extern void undeclared_variable (location_t, tree);
+extern tree lookup_label_for_goto (location_t, tree);
 extern tree declare_label (tree);
 extern tree define_label (location_t, tree);
+extern struct c_spot_bindings *c_get_switch_bindings (void);
+extern void c_release_switch_bindings (struct c_spot_bindings *);
+extern bool c_check_switch_jump_warnings (struct c_spot_bindings *,
+                                         location_t, location_t);
 extern void c_maybe_initialize_eh (void);
 extern void finish_decl (tree, location_t, tree, tree, tree);
 extern tree finish_enum (tree, tree, tree);
@@ -583,8 +529,6 @@ extern int in_sizeof;
 extern int in_typeof;
 
 extern struct c_switch *c_switch_stack;
-extern struct c_label_context_se *label_context_stack_se;
-extern struct c_label_context_vm *label_context_stack_vm;
 
 extern tree c_objc_common_truthvalue_conversion (location_t, tree);
 extern tree require_complete_type (tree);
@@ -643,8 +587,6 @@ extern tree c_finish_return (location_t, tree, tree);
 extern tree c_finish_bc_stmt (location_t, tree *, bool);
 extern tree c_finish_goto_label (location_t, tree);
 extern tree c_finish_goto_ptr (location_t, tree);
-extern void c_begin_vm_scope (unsigned int);
-extern void c_end_vm_scope (unsigned int);
 extern tree c_expr_to_decl (tree, bool *, bool *);
 extern tree c_begin_omp_parallel (void);
 extern tree c_finish_omp_parallel (location_t, tree, tree);
index 978e95c..0dd97d3 100644 (file)
@@ -70,9 +70,6 @@ int in_sizeof;
 /* The level of nesting inside "typeof".  */
 int in_typeof;
 
-struct c_label_context_se *label_context_stack_se;
-struct c_label_context_vm *label_context_stack_vm;
-
 /* Nonzero if we've already printed a "missing braces around initializer"
    message within this initializer.  */
 static int missing_braces_mentioned;
@@ -7979,46 +7976,9 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs,
 tree
 c_finish_goto_label (location_t loc, tree label)
 {
-  tree decl = lookup_label (label);
+  tree decl = lookup_label_for_goto (loc, label);
   if (!decl)
     return NULL_TREE;
-
-  if (C_DECL_UNJUMPABLE_STMT_EXPR (decl))
-    {
-      error_at (loc, "jump into statement expression");
-      return NULL_TREE;
-    }
-
-  if (C_DECL_UNJUMPABLE_VM (decl))
-    {
-      error_at (loc,
-               "jump into scope of identifier with variably modified type");
-      return NULL_TREE;
-    }
-
-  if (!C_DECL_UNDEFINABLE_STMT_EXPR (decl))
-    {
-      /* No jump from outside this statement expression context, so
-        record that there is a jump from within this context.  */
-      struct c_label_list *nlist;
-      nlist = XOBNEW (&parser_obstack, struct c_label_list);
-      nlist->next = label_context_stack_se->labels_used;
-      nlist->label = decl;
-      label_context_stack_se->labels_used = nlist;
-    }
-
-  if (!C_DECL_UNDEFINABLE_VM (decl))
-    {
-      /* No jump from outside this context context of identifiers with
-        variably modified type, so record that there is a jump from
-        within this context.  */
-      struct c_label_list *nlist;
-      nlist = XOBNEW (&parser_obstack, struct c_label_list);
-      nlist->next = label_context_stack_vm->labels_used;
-      nlist->label = decl;
-      label_context_stack_vm->labels_used = nlist;
-    }
-
   TREE_USED (decl) = 1;
   {
     tree t = build1 (GOTO_EXPR, void_type_node, decl);
@@ -8189,15 +8149,9 @@ struct c_switch {
      of the GNU case range extension.  */
   splay_tree cases;
 
-  /* Number of nested statement expressions within this switch
-     statement; if nonzero, case and default labels may not
-     appear.  */
-  unsigned int blocked_stmt_expr;
-
-  /* Scope of outermost declarations of identifiers with variably
-     modified type within this switch statement; if nonzero, case and
-     default labels may not appear.  */
-  unsigned int blocked_vm;
+  /* The bindings at the point of the switch.  This is used for
+     warnings crossing decls when branching to a case label.  */
+  struct c_spot_bindings *bindings;
 
   /* The next node on the stack.  */
   struct c_switch *next;
@@ -8261,8 +8215,7 @@ c_start_case (location_t switch_loc,
   SET_EXPR_LOCATION (cs->switch_expr, switch_loc);
   cs->orig_type = orig_type;
   cs->cases = splay_tree_new (case_compare, NULL, NULL);
-  cs->blocked_stmt_expr = 0;
-  cs->blocked_vm = 0;
+  cs->bindings = c_get_switch_bindings ();
   cs->next = c_switch_stack;
   c_switch_stack = cs;
 
@@ -8292,40 +8245,26 @@ do_case (location_t loc, tree low_value, tree high_value)
                 "case label is not an integer constant expression");
     }
 
-  if (c_switch_stack && !c_switch_stack->blocked_stmt_expr
-      && !c_switch_stack->blocked_vm)
-    {
-      label = c_add_case_label (loc, c_switch_stack->cases,
-                               SWITCH_COND (c_switch_stack->switch_expr),
-                               c_switch_stack->orig_type,
-                               low_value, high_value);
-      if (label == error_mark_node)
-       label = NULL_TREE;
-    }
-  else if (c_switch_stack && c_switch_stack->blocked_stmt_expr)
-    {
-      if (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);
 }
 \f
@@ -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;
-    }
-}
 \f
 /* Begin and end compound statements.  This is as simple as pushing
    and popping new statement lists from the tree.  */
index da1de00..e8a9a31 100644 (file)
--- 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
index 1a0e935..911081a 100644 (file)
@@ -1,3 +1,8 @@
+2009-06-15  Ian Lance Taylor  <iant@google.com>
+
+       * parser.c (cp_parser_direct_declarator): Add braces around
+       variables declared before label.
+
 2009-06-15  Rafael Avila de Espindola  <espindola@google.com>
 
        * cp-objcp-common.h (LANG_HOOKS_COMDAT_GROUP): Remove.
index 07f0375..0314bb3 100644 (file)
@@ -13371,181 +13371,183 @@ cp_parser_direct_declarator (cp_parser* parser,
        }
       else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT)
        {
-         tree qualifying_scope;
-         tree unqualified_name;
-         special_function_kind sfk;
-         bool abstract_ok;
-          bool pack_expansion_p = false;
-         cp_token *declarator_id_start_token;
-
-         /* 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);
index f48da9b..1d1dc9c 100644 (file)
@@ -3912,19 +3912,21 @@ df_simulate_one_insn_forwards (basic_block bb, rtx insn, bitmap live)
   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
     {
       switch (REG_NOTE_KIND (link))
+       {
        case REG_DEAD:
        case REG_UNUSED:
-       {
-         rtx reg = XEXP (link, 0);
-         int regno = REGNO (reg);
-         if (regno < FIRST_PSEUDO_REGISTER)
-           {
-             int n = hard_regno_nregs[regno][GET_MODE (reg)];
-             while (--n >= 0)
-               bitmap_clear_bit (live, regno + n);
-           }
-         else 
-           bitmap_clear_bit (live, regno);
+         {
+           rtx reg = XEXP (link, 0);
+           int regno = REGNO (reg);
+           if (regno < FIRST_PSEUDO_REGISTER)
+             {
+               int n = hard_regno_nregs[regno][GET_MODE (reg)];
+               while (--n >= 0)
+                 bitmap_clear_bit (live, regno + n);
+             }
+           else 
+             bitmap_clear_bit (live, regno);
+         }
          break;
        default:
          break;
index 8d133d0..f75a6a8 100644 (file)
@@ -238,7 +238,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wfatal-errors  -Wfloat-equal  -Wformat  -Wformat=2 @gol
 -Wno-format-contains-nul -Wno-format-extra-args -Wformat-nonliteral @gol
 -Wformat-security  -Wformat-y2k @gol
--Wframe-larger-than=@var{len} -Wignored-qualifiers @gol
+-Wframe-larger-than=@var{len} -Wjump-misses-init -Wignored-qualifiers @gol
 -Wimplicit  -Wimplicit-function-declaration  -Wimplicit-int @gol
 -Winit-self  -Winline @gol
 -Wno-int-to-pointer-cast -Wno-invalid-offsetof @gol
@@ -2973,6 +2973,20 @@ requiring a non-null value by the @code{nonnull} function attribute.
 @option{-Wnonnull} is included in @option{-Wall} and @option{-Wformat}.  It
 can be disabled with the @option{-Wno-nonnull} option.
 
+@item -Wjump-misses-init @r{(C, Objective-C only)}
+@opindex Wjump-misses-init
+@opindex Wno-jump-misses-init
+Warn if a @code{goto} statement or a @code{switch} statement jumps
+forward across the initialization of a variable, or jumps backward to a
+label after the variable has been initialized.  This only warns about
+variables which are initialized when they are declared.  This warning is
+only supported for C and Objective C; in C++ this sort of branch is an
+error in any case.
+
+@option{-Wjump-misses-init} is included in @option{-Wall} and
+@option{-Wc++-compat}.  It can be disabled with the
+@option{-Wno-jump-misses-init} option.
+
 @item -Winit-self @r{(C, C++, Objective-C and Objective-C++ only)}
 @opindex Winit-self
 @opindex Wno-init-self
index 61ac7ed..4f5c3d4 100644 (file)
@@ -1065,27 +1065,29 @@ read_count_file (void)
        program_count++;
       else if (tag == GCOV_TAG_FUNCTION)
        {
-         unsigned ident = gcov_read_unsigned ();
-         struct function_info *fn_n = functions;
+         {
+           unsigned ident = gcov_read_unsigned ();
+           struct function_info *fn_n = functions;
 
-         /* Try to find the function in the list.
-            To speed up the search, first start from the last function
-            found.   */
-         for (fn = fn ? fn->next : NULL; ; fn = fn->next)
-           {
-             if (fn)
-               ;
-             else if ((fn = fn_n))
-               fn_n = NULL;
-             else
-               {
-                 fnotice (stderr, "%s:unknown function '%u'\n",
-                          da_file_name, ident);
+           /* Try to find the function in the list.
+              To speed up the search, first start from the last function
+              found.   */
+           for (fn = fn ? fn->next : NULL; ; fn = fn->next)
+             {
+               if (fn)
+                 ;
+               else if ((fn = fn_n))
+                 fn_n = NULL;
+               else
+                 {
+                   fnotice (stderr, "%s:unknown function '%u'\n",
+                            da_file_name, ident);
+                   break;
+                 }
+               if (fn->ident == ident)
                  break;
-               }
-             if (fn->ident == ident)
-               break;
-           }
+             }
+         }
 
          if (!fn)
            ;
index 5aaa3b7..2fe4b25 100644 (file)
@@ -1,3 +1,8 @@
+2009-06-15  Ian Lance Taylor  <iant@google.com>
+
+       * objc-act.c (objc_start_function): Don't set
+       label_context_stack_se or label_context_stack_vm.
+
 2009-06-12  Aldy Hernandez  <aldyh@redhat.com>
        
        * objc-act.c (finish_var_decl): Pass location to finish_decl.
index 0c91faa..f114b65 100644 (file)
@@ -8632,19 +8632,6 @@ objc_start_function (tree name, tree type, tree attrs,
   cplus_decl_attributes (&fndecl, attrs, 0);
   start_preparsed_function (fndecl, attrs, /*flags=*/SF_DEFAULT);
 #else
-  struct c_label_context_se *nstack_se;
-  struct c_label_context_vm *nstack_vm;
-  nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se);
-  nstack_se->labels_def = NULL;
-  nstack_se->labels_used = NULL;
-  nstack_se->next = label_context_stack_se;
-  label_context_stack_se = nstack_se;
-  nstack_vm = XOBNEW (&parser_obstack, struct c_label_context_vm);
-  nstack_vm->labels_def = NULL;
-  nstack_vm->labels_used = NULL;
-  nstack_vm->scope = 0;
-  nstack_vm->next = label_context_stack_vm;
-  label_context_stack_vm = nstack_vm;
   current_function_returns_value = 0;  /* Assume, until we see it does.  */
   current_function_returns_null = 0;
 
index 62874a7..c961525 100644 (file)
@@ -1,3 +1,20 @@
+2009-06-15  Ian Lance Taylor  <iant@google.com>
+
+       * gcc.dg/Wjump-misses-init-1.c: New testcase.
+       * gcc.dg/Wjump-misses-init-2.c: New testcase.
+       * gcc.dg/c99-vla-jump-5.c: Adjust expected error messages.
+       Recognize new notes.
+       * gcc.dg/stmt-expr-label-2.c: Likewise.
+       * gcc.dg/c99-vla-jump-1.c: Recognize new notes.  Fix column
+       numbers.
+       * gcc.dg/c99-vla-jump-2.c: Recognize new notes.
+       * gcc.dg/c99-vla-jump-3.c: Recognize new notes.
+       * gcc.dg/c99-vla-jump-4.c: Likewise.
+       * gcc.dg/stmt-expr-label-1.c: Likewise.
+       * gcc.dg/stmt-expr-label-3.c: Likewise.
+       * gcc.dg/vla-8.c: Likewise.  Move error message to different
+       line.
+
 2009-06-16  Kaveh R. Ghazi  <ghazi@caip.rutgers.edu>
 
        * gcc.dg/torture/builtin-math-6.c: Robustify and fix clog cases.
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 (file)
index 0000000..86117f1
--- /dev/null
@@ -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 (file)
index 0000000..042c02a
--- /dev/null
@@ -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;
+}
index 3cfa384..8e34b10 100644 (file)
 /* { 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 } */
index 27cecaa..2b4d4d5 100644 (file)
@@ -303,3 +303,7 @@ void fb285 (int n) { P0A:goto P0A;{ int b[n]; P01A:goto P01A;{ int c[n]; P012A:g
 void fb286 (int n) { P0A:goto P0A;{ int b[n]; P01A:goto P01A;{ int c[n]; P012A:goto P012A;0;} P01B:goto P01B;{ int d[n]; P013A:goto P013A;0;} P01C:goto P01C;; int e[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ int f[n]; P02A:goto P02A;{ int g[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ int h[n]; P025A:goto P025A;0;}; P02C:goto P02C;; int i[n]; P026A:goto P026A;0;}; a:; int j[n]; P03A:goto P03A;0;p03B:goto p03B; goto a; P03B:goto P03B; }
 void fb287 (int n) { P0A:goto P0A;{ int b[n]; P01A:goto P01A;{ int c[n]; P012A:goto P012A;0;} P01B:goto P01B;{ int d[n]; P013A:goto P013A;0;} P01C:goto P01C;; int e[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ int f[n]; P02A:goto P02A;{ int g[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ int h[n]; P025A:goto P025A;0;}; P02C:goto P02C;; int i[n]; P026A:goto P026A;0;}; P0C:goto P0C;; int j[n]; a:0;p03B:goto p03B; goto a; P03B:goto P03B; }
 void fb288 (int n) { P0A:goto P0A;{ int b[n]; P01A:goto P01A;{ int c[n]; P012A:goto P012A;0;} P01B:goto P01B;{ int d[n]; P013A:goto P013A;0;} P01C:goto P01C;; int e[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ int f[n]; P02A:goto P02A;{ int g[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ int h[n]; P025A:goto P025A;0;}; P02C:goto P02C;; int i[n]; P026A:goto P026A;0;}; P0C:goto P0C;; int j[n]; P03A:goto P03A;0;a: goto a; P03B:goto P03B; }
+
+/* Match extra informative notes.  */
+/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */
+/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */
index 0aff362..ac1ae96 100644 (file)
@@ -303,3 +303,7 @@ void fc285 (int n) { { typedef int (*b)[n]; { typedef int (*c)[n]; 0;} { typedef
 void fc286 (int n) { { typedef int (*b)[n]; { typedef int (*c)[n]; 0;} { typedef int (*d)[n]; 0;} ; typedef int (*e)[n]; 0;}; { typedef int (*f)[n]; { typedef int (*g)[n]; 0;}; { typedef int (*h)[n]; 0;}; ; typedef int (*i)[n]; 0;}; a:; typedef int (*j)[n]; 0; goto a;  }
 void fc287 (int n) { { typedef int (*b)[n]; { typedef int (*c)[n]; 0;} { typedef int (*d)[n]; 0;} ; typedef int (*e)[n]; 0;}; { typedef int (*f)[n]; { typedef int (*g)[n]; 0;}; { typedef int (*h)[n]; 0;}; ; typedef int (*i)[n]; 0;}; ; typedef int (*j)[n]; a:0; goto a;  }
 void fc288 (int n) { { typedef int (*b)[n]; { typedef int (*c)[n]; 0;} { typedef int (*d)[n]; 0;} ; typedef int (*e)[n]; 0;}; { typedef int (*f)[n]; { typedef int (*g)[n]; 0;}; { typedef int (*h)[n]; 0;}; ; typedef int (*i)[n]; 0;}; ; typedef int (*j)[n]; 0;a: goto a;  }
+
+/* Match extra informative notes.  */
+/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */
+/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */
index e77a142..848dfba 100644 (file)
@@ -303,3 +303,7 @@ void fd285 (int n) { P0A:goto P0A;{ typedef int (*b)[n]; P01A:goto P01A;{ typede
 void fd286 (int n) { P0A:goto P0A;{ typedef int (*b)[n]; P01A:goto P01A;{ typedef int (*c)[n]; P012A:goto P012A;0;} P01B:goto P01B;{ typedef int (*d)[n]; P013A:goto P013A;0;} P01C:goto P01C;; typedef int (*e)[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ typedef int (*f)[n]; P02A:goto P02A;{ typedef int (*g)[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ typedef int (*h)[n]; P025A:goto P025A;0;}; P02C:goto P02C;; typedef int (*i)[n]; P026A:goto P026A;0;}; a:; typedef int (*j)[n]; P03A:goto P03A;0;p03B:goto p03B; goto a; P03B:goto P03B; }
 void fd287 (int n) { P0A:goto P0A;{ typedef int (*b)[n]; P01A:goto P01A;{ typedef int (*c)[n]; P012A:goto P012A;0;} P01B:goto P01B;{ typedef int (*d)[n]; P013A:goto P013A;0;} P01C:goto P01C;; typedef int (*e)[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ typedef int (*f)[n]; P02A:goto P02A;{ typedef int (*g)[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ typedef int (*h)[n]; P025A:goto P025A;0;}; P02C:goto P02C;; typedef int (*i)[n]; P026A:goto P026A;0;}; P0C:goto P0C;; typedef int (*j)[n]; a:0;p03B:goto p03B; goto a; P03B:goto P03B; }
 void fd288 (int n) { P0A:goto P0A;{ typedef int (*b)[n]; P01A:goto P01A;{ typedef int (*c)[n]; P012A:goto P012A;0;} P01B:goto P01B;{ typedef int (*d)[n]; P013A:goto P013A;0;} P01C:goto P01C;; typedef int (*e)[n]; P014A:goto P014A;0;}; P0B:goto P0B;{ typedef int (*f)[n]; P02A:goto P02A;{ typedef int (*g)[n]; P024A:goto P024A;0;}; P02B:goto P02B;{ typedef int (*h)[n]; P025A:goto P025A;0;}; P02C:goto P02C;; typedef int (*i)[n]; P026A:goto P026A;0;}; P0C:goto P0C;; typedef int (*j)[n]; P03A:goto P03A;0;a: goto a; P03B:goto P03B; }
+
+/* Match extra informative notes.  */
+/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */
+/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */
index ca3f85f..683bcf2 100644 (file)
@@ -16,8 +16,8 @@ f (int a, int b)
 {
   switch (a) {
     int v[b];
-  case 2: /* { dg-error "case label in scope of identifier with variably modified type not containing enclosing switch statement" } */
-  default: /* { dg-error "'default' label in scope of identifier with variably modified type not containing enclosing switch statement" } */
+  case 2: /* { dg-error "switch jumps into scope of identifier with variably modified type" } */
+  default: /* { dg-error "switch jumps into scope of identifier with variably modified type" } */
   switch (a)
     {
     case 4:
@@ -28,3 +28,7 @@ f (int a, int b)
     }
   }
 }
+
+/* Match extra informative notes.  */
+/* { dg-message "note: switch starts here" "note: expected" { target *-*-* } 0 } */
+/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */
index 57ab34e..a9dd466 100644 (file)
@@ -402,3 +402,6 @@ void f194 (void) { ({ ({0;}); ({0;}); 0;}); ({ ({0;}); ({0;}); 0;}); a:0; goto a
 void fa194 (void) { P0A:goto P0A;({ P01A:goto P01A;({P012A:goto P012A;0;}); P01B:goto P01B;({P013A:goto P013A;0;}); P01C:goto P01C;0;}); P0B:goto P0B;({ P02A:goto P02A;({P024A:goto P024A;0;}); P02B:goto P02B;({P025A:goto P025A;0;}); P02C:goto P02C;0;}); a:0;p0D:goto p0D; goto a; P0D:goto P0D; }
 void f195 (void) { ({ ({0;}); ({0;}); 0;}); ({ ({0;}); ({0;}); 0;}); 0;a: goto a;  }
 void fa195 (void) { P0A:goto P0A;({ P01A:goto P01A;({P012A:goto P012A;0;}); P01B:goto P01B;({P013A:goto P013A;0;}); P01C:goto P01C;0;}); P0B:goto P0B;({ P02A:goto P02A;({P024A:goto P024A;0;}); P02B:goto P02B;({P025A:goto P025A;0;}); P02C:goto P02C;0;}); P0C:goto P0C;0;a: goto a; P0D:goto P0D; }
+
+/* Match extra informative notes.  */
+/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */
index 35b96e8..be7aa52 100644 (file)
@@ -8,13 +8,13 @@
 void
 f (int a)
 {
-  switch (a)
+  switch (a) /* { dg-message "here" } */
     {
     case 0:
     case 1:
       ({
-      case 2: /* { dg-error "case label in statement expression not containing enclosing switch statement" } */
-      default: /* { dg-error "'default' label in statement expression not containing enclosing switch statement" } */
+      case 2: /* { dg-error "switch jumps into statement expression" } */
+      default: /* { dg-error "switch jumps into statement expression" } */
        switch (a)
          {
          case 3:
index 7b1515f..0a67222 100644 (file)
@@ -6,3 +6,6 @@
 /* { dg-options "-O2" } */
 
 void f(void) { 1 ? 1 : ({ a : 1; 1; }); goto a; } /* { dg-error "jump into statement expression" } */
+
+/* Match extra informative notes.  */
+/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */
index 1d31876..6e14a06 100644 (file)
@@ -23,8 +23,12 @@ void foo1(int n) {
 }
 
 void foo2(int n) {
-  goto A;
+  goto A;      /* { dg-error "jump into scope of identifier with variably modified type" } */
   int (*(*bar2)(void))[n];
- A:    /* { dg-error "jump into scope of identifier with variably modified type" } */
+ A:
   ;
 }
+
+/* Match extra informative notes.  */
+/* { dg-message "note: label '\[^\n'\]*' defined here" "note: expected" { target *-*-* } 0 } */
+/* { dg-message "note: '\[^\n'\]*' declared here" "note: expected" { target *-*-* } 0 } */