OSDN Git Service

Fix goto checking.
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 26 May 2000 21:05:05 +0000 (21:05 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 26 May 2000 21:05:05 +0000 (21:05 +0000)
        * cp-tree.h (struct language_function): x_named_labels is now
        a struct named_label_list*.
        * decl.c (struct named_label_use_list): Renamed from...
        (struct named_label_list): ...this.  New struct.
        (push_binding_level): Don't set eh_region.
        (note_level_for_eh): New fn.
        (pop_label): Take label and old value directly.
        (pop_labels): Adjust for new named_labels format.
        (lookup_label): Likewise.
        (poplevel): Note characteristics of a binding level containing a
        named label.  Mess with named label lists earlier.
        (mark_named_label_lists): New fn.
        (mark_lang_function): Call it.
        (use_label): New fn, split out from...
        (make_label_decl): ...here.  Don't call it.
        (decl_jump_unsafe, check_previous_goto, check_previous_goto_1,
        check_previous_gotos): New fns, split out from...
        (define_label): ...here.
        (check_switch_goto): New fn.
        (define_case_label): Call it.
        (check_goto): New fn.
        * semantics.c (finish_goto_stmt): Call it and use_label.
        (begin_compound_stmt): If we're a try block, call note_level_for_eh.
        (expand_stmt): Never pass 1 as DONT_JUMP_IN to expand_end_bindings.

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

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/semantics.c

index 656ce2a..0b087f8 100644 (file)
@@ -1,3 +1,31 @@
+2000-05-26  Jason Merrill  <jason@casey.soma.redhat.com>
+
+       Fix goto checking.
+       * cp-tree.h (struct language_function): x_named_labels is now
+       a struct named_label_list*.
+       * decl.c (struct named_label_use_list): Renamed from...
+       (struct named_label_list): ...this.  New struct.
+       (push_binding_level): Don't set eh_region.
+       (note_level_for_eh): New fn.
+       (pop_label): Take label and old value directly.
+       (pop_labels): Adjust for new named_labels format.
+       (lookup_label): Likewise.
+       (poplevel): Note characteristics of a binding level containing a
+       named label.  Mess with named label lists earlier.
+       (mark_named_label_lists): New fn.
+       (mark_lang_function): Call it.
+       (use_label): New fn, split out from...
+       (make_label_decl): ...here.  Don't call it.
+       (decl_jump_unsafe, check_previous_goto, check_previous_goto_1, 
+       check_previous_gotos): New fns, split out from...
+       (define_label): ...here.
+       (check_switch_goto): New fn.
+       (define_case_label): Call it.
+       (check_goto): New fn.
+       * semantics.c (finish_goto_stmt): Call it and use_label.
+       (begin_compound_stmt): If we're a try block, call note_level_for_eh.
+       (expand_stmt): Never pass 1 as DONT_JUMP_IN to expand_end_bindings.
+
 2000-05-26  Mark Mitchell  <mark@codesourcery.com>
 
        * class.c (build_vtable_entry_ref): Correct usage of
index 4f255a4..810d174 100644 (file)
@@ -841,7 +841,6 @@ extern struct saved_scope *scope_chain;
 
 struct language_function
 {
-  tree x_named_labels;
   tree x_ctor_label;
   tree x_dtor_label;
   tree x_base_init_list;
@@ -867,7 +866,8 @@ struct language_function
 
   struct stmt_tree x_stmt_tree;
 
-  struct named_label_list *x_named_label_uses;
+  struct named_label_use_list *x_named_label_uses;
+  struct named_label_list *x_named_labels;
   struct binding_level *bindings;
 
   const char *cannot_inline;
@@ -3892,6 +3892,7 @@ extern void set_class_shadows                     PARAMS ((tree));
 extern void begin_scope                         PARAMS ((scope_kind));
 extern void finish_scope                        PARAMS ((void));
 extern void note_level_for_for                 PARAMS ((void));
+extern void note_level_for_eh                  PARAMS ((void));
 extern void resume_level                       PARAMS ((struct binding_level *));
 extern void delete_block                       PARAMS ((tree));
 extern void insert_block                       PARAMS ((tree));
@@ -3930,6 +3931,7 @@ extern tree implicitly_declare                    PARAMS ((tree));
 extern tree lookup_label                       PARAMS ((tree));
 extern tree declare_local_label                 PARAMS ((tree));
 extern tree define_label                       PARAMS ((const char *, int, tree));
+extern void check_goto                         PARAMS ((tree));
 extern void push_switch                                PARAMS ((void));
 extern void pop_switch                         PARAMS ((void));
 extern void define_case_label                  PARAMS ((void));
index dc95473..eecf36d 100644 (file)
@@ -105,6 +105,7 @@ static void resume_binding_level PARAMS ((struct binding_level *));
 static struct binding_level *make_binding_level PARAMS ((void));
 static void declare_namespace_level PARAMS ((void));
 static void signal_catch PARAMS ((int)) ATTRIBUTE_NORETURN;
+static int decl_jump_unsafe PARAMS ((tree));
 static void storedecls PARAMS ((tree));
 static void require_complete_types_for_parms PARAMS ((tree));
 static int ambi_op_p PARAMS ((tree));
@@ -151,7 +152,13 @@ static int walk_namespaces_r PARAMS ((tree, walk_namespaces_fn, void *));
 static int walk_globals_r PARAMS ((tree, void *));
 static void add_decl_to_level PARAMS ((tree, struct binding_level *));
 static tree make_label_decl PARAMS ((tree, int));
-static void pop_label PARAMS ((tree));
+static void use_label PARAMS ((tree));
+static void check_previous_goto_1 PARAMS ((tree, struct binding_level *, tree,
+                                          const char *, int));
+static void check_previous_goto PARAMS ((struct named_label_use_list *));
+static void check_switch_goto PARAMS ((struct binding_level *));
+static void check_previous_gotos PARAMS ((tree));
+static void pop_label PARAMS ((tree, tree));
 static void pop_labels PARAMS ((tree));
 static void maybe_deduce_size_from_array_init PARAMS ((tree, tree));
 static void layout_var_decl PARAMS ((tree));
@@ -268,19 +275,19 @@ static int only_namespace_names;
 
 #define original_result_rtx cp_function_chain->x_result_rtx
 
-struct named_label_list
+/* Used only for jumps to as-yet undefined labels, since jumps to
+   defined labels can have their validity checked immediately.  */
+
+struct named_label_use_list
 {
   struct binding_level *binding_level;
   tree names_in_scope;
   tree label_decl;
   const char *filename_o_goto;
   int lineno_o_goto;
-  struct named_label_list *next;
+  struct named_label_use_list *next;
 };
 
-/* Used only for jumps to as-yet undefined labels, since jumps to
-   defined labels can have their validity checked by stmt.c.  */
-
 #define named_label_uses cp_function_chain->x_named_label_uses
 
 /* A list of objects which have constructors or destructors
@@ -304,10 +311,20 @@ static tree last_function_parm_tags;
 tree last_function_parms;
 static tree current_function_parm_tags;
 
-/* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function
-   that have names.  Here so we can clear out their names' definitions
-   at the end of the function.  The TREE_VALUE is a LABEL_DECL; the
-   TREE_PURPOSE is the previous binding of the label.  */
+/* A list of all LABEL_DECLs in the function that have names.  Here so
+   we can clear out their names' definitions at the end of the
+   function, and so we can check the validity of jumps to these labels.  */
+
+struct named_label_list
+{
+  struct binding_level *binding_level;
+  tree names_in_scope;
+  tree old_value;
+  tree label_decl;
+  tree bad_decls;
+  int eh_region;
+  struct named_label_list *next;
+};
 
 #define named_labels cp_function_chain->x_named_labels
 
@@ -481,7 +498,9 @@ struct binding_level
        worry about ambiguous (ARM or ISO) scope rules.  */
     unsigned is_for_scope : 1;
 
-    /* True if this level corresponds to an EH region, as for a try block.  */
+    /* True if this level corresponds to an EH region, as for a try block.
+       Currently this information is only available while building the
+       tree structure.  */
     unsigned eh_region : 1;
 
     /* Four bits left for this word.  */
@@ -548,11 +567,6 @@ push_binding_level (newlevel, tag_transparent, keep)
   newlevel->tag_transparent = tag_transparent;
   newlevel->more_cleanups_ok = 1;
 
-  /* We are called before expand_start_bindings, but after
-     expand_eh_region_start for a try block; so we check this now,
-     before the EH block is covered up.  */
-  newlevel->eh_region = is_eh_region ();
-
   newlevel->keep = keep;
 #if defined(DEBUG_CP_BINDING_LEVELS)
   newlevel->binding_depth = binding_depth;
@@ -927,6 +941,14 @@ note_level_for_for ()
   current_binding_level->is_for_scope = 1;
 }
 
+/* Record that the current binding level represents a try block.  */
+
+void
+note_level_for_eh ()
+{
+  current_binding_level->eh_region = 1;
+}
+
 /* For a binding between a name and an entity at a block scope,
    this is the `struct binding_level' for the block.  */
 #define BINDING_LEVEL(NODE) \
@@ -1180,11 +1202,10 @@ pop_binding (id, decl)
    in a valid manner, and issue any appropriate warnings or errors.  */
 
 static void
-pop_label (link)
-     tree link;
+pop_label (label, old_value)
+     tree label;
+     tree old_value;
 {
-  tree label = TREE_VALUE (link);
-
   if (!processing_template_decl && doing_semantic_analysis_p ())
     {
       if (DECL_INITIAL (label) == NULL_TREE)
@@ -1197,7 +1218,7 @@ pop_label (link)
        cp_warning_at ("label `%D' defined but not used", label);
     }
 
-  SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), TREE_PURPOSE (link));
+  SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), old_value);
 }
 
 /* At the end of a function, all labels declared within the fucntion
@@ -1208,20 +1229,20 @@ static void
 pop_labels (block)
      tree block;
 {
-  tree link;
+  struct named_label_list *link;
 
   /* Clear out the definitions of all label names, since their scopes
      end here.  */
