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]
Other format: [Raw text]

C++ PATCH: Fix copy constructor problems


Our ABI testsuite accidentally discovered this bug:

  + struct S { S (); };
  + 
  + volatile S s[1] = { S () };

This program was incorrectly rejected by G++.  The basic problem was
that for array initializers, we called digest_init (to handle brace
elision so that we could compute the size of the array if an explicit
bound was not provided) and then later called build_aggr_init to
convert the initializer.  But, digest_init had already done that, so
we ended up trying to do the conversions twice.  In this case, we
complained that a "volatile S" could not be passed to "const S&".

A more insidious case is this one:

  + S s[1] = { S () };

With -fno-elide-constructors, we actually copied the object *twice*,
which is a case of silent bad code generation.

In the process of fixing this (by separating the handling of brace
elision from the process of conversion), I accidentally fixed things
like this:

  ! int (Foo::*pA)() = { &Foo::DoSomething };	// ERROR - 

which we previously accepted despite the invalid extra set of braces.

I suspect that there is now some cleanup that could be done in
digest_init (it should no longer have to hadle brace elision), but I
didn't go that far.

To make things a little simpler, I removed the already deprecated 
"new X = ..." extension.  (This extension was already documented as
having been removed, but it wasn't.)

Bootstrapped and tested on i686-pc-linux-gnu, applied on the mainline.

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

2002-10-11  Mark Mitchell  <mark@codesourcery.com>

	* NEWS: Document removal of "new X = ..." extension.
	* class.c (initialize_array): Set TREE_HAS_CONSTRUCTOR on
	brace-enclosed initializers.
	* cp-tree.h (CP_AGGREGATE_TYPE_P): New macro.
	(initialize_local_var): Remove declaration.
	(expand_static_init): Likewise.
	* decl.c (next_initializable_field): New function.
	(reshape_init): Likewise.
	(check_initializer): Use them.  Build dynamic initializer for
	aggregates here too.
	(initialize_local_var): Simplify, and incorporate cleanup
	insertion code as well.
	(destroy_local_var): Remove.
	(cp_finish_decl): Tidy.
	(expand_static_init): Fold checks for whether or not a variable
	needs initialization into this function.  Simplify.
	* decl2.c (do_static_initialization): Simplify.
	* init.c (build_init): Do not set TREE_SIDE_EFFECTS when it will
	be done for us automatically.
	(expand_default_init): Handle brace-enclosed initializers
	correctly.
	(expand_aggr_init_1): Remove RTL-generation code.
	(build_vec_init): Remove "new X = ..." support.
	* parse.y (new_initializer): Likewise.
	* rtti.c (get_pseudo_ti_init): Set TREE_HAS_CONSTRUCTOR on
	brace-enclosed initializer.
	(create_pseudo_type_info): Likewise.
	* typeck2.c (store_init_value): Don't try to handle digest_init
	being called more than once.
	(digest_init): Tidy handling of brace-enclosed initializers.

2002-10-11  Mark Mitchell  <mark@codesourcery.com>

	* g++.dg/init/array1.C: Remove invalid braces.
	* g++.dg/init/brace1.C: New test.
	* g++.dg/init/copy2.C: Likewise.
	* g++.dg/init/copy3.C: Likewise.
	* g++.old-deja/g++.ext/arrnew.C: Change WARNING to ERROR.
	* g++.old-deja/g++.mike/p9129.C: Add ERROR on invalid use of
	braces.

Index: cp/NEWS
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/NEWS,v
retrieving revision 1.34
diff -c -5 -p -r1.34 NEWS
*** cp/NEWS	19 Mar 2002 00:21:38 -0000	1.34
--- cp/NEWS	11 Oct 2002 16:19:51 -0000
***************
*** 1,5 ****
--- 1,9 ----
+ *** Changes in GCC 3.3:
+ 
+ * The "new X = 3" extension has been removed; you must now use "new X(3)".
+ 
  *** Changes in GCC 3.1:
  
  * -fhonor-std and -fno-honor-std have been removed. -fno-honor-std was
    a workaround to allow std compliant code to work with the non-std
    compliant libstdc++-v2. libstdc++-v3 is std compliant.
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.473
diff -c -5 -p -r1.473 class.c
*** cp/class.c	2 Oct 2002 20:02:10 -0000	1.473
--- cp/class.c	11 Oct 2002 16:19:52 -0000
*************** initialize_array (decl, inits)
*** 6992,7001 ****
--- 6992,7002 ----
    tree context;
  
    context = DECL_CONTEXT (decl);
    DECL_CONTEXT (decl) = NULL_TREE;
    DECL_INITIAL (decl) = build_nt (CONSTRUCTOR, NULL_TREE, inits);
+   TREE_HAS_CONSTRUCTOR (DECL_INITIAL (decl)) = 1;
    cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0);
    DECL_CONTEXT (decl) = context;
  }
  
  /* Build the VTT (virtual table table) for T.
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.756
diff -c -5 -p -r1.756 cp-tree.h
*** cp/cp-tree.h	2 Oct 2002 20:01:35 -0000	1.756
--- cp/cp-tree.h	11 Oct 2002 16:19:53 -0000
*************** struct lang_decl GTY(())
*** 2435,2446 ****
     || TREE_CODE (TYPE) == ENUMERAL_TYPE		\
     || TYPE_PTR_P (TYPE)				\
     || TYPE_PTRMEM_P (TYPE)			\
     || TYPE_PTRMEMFUNC_P (TYPE))
  
! /* Nonzero for _TYPE means that the _TYPE defines
!    at least one constructor.  */
  #define TYPE_HAS_CONSTRUCTOR(NODE) (TYPE_LANG_FLAG_1 (NODE))
  
  /* When appearing in an INDIRECT_REF, it means that the tree structure
     underneath is actually a call to a constructor.  This is needed
     when the constructor must initialize local storage (which can
--- 2435,2456 ----
     || TREE_CODE (TYPE) == ENUMERAL_TYPE		\
     || TYPE_PTR_P (TYPE)				\
     || TYPE_PTRMEM_P (TYPE)			\
     || TYPE_PTRMEMFUNC_P (TYPE))
  
! /* [dcl.init.aggr]
! 
!    An aggregate is an array or a class with no user-declared
!    constructors, no private or protected non-static data members, no
!    base classes, and no virtual functions.  */
! #define CP_AGGREGATE_TYPE_P(TYPE)		\
!   (TREE_CODE (TYPE) == ARRAY_TYPE		\
!    || (CLASS_TYPE_P (TYPE)			\
!        && !CLASSTYPE_NON_AGGREGATE (TYPE)))
! 
! /* Nonzero for a class type means that the class type has a
!    user-declared constructor.  */
  #define TYPE_HAS_CONSTRUCTOR(NODE) (TYPE_LANG_FLAG_1 (NODE))
  
  /* When appearing in an INDIRECT_REF, it means that the tree structure
     underneath is actually a call to a constructor.  This is needed
     when the constructor must initialize local storage (which can
*************** extern tree groktypename			PARAMS ((tree
*** 3665,3676 ****
  extern tree start_decl				PARAMS ((tree, tree, int, tree, tree));
  extern void start_decl_1			PARAMS ((tree));
  extern void cp_finish_decl			PARAMS ((tree, tree, tree, int));
  extern void finish_decl				PARAMS ((tree, tree, tree));
  extern void maybe_inject_for_scope_var          PARAMS ((tree));
- extern void initialize_local_var                PARAMS ((tree, tree, int));
- extern void expand_static_init			PARAMS ((tree, tree));
  extern tree start_handler_parms                 PARAMS ((tree, tree));
  extern int complete_array_type			PARAMS ((tree, tree, int));
  extern tree build_ptrmemfunc_type		PARAMS ((tree));
  extern tree build_ptrmem_type                   (tree, tree);
  /* the grokdeclarator prototype is in decl.h */
