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 for local-declaration processing



This patch continues preparations for ordinary functions in
function-at-a-time mode by separating the semantic analysis required
for processing a local declaration from the process of generating RTL
and initializing it.  It also fixes a regression which I introduced
last week, adds a test case for same, and introduces a couple of
assertions to verify critical assumptions.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

1999-08-29  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.h (TYPE_NEEDS_CONSTRUCTING): Remove #if 0'd definition.
	(maybe_inject_for_scope_var): Declare it.
	(initialize_local_var): Likewise.
	* decl.c (maybe_inject_for_scope_var): Make it global.
	(initialize_local_var): Likewise.  Move cleanup handling here,
	from cp_finish_decl.
	(make_rtl_for_nonlocal_decl): Use
	push_obstacks_nochange/pop_obstacks, rather than
	end_temporary_allocation/resume_temporary_allocation.
	(cp_finish_decl): Try to complete the type of a variable when it
	is declared.  Move cleanup-handling to initialize_local_var.
	(expand_static_init): Use tree-building code, rather than
	RTL-building code.
	* decl2.c (get_temp_name): Assert non-initializedness of
	temporaries.
	* init.c (create_temporary_var): Move RTL-assigning code to ...
	(get_temp_regvar): Here.
	* pt.c (tsbust_expr): Fix indentation.  Call cp_finish_decl here.
	* semantics.c (expand_stmt): Don't call cp_finish_decl here.  Just
	call initialize_local_var to generate initialization code.
	
Index: testsuite/g++.old-deja/g++.pt/crash52.C
===================================================================
RCS file: crash52.C
diff -N crash52.C
*** /dev/null	Sat Dec  5 20:30:03 1998
--- crash52.C	Sun Aug 29 11:51:02 1999
***************
*** 0 ****
--- 1,25 ----
+ // Build don't link:
+ // Origin: Mark Mitchell <mark@codesourcery.com>
+ 
+ template <class T>
+ struct S1
+ {
+   template <class U>
+   struct S2
+   { 
+     S2(U);
+   };
+ 
+   template <class U>
+   void f(U u)
+     {
+       S2<U> s2u(u);
+     }
+ };
+ 
+ void g()
+ {
+   S1<int> s1;
+   s1.f(3.0);
+ }
+ 
Index: cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.275
diff -c -p -r1.275 cp-tree.h
*** cp-tree.h	1999/08/29 01:39:00	1.275
--- cp-tree.h	1999/08/29 18:51:10
*************** extern int flag_new_for_scope;
*** 1690,1702 ****
  /* Nonzero for _TYPE means that the _TYPE defines a destructor.  */
  #define TYPE_HAS_DESTRUCTOR(NODE) (TYPE_LANG_FLAG_2(NODE))
  
- #if 0
- /* Nonzero for _TYPE node means that creating an object of this type
-    will involve a call to a constructor.  This can apply to objects
-    of ARRAY_TYPE if the type of the elements needs a constructor.  */
- #define TYPE_NEEDS_CONSTRUCTING(NODE) ... defined in ../tree.h ...
- #endif
- 
  /* Nonzero means that an object of this type can not be initialized using
     an initializer list.  */
  #define CLASSTYPE_NON_AGGREGATE(NODE) \