-  for (link = named_labels; link; link = TREE_CHAIN (link))
+  for (link = named_labels; link; link = link->next)
     {
-      pop_label (link);
+      pop_label (link->label_decl, link->old_value);
       /* Put the labels into the "variables" of the top-level block,
         so debugger can see them.  */
-      TREE_CHAIN (TREE_VALUE (link)) = BLOCK_VARS (block);
-      BLOCK_VARS (block) = TREE_VALUE (link);
+      TREE_CHAIN (link->label_decl) = BLOCK_VARS (block);
+      BLOCK_VARS (block) = link->label_decl;
     }
 
-  named_labels = NULL_TREE;
+  named_labels = NULL;
 }
 
 /* Exit a binding level.
@@ -1285,6 +1306,40 @@ poplevel (keep, reverse, functionbody)
   if (current_binding_level->keep == 1)
     keep = 1;
 
+  /* Any uses of undefined labels, and any defined labels, now operate
+     under constraints of next binding contour.  */
+  if (cfun && !functionbody)
+    {
+      struct binding_level *level_chain;
+      level_chain = current_binding_level->level_chain;
+      if (level_chain)
+       {
+         struct named_label_use_list *uses;
+         struct named_label_list *labels;
+         for (labels = named_labels; labels; labels = labels->next)
+           if (labels->binding_level == current_binding_level)
+             {
+               tree decl;
+               if (current_binding_level->eh_region)
+                 labels->eh_region = 1;
+               for (decl = labels->names_in_scope; decl;
+                    decl = TREE_CHAIN (decl))
+                 if (decl_jump_unsafe (decl))
+                   labels->bad_decls = tree_cons (NULL_TREE, decl,
+                                                  labels->bad_decls);
+               labels->binding_level = level_chain;
+               labels->names_in_scope = level_chain->names;
+             }
+
+         for (uses = named_label_uses; uses; uses = uses->next)
+           if (uses->binding_level == current_binding_level)
+             {
+               uses->binding_level = level_chain;
+               uses->names_in_scope = level_chain->names;
+             }
+       }
+    }
+
   /* Get the decls in the order they were written.
      Usually current_binding_level->names is in reverse order.
      But parameter decls were previously put in forward order.  */