--- 3675,3684 ----
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.945
diff -c -5 -p -r1.945 decl.c
*** cp/decl.c	11 Oct 2002 01:28:26 -0000	1.945
--- cp/decl.c	11 Oct 2002 16:19:56 -0000
*************** static void check_previous_gotos PARAMS 
*** 119,133 ****
  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 void maybe_commonize_var PARAMS ((tree));
! static tree check_initializer PARAMS ((tree, tree));
  static void make_rtl_for_nonlocal_decl PARAMS ((tree, tree, const char *));
  static void save_function_data PARAMS ((tree));
  static void check_function_type PARAMS ((tree, tree));
- static void destroy_local_var PARAMS ((tree));
  static void begin_constructor_body PARAMS ((void));
  static void finish_constructor_body PARAMS ((void));
  static void begin_destructor_body PARAMS ((void));
  static void finish_destructor_body PARAMS ((void));
  static tree create_array_type_for_decl PARAMS ((tree, tree, tree));
--- 119,132 ----
  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 void maybe_commonize_var PARAMS ((tree));
! static tree check_initializer (tree, tree, int);
  static void make_rtl_for_nonlocal_decl PARAMS ((tree, tree, const char *));
  static void save_function_data PARAMS ((tree));
  static void check_function_type PARAMS ((tree, tree));
  static void begin_constructor_body PARAMS ((void));
  static void finish_constructor_body PARAMS ((void));
  static void begin_destructor_body PARAMS ((void));
  static void finish_destructor_body PARAMS ((void));
  static tree create_array_type_for_decl PARAMS ((tree, tree, tree));
*************** static tree check_special_function_retur
*** 141,150 ****
--- 140,153 ----
    PARAMS ((special_function_kind, tree, tree));
  static tree push_cp_library_fn PARAMS ((enum tree_code, tree));
  static tree build_cp_library_fn PARAMS ((tree, enum tree_code, tree));
  static void store_parm_decls PARAMS ((tree));
  static int cp_missing_noreturn_ok_p PARAMS ((tree));
+ static void initialize_local_var (tree, tree);
+ static void expand_static_init (tree, tree);
+ static tree next_initializable_field (tree);
+ static tree reshape_init (tree, tree *);
  
  #if defined (DEBUG_BINDING_LEVELS)
  static void indent PARAMS ((void));
  #endif
  
*************** check_for_uninitialized_const_var (decl)
*** 7725,7742 ****
        && !TYPE_NEEDS_CONSTRUCTING (type)
        && !DECL_INITIAL (decl))
      error ("uninitialized const `%D'", decl);
  }
  
  /* Verify INIT (the initializer for DECL), and record the
!    initialization in DECL_INITIAL, if appropriate.  Returns a new
!    value for INIT.  */
  
  static tree
! check_initializer (decl, init)
!      tree decl;
!      tree init;
  {
    tree type = TREE_TYPE (decl);
  
    /* If `start_decl' didn't like having an initialization, ignore it now.  */
    if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE)
--- 7728,7951 ----
        && !TYPE_NEEDS_CONSTRUCTING (type)
        && !DECL_INITIAL (decl))
      error ("uninitialized const `%D'", decl);
  }
  