--- 1690,1695 ----
*************** extern tree start_decl				PROTO((tree, t
*** 2936,2941 ****
--- 2929,2936 ----
  extern void start_decl_1			PROTO((tree));
  extern void cp_finish_decl			PROTO((tree, tree, tree, int, int));
  extern void finish_decl				PROTO((tree, tree, tree));
+ extern void maybe_inject_for_scope_var          PROTO((tree));
+ extern void initialize_local_var                PROTO((tree, tree, int));
  extern void expand_static_init			PROTO((tree, tree));
  extern int complete_array_type			PROTO((tree, tree, int));
  extern tree build_ptrmemfunc_type		PROTO((tree));
Index: cp/decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.420
diff -c -p -r1.420 decl.c
*** decl.c	1999/08/29 01:39:01	1.420
--- decl.c	1999/08/29 18:51:19
*************** static void pop_labels PROTO((tree));
*** 196,203 ****
  static void maybe_deduce_size_from_array_init PROTO((tree, tree));
  static void layout_var_decl PROTO((tree, tree *));
  static void maybe_commonize_var PROTO((tree));
- static void maybe_inject_for_scope_var PROTO((tree));
- static void initialize_local_var PROTO((tree, tree, tree, int));
  static tree build_cleanup_on_safe_obstack PROTO((tree));
  static void check_initializer PROTO((tree, tree *));
  static void make_rtl_for_nonlocal_decl PROTO((tree, tree, const char *));
--- 196,201 ----
*************** make_rtl_for_nonlocal_decl (decl, init, 
*** 7669,7684 ****
       tree init;
       const char *asmspec;
  {
-   int was_temp;
    int toplev;
    tree type;
  
    type = TREE_TYPE (decl);
    toplev = toplevel_bindings_p ();
!   was_temp = (TREE_STATIC (decl) && TYPE_NEEDS_DESTRUCTOR (type)
! 	      && allocation_temporary_p ());
!   if (was_temp)
!     end_temporary_allocation ();
  
    if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl))
      make_decl_rtl (decl, NULL_PTR, toplev);
--- 7667,7682 ----
       tree init;
       const char *asmspec;
  {
    int toplev;
    tree type;
  
    type = TREE_TYPE (decl);
    toplev = toplevel_bindings_p ();
!   push_obstacks_nochange ();
!   if (TREE_STATIC (decl) 
!       && TYPE_NEEDS_DESTRUCTOR (type)
!       && allocation_temporary_p ())
!     end_temporary_allocation  ();
  
    if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl))
      make_decl_rtl (decl, NULL_PTR, toplev);
*************** make_rtl_for_nonlocal_decl (decl, init, 
*** 7747,7754 ****
    else
      rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
  
!   if (was_temp)
!     resume_temporary_allocation ();
  }
  
  /* The old ARM scoping rules injected variables declared in the
--- 7745,7751 ----
    else
      rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
  
!   pop_obstacks ();
  }
  
  /* The old ARM scoping rules injected variables declared in the
*************** make_rtl_for_nonlocal_decl (decl, init, 
*** 7757,7763 ****
     DECL is a just-declared VAR_DECL; if necessary inject its
     declaration into the surrounding scope.  */
  
! static void
  maybe_inject_for_scope_var (decl)
       tree decl;
  {
--- 7754,7760 ----
     DECL is a just-declared VAR_DECL; if necessary inject its
     declaration into the surrounding scope.  */
  
! void
  maybe_inject_for_scope_var (decl)
       tree decl;
  {
*************** maybe_inject_for_scope_var (decl)
*** 7794,7809 ****
  
  /* Generate code to initialized DECL (a local variable).  */
  
! static void
! initialize_local_var (decl, init, cleanup, flags)
       tree decl;
       tree init;
-      tree cleanup;
       int flags;
  {
    tree type;
  
    type = TREE_TYPE (decl);
    expand_start_target_temps ();
  
    if (DECL_SIZE (decl) && type != error_mark_node)
--- 7791,7824 ----
  
  /* Generate code to initialized DECL (a local variable).  */
  
! void
! initialize_local_var (decl, init, flags)
       tree decl;
       tree init;
       int flags;
  {
    tree type;
+   tree cleanup;
  
    type = TREE_TYPE (decl);
+ 
+   cleanup = build_cleanup_on_safe_obstack (decl);
+ 
+   if (DECL_SIZE (decl) == NULL_TREE && !TREE_STATIC (decl))
+     {
+       /* If we used it already as memory, it must stay in memory.  */
+       DECL_INITIAL (decl) = NULL_TREE;
+       TREE_ADDRESSABLE (decl) = TREE_USED (decl);
+     }
+ 
+   if (DECL_RTL (decl))
+     /* Only a RESULT_DECL should have non-NULL RTL when arriving here.
+        All other local variables are assigned RTL in this function.  */
+     my_friendly_assert (TREE_CODE (decl) == RESULT_DECL, 19990828);
+   else
+     /* Create RTL for this variable.  */
+     expand_decl (decl);
+ 
    expand_start_target_temps ();
  
    if (DECL_SIZE (decl) && type != error_mark_node)
*************** initialize_local_var (decl, init, cleanu
*** 7811,7817 ****
        int already_used;
    
        /* Compute and store the initial value.  */
-       expand_decl_init (decl);
        already_used = TREE_USED (decl) || TREE_USED (type);
  
        if (init || TYPE_NEEDS_CONSTRUCTING (type))
--- 7826,7831 ----
*************** initialize_local_var (decl, init, cleanu
*** 7829,7867 ****
  	  finish_expr_stmt (build_aggr_init (decl, init, flags));
  	  pop_momentary ();
  	}
  
        /* Set this to 0 so we can tell whether an aggregate which was
  	 initialized was ever used.  Don't do this if it has a
  	 destructor, so we don't complain about the 'resource
! 	 allocation is initialization' idiom.  */
!       /* Now set attribute((unused)) on types so decls of that type
! 	 will be marked used. (see TREE_USED, above.)  This avoids the
! 	 warning problems this particular code tried to work
! 	 around. */
! 
        if (TYPE_NEEDS_CONSTRUCTING (type)
  	  && ! already_used
  	  && cleanup == NULL_TREE
  	  && DECL_NAME (decl))
  	TREE_USED (decl) = 0;
! 
!       if (already_used)
  	TREE_USED (decl) = 1;
      }
  
    /* Cleanup any temporaries needed for the initial value.  */
    expand_end_target_temps ();
  
!   if (DECL_SIZE (decl) && type != error_mark_node)
!     {
!       /* Store the cleanup, if there was one.  */
!       if (cleanup)
! 	{
! 	  if (! expand_decl_cleanup (decl, cleanup))
! 	    cp_error ("parser lost in parsing declaration of `%D'",
! 		      decl);
! 	}
!     }
  }
  
  /* Finish processing of a declaration;
--- 7843,7875 ----
  	  finish_expr_stmt (build_aggr_init (decl, init, flags));
  	  pop_momentary ();
  	}
+       else
+ 	expand_decl_init (decl);
  
        /* Set this to 0 so we can tell whether an aggregate which was
  	 initialized was ever used.  Don't do this if it has a
  	 destructor, so we don't complain about the 'resource
! 	 allocation is initialization' idiom.  Now set
! 	 attribute((unused)) on types so decls of that type will be
! 	 marked used. (see TREE_USED, above.)  */
        if (TYPE_NEEDS_CONSTRUCTING (type)
  	  && ! already_used
  	  && cleanup == NULL_TREE
  	  && DECL_NAME (decl))
  	TREE_USED (decl) = 0;
!       else if (already_used)
  	TREE_USED (decl) = 1;
      }
  
    /* Cleanup any temporaries needed for the initial value.  */
    expand_end_target_temps ();
  
!   /* Record the cleanup required for this declaration.  */
!   if (DECL_SIZE (decl) 
!       && type != error_mark_node
!       && cleanup
!       && !expand_decl_cleanup (decl, cleanup))
!     cp_error ("parser lost in parsing declaration of `%D'", decl);
  }
  
  /* Finish processing of a declaration;
*************** cp_finish_decl (decl, init, asmspec_tree
*** 7895,7901 ****
  {
    register tree type;
    tree ttype = NULL_TREE;
-   int was_incomplete;
    int temporary = allocation_temporary_p ();
    const char *asmspec = NULL;
    int was_readonly = 0;
--- 7903,7908 ----
*************** cp_finish_decl (decl, init, asmspec_tree
*** 7934,7947 ****
        /* Leave the namespace of the object. */
        pop_decl_namespace ();
      }
- 
-   /* If the type of the thing we are declaring either has
-      a constructor, or has a virtual function table pointer,
-      AND its initialization was accepted by `start_decl',
-      then we stayed on the permanent obstack through the
-      declaration, otherwise, changed obstacks as GCC would.  */
  
!   type = TREE_TYPE (decl);
  
    if (type == error_mark_node)
      {
--- 7941,7948 ----
        /* Leave the namespace of the object. */
        pop_decl_namespace ();
      }
  
!   type = complete_type (TREE_TYPE (decl));
  
    if (type == error_mark_node)
      {
*************** cp_finish_decl (decl, init, asmspec_tree
*** 8039,8047 ****
    /* Output the assembler code and/or RTL code for variables and functions,
       unless the type is an undefined structure or union.
       If not, it will get done when the type is completed.  */
- 
-   was_incomplete = (DECL_SIZE (decl) == NULL_TREE);
- 
    if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL
        || TREE_CODE (decl) == RESULT_DECL)
      {
--- 8040,8045 ----
*************** cp_finish_decl (decl, init, asmspec_tree
*** 8078,8121 ****
  	}
        else if (! toplev)
  	{
! 	  tree cleanup = build_cleanup_on_safe_obstack (decl);
! 
! 	  /* This is a declared decl which must live until the
! 	     end of the binding contour.  It may need a cleanup.  */
! 
! 	  /* Recompute the RTL of a local array now
! 	     if it used to be an incomplete type.  */
! 	  if (was_incomplete && ! TREE_STATIC (decl))
! 	    {
! 	      /* If we used it already as memory, it must stay in memory.  */
! 	      TREE_ADDRESSABLE (decl) = TREE_USED (decl);
! 	      /* If it's still incomplete now, no init will save it.  */
! 	      if (DECL_SIZE (decl) == NULL_TREE)
! 		DECL_INITIAL (decl) = NULL_TREE;
! 	      expand_decl (decl);
! 	    }
! 	  else if (! TREE_ASM_WRITTEN (decl)
! 		   && (TYPE_SIZE (type) != NULL_TREE
! 		       || TREE_CODE (type) == ARRAY_TYPE))
! 	    {
! 	      /* Do this here, because we did not expand this decl's
! 		 rtl in start_decl.  */
! 	      if (DECL_RTL (decl) == NULL_RTX)
! 		expand_decl (decl);
! 	      else if (cleanup)
! 		{
! 		  /* XXX: Why don't we use decl here?  */
! 		  /* Ans: Because it was already expanded? */
! 		  if (! expand_decl_cleanup (NULL_TREE, cleanup))
! 		    cp_error ("parser lost in parsing declaration of `%D'",
! 			      decl);
! 		  /* Cleanup used up here.  */
! 		  cleanup = NULL_TREE;
! 		}
! 	    }
! 
  	  maybe_inject_for_scope_var (decl);
! 	  initialize_local_var (decl, init, cleanup, flags);
  	}
      finish_end0:
  
--- 8076,8090 ----
  	}
        else if (! toplev)
  	{
! 	  /* This is a local declaration.  */
  	  maybe_inject_for_scope_var (decl);
! 	  /* Initialize the local variable.  But, if we're building a
! 	     statement-tree, we'll do the initialization when we
! 	     expand the tree.  */
! 	  if (!building_stmt_tree ())
! 	    initialize_local_var (decl, init, flags);
! 	  else if (init || DECL_INITIAL (decl) == error_mark_node)
! 	    DECL_INITIAL (decl) = init;
  	}
      finish_end0:
  
*************** expand_static_init (decl, init)
*** 8195,8200 ****
--- 8164,8170 ----
      {
        /* Emit code to perform this initialization but once.  */
        tree temp;
+       tree if_stmt;
        tree assignment;
        tree temp_init;
  
*************** expand_static_init (decl, init)
*** 8229,8236 ****
        rest_of_decl_compilation (temp, NULL_PTR, 0, 0);
  
        /* Begin the conditional initialization.  */
!       expand_start_cond (build_binary_op (EQ_EXPR, temp,
! 					  integer_zero_node), 0);
  
        /* Do the initialization itself.  */
        if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
--- 8199,8208 ----
        rest_of_decl_compilation (temp, NULL_PTR, 0, 0);
  
        /* Begin the conditional initialization.  */
!       if_stmt = begin_if_stmt ();
!       finish_if_stmt_cond (build_binary_op (EQ_EXPR, temp,
! 					    integer_zero_node), 
! 			   if_stmt);
  
        /* Do the initialization itself.  */
        if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
*************** expand_static_init (decl, init)
*** 8325,8334 ****
  				       expr_tree_cons (NULL_TREE, 
  						       cleanup, 
  						       NULL_TREE));
! 	  expand_expr_stmt (fcall);
  	}
  
-       expand_end_cond ();
        /* Resume old (possibly temporary) allocation.  */
        pop_obstacks ();
      }