@@ -1468,7 +1523,7 @@ poplevel (keep, reverse, functionbody)
   for (link = current_binding_level->shadowed_labels;
        link;
        link = TREE_CHAIN (link))
-    pop_label (link);
+    pop_label (TREE_VALUE (link), TREE_PURPOSE (link));
 
   /* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs
      list if a `using' declaration put them there.  The debugging
@@ -1500,24 +1555,6 @@ poplevel (keep, reverse, functionbody)
       pop_labels (block);
     }
 
-  /* Any uses of undefined labels now operate under constraints
-     of next binding contour.  */
-  if (cfun)
-    {
-      struct binding_level *level_chain;
-      level_chain = current_binding_level->level_chain;
-      if (level_chain)
-       {
-         struct named_label_list *labels;
-         for (labels = named_label_uses; labels; labels = labels->next)
-           if (labels->binding_level == current_binding_level)
-             {
-               labels->binding_level = level_chain;
-               labels->names_in_scope = level_chain->names;
-             }
-       }
-    }
-
   tmp = current_binding_level->keep;
 
   pop_binding_level ();
@@ -1951,7 +1988,7 @@ mark_binding_level (arg)
 {
   struct binding_level *lvl = *(struct binding_level **)arg;
 
-  while (lvl)
+  for (; lvl; lvl = lvl->level_chain)
     {
       ggc_mark_tree (lvl->names);
       ggc_mark_tree (lvl->tags);
@@ -1965,9 +2002,28 @@ mark_binding_level (arg)
       ggc_mark_tree (lvl->this_class);
       ggc_mark_tree (lvl->incomplete);
       ggc_mark_tree (lvl->dead_vars_from_for);
+    }
+}
+
+static void
+mark_named_label_lists (labs, uses)
+     void *labs;
+     void *uses;
+{
+  struct named_label_list *l = *(struct named_label_list **)labs;
+  struct named_label_use_list *u = *(struct named_label_use_list **)uses;
 
-      lvl = lvl->level_chain;
+  for (; l; l = l->next)
+    {
+      ggc_mark (l);
+      mark_binding_level (l->binding_level);
+      ggc_mark_tree (l->old_value);
+      ggc_mark_tree (l->label_decl);
+      ggc_mark_tree (l->bad_decls);
     }
+
+  for (; u; u = u->next)
+    ggc_mark (u);
 }
 \f
 /* For debugging.  */