+ /* FIELD is a FIELD_DECL or NULL.  In the former case, the value
+    returned is the next FIELD_DECL (possibly FIELD itself) that can be
+    initialized.  If there are no more such fields, the return value
+    will be NULL.  */
+ 
+ static tree
+ next_initializable_field (tree field)
+ {
+   while (field
+ 	 && (TREE_CODE (field) != FIELD_DECL
+ 	     || (DECL_C_BIT_FIELD (field) && !DECL_NAME (field))
+ 	     || DECL_ARTIFICIAL (field)))
+     field = TREE_CHAIN (field);
+ 
+   return field;
+ }
+ 
+ /* Undo the brace-elision allowed by [dcl.init.aggr] in a
+    brace-enclosed aggregate initializer.
+ 
+    *INITP is one of a list of initializers describing a brace-enclosed
+    initializer for an entity of the indicated aggregate TYPE.  It may
+    not presently match the shape of the TYPE; for example:
+    
+      struct S { int a; int b; };
+      struct S a[] = { 1, 2, 3, 4 };
+ 
+    Here *INITP will point to TREE_LIST of four elements, rather than a
+    list of two elements, each itself a list of two elements.  This
+    routine transforms INIT from the former form into the latter.  The
+    revised initializer is returned.  */
+ 
+ static tree
+ reshape_init (tree type, tree *initp)
+ {
+   tree inits;
+   tree old_init;
+   tree old_init_value;
+   tree new_init;
+   bool brace_enclosed_p;
+ 
+   old_init = *initp;
+   old_init_value = (TREE_CODE (*initp) == TREE_LIST
+ 		    ? TREE_VALUE (*initp) : old_init);
+ 
+   /* If the initializer is brace-enclosed, pull initializers from the
+      enclosed elements.  Advance past the brace-enclosed initializer
+      now.  */
+   if (TREE_CODE (old_init_value) == CONSTRUCTOR 
+       && TREE_HAS_CONSTRUCTOR (old_init_value))
+     {
+       *initp = TREE_CHAIN (old_init);
+       TREE_CHAIN (old_init) = NULL_TREE;
+       inits = CONSTRUCTOR_ELTS (old_init_value);
+       initp = &inits;
+       brace_enclosed_p = true;
+     }
+   else
+     {
+       inits = NULL_TREE;
+       brace_enclosed_p = false;
+     }
+ 
+   /* A non-aggregate type is always initialized with a single
+      initializer.  */
+   if (!CP_AGGREGATE_TYPE_P (type))
+       {
+ 	*initp = TREE_CHAIN (old_init);
+ 	TREE_CHAIN (old_init) = NULL_TREE;
+ 	/* It is invalid to initialize a non-aggregate type with a
+ 	   brace-enclosed initializer.  */
+ 	if (brace_enclosed_p)
+ 	  {
+ 	    error ("brace-enclosed initializer used to initialize `%T'",
+ 		   type);
+ 	    if (TREE_CODE (old_init) == TREE_LIST)
+ 	      TREE_VALUE (old_init) = error_mark_node;
+ 	    else
+ 	      old_init = error_mark_node;
+ 	  }
+ 	
+ 	return old_init;
+       }
+ 
+   /* [dcl.init.aggr]
+ 
+      All implicit type conversions (clause _conv_) are considered when
+      initializing the aggregate member with an initializer from an
+      initializer-list.  If the initializer can initialize a member,
+      the member is initialized.  Otherwise, if the member is itself a
+      non-empty subaggregate, brace elision is assumed and the
+      initializer is considered for the initialization of the first
+      member of the subaggregate.  */
+   if (CLASS_TYPE_P (type) 
+       && !brace_enclosed_p
+       && can_convert_arg (type, TREE_TYPE (old_init_value), old_init_value))
+     {
+       *initp = TREE_CHAIN (old_init);
+       TREE_CHAIN (old_init) = NULL_TREE;
+       return old_init;
+     }
+ 
+   if (TREE_CODE (old_init) == STRING_CST
+       && TREE_CODE (type) == ARRAY_TYPE
+       && char_type_p (TREE_TYPE (type)))
+     {
+       /* [dcl.init.string]
+ 
+ 	 A char array (whether plain char, signed char, or unsigned char)
+ 	 can be initialized by a string-literal (optionally enclosed in
+ 	 braces); a wchar_t array can be initialized by a wide
+ 	 string-literal (optionally enclosed in braces).  */
+       new_init = old_init;
+       /* Move past the initializer.  */
+       *initp = TREE_CHAIN (old_init);
+       TREE_CHAIN (old_init) = NULL_TREE;
+     }
+   else
+     {
+       /* Build a CONSTRUCTOR to hold the contents of the aggregate.  */  
+       new_init = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
+       TREE_HAS_CONSTRUCTOR (new_init) = 1;
+ 
+       if (CLASS_TYPE_P (type))
+ 	{
+ 	  tree field;
+ 
+ 	  field = next_initializable_field (TYPE_FIELDS (type));
+ 
+ 	  if (!field)
+ 	    {
+ 	      /* [dcl.init.aggr]
+ 	      
+ 		 An initializer for an aggregate member that is an
+ 		 empty class shall have the form of an empty
+ 		 initializer-list {}.  */
+ 	      if (!brace_enclosed_p)
+ 		error ("initializer for `%T' must be brace-enclosed",
+ 		       type);
+ 	    }
+ 	  else
+ 	    {
+ 	      /* Loop through the initializable fields, gathering
+ 		 initializers.  */
+ 	      while (*initp && field)
+ 		{
+ 		  tree field_init;
+ 
+ 		  field_init = reshape_init (TREE_TYPE (field), initp);
+ 		  TREE_CHAIN (field_init) = CONSTRUCTOR_ELTS (new_init);
+ 		  CONSTRUCTOR_ELTS (new_init) = field_init;
+ 		  /* [dcl.init.aggr] 
+ 
+ 		     When a union  is  initialized with a brace-enclosed
+ 		     initializer, the braces shall only contain an
+ 		     initializer for the first member of the union.  */
+ 		  if (TREE_CODE (type) == UNION_TYPE)
+ 		    break;
+ 		  if (TREE_PURPOSE (field_init))
+ 		    field = TREE_PURPOSE (field_init);
+ 		  field = next_initializable_field (TREE_CHAIN (field));
+ 		}
+ 	    }
+ 	}
+       else if (TREE_CODE (type) == ARRAY_TYPE)
+ 	{
+ 	  tree index;
+ 	  tree max_index;
+ 
+ 	  /* If the bound of the array is known, take no more initializers
+ 	     than are allowed.  */
+ 	  max_index = (TYPE_DOMAIN (type) 
+ 		       ? array_type_nelts (type) : NULL_TREE);
+ 	  /* Loop through the array elements, gathering initializers.  */
+ 	  for (index = size_zero_node;
+ 	       *initp && (!max_index || !tree_int_cst_lt (max_index, index));
+ 	       index = size_binop (PLUS_EXPR, index, size_one_node))
+ 	    {
+ 	      tree element_init;
+ 
+ 	      element_init = reshape_init (TREE_TYPE (type), initp);
+ 	      TREE_CHAIN (element_init) = CONSTRUCTOR_ELTS (new_init);
+ 	      CONSTRUCTOR_ELTS (new_init) = element_init;
+ 	      if (TREE_PURPOSE (element_init))
+ 		index = TREE_PURPOSE (element_init);
+ 	    }
+ 	}
+       else
+ 	abort ();
+ 
+       /* The initializers were placed in reverse order in the
+ 	 CONSTRUCTOR.  */
+       CONSTRUCTOR_ELTS (new_init) = nreverse (CONSTRUCTOR_ELTS (new_init));
+ 
+       if (TREE_CODE (old_init) == TREE_LIST)
+ 	new_init = build_tree_list (TREE_PURPOSE (old_init), new_init);
+     }
+ 
+   /* If this was a brace-enclosed initializer and all of the
+      initializers were not used up, there is a problem.  */
+   if (brace_enclosed_p && *initp)
+     error ("too many initializers for `%T'", type);
+ 
+   return new_init;
+ }
+ 
  /* Verify INIT (the initializer for DECL), and record the
!    initialization in DECL_INITIAL, if appropriate.  
! 
!    If the return value is non-NULL, it is an expression that must be
!    evaluated dynamically to initialize DECL.  */
  
  static tree
! check_initializer (tree decl, tree init, int flags)
  {
    tree type = TREE_TYPE (decl);
  
    /* If `start_decl' didn't like having an initialization, ignore it now.  */
    if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE)
*************** check_initializer (decl, init)
*** 7788,7842 ****
      }
    else if (!DECL_EXTERNAL (decl) && TREE_CODE (type) == REFERENCE_TYPE)
      init = grok_reference_init (decl, type, init);
    else if (init)
      {
        if (TYPE_HAS_CONSTRUCTOR (type) || TYPE_NEEDS_CONSTRUCTING (type))
  	{
  	  if (TREE_CODE (type) == ARRAY_TYPE)
! 	    init = digest_init (type, init, (tree *) 0);
  	  else if (TREE_CODE (init) == CONSTRUCTOR
  		   && TREE_HAS_CONSTRUCTOR (init))
  	    {
  	      if (TYPE_NON_AGGREGATE_CLASS (type))
  		{
  		  error ("`%D' must be initialized by constructor, not by `{...}'",
! 			    decl);
  		  init = error_mark_node;
  		}
  	      else
  		goto dont_use_constructor;
  	    }
  	}
        else
  	{
  	dont_use_constructor:
  	  if (TREE_CODE (init) != TREE_VEC)
  	    init = store_init_value (decl, init);
  	}
      }
    else if (DECL_EXTERNAL (decl))
      ;
!   else if (TYPE_P (type)
! 	   && (IS_AGGR_TYPE (type) || TYPE_NEEDS_CONSTRUCTING (type)))
      {
        tree core_type = strip_array_types (type);
  
!       if (! TYPE_NEEDS_CONSTRUCTING (core_type))
! 	{
! 	  if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type))
! 	    error ("structure `%D' with uninitialized const members", decl);
! 	  if (CLASSTYPE_REF_FIELDS_NEED_INIT (core_type))
! 	    error ("structure `%D' with uninitialized reference members",
! 		      decl);
! 	}
  
        check_for_uninitialized_const_var (decl);
      }
    else
      check_for_uninitialized_const_var (decl);
  
    return init;
  }
  
  /* If DECL is not a local variable, give it RTL.  */
  
--- 7997,8079 ----
      }
    else if (!DECL_EXTERNAL (decl) && TREE_CODE (type) == REFERENCE_TYPE)
      init = grok_reference_init (decl, type, init);
    else if (init)
      {
+       if (TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init))
+ 	init = reshape_init (type, &init);
+ 
+       /* If DECL has an array type without a specific bound, deduce the
+ 	 array size from the initializer.  */
+       maybe_deduce_size_from_array_init (decl, init);
+       type = TREE_TYPE (decl);
+       if (TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init))
+ 	TREE_TYPE (init) = type;
+ 
        if (TYPE_HAS_CONSTRUCTOR (type) || TYPE_NEEDS_CONSTRUCTING (type))
  	{
  	  if (TREE_CODE (type) == ARRAY_TYPE)
! 	    goto initialize_aggr;
  	  else if (TREE_CODE (init) == CONSTRUCTOR
  		   && TREE_HAS_CONSTRUCTOR (init))
  	    {
  	      if (TYPE_NON_AGGREGATE_CLASS (type))
  		{
  		  error ("`%D' must be initialized by constructor, not by `{...}'",
! 			 decl);
  		  init = error_mark_node;
  		}
  	      else
  		goto dont_use_constructor;
  	    }
+ 	  else
+ 	    {
+ 	      int saved_stmts_are_full_exprs_p;
+ 
+ 	    initialize_aggr:
+ 	      saved_stmts_are_full_exprs_p = 0;
+ 	      if (building_stmt_tree ())
+ 		{
+ 		  saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
+ 		  current_stmt_tree ()->stmts_are_full_exprs_p = 1;
+ 		}
+ 	      init = build_aggr_init (decl, init, flags);
+ 	      if (building_stmt_tree ())
+ 		current_stmt_tree ()->stmts_are_full_exprs_p =
+ 		  saved_stmts_are_full_exprs_p;
+ 	      return init;
+ 	    }
  	}
        else
  	{
  	dont_use_constructor:
  	  if (TREE_CODE (init) != TREE_VEC)
  	    init = store_init_value (decl, init);
  	}
      }
    else if (DECL_EXTERNAL (decl))
      ;