--- 8297,8308 ----
  				       expr_tree_cons (NULL_TREE, 
  						       cleanup, 
  						       NULL_TREE));
! 	  finish_expr_stmt (fcall);
  	}
+ 
+       finish_then_clause (if_stmt);
+       finish_if_stmt ();
  
        /* Resume old (possibly temporary) allocation.  */
        pop_obstacks ();
      }
Index: cp/decl2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl2.c,v
retrieving revision 1.244
diff -c -p -r1.244 decl2.c
*** decl2.c	1999/08/29 01:20:54	1.244
--- decl2.c	1999/08/29 18:51:22
*************** get_temp_name (type, staticp)
*** 2070,2076 ****
    if (! toplev)
      {
        expand_decl (decl);
!       expand_decl_init (decl);
      }
    pop_obstacks ();
  
--- 2070,2077 ----
    if (! toplev)
      {
        expand_decl (decl);
!       my_friendly_assert (DECL_INITIAL (decl) == NULL_TREE,
! 			  19990826);
      }
    pop_obstacks ();
  
Index: cp/init.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/init.c,v
retrieving revision 1.122
diff -c -p -r1.122 init.c
*** init.c	1999/08/25 22:07:03	1.122
--- init.c	1999/08/29 18:51:25
*************** create_temporary_var (type)
*** 2706,2713 ****
  
    if (building_stmt_tree ())
      add_decl_stmt (decl);