@@ -4708,17 +4764,25 @@ make_label_decl (id, local_p)
   /* Record the fact that this identifier is bound to this label.  */
   SET_IDENTIFIER_LABEL_VALUE (id, decl);
 
-  /* Record this label on the list of used labels so that we can check
-     at the end of the function to see whether or not the label was
-     actually defined.  */
-  if ((named_label_uses == NULL || named_label_uses->label_decl != decl)
-      && (named_label_uses == NULL
-         || named_label_uses->names_in_scope != current_binding_level->names
-         || named_label_uses->label_decl != decl))
-    {
-      struct named_label_list *new_ent;
-      new_ent
-       = (struct named_label_list*)oballoc (sizeof (struct named_label_list));
+  return decl;
+}
+
+/* Record this label on the list of used labels so that we can check
+   at the end of the function to see whether or not the label was
+   actually defined, and so we can check when the label is defined whether
+   this use is valid.  */
+
+static void
+use_label (decl)
+     tree decl;
+{
+  if (named_label_uses == NULL
+      || named_label_uses->names_in_scope != current_binding_level->names
+      || named_label_uses->label_decl != decl)
+    {
+      struct named_label_use_list *new_ent;
+      new_ent = ((struct named_label_use_list *)
+                ggc_alloc (sizeof (struct named_label_use_list)));
       new_ent->label_decl = decl;
       new_ent->names_in_scope = current_binding_level->names;
       new_ent->binding_level = current_binding_level;
@@ -4727,8 +4791,6 @@ make_label_decl (id, local_p)
       new_ent->next = named_label_uses;
       named_label_uses = new_ent;
     }
-
-  return decl;
 }
 
 /* Look for a label named ID in the current function.  If one cannot
@@ -4740,6 +4802,7 @@ lookup_label (id)
      tree id;
 {
   tree decl;
+  struct named_label_list *ent;
 
   /* You can't use labels at global scope.  */
   if (current_function_decl == NULL_TREE)