!   else if (TYPE_P (type) && TYPE_NEEDS_CONSTRUCTING (type))
!     goto initialize_aggr;
!   else if (IS_AGGR_TYPE (type))
      {
        tree core_type = strip_array_types (type);
  
!       if (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type))
! 	error ("structure `%D' with uninitialized const members", decl);
!       if (CLASSTYPE_REF_FIELDS_NEED_INIT (core_type))
! 	error ("structure `%D' with uninitialized reference members",
! 	       decl);
  
        check_for_uninitialized_const_var (decl);
      }
    else
      check_for_uninitialized_const_var (decl);
  
+   if (init && init != error_mark_node)
+     init = build (INIT_EXPR, type, decl, init);
+ 
    return init;
  }
  
  /* If DECL is not a local variable, give it RTL.  */
  
*************** maybe_inject_for_scope_var (decl)
*** 7966,8019 ****
      }
  }
  
  /* Generate code to initialize DECL (a local variable).  */
  
! void
! initialize_local_var (decl, init, flags)
       tree decl;
       tree init;
-      int flags;
  {
    tree type = TREE_TYPE (decl);
  
!   /* If the type is bogus, don't bother initializing the variable.  */
!   if (type == error_mark_node)
!     return;
  
!   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);
      }
  
-   /* Local statics are handled differently from ordinary automatic
-      variables.  */
-   if (TREE_STATIC (decl))
-     {
-       if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
- 	  || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
- 	expand_static_init (decl, init);
-       return;
-     }
- 
    if (DECL_SIZE (decl) && type != error_mark_node)
      {
        int already_used;
  
        /* Compute and store the initial value.  */
        already_used = TREE_USED (decl) || TREE_USED (type);
  
!       if (init || TYPE_NEEDS_CONSTRUCTING (type))
  	{
  	  int saved_stmts_are_full_exprs_p;
  
  	  my_friendly_assert (building_stmt_tree (), 20000906);
  	  saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
  	  current_stmt_tree ()->stmts_are_full_exprs_p = 1;
! 	  finish_expr_stmt (build_aggr_init (decl, init, flags));
  	  current_stmt_tree ()->stmts_are_full_exprs_p =
  	    saved_stmts_are_full_exprs_p;
  	}
  
        /* Set this to 0 so we can tell whether an aggregate which was
--- 8203,8247 ----
      }
  }
  
  /* Generate code to initialize DECL (a local variable).  */
  
! static void
! initialize_local_var (decl, init)
       tree decl;
       tree init;
  {
    tree type = TREE_TYPE (decl);
  
!   my_friendly_assert (TREE_CODE (decl) == VAR_DECL
! 		      || TREE_CODE (decl) == RESULT_DECL, 
! 		      20021010);
!   my_friendly_assert (!TREE_STATIC (decl), 20021010);
  
!   if (DECL_SIZE (decl) == NULL_TREE)
      {
        /* 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_SIZE (decl) && type != error_mark_node)
      {
        int already_used;
  
        /* Compute and store the initial value.  */
        already_used = TREE_USED (decl) || TREE_USED (type);
  
!       /* Perform the initialization.  */
!       if (init)
  	{
  	  int saved_stmts_are_full_exprs_p;
  
  	  my_friendly_assert (building_stmt_tree (), 20000906);
  	  saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
  	  current_stmt_tree ()->stmts_are_full_exprs_p = 1;
! 	  finish_expr_stmt (init);
  	  current_stmt_tree ()->stmts_are_full_exprs_p =
  	    saved_stmts_are_full_exprs_p;
  	}
  
        /* Set this to 0 so we can tell whether an aggregate which was
*************** initialize_local_var (decl, init, flags)
*** 8028,8070 ****
  	  && DECL_NAME (decl))
  	TREE_USED (decl) = 0;
        else if (already_used)
  	TREE_USED (decl) = 1;
      }
- }
- 
- /* Generate code to destroy DECL (a local variable).  */
- 
- static void
- destroy_local_var (decl)
-      tree decl;
- {
-   tree type = TREE_TYPE (decl);
-   tree cleanup;
- 
-   /* Only variables get cleaned up.  */
-   if (TREE_CODE (decl) != VAR_DECL)
-     return;
- 
-   /* And only things with destructors need cleaning up.  */
-   if (type == error_mark_node
-       || TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
-     return;
  
!   if (TREE_CODE (decl) == VAR_DECL &&
!       (DECL_EXTERNAL (decl) || TREE_STATIC (decl)))
!     /* We don't clean up things that aren't defined in this
!        translation unit, or that need a static cleanup.  The latter
!        are handled by finish_file.  */
!     return;
! 
!   /* Compute the cleanup.  */
!   cleanup = cxx_maybe_build_cleanup (decl);
  
!   /* Record the cleanup required for this declaration.  */
!   if (DECL_SIZE (decl) && cleanup)
!     finish_decl_cleanup (decl, cleanup);
  }
  
  /* Finish processing of a declaration;
     install its line number and initial value.
     If the length of an array type is not known before,
--- 8256,8278 ----
  	  && DECL_NAME (decl))
  	TREE_USED (decl) = 0;
        else if (already_used)
  	TREE_USED (decl) = 1;
      }
  
!   /* Generate a cleanup, if necessary.  */
!   if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
!     {
!       tree cleanup;
  
!       /* Compute the cleanup.  */
!       cleanup = cxx_maybe_build_cleanup (decl);
!       
!       /* Record the cleanup required for this declaration.  */
!       if (DECL_SIZE (decl) && cleanup)
! 	finish_decl_cleanup (decl, cleanup);
!     }
  }
  
  /* Finish processing of a declaration;
     install its line number and initial value.
     If the length of an array type is not known before,
*************** cp_finish_decl (decl, init, asmspec_tree
*** 8191,8201 ****
        SET_DECL_RTL (TREE_TYPE (decl), NULL_RTX);
        SET_DECL_ASSEMBLER_NAME (decl, get_identifier (asmspec));
        make_decl_rtl (decl, asmspec);
      }
    else if (TREE_CODE (decl) == RESULT_DECL)
!     init = check_initializer (decl, init);
    else if (TREE_CODE (decl) == VAR_DECL)
      {
        /* Only PODs can have thread-local storage.  Other types may require
  	 various kinds of non-trivial initialization.  */
        if (DECL_THREAD_LOCAL (decl) && !pod_type_p (TREE_TYPE (decl)))
--- 8399,8409 ----
        SET_DECL_RTL (TREE_TYPE (decl), NULL_RTX);
        SET_DECL_ASSEMBLER_NAME (decl, get_identifier (asmspec));
        make_decl_rtl (decl, asmspec);
      }
    else if (TREE_CODE (decl) == RESULT_DECL)
!     init = check_initializer (decl, init, flags);
    else if (TREE_CODE (decl) == VAR_DECL)
      {
        /* Only PODs can have thread-local storage.  Other types may require
  	 various kinds of non-trivial initialization.  */
        if (DECL_THREAD_LOCAL (decl) && !pod_type_p (TREE_TYPE (decl)))
*************** cp_finish_decl (decl, init, asmspec_tree
*** 8203,8234 ****
  	       decl, TREE_TYPE (decl));
        /* Convert the initializer to the type of DECL, if we have not
  	 already initialized DECL.  */
        if (!DECL_INITIALIZED_P (decl)
  	  /* If !DECL_EXTERNAL then DECL is being defined.  In the
! 	     case of a static data memberm initialized inside the
  	     class-specifier, there can be an initializer even if DECL
  	     is *not* defined.  */
  	  && (!DECL_EXTERNAL (decl) || init))
  	{
! 	  init = check_initializer (decl, init);
  	  /* Thread-local storage cannot be dynamically initialized.  */
  	  if (DECL_THREAD_LOCAL (decl) && init)
  	    {
  	      error ("`%D' is thread-local and so cannot be dynamically "
  		     "initialized", decl);
  	      init = NULL_TREE;
  	    }
- 	  /* If DECL has an array type without a specific bound, deduce the
- 	     array size from the initializer.  Note that this must be done
- 	     after check_initializer is called because of cases like this:
- 	     
-  	       struct S { int a; int b; };
- 	       struct S a[] = { 1, 2 };
- 	 
- 	     which creates a one-element array, not a two-element array.  */
- 	  maybe_deduce_size_from_array_init (decl, init);
  	  /* Handle:
  	     
  	     [dcl.init]
  	     
  	     The memory occupied by any object of static storage
--- 8411,8433 ----
  	       decl, TREE_TYPE (decl));
        /* Convert the initializer to the type of DECL, if we have not
  	 already initialized DECL.  */
        if (!DECL_INITIALIZED_P (decl)
  	  /* If !DECL_EXTERNAL then DECL is being defined.  In the
! 	     case of a static data member initialized inside the
  	     class-specifier, there can be an initializer even if DECL
  	     is *not* defined.  */
  	  && (!DECL_EXTERNAL (decl) || init))
  	{
! 	  init = check_initializer (decl, init, flags);
  	  /* Thread-local storage cannot be dynamically initialized.  */
  	  if (DECL_THREAD_LOCAL (decl) && init)
  	    {
  	      error ("`%D' is thread-local and so cannot be dynamically "
  		     "initialized", decl);
  	      init = NULL_TREE;
  	    }
  	  /* Handle:
  	     
  	     [dcl.init]
  	     
  	     The memory occupied by any object of static storage
*************** cp_finish_decl (decl, init, asmspec_tree
*** 8281,8328 ****
  	abstract_virtuals_error (decl,
  				 strip_array_types (TREE_TYPE (type)));
        else
  	abstract_virtuals_error (decl, strip_array_types (type));
  
!       if (TREE_CODE (decl) == FUNCTION_DECL)
  	;
        else if (DECL_EXTERNAL (decl)
  	       && ! (DECL_LANG_SPECIFIC (decl)
  		     && DECL_NOT_REALLY_EXTERN (decl)))
  	{
  	  if (init)
  	    DECL_INITIAL (decl) = init;
  	}
!       else if (TREE_CODE (CP_DECL_CONTEXT (decl)) == FUNCTION_DECL)
  	{
! 	  /* This is a local declaration.  */
! 	  if (doing_semantic_analysis_p ())
! 	    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 (processing_template_decl)
  	    {
! 	      if (init || DECL_INITIAL (decl) == error_mark_node)
! 		DECL_INITIAL (decl) = init;
! 	    }
! 	  else
! 	    {
! 	      /* If we're not building RTL, then we need to do so
! 		 now.  */
! 	      my_friendly_assert (building_stmt_tree (), 20000906);
! 	      /* Initialize the variable.  */
! 	      initialize_local_var (decl, init, flags);
! 	      /* Clean up the variable.  */
! 	      destroy_local_var (decl);
  	    }
! 	}
!       else if (TREE_STATIC (decl) && type != error_mark_node)
! 	{
! 	  /* Cleanups for static variables are handled by `finish_file'.  */
! 	  if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
! 	      || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
  	    expand_static_init (decl, init);
  	}
      finish_end0:
  
        /* Undo call to `pushclass' that was done in `start_decl'
--- 8480,8519 ----
  	abstract_virtuals_error (decl,
  				 strip_array_types (TREE_TYPE (type)));
        else
  	abstract_virtuals_error (decl, strip_array_types (type));
  
!       if (TREE_CODE (decl) == FUNCTION_DECL 
! 	  || TREE_TYPE (decl) == error_mark_node)
! 	/* No initialization required.  */
  	;
        else if (DECL_EXTERNAL (decl)
  	       && ! (DECL_LANG_SPECIFIC (decl)
  		     && DECL_NOT_REALLY_EXTERN (decl)))
  	{
  	  if (init)
  	    DECL_INITIAL (decl) = init;
  	}
!       else
  	{
! 	  /* A variable definition.  */
! 	  if (DECL_FUNCTION_SCOPE_P (decl))
  	    {
! 	      /* This is a local declaration.  */
! 	      if (doing_semantic_analysis_p ())
! 		maybe_inject_for_scope_var (decl);
! 	      /* Initialize the local variable.  */
! 	      if (processing_template_decl)
! 		{
! 		  if (init || DECL_INITIAL (decl) == error_mark_node)
! 		    DECL_INITIAL (decl) = init;
! 		}
! 	      else if (!TREE_STATIC (decl))
! 		initialize_local_var (decl, init);
  	    }
! 
! 	  if (TREE_STATIC (decl))
  	    expand_static_init (decl, init);
  	}
      finish_end0:
  
        /* Undo call to `pushclass' that was done in `start_decl'
*************** register_dtor_fn (decl)
*** 8598,8613 ****
    else
      args = tree_cons (NULL_TREE, cleanup, NULL_TREE);
    finish_expr_stmt (build_function_call (get_atexit_node (), args));
  }
  
! void
  expand_static_init (decl, init)
       tree decl;
       tree init;
  {
!   tree oldstatic = value_member (decl, static_aggregates);
  
    if (oldstatic)
      {
        if (TREE_PURPOSE (oldstatic) && init != NULL_TREE)
  	error ("multiple initializations given for `%D'", decl);
--- 8789,8819 ----
    else
      args = tree_cons (NULL_TREE, cleanup, NULL_TREE);
    finish_expr_stmt (build_function_call (get_atexit_node (), args));
  }
  
! /* DECL is a VAR_DECL with static storage duration.  INIT, if present,
!    is its initializer.  Generate code to handle the construction
!    and destruction of DECL.  */
! 
! static void
  expand_static_init (decl, init)
       tree decl;
       tree init;
  {
!   tree oldstatic;
! 
!   my_friendly_assert (TREE_CODE (decl) == VAR_DECL, 20021010);
!   my_friendly_assert (TREE_STATIC (decl), 20021010);
! 
!   /* Some variables require no initialization.  */
!   if (!init 
!       && !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
!       && TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
!     return;
! 
!   oldstatic = value_member (decl, static_aggregates);
  
    if (oldstatic)
      {
        if (TREE_PURPOSE (oldstatic) && init != NULL_TREE)
  	error ("multiple initializations given for `%D'", decl);
*************** expand_static_init (decl, init)
*** 8653,8671 ****
        if_stmt = begin_if_stmt ();
        finish_if_stmt_cond (get_guard_cond (guard), if_stmt);
        then_clause = begin_compound_stmt (/*has_no_scope=*/0);
  
        /* Do the initialization itself.  */
!       if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
! 	  || (init && TREE_CODE (init) == TREE_LIST))
! 	assignment = build_aggr_init (decl, init, 0);
!       else if (init)
! 	/* The initialization we're doing here is just a bitwise
! 	   copy.  */
! 	assignment = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
!       else
! 	assignment = NULL_TREE;
  
        /* Once the assignment is complete, set TEMP to 1.  Since the
  	 construction of the static object is complete at this point,
  	 we want to make sure TEMP is set to 1 even if a temporary
  	 constructed during the initialization throws an exception
--- 8859,8869 ----
        if_stmt = begin_if_stmt ();
        finish_if_stmt_cond (get_guard_cond (guard), if_stmt);
        then_clause = begin_compound_stmt (/*has_no_scope=*/0);
  
        /* Do the initialization itself.  */
!       assignment = init ? init : NULL_TREE;
  
        /* Once the assignment is complete, set TEMP to 1.  Since the
  	 construction of the static object is complete at this point,
  	 we want to make sure TEMP is set to 1 even if a temporary
  	 constructed during the initialization throws an exception
Index: cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.567
diff -c -5 -p -r1.567 decl2.c
*** cp/decl2.c	9 Oct 2002 21:08:42 -0000	1.567
--- cp/decl2.c	11 Oct 2002 16:19:57 -0000
*************** finish_static_initialization_or_destruct
*** 2506,2543 ****
       member of its class any longer.  */
    DECL_CONTEXT (current_function_decl) = NULL_TREE;
    DECL_STATIC_FUNCTION_P (current_function_decl) = 0;
  }
  
! /* Generate code to do the static initialization of DECL.  The
!    initialization is INIT.  If DECL may be initialized more than once
!    in different object files, GUARD is the guard variable to 
!    check.  PRIORITY is the priority for the initialization.  */
  
  static void
  do_static_initialization (decl, init)
       tree decl;
       tree init;
  {
-   tree expr;
    tree guard_if_stmt;
  
    /* Set up for the initialization.  */
    guard_if_stmt
      = start_static_initialization_or_destruction (decl,
  						  /*initp=*/1);
!   
!   /* Do the initialization itself.  */
!   if (IS_AGGR_TYPE (TREE_TYPE (decl))
!       || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
!     expr = build_aggr_init (decl, init, 0);
!   else
!     {
!       expr = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
!       TREE_SIDE_EFFECTS (expr) = 1;
!     }
!   finish_expr_stmt (expr);
  
    /* If we're using __cxa_atexit, register a a function that calls the
       destructor for the object.  */
    if (flag_use_cxa_atexit)
      register_dtor_fn (decl);
--- 2506,2533 ----
       member of its class any longer.  */
    DECL_CONTEXT (current_function_decl) = NULL_TREE;
    DECL_STATIC_FUNCTION_P (current_function_decl) = 0;
  }
  
! /* Generate code to do the initialization of DECL, a VAR_DECL with
!    static storage duration.  The initialization is INIT.  */
  
  static void
  do_static_initialization (decl, init)
       tree decl;
       tree init;
  {
    tree guard_if_stmt;
  
    /* Set up for the initialization.  */
    guard_if_stmt
      = start_static_initialization_or_destruction (decl,
  						  /*initp=*/1);
! 
!   /* Perform the initialization.  */
!   if (init)
!     finish_expr_stmt (init);
  
    /* If we're using __cxa_atexit, register a a function that calls the
       destructor for the object.  */
    if (flag_use_cxa_atexit)
      register_dtor_fn (decl);
*************** do_static_destruction (decl)
*** 2565,2575 ****
    if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
      return;
  
    /* Actually do the destruction.  */
    guard_if_stmt = start_static_initialization_or_destruction (decl,
! 							       /*initp=*/0);
    finish_expr_stmt (build_cleanup (decl));
    finish_static_initialization_or_destruction (guard_if_stmt);
  }
  
  /* VARS is a list of variables with static storage duration which may
--- 2555,2565 ----
    if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
      return;
  
    /* Actually do the destruction.  */
    guard_if_stmt = start_static_initialization_or_destruction (decl,
! 							      /*initp=*/0);
    finish_expr_stmt (build_cleanup (decl));
    finish_static_initialization_or_destruction (guard_if_stmt);
  }
  
  /* VARS is a list of variables with static storage duration which may
Index: cp/init.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/init.c,v
retrieving revision 1.294
diff -c -5 -p -r1.294 init.c
*** cp/init.c	2 Oct 2002 20:01:35 -0000	1.294
--- cp/init.c	11 Oct 2002 16:19:58 -0000
*************** expand_member_init (tree name, tree init
*** 1039,1050 ****
     initialization.
  
     The virtual function table pointer cannot be set up here, because
     we do not really know its type.
  
-    Virtual baseclass pointers are also set up here.
- 
     This never calls operator=().
  
     When initializing, nothing is CONST.
  
     A default copy constructor may have to be used to perform the
--- 1039,1048 ----
*************** build_init (decl, init, flags)
*** 1142,1155 ****
  
    if (IS_AGGR_TYPE (TREE_TYPE (decl))
        || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
      expr = build_aggr_init (decl, init, flags);
    else
!     {
!       expr = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
!       TREE_SIDE_EFFECTS (expr) = 1;
!     }
    return expr;
  }
  
  static void
  expand_default_init (binfo, true_exp, exp, init, flags)
--- 1140,1151 ----
  
    if (IS_AGGR_TYPE (TREE_TYPE (decl))
        || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
      expr = build_aggr_init (decl, init, flags);
    else
!     expr = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
! 
    return expr;
  }
  
  static void
  expand_default_init (binfo, true_exp, exp, init, flags)
*************** expand_default_init (binfo, true_exp, ex
*** 1182,1194 ****
  	   where we aren't initializing a real variable, so we don't want
  	   to run a new constructor; and catching an exception, where we
  	   have already built up the constructor call so we could wrap it
  	   in an exception region.  */;
        else if (TREE_CODE (init) == CONSTRUCTOR)
! 	/* A brace-enclosed initializer has whatever type is
! 	   required.  There's no need to convert it.  */
! 	;
        else
  	init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
  
        if (TREE_CODE (init) == TRY_CATCH_EXPR)
  	/* We need to protect the initialization of a catch parm
--- 1178,1198 ----
  	   where we aren't initializing a real variable, so we don't want
  	   to run a new constructor; and catching an exception, where we
  	   have already built up the constructor call so we could wrap it
  	   in an exception region.  */;
        else if (TREE_CODE (init) == CONSTRUCTOR)
! 	{
! 	  if (!TYPE_HAS_CONSTRUCTOR (type))
! 	    /* A brace-enclosed initializer has whatever type is
! 	       required.  There's no need to convert it.  */
! 	    ;
! 	  else
! 	    init = ocp_convert (type, 
! 				TREE_VALUE (CONSTRUCTOR_ELTS (init)),
! 				CONV_IMPLICIT | CONV_FORCE_TEMP, 
! 				flags);
! 	}
        else
  	init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
  
        if (TREE_CODE (init) == TRY_CATCH_EXPR)
  	/* We need to protect the initialization of a catch parm
*************** expand_aggr_init_1 (binfo, true_exp, exp
*** 1257,1266 ****
--- 1261,1271 ----
       int flags;
  {
    tree type = TREE_TYPE (exp);
  
    my_friendly_assert (init != error_mark_node && type != error_mark_node, 211);
+   my_friendly_assert (building_stmt_tree (), 20021010);
  
    /* Use a function returning the desired type to initialize EXP for us.
       If the function is a constructor, and its first argument is
       NULL_TREE, know that it was meant for us--just slide exp on
       in and expand the constructor.  Constructors now come
*************** expand_aggr_init_1 (binfo, true_exp, exp
*** 1271,1286 ****
        && TREE_HAS_CONSTRUCTOR (init))
      {
        /* If store_init_value returns NULL_TREE, the INIT has been
  	 record in the DECL_INITIAL for EXP.  That means there's
  	 nothing more we have to do.  */
!       if (!store_init_value (exp, init))
! 	{
! 	  if (!building_stmt_tree ())
! 	    expand_decl_init (exp);
! 	}
!       else
  	finish_expr_stmt (build (INIT_EXPR, type, exp, init));
        return;
      }
  
    /* We know that expand_default_init can handle everything we want
--- 1276,1286 ----
        && TREE_HAS_CONSTRUCTOR (init))
      {
        /* If store_init_value returns NULL_TREE, the INIT has been
  	 record in the DECL_INITIAL for EXP.  That means there's
  	 nothing more we have to do.  */
!       if (store_init_value (exp, init))
  	finish_expr_stmt (build (INIT_EXPR, type, exp, init));
        return;
      }
  
    /* We know that expand_default_init can handle everything we want
*************** build_vec_init (base, init, from_array)
*** 2723,2736 ****
    tree maxindex = array_type_nelts (TREE_TYPE (base));
  
    if (maxindex == error_mark_node)
      return error_mark_node;
  
-   /* For g++.ext/arrnew.C.  */
-   if (init && TREE_CODE (init) == CONSTRUCTOR && TREE_TYPE (init) == NULL_TREE)
-     init = digest_init (atype, init, 0);
-       
    if (init
        && (from_array == 2
  	  ? (!CLASS_TYPE_P (type) || !TYPE_HAS_COMPLEX_ASSIGN_REF (type))
  	  : !TYPE_NEEDS_CONSTRUCTING (type))
        && ((TREE_CODE (init) == CONSTRUCTOR
--- 2723,2732 ----
*************** build_vec_init (base, init, from_array)
*** 2743,2753 ****
        /* Do non-default initialization of POD arrays resulting from
  	 brace-enclosed initializers.  In this case, digest_init and
  	 store_constructor will handle the semantics for us.  */
  
        stmt_expr = build (INIT_EXPR, atype, base, init);
-       TREE_SIDE_EFFECTS (stmt_expr) = 1;
        return stmt_expr;
      }
  
    maxindex = cp_convert (ptrdiff_type_node, maxindex);
    ptype = build_pointer_type (type);
--- 2739,2748 ----
Index: cp/parse.y
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parse.y,v
retrieving revision 1.281
diff -c -5 -p -r1.281 parse.y
*** cp/parse.y	2 Oct 2002 20:01:35 -0000	1.281
--- cp/parse.y	11 Oct 2002 16:19:58 -0000
*************** new_initializer:
*** 1349,1373 ****
  	| '(' typespec ')'
  		{
  		  error ("`%T' is not a valid expression", $2.t);
  		  $$ = error_mark_node;
  		}
- 	/* GNU extension so people can use initializer lists.  Note that
- 	   this alters the meaning of `new int = 1', which was previously
- 	   syntactically valid but semantically invalid.
-            This feature is now deprecated and will be removed in a future
-            release.  */
  	| '=' init
  		{
! 		  if (pedantic)
! 		    pedwarn ("ISO C++ forbids initialization of new expression with `='");
! 		  cp_deprecated ("new initializer lists extension");
! 		  if (TREE_CODE ($2) != TREE_LIST
! 		      && TREE_CODE ($2) != CONSTRUCTOR)
! 		    $$ = build_tree_list (NULL_TREE, $2);
! 		  else
! 		    $$ = $2;
  		}
  	;
  
  /* This is necessary to postpone reduction of `int ((int)(int)(int))'.  */
  regcast_or_absdcl:
--- 1349,1364 ----
  	| '(' typespec ')'
  		{
  		  error ("`%T' is not a valid expression", $2.t);
  		  $$ = error_mark_node;
  		}
  	| '=' init
  		{
! 		  /* This was previously allowed as an extension, but
! 		     was removed in G++ 3.3.  */
! 		  error ("initialization of new expression with `='");
! 		  $$ = error_mark_node;
  		}
  	;
  
  /* This is necessary to postpone reduction of `int ((int)(int)(int))'.  */
  regcast_or_absdcl:
Index: cp/rtti.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/rtti.c,v
retrieving revision 1.143
diff -c -5 -p -r1.143 rtti.c
*** cp/rtti.c	29 Sep 2002 18:27:01 -0000	1.143
--- cp/rtti.c	11 Oct 2002 16:19:59 -0000
*************** get_pseudo_ti_init (type, var_desc, non_
*** 1094,1107 ****
--- 1094,1109 ----
                offset = cp_build_binary_op (BIT_IOR_EXPR, offset,
  					   build_int_2 (flags, 0));
                base_init = tree_cons (NULL_TREE, offset, base_init);
                base_init = tree_cons (NULL_TREE, tinfo, base_init);
                base_init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, base_init);
+ 	      TREE_HAS_CONSTRUCTOR (base_init) = 1;
                base_inits = tree_cons (NULL_TREE, base_init, base_inits);
              }
  	  base_inits = build (CONSTRUCTOR,
  			      NULL_TREE, NULL_TREE, base_inits);
+ 	  TREE_HAS_CONSTRUCTOR (base_inits) = 1;
  	  base_inits = tree_cons (NULL_TREE, base_inits, NULL_TREE);
  	  /* Prepend the number of bases.  */
  	  base_inits = tree_cons (NULL_TREE,
  				  build_int_2 (nbases, 0), base_inits);
  	  /* Prepend the hint flags.  */
*************** create_pseudo_type_info VPARAMS((const c
*** 1161,1171 ****
      fields[++ix] = field_decl;
    
    /* Create the pseudo type.  */
    pseudo_type = make_aggr_type (RECORD_TYPE);
    finish_builtin_type (pseudo_type, pseudo_name, fields, ix, ptr_type_node);
!   TYPE_HAS_CONSTRUCTOR (pseudo_type) = 1;
  
    result = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE);
    TINFO_REAL_NAME (result) = get_identifier (real_name);
    TINFO_PSEUDO_TYPE (result) =
      cp_build_qualified_type (pseudo_type, TYPE_QUAL_CONST);
--- 1163,1173 ----
      fields[++ix] = field_decl;
    
    /* Create the pseudo type.  */
    pseudo_type = make_aggr_type (RECORD_TYPE);
    finish_builtin_type (pseudo_type, pseudo_name, fields, ix, ptr_type_node);
!   CLASSTYPE_AS_BASE (pseudo_type) = pseudo_type;
  
    result = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE);
    TINFO_REAL_NAME (result) = get_identifier (real_name);
    TINFO_PSEUDO_TYPE (result) =
      cp_build_qualified_type (pseudo_type, TYPE_QUAL_CONST);
Index: cp/typeck2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck2.c,v
retrieving revision 1.129
diff -c -5 -p -r1.129 typeck2.c
*** cp/typeck2.c	30 Sep 2002 16:52:15 -0000	1.129
--- cp/typeck2.c	11 Oct 2002 16:19:59 -0000
*************** store_init_value (decl, init)
*** 365,383 ****
  	}
      }
  
    /* End of special C++ code.  */
  
!   /* We might have already run this bracketed initializer through
!      digest_init.  Don't do so again.  */
!   if (TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init)
!       && TREE_TYPE (init)
!       && TYPE_MAIN_VARIANT (TREE_TYPE (init)) == TYPE_MAIN_VARIANT (type))
!     value = init;
!   else
!     /* Digest the specified initializer into an expression.  */
!     value = digest_init (type, init, (tree *) 0);
  
    /* Store the expression if valid; else report error.  */
  
    if (TREE_CODE (value) == ERROR_MARK)
      ;