-   else
-     DECL_RTL (decl) = assign_temp (type, 2, 0, 1);
  
    return decl;
  }
--- 2706,2711 ----
*************** get_temp_regvar (type, init)
*** 2727,2732 ****
--- 2725,2732 ----
  
    decl = create_temporary_var (type);
    DECL_REGISTER (decl) = 1;
+   if (!building_stmt_tree ())
+     DECL_RTL (decl) = assign_temp (type, 2, 0, 1);
    finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
  
    return decl;
Index: cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.342
diff -c -p -r1.342 pt.c
*** pt.c	1999/08/28 21:45:37	1.342
--- pt.c	1999/08/29 18:51:31
*************** tsubst_expr (t, args, complain, in_decl)
*** 7272,7284 ****
  	    decl = tsubst (decl, args, complain, in_decl);
  	    init = tsubst_expr (init, args, complain, in_decl);
  	    DECL_INITIAL (decl) = init;
! 	    /* By marking the declaration as instantiated, we avoid trying
! 	   to instantiate it.  Since instantiate_decl can't handle
! 	   local variables, and since we've already done all that
! 	   needs to be done, that's the right thing to do.  */
  	    if (TREE_CODE (decl) == VAR_DECL)
  	      DECL_TEMPLATE_INSTANTIATED (decl) = 1;
  	    maybe_push_decl (decl);
  	    add_decl_stmt (decl);
  	  }
  	resume_momentary (i);