@@ -4757,12 +4820,17 @@ lookup_label (id)
   /* Record this label on the list of labels used in this function.
      We do this before calling make_label_decl so that we get the
      IDENTIFIER_LABEL_VALUE before the new label is declared.  */
-  named_labels = tree_cons (IDENTIFIER_LABEL_VALUE (id), NULL_TREE,
-                           named_labels);
+  ent = ((struct named_label_list *)
+        ggc_alloc_obj (sizeof (struct named_label_list), 1));
+  ent->old_value = IDENTIFIER_LABEL_VALUE (id);
+  ent->next = named_labels;
+  named_labels = ent;
+
   /* We need a new label.  */
   decl = make_label_decl (id, /*local_p=*/0);
+
   /* Now fill in the information we didn't have before.  */
-  TREE_VALUE (named_labels) = decl;
+  ent->label_decl = decl;
 
   return decl;
 }
@@ -4789,6 +4857,193 @@ declare_local_label (id)
   return decl;
 }
 
+/* Returns nonzero if it is ill-formed to jump past the declaration of
+   DECL.  Returns 2 if it's also a real problem.  */
+
+static int
+decl_jump_unsafe (decl)
+     tree decl;
+{
+  if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl))
+    return 0;
+
+  if (DECL_INITIAL (decl) == NULL_TREE
+      && pod_type_p (TREE_TYPE (decl)))
+    return 0;
+
+  /* This is really only important if we're crossing an initialization.
+     The POD stuff is just pedantry; why should it matter if the class
+     contains a field of pointer to member type?  */
+  if (DECL_INITIAL (decl)
+      || (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))))
+    return 2;
+  return 1;
+}
+
+/* Check that a single previously seen jump to a newly defined label
+   is OK.  DECL is the LABEL_DECL or 0; LEVEL is the binding_level for
+   the jump context; NAMES are the names in scope in LEVEL at the jump
+   context; FILE and LINE are the source position of the jump or 0.  */
+
+static void
+check_previous_goto_1 (decl, level, names, file, line)
+     tree decl;
+     struct binding_level *level;
+     tree names;
+     const char *file;
+     int line;
+{
+  int identified = 0;
+  int saw_eh = 0;
+  struct binding_level *b = current_binding_level;
+  for (; b; b = b->level_chain)
+    {
+      tree new_decls = b->names;
+      tree old_decls = (b == level ? names : NULL_TREE);
+      for (; new_decls != old_decls;
+          new_decls = TREE_CHAIN (new_decls))
+       {
+         int problem = decl_jump_unsafe (new_decls);
+         if (! problem)
+           continue;
+
+         if (! identified)
+           {
+             if (decl)
+               cp_pedwarn ("jump to label `%D'", decl);
+             else
+               pedwarn ("jump to case label");
+
+             if (file)
+               pedwarn_with_file_and_line (file, line, "  from here");
+             identified = 1;
+           }
+
+         if (problem > 1 && DECL_ARTIFICIAL (new_decls))
+           /* Can't skip init of __exception_info.  */
+           cp_error_at ("  enters catch block", new_decls);
+         else if (problem > 1)
+           cp_error_at ("  crosses initialization of `%#D'",
+                        new_decls);
+         else
+           cp_pedwarn_at ("  enters scope of non-POD `%#D'",
+                          new_decls);
+       }
+
+      if (b == level)
+       break;
+      if (b->eh_region && ! saw_eh)
+       {
+         if (! identified)
+           {
+             if (decl)
+               cp_pedwarn ("jump to label `%D'", decl);
+             else
+               pedwarn ("jump to case label");
+
+             if (file)
+               pedwarn_with_file_and_line (file, line, "  from here");
+             identified = 1;
+           }
+         error ("  enters try block");
+         saw_eh = 1;
+       }
+    }
+}
+
+static void
+check_previous_goto (use)
+     struct named_label_use_list *use;
+{
+  check_previous_goto_1 (use->label_decl, use->binding_level,
+                        use->names_in_scope, use->filename_o_goto,
+                        use->lineno_o_goto);
+}
+
+static void
+check_switch_goto (level)
+     struct binding_level *level;
+{
+  check_previous_goto_1 (NULL_TREE, level, level->names, NULL, 0);
+}
+
+/* Check that any previously seen jumps to a newly defined label DECL
+   are OK.  Called by define_label.  */
+
+static void
+check_previous_gotos (decl)
+     tree decl;
+{
+  struct named_label_use_list **usep;
+
+  if (! TREE_USED (decl))
+    return;
+
+  for (usep = &named_label_uses; *usep; )
+    {
+      struct named_label_use_list *use = *usep;
+      if (use->label_decl == decl)
+       {
+         check_previous_goto (use);
+         *usep = use->next;
+       }
+      else
+       usep = &(use->next);
+    }
+}
+
+/* Check that a new jump to a label DECL is OK.  Called by
+   finish_goto_stmt.  */
+
+void
+check_goto (decl)
+     tree decl;
+{
+  int identified = 0;
+  tree bad;
+  struct named_label_list *lab;
+
+  /* If the label hasn't been defined yet, defer checking.  */
+  if (! DECL_INITIAL (decl))
+    {
+      use_label (decl);
+      return;
+    }
+
+  for (lab = named_labels; lab; lab = lab->next)
+    if (decl == lab->label_decl)
+      break;
+
+  /* If the label is not on named_labels it's a gcc local label, so
+     it must be in an outer scope, so jumping to it is always OK.  */
+  if (lab == 0)
+    return;
+
+  if ((lab->eh_region || lab->bad_decls) && !identified)
+    {
+      cp_pedwarn_at ("jump to label `%D'", decl);
+      pedwarn ("  from here");
+      identified = 1;
+    }
+
+  for (bad = lab->bad_decls; bad; bad = TREE_CHAIN (bad))
+    {
+      tree b = TREE_VALUE (bad);
+      int u = decl_jump_unsafe (b);
+
+      if (u > 1 && DECL_ARTIFICIAL (b))
+       /* Can't skip init of __exception_info.  */
+       cp_error_at ("  enters catch block", b);
+      else if (u > 1)
+       cp_error_at ("  skips initialization of `%#D'", b);
+      else
+       cp_pedwarn_at ("  enters scope of non-POD `%#D'", b);
+    }
+
+  if (lab->eh_region)
+    error ("  enters try block");
+}
+
 /* 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.  */
