This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

(C++) patch to fix goto checking


I started out adding code to define_label to notice jumps into catch
blocks, and it got a bit out of hand...fixes g++.other/goto3.C.

Along with that and some factorization, we now check jumps to
previously defined labels in the frontend rather than the backend; the
old code was checking the wrong thing (jumping after a variable with a
cleanup, which is not what we care about), and language semantics
should be checked in the frontend anyway.

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.

Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.462
diff -c -p -r1.462 cp-tree.h
*** cp-tree.h	2000/05/26 08:50:46	1.462
--- cp-tree.h	2000/05/26 20:50:45
*************** extern struct saved_scope *scope_chain;
*** 841,847 ****
  
  struct language_function
  {
-   tree x_named_labels;
    tree x_ctor_label;
    tree x_dtor_label;
    tree x_base_init_list;
--- 841,846 ----
*************** struct language_function
*** 867,873 ****
  
    struct stmt_tree x_stmt_tree;
  
!   struct named_label_list *x_named_label_uses;
    struct binding_level *bindings;
  
    const char *cannot_inline;
--- 866,873 ----
  
    struct stmt_tree x_stmt_tree;
  
!   struct named_label_use_list *x_named_label_uses;
!   struct named_label_list *x_named_labels;
    struct binding_level *bindings;
  
    const char *cannot_inline;
*************** extern void set_class_shadows			PARAMS (
*** 3892,3897 ****
--- 3892,3898 ----
  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));
*************** extern tree implicitly_declare			PARAMS 
*** 3930,3935 ****
--- 3931,3937 ----
  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: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.613
diff -c -p -r1.613 decl.c
*** decl.c	2000/05/26 08:50:46	1.613
--- decl.c	2000/05/26 20:50:55
*************** static void resume_binding_level PARAMS 
*** 105,110 ****
--- 105,111 ----
  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));
*************** static int walk_namespaces_r PARAMS ((tr
*** 151,157 ****
  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 pop_labels PARAMS ((tree));
  static void maybe_deduce_size_from_array_init PARAMS ((tree, tree));
  static void layout_var_decl PARAMS ((tree));
--- 152,164 ----
  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 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));
*************** static int only_namespace_names;
*** 268,286 ****
  
  #define original_result_rtx cp_function_chain->x_result_rtx
  
! struct named_label_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;
  };
  
- /* 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
--- 275,293 ----
  
  #define original_result_rtx cp_function_chain->x_result_rtx
  
! /* 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_use_list *next;
  };
  
  #define named_label_uses cp_function_chain->x_named_label_uses
  
  /* A list of objects which have constructors or destructors
*************** static tree last_function_parm_tags;
*** 303,313 ****
  /* Similar, for 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.  */
  
  #define named_labels cp_function_chain->x_named_labels
  
--- 310,330 ----
  /* Similar, for last_function_parm_tags.  */
  tree last_function_parms;
  static tree current_function_parm_tags;
+ 
+ /* 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
  
*************** struct binding_level
*** 481,487 ****
         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.  */
      unsigned eh_region : 1;
  
      /* Four bits left for this word.  */
--- 498,506 ----
         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.
!        Currently this information is only available while building the
!        tree structure.  */
      unsigned eh_region : 1;
  
      /* Four bits left for this word.  */
*************** push_binding_level (newlevel, tag_transp
*** 548,558 ****
    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;
--- 567,572 ----
*************** note_level_for_for ()
*** 927,932 ****
--- 941,954 ----
    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) \
*************** pop_binding (id, decl)
*** 1180,1190 ****
     in a valid manner, and issue any appropriate warnings or errors.  */
  
  static void
! pop_label (link)
!      tree link;
  {
-   tree label = TREE_VALUE (link);
- 
    if (!processing_template_decl && doing_semantic_analysis_p ())
      {
        if (DECL_INITIAL (label) == NULL_TREE)
--- 1202,1211 ----
     in a valid manner, and issue any appropriate warnings or errors.  */
  
  static void
! pop_label (label, old_value)
!      tree label;
!      tree old_value;
  {
    if (!processing_template_decl && doing_semantic_analysis_p ())
      {
        if (DECL_INITIAL (label) == NULL_TREE)
*************** pop_label (link)
*** 1197,1203 ****
  	cp_warning_at ("label `%D' defined but not used", label);
      }
  
!   SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), TREE_PURPOSE (link));
  }
  
  /* At the end of a function, all labels declared within the fucntion
--- 1218,1224 ----
  	cp_warning_at ("label `%D' defined but not used", label);
      }
  
!   SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), old_value);
  }
  
  /* At the end of a function, all labels declared within the fucntion
*************** static void
*** 1208,1227 ****
  pop_labels (block)
       tree block;
  {
!   tree link;
  
    /* Clear out the definitions of all label names, since their scopes
       end here.  */
!   for (link = named_labels; link; link = TREE_CHAIN (link))
      {
!       pop_label (link);
        /* 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);
      }
  
!   named_labels = NULL_TREE;
  }
  
  /* Exit a binding level.
--- 1229,1248 ----
  pop_labels (block)
       tree block;
  {
!   struct named_label_list *link;
  
    /* Clear out the definitions of all label names, since their scopes
       end here.  */
!   for (link = named_labels; link; link = link->next)
      {
!       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 (link->label_decl) = BLOCK_VARS (block);
!       BLOCK_VARS (block) = link->label_decl;
      }
  
!   named_labels = NULL;
  }
  
  /* Exit a binding level.
*************** poplevel (keep, reverse, functionbody)
*** 1285,1290 ****
--- 1306,1345 ----
    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.  */