--- 365,376 ----
  	}
      }
  
    /* End of special C++ code.  */
  
!   /* Digest the specified initializer into an expression.  */
!   value = digest_init (type, init, (tree *) 0);
  
    /* Store the expression if valid; else report error.  */
  
    if (TREE_CODE (value) == ERROR_MARK)
      ;
*************** digest_init (type, init, tail)
*** 437,448 ****
       tree type, init, *tail;
  {
    enum tree_code code = TREE_CODE (type);
    tree element = NULL_TREE;
    tree old_tail_contents = NULL_TREE;
!   /* Nonzero if INIT is a braced grouping, which comes in as a CONSTRUCTOR
!      tree node which has no TREE_TYPE.  */
    int raw_constructor;
  
    /* By default, assume we use one element from a list.
       We correct this later in the sole case where it is not true.  */
  
--- 430,440 ----
       tree type, init, *tail;
  {
    enum tree_code code = TREE_CODE (type);
    tree element = NULL_TREE;
    tree old_tail_contents = NULL_TREE;
!   /* Nonzero if INIT is a braced grouping.  */
    int raw_constructor;
  
    /* By default, assume we use one element from a list.
       We correct this later in the sole case where it is not true.  */
  
*************** digest_init (type, init, tail)
*** 469,482 ****
    
    /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
    if (TREE_CODE (init) == NON_LVALUE_EXPR)
      init = TREE_OPERAND (init, 0);
  
!   if (TREE_CODE (init) == CONSTRUCTOR && TREE_TYPE (init) == type)
!     return init;
! 
!   raw_constructor = TREE_CODE (init) == CONSTRUCTOR && TREE_TYPE (init) == 0;
  
    if (raw_constructor
        && CONSTRUCTOR_ELTS (init) != 0
        && TREE_CHAIN (CONSTRUCTOR_ELTS (init)) == 0)
      {
--- 461,472 ----
    
    /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
    if (TREE_CODE (init) == NON_LVALUE_EXPR)
      init = TREE_OPERAND (init, 0);
  
!   raw_constructor = (TREE_CODE (init) == CONSTRUCTOR 
! 		     && TREE_HAS_CONSTRUCTOR (init));
  
    if (raw_constructor
        && CONSTRUCTOR_ELTS (init) != 0
        && TREE_CHAIN (CONSTRUCTOR_ELTS (init)) == 0)
      {
Index: testsuite/g++.dg/init/array1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/init/array1.C,v
retrieving revision 1.1
diff -c -5 -p -r1.1 array1.C
*** testsuite/g++.dg/init/array1.C	9 Oct 2001 15:44:25 -0000	1.1
--- testsuite/g++.dg/init/array1.C	11 Oct 2002 16:20:00 -0000
***************
*** 4,22 ****
  // { dg-do run }
  
  typedef int iArr[];
  
  const iArr array4={
!   {1},{2},{3},{4}
  };
  
  const iArr array3={
!   {1},{2},{3}
  };
  
  const iArr array5={
!   {1},{2},{3},{4},{5}
  };
  
  int main()
  {
    if (sizeof (array4)/sizeof (array4[0]) != 4
--- 4,22 ----
  // { dg-do run }
  
  typedef int iArr[];
  
  const iArr array4={
!   1, 2, 3, 4
  };
  
  const iArr array3={
!   1, 2, 3
  };
  
  const iArr array5={
!   1, 2, 3, 4, 5
  };
  
  int main()
  {
    if (sizeof (array4)/sizeof (array4[0]) != 4
Index: testsuite/g++.dg/init/brace1.C
===================================================================
RCS file: testsuite/g++.dg/init/brace1.C
diff -N testsuite/g++.dg/init/brace1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/init/brace1.C	11 Oct 2002 16:20:00 -0000
***************
*** 0 ****
--- 1,4 ----
+ // { dg-do compile }
+ 
+ int i[4] = { { 3 } }; // { dg-error "brace" }
+ 
Index: testsuite/g++.dg/init/copy2.C
===================================================================
RCS file: testsuite/g++.dg/init/copy2.C
diff -N testsuite/g++.dg/init/copy2.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/init/copy2.C	11 Oct 2002 16:20:00 -0000
***************
*** 0 ****
--- 1,5 ----
+ // { dg-do compile }
+ 
+ struct S { S (); };
+ 
+ volatile S s[1] = { S () };
Index: testsuite/g++.dg/init/copy3.C
===================================================================
RCS file: testsuite/g++.dg/init/copy3.C
diff -N testsuite/g++.dg/init/copy3.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/init/copy3.C	11 Oct 2002 16:20:00 -0000
***************
*** 0 ****
--- 1,16 ----
+ // { dg-do run }
+ // { dg-options "-fno-elide-constructors" }
+ 
+ int copies;
+ 
+ struct S { 
+   S () {}
+   S (const S&) { ++copies; }
+ };
+ 
+ S s[1] = { S () };
+ 
+ int main () {
+   if (copies != 1)
+     return 1;
+ }
Index: testsuite/g++.old-deja/g++.ext/arrnew.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.ext/arrnew.C,v
retrieving revision 1.3
diff -c -5 -p -r1.3 arrnew.C
*** testsuite/g++.old-deja/g++.ext/arrnew.C	12 Feb 2001 14:29:13 -0000	1.3
--- testsuite/g++.old-deja/g++.ext/arrnew.C	11 Oct 2002 16:20:00 -0000
***************
*** 1,7 ****
  // PRMS Id: 4992
  // Build don't link:
  // Special g++ Options:
  
  int *f(){
!   return new int[1] = { 1 };   // WARNING - deprecated
  }
--- 1,7 ----
  // PRMS Id: 4992
  // Build don't link:
  // Special g++ Options:
  
  int *f(){
!   return new int[1] = { 1 };   // ERROR - removed
  }
Index: testsuite/g++.old-deja/g++.mike/p9129.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.mike/p9129.C,v
retrieving revision 1.3
diff -c -5 -p -r1.3 p9129.C
*** testsuite/g++.old-deja/g++.mike/p9129.C	16 Dec 1998 21:48:47 -0000	1.3
--- testsuite/g++.old-deja/g++.mike/p9129.C	11 Oct 2002 16:20:00 -0000
***************
*** 5,12 ****
  class Foo {
  public:
    int DoSomething();
  };
  
! int (Foo::*pA)() = { &Foo::DoSomething };	
  int (Foo::*X[1])(int) = { { &Foo::DoSomething } };		    // ERROR - 
  int (Foo::*Y[])(int) = { { &Foo::DoSomething, &Foo::DoSomething, 0 } }; // ERROR - 
--- 5,12 ----
  class Foo {
  public:
    int DoSomething();
  };
  
! int (Foo::*pA)() = { &Foo::DoSomething };	// ERROR - 
  int (Foo::*X[1])(int) = { { &Foo::DoSomething } };		    // ERROR - 
  int (Foo::*Y[])(int) = { { &Foo::DoSomething, &Foo::DoSomething, 0 } }; // ERROR - 


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