@@ -4800,6 +5055,11 @@ define_label (filename, line, name)
      tree name;
 {
   tree decl = lookup_label (name);
+  struct named_label_list *ent;
+
+  for (ent = named_labels; ent; ent = ent->next)
+    if (ent->label_decl == decl)
+      break;
 
   /* After labels, make any new cleanups go into their
      own new (temporary) binding contour.  */
@@ -4815,104 +5075,17 @@ define_label (filename, line, name)
     }
   else
     {
-      struct named_label_list *uses, *prev;
-      int identified = 0;
-      int saw_eh = 0;
-
       /* Mark label as having been defined.  */
       DECL_INITIAL (decl) = error_mark_node;
       /* Say where in the source.  */
       DECL_SOURCE_FILE (decl) = filename;
       DECL_SOURCE_LINE (decl) = line;
-
-      prev = NULL;
-      uses = named_label_uses;
-      while (uses != NULL)
-       if (uses->label_decl == decl)
-         {
-           struct binding_level *b = current_binding_level;
-           while (b)
-             {
-               tree new_decls = b->names;
-               tree old_decls = (b == uses->binding_level)
-                                 ? uses->names_in_scope : NULL_TREE;
-               while (new_decls != old_decls)
-                 {
-                   if (TREE_CODE (new_decls) == VAR_DECL
-                       /* Don't complain about crossing initialization
-                          of internal entities.  They can't be accessed,
-                          and they should be cleaned up
-                          by the time we get to the label.  */
-                       && ! DECL_ARTIFICIAL (new_decls)
-                       && !(DECL_INITIAL (new_decls) == NULL_TREE
-                            && pod_type_p (TREE_TYPE (new_decls))))
-                     {
-                       /* This is really only important if we're crossing
-                          an initialization.  The POD stuff is just
-                          pedantry; why should it matter if the class
-                          contains a field of pointer to member type?  */
-                       int problem = (DECL_INITIAL (new_decls)
-                                      || (TYPE_NEEDS_CONSTRUCTING
-                                          (TREE_TYPE (new_decls))));
-
-                       if (! identified)
-                         {
-                           if (problem)
-                             {
-                               cp_error ("jump to label `%D'", decl);
-                               error_with_file_and_line
-                                 (uses->filename_o_goto,
-                                  uses->lineno_o_goto, "  from here");
-                             }
-                           else
-                             {
-                               cp_pedwarn ("jump to label `%D'", decl);
-                               pedwarn_with_file_and_line
-                                 (uses->filename_o_goto,
-                                  uses->lineno_o_goto, "  from here");
-                             }
-                           identified = 1;
-                         }
-
-                       if (problem)
-                         cp_error_at ("  crosses initialization of `%#D'",
-                                      new_decls);
-                       else
-                         cp_pedwarn_at ("  enters scope of non-POD `%#D'",
-                                        new_decls);
-                     }
-                   new_decls = TREE_CHAIN (new_decls);
-                 }
-               if (b == uses->binding_level)
-                 break;
-               if (b->eh_region && ! saw_eh)
-                 {
-                   if (! identified)
-                     {
-                       cp_error ("jump to label `%D'", decl);
-                       error_with_file_and_line
-                         (uses->filename_o_goto,
-                          uses->lineno_o_goto, "  from here");
-                       identified = 1;
-                     }
-                   error ("  enters exception handling block");
-                   saw_eh = 1;
-                 }
-               b = b->level_chain;
-             }
-
-           if (prev != NULL)
-             prev->next = uses->next;
-           else
-             named_label_uses = uses->next;
-
-           uses = uses->next;
-         }
-       else
-         {
-           prev = uses;
-           uses = uses->next;
-         }
+      if (ent)
+       {
+         ent->names_in_scope = current_binding_level->names;
+         ent->binding_level = current_binding_level;
+       }
+      check_previous_gotos (decl);
       current_function_return_value = NULL_TREE;
       return decl;
     }