*************** poplevel (keep, reverse, functionbody)
*** 1468,1474 ****
    for (link = current_binding_level->shadowed_labels;
         link;
         link = TREE_CHAIN (link))
!     pop_label (link);
  
    /* There may be OVERLOADs (wrapped in TREE_LISTs) on the BLOCK_VARs
       list if a `using' declaration put them there.  The debugging
--- 1523,1529 ----
    for (link = current_binding_level->shadowed_labels;
         link;
         link = TREE_CHAIN (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
*************** poplevel (keep, reverse, functionbody)
*** 1500,1523 ****
        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 ();
--- 1555,1560 ----
*************** mark_binding_level (arg)
*** 1951,1957 ****
  {
    struct binding_level *lvl = *(struct binding_level **)arg;
  
!   while (lvl)
      {
        ggc_mark_tree (lvl->names);
        ggc_mark_tree (lvl->tags);
--- 1988,1994 ----
  {
    struct binding_level *lvl = *(struct binding_level **)arg;
  
!   for (; lvl; lvl = lvl->level_chain)
      {
        ggc_mark_tree (lvl->names);
        ggc_mark_tree (lvl->tags);
*************** mark_binding_level (arg)
*** 1965,1973 ****
        ggc_mark_tree (lvl->this_class);
        ggc_mark_tree (lvl->incomplete);
        ggc_mark_tree (lvl->dead_vars_from_for);
  
!       lvl = lvl->level_chain;
      }
  }
  
  /* For debugging.  */
--- 2002,2029 ----
        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;
  
!   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);
  }
  
  /* For debugging.  */
*************** make_label_decl (id, local_p)
*** 4707,4724 ****
  
    /* 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));
        new_ent->label_decl = decl;
        new_ent->names_in_scope = current_binding_level->names;
        new_ent->binding_level = current_binding_level;
--- 4763,4788 ----
  
    /* Record the fact that this identifier is bound to this label.  */
    SET_IDENTIFIER_LABEL_VALUE (id, decl);
+ 
+   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;
*************** make_label_decl (id, local_p)
*** 4727,4734 ****
        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
--- 4791,4796 ----
*************** lookup_label (id)
*** 4740,4745 ****
--- 4802,4808 ----
       tree id;
  {
    tree decl;
+   struct named_label_list *ent;
  
    /* You can't use labels at global scope.  */
    if (current_function_decl == NULL_TREE)
*************** lookup_label (id)
*** 4757,4768 ****
    /* 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);
    /* 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;
  
    return decl;
  }
--- 4820,4836 ----
    /* 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.  */
!   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.  */
!   ent->label_decl = decl;
  
    return decl;
  }
*************** declare_local_label (id)
*** 4789,4794 ****
--- 4857,5049 ----
    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.  */
*************** define_label (filename, line, name)
*** 4800,4806 ****
--- 5055,5066 ----
       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.  */
    current_binding_level->more_cleanups_ok = 0;
*************** define_label (filename, line, name)
*** 4815,4918 ****
      }
    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;
! 	  }
        current_function_return_value = NULL_TREE;
        return decl;
      }
--- 5075,5091 ----
      }
    else
      {
        /* 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;
!       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;
      }
*************** void
*** 4953,4960 ****
  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.  */
--- 5126,5131 ----
*************** define_case_label ()
*** 4973,5001 ****
  	}
      }
  
!   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);
! 	    }
! 	}
!     }
  
    /* After labels, make any new cleanups go into their
       own new (temporary) binding contour.  */
--- 5144,5150 ----
  	}
      }
  
!   check_switch_goto (switch_stack->level);
  
    /* After labels, make any new cleanups go into their
       own new (temporary) binding contour.  */
*************** mark_lang_function (p)
*** 14660,14666 ****
    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);
--- 14809,14814 ----
*************** mark_lang_function (p)
*** 14672,14677 ****
--- 14820,14826 ----
  
    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: semantics.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/semantics.c,v
retrieving revision 1.145
diff -c -p -r1.145 semantics.c
*** semantics.c	2000/05/25 23:27:18	1.145
--- semantics.c	2000/05/26 20:50:56
*************** finish_goto_stmt (destination)
*** 703,708 ****
--- 703,710 ----
  	   addresses, or some such.  */
  	DECL_UNINLINABLE (current_function_decl) = 1;
  
+       check_goto (destination);
+ 
        add_tree (build_min_nt (GOTO_STMT, destination));
      }
    else
*************** begin_compound_stmt (has_no_scope)
*** 965,974 ****
--- 967,981 ----
       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;
*************** begin_compound_stmt (has_no_scope)
*** 979,985 ****
    last_expr_type = NULL_TREE;
  
    if (!has_no_scope)
!     do_pushlevel ();
    else
      /* Normally, we try hard to keep the BLOCK for a
         statement-expression.  But, if it's a statement-expression with
--- 986,996 ----
    last_expr_type = NULL_TREE;
  
    if (!has_no_scope)
!     {
!       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
*************** expand_stmt (t)
*** 2581,2588 ****
  		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));
  	    }
  	  else if (!SCOPE_NULLIFIED_P (t))
  	    {
--- 2592,2598 ----
  		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), 0);
  	    }
  	  else if (!SCOPE_NULLIFIED_P (t))
  	    {


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]