--- 7272,7286 ----
  	    decl = tsubst (decl, args, complain, in_decl);
  	    init = tsubst_expr (init, args, complain, in_decl);
  	    DECL_INITIAL (decl) = init;
! 	    /* By marking the declaration as instantiated, we avoid
! 	       trying to instantiate it.  Since instantiate_decl can't
! 	       handle local variables, and since we've already done
! 	       all that needs to be done, that's the right thing to
! 	       do.  */
  	    if (TREE_CODE (decl) == VAR_DECL)
  	      DECL_TEMPLATE_INSTANTIATED (decl) = 1;
  	    maybe_push_decl (decl);
+ 	    cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0, 0);
  	    add_decl_stmt (decl);
  	  }
  	resume_momentary (i);
Index: cp/semantics.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/semantics.c,v
retrieving revision 1.67
diff -c -p -r1.67 semantics.c
*** semantics.c	1999/08/28 21:45:37	1.67
--- semantics.c	1999/08/29 18:51:32
*************** expand_stmt (t)
*** 2046,2052 ****
  	    if (TREE_CODE (decl) == VAR_DECL)
  	      DECL_DEAD_FOR_LOCAL (decl) = 0;
  	    maybe_push_decl (decl);
! 	    cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0, 0);
  	  }
  	resume_momentary (i);
        }
--- 2046,2056 ----
  	    if (TREE_CODE (decl) == VAR_DECL)
  	      DECL_DEAD_FOR_LOCAL (decl) = 0;
  	    maybe_push_decl (decl);
! 	    if (TREE_CODE (decl) == VAR_DECL && !TREE_STATIC (decl))
! 	      {
! 		maybe_inject_for_scope_var (decl);
! 		initialize_local_var (decl, DECL_INITIAL (decl), 0);
! 	      }
  	  }
  	resume_momentary (i);
        }


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