@@ -4953,8 +5126,6 @@ void
 define_case_label ()
 {
   tree cleanup = last_cleanup_this_contour ();
-  struct binding_level *b = current_binding_level;
-  int identified = 0;
 
   if (! switch_stack)
     /* Don't crash; we'll complain in do_case.  */
@@ -4973,29 +5144,7 @@ define_case_label ()
        }
     }
 
-  for (; b && b != switch_stack->level; b = b->level_chain)
-    {
-      tree new_decls = b->names;
-      for (; new_decls; new_decls = TREE_CHAIN (new_decls))
-       {
-         if (TREE_CODE (new_decls) == VAR_DECL
-             /* Don't complain about crossing initialization
-                of internal entities.  They can't be accessed,
-                and they should be cleaned up
-                by the time we get to the label.  */
-             && ! DECL_ARTIFICIAL (new_decls)
-             && ((DECL_INITIAL (new_decls) != NULL_TREE
-                  && DECL_INITIAL (new_decls) != error_mark_node)
-                 || TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (new_decls))))
-           {
-             if (! identified)
-               error ("jump to case label");
-             identified = 1;
-             cp_error_at ("  crosses initialization of `%#D'",
-                          new_decls);
-           }
-       }
-    }
+  check_switch_goto (switch_stack->level);
 
   /* After labels, make any new cleanups go into their
      own new (temporary) binding contour.  */
@@ -14660,7 +14809,6 @@ mark_lang_function (p)
   if (!p)
     return;
 
-  ggc_mark_tree (p->x_named_labels);
   ggc_mark_tree (p->x_ctor_label);
   ggc_mark_tree (p->x_dtor_label);
   ggc_mark_tree (p->x_base_init_list);
@@ -14672,6 +14820,7 @@ mark_lang_function (p)
 
   ggc_mark_rtx (p->x_result_rtx);
 
+  mark_named_label_lists (&p->x_named_labels, &p->x_named_label_uses);
   mark_stmt_tree (&p->x_stmt_tree);
   mark_binding_level (&p->bindings);
 }
index 77728ba..505c487 100644 (file)
@@ -703,6 +703,8 @@ finish_goto_stmt (destination)
           addresses, or some such.  */
        DECL_UNINLINABLE (current_function_decl) = 1;
 
+      check_goto (destination);
+
       add_tree (build_min_nt (GOTO_STMT, destination));
     }
   else
@@ -965,10 +967,15 @@ begin_compound_stmt (has_no_scope)
      int has_no_scope;
 {
   tree r; 
+  int is_try = 0;
 
   if (building_stmt_tree ())
     {
       r = build_min_nt (COMPOUND_STMT, NULL_TREE);
+      /* Mark that this block is for a try so that we can yell at
+         people trying to jump in.  */
+      if (last_tree && TREE_CODE (last_tree) == TRY_BLOCK)
+       is_try = 1;
       add_tree (r);
       if (has_no_scope)
        COMPOUND_STMT_NO_SCOPE (r) = 1;
@@ -979,7 +986,11 @@ begin_compound_stmt (has_no_scope)
   last_expr_type = NULL_TREE;
 
   if (!has_no_scope)
-    do_pushlevel ();
+    {
+      do_pushlevel ();
+      if (is_try)
+       note_level_for_eh ();
+    }
   else
     /* Normally, we try hard to keep the BLOCK for a
        statement-expression.  But, if it's a statement-expression with
@@ -2581,8 +2592,7 @@ expand_stmt (t)
                expand_start_bindings_and_block (2 * SCOPE_NULLIFIED_P (t),
                                                 SCOPE_STMT_BLOCK (t));
              else if (SCOPE_END_P (t))
-               expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 
-                                    SCOPE_PARTIAL_P (t));
+               expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0);
            }
          else if (!SCOPE_NULLIFIED_P (t))
            {