OSDN Git Service

gcc/testsuite
[pf3gnuchains/gcc-fork.git] / gcc / cp / init.c
index 8faa03d..a6da19f 100644 (file)
@@ -1,13 +1,14 @@
 /* Handle initialization things in C++.
    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -16,9 +17,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* High-level class interface.  */
 
@@ -51,7 +51,6 @@ static tree initializing_context (tree);
 static void expand_cleanup_for_base (tree, tree);
 static tree get_temp_regvar (tree, tree);
 static tree dfs_initialize_vtbl_ptrs (tree, void *);
-static tree build_default_init (tree, tree);
 static tree build_dtor_call (tree, special_function_kind, int);
 static tree build_field_list (tree, tree, int *);
 static tree build_vtbl_address (tree);
@@ -137,11 +136,12 @@ initialize_vtbl_ptrs (tree addr)
 /* Return an expression for the zero-initialization of an object with
    type T.  This expression will either be a constant (in the case
    that T is a scalar), or a CONSTRUCTOR (in the case that T is an
-   aggregate).  In either case, the value can be used as DECL_INITIAL
-   for a decl of the indicated TYPE; it is a valid static initializer.
-   If NELTS is non-NULL, and TYPE is an ARRAY_TYPE, NELTS is the
-   number of elements in the array.  If STATIC_STORAGE_P is TRUE,
-   initializers are only generated for entities for which
+   aggregate), or NULL (in the case that T does not require
+   initialization).  In either case, the value can be used as
+   DECL_INITIAL for a decl of the indicated TYPE; it is a valid static
+   initializer. If NELTS is non-NULL, and TYPE is an ARRAY_TYPE, NELTS
+   is the number of elements in the array.  If STATIC_STORAGE_P is
+   TRUE, initializers are only generated for entities for which
    zero-initialization does not simply mean filling the storage with
    zero bytes.  */
 
@@ -178,8 +178,7 @@ build_zero_init (tree type, tree nelts, bool static_storage_p)
        items with static storage duration that are not otherwise
        initialized are initialized to zero.  */
     ;
-  else if (SCALAR_TYPE_P (type)
-          || TREE_CODE (type) == COMPLEX_TYPE)
+  else if (SCALAR_TYPE_P (type))
     init = convert (type, integer_zero_node);
   else if (CLASS_TYPE_P (type))
     {
@@ -196,12 +195,13 @@ build_zero_init (tree type, tree nelts, bool static_storage_p)
             corresponding to base classes as well.  Thus, iterating
             over TYPE_FIELDs will result in correct initialization of
             all of the subobjects.  */
-         if (static_storage_p && !zero_init_p (TREE_TYPE (field)))
+         if (!static_storage_p || !zero_init_p (TREE_TYPE (field)))
            {
              tree value = build_zero_init (TREE_TYPE (field),
                                            /*nelts=*/NULL_TREE,
                                            static_storage_p);
-             CONSTRUCTOR_APPEND_ELT(v, field, value);
+             if (value)
+               CONSTRUCTOR_APPEND_ELT(v, field, value);
            }
 
          /* For unions, only the first field is initialized.  */
@@ -276,7 +276,7 @@ build_zero_init (tree type, tree nelts, bool static_storage_p)
    returns NULL_TREE; the caller is responsible for arranging for the
    constructors to be called.  */
 
-static tree
+tree
 build_default_init (tree type, tree nelts)
 {
   /* [dcl.init]:
@@ -786,7 +786,7 @@ expand_virtual_init (tree binfo, tree decl)
 
       /* Compute the value to use, when there's a VTT.  */
       vtt_parm = current_vtt_parm;
-      vtbl2 = build2 (PLUS_EXPR,
+      vtbl2 = build2 (POINTER_PLUS_EXPR,
                      TREE_TYPE (vtt_parm),
                      vtt_parm,
                      vtt_index);
@@ -863,7 +863,7 @@ construct_virtual_base (tree vbase, tree arguments)
      confuses the sjlj exception-handling code.  Therefore, we do not
      create a single conditional block, but one for each
      initialization.  (That way the cleanup regions always begin
-     in the outer block.)  We trust the back-end to figure out
+     in the outer block.)  We trust the back end to figure out
      that the FLAG will not change across initializations, and
      avoid doing multiple tests.  */
   flag = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
@@ -1135,7 +1135,6 @@ build_aggr_init (tree exp, tree init, int flags)
     /* Just know that we've seen something for this node.  */
     TREE_USED (exp) = 1;
 
-  TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
   is_global = begin_init_stmts (&stmt_expr, &compound_stmt);
   destroy_temps = stmts_are_full_exprs_p ();
   current_stmt_tree ()->stmts_are_full_exprs_p = 0;
@@ -1143,7 +1142,6 @@ build_aggr_init (tree exp, tree init, int flags)
                      init, LOOKUP_NORMAL|flags);
   stmt_expr = finish_init_stmts (is_global, stmt_expr, compound_stmt);
   current_stmt_tree ()->stmts_are_full_exprs_p = destroy_temps;
-  TREE_TYPE (exp) = type;
   TREE_READONLY (exp) = was_const;
   TREE_THIS_VOLATILE (exp) = was_volatile;
 
@@ -1283,9 +1281,7 @@ is_aggr_type (tree type, int or_else)
   if (type == error_mark_node)
     return 0;
 
-  if (! IS_AGGR_TYPE (type)
-      && TREE_CODE (type) != TEMPLATE_TYPE_PARM
-      && TREE_CODE (type) != BOUND_TEMPLATE_TEMPLATE_PARM)
+  if (! IS_AGGR_TYPE (type))
     {
       if (or_else)
        error ("%qT is not an aggregate type", type);
@@ -1383,9 +1379,9 @@ build_offset_ref (tree type, tree member, bool address_p)
               (or any class derived from that class).  */
          if (address_p && DECL_P (t)
              && DECL_NONSTATIC_MEMBER_P (t))
-           perform_or_defer_access_check (TYPE_BINFO (type), t);
+           perform_or_defer_access_check (TYPE_BINFO (type), t, t);
          else
-           perform_or_defer_access_check (basebinfo, t);
+           perform_or_defer_access_check (basebinfo, t, t);
 
          if (DECL_STATIC_FUNCTION_P (t))
            return t;
@@ -1398,7 +1394,7 @@ build_offset_ref (tree type, tree member, bool address_p)
     /* We need additional test besides the one in
        check_accessibility_of_qualified_id in case it is
        a pointer to non-static member.  */
-    perform_or_defer_access_check (TYPE_BINFO (type), member);
+    perform_or_defer_access_check (TYPE_BINFO (type), member, member);
 
   if (!address_p)
     {
@@ -1522,7 +1518,7 @@ integral_constant_value (tree decl)
 }
 
 /* A more relaxed version of integral_constant_value, used by the
-   common C/C++ code and by the C++ front-end for optimization
+   common C/C++ code and by the C++ front end for optimization
    purposes.  */
 
 tree
@@ -1540,7 +1536,7 @@ static tree
 build_builtin_delete_call (tree addr)
 {
   mark_used (global_delete_fndecl);
-  return build_call (global_delete_fndecl, build_tree_list (NULL_TREE, addr));
+  return build_call_n (global_delete_fndecl, 1, addr);
 }
 \f
 /* Build and return a NEW_EXPR.  If NELTS is non-NULL, TYPE[NELTS] is
@@ -1565,6 +1561,55 @@ build_raw_new_expr (tree placement, tree type, tree nelts, tree init,
   return new_expr;
 }
 
+/* Make sure that there are no aliasing issues with T, a placement new
+   expression applied to PLACEMENT, by recording the change in dynamic
+   type.  If placement new is inlined, as it is with libstdc++, and if
+   the type of the placement new differs from the type of the
+   placement location itself, then alias analysis may think it is OK
+   to interchange writes to the location from before the placement new
+   and from after the placement new.  We have to prevent type-based
+   alias analysis from applying.  PLACEMENT may be NULL, which means
+   that we couldn't capture it in a temporary variable, in which case
+   we use a memory clobber.  */
+
+static tree
+avoid_placement_new_aliasing (tree t, tree placement)
+{
+  tree type_change;
+
+  if (processing_template_decl)
+    return t;
+
+  /* If we are not using type based aliasing, we don't have to do
+     anything.  */
+  if (!flag_strict_aliasing)
+    return t;
+
+  /* If we have a pointer and a location, record the change in dynamic
+     type.  Otherwise we need a general memory clobber.  */
+  if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE
+      && placement != NULL_TREE
+      && TREE_CODE (TREE_TYPE (placement)) == POINTER_TYPE)
+    type_change = build_stmt (CHANGE_DYNAMIC_TYPE_EXPR,
+                             TREE_TYPE (t),
+                             placement);
+  else
+    {
+      /* Build a memory clobber.  */
+      type_change = build_stmt (ASM_EXPR,
+                               build_string (0, ""),
+                               NULL_TREE,
+                               NULL_TREE,
+                               tree_cons (NULL_TREE,
+                                          build_string (6, "memory"),
+                                          NULL_TREE));
+
+      ASM_VOLATILE_P (type_change) = 1;
+    }
+
+  return build2 (COMPOUND_EXPR, TREE_TYPE (t), type_change, t);
+}
+
 /* Generate code for a new-expression, including calling the "operator
    new" function, initializing the object, and, if an exception occurs
    during construction, cleaning up.  The arguments are as for
@@ -1608,6 +1653,7 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
      beginning of the storage allocated for an array-new expression in
      order to store the number of elements.  */
   tree cookie_size = NULL_TREE;
+  tree placement_expr;
   /* True if the function we are calling is a placement allocation
      function.  */
   bool placement_allocation_fn_p;
@@ -1641,6 +1687,7 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
          of the incomplete array type.  */
       full_type = build_distinct_type_copy (full_type);
       TYPE_DOMAIN (full_type) = index;
+      SET_TYPE_STRUCTURAL_EQUALITY (full_type);
     }
   else
     {
@@ -1654,9 +1701,6 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
        }
     }
 
-  if (!complete_type_or_else (type, NULL_TREE))
-    return error_mark_node;
-
   /* If our base type is an array, then make sure we know how many elements
      it has.  */
   for (elt_type = type;
@@ -1701,6 +1745,19 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
 
   alloc_fn = NULL_TREE;
 
+  /* If PLACEMENT is a simple pointer type, then copy it into
+     PLACEMENT_EXPR.  */
+  if (processing_template_decl
+      || placement == NULL_TREE
+      || TREE_CHAIN (placement) != NULL_TREE
+      || TREE_CODE (TREE_TYPE (TREE_VALUE (placement))) != POINTER_TYPE)
+    placement_expr = NULL_TREE;
+  else
+    {
+      placement_expr = get_target_expr (TREE_VALUE (placement));
+      placement = tree_cons (NULL_TREE, placement_expr, NULL_TREE);
+    }
+
   /* Allocate the object.  */
   if (! placement && TYPE_FOR_JAVA (elt_type))
     {
@@ -1729,6 +1786,11 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
                    (alloc_fn,
                     build_tree_list (NULL_TREE, class_addr)));
     }
+  else if (TYPE_FOR_JAVA (elt_type) && IS_AGGR_TYPE (elt_type))
+    {
+      error ("Java class %q#T object allocated using placement new", elt_type);
+      return error_mark_node;
+    }
   else
     {
       tree fnname;
@@ -1793,7 +1855,12 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
   /* In the simple case, we can stop now.  */
   pointer_type = build_pointer_type (type);
   if (!cookie_size && !is_initialized)
-    return build_nop (pointer_type, alloc_call);
+    {
+      rval = build_nop (pointer_type, alloc_call);
+      if (placement != NULL)
+       rval = avoid_placement_new_aliasing (rval, placement_expr);
+      return rval;
+    }
 
   /* While we're working, use a pointer to the type we've actually
      allocated. Store the result of the call in a variable so that we
@@ -1848,16 +1915,19 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
     {
       tree cookie;
       tree cookie_ptr;
+      tree size_ptr_type;
 
       /* Adjust so we're pointing to the start of the object.  */
-      data_addr = get_target_expr (build2 (PLUS_EXPR, full_pointer_type,
+      data_addr = get_target_expr (build2 (POINTER_PLUS_EXPR, full_pointer_type,
                                           alloc_node, cookie_size));
 
       /* Store the number of bytes allocated so that we can know how
         many elements to destroy later.  We use the last sizeof
         (size_t) bytes to store the number of elements.  */
-      cookie_ptr = build2 (MINUS_EXPR, build_pointer_type (sizetype),
-                          data_addr, size_in_bytes (sizetype));
+      cookie_ptr = fold_build1 (NEGATE_EXPR, sizetype, size_in_bytes (sizetype));
+      size_ptr_type = build_pointer_type (sizetype);
+      cookie_ptr = build2 (POINTER_PLUS_EXPR, size_ptr_type,
+                          fold_convert (size_ptr_type, data_addr), cookie_ptr);
       cookie = build_indirect_ref (cookie_ptr, NULL);
 
       cookie_expr = build2 (MODIFY_EXPR, sizetype, cookie, nelts);
@@ -1865,8 +1935,10 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
       if (targetm.cxx.cookie_has_size ())
        {
          /* Also store the element size.  */
-         cookie_ptr = build2 (MINUS_EXPR, build_pointer_type (sizetype),
-                              cookie_ptr, size_in_bytes (sizetype));
+         cookie_ptr = build2 (POINTER_PLUS_EXPR, size_ptr_type, cookie_ptr,
+                              fold_build1 (NEGATE_EXPR, sizetype,
+                                           size_in_bytes (sizetype)));
+
          cookie = build_indirect_ref (cookie_ptr, NULL);
          cookie = build2 (MODIFY_EXPR, sizetype, cookie,
                           size_in_bytes(elt_type));
@@ -1970,8 +2042,7 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
                                          globally_qualified_p,
                                          (placement_allocation_fn_p
                                           ? alloc_call : NULL_TREE),
-                                         (placement_allocation_fn_p
-                                          ? alloc_fn : NULL_TREE));
+                                         alloc_fn);
 
          if (!cleanup)
            /* We're done.  */;
@@ -2053,6 +2124,9 @@ build_new_1 (tree placement, tree type, tree nelts, tree init,
   /* A new-expression is never an lvalue.  */
   gcc_assert (!lvalue_p (rval));
 
+  if (placement != NULL)
+    rval = avoid_placement_new_aliasing (rval, placement_expr);
+
   return rval;
 }
 
@@ -2075,7 +2149,8 @@ build_new (tree placement, tree type, tree nelts, tree init,
   tree orig_nelts;
   tree orig_init;
 
-  if (placement == error_mark_node || type == error_mark_node)
+  if (placement == error_mark_node || type == error_mark_node
+      || init == error_mark_node)
     return error_mark_node;
 
   orig_placement = placement;
@@ -2103,21 +2178,6 @@ build_new (tree placement, tree type, tree nelts, tree init,
       if (!build_expr_type_conversion (WANT_INT | WANT_ENUM, nelts, false))
        pedwarn ("size in array new must have integral type");
       nelts = cp_save_expr (cp_convert (sizetype, nelts));
-      /* It is valid to allocate a zero-element array:
-
-          [expr.new]
-
-          When the value of the expression in a direct-new-declarator
-          is zero, the allocation function is called to allocate an
-          array with no elements.  The pointer returned by the
-          new-expression is non-null.  [Note: If the library allocation
-          function is called, the pointer returned is distinct from the
-          pointer to any other object.]
-
-        However, that is not generally useful, so we issue a
-        warning.  */
-      if (integer_zerop (nelts))
-       warning (0, "allocating zero-element array");
     }
 
   /* ``A reference cannot be created by the new operator.  A reference
@@ -2135,6 +2195,12 @@ build_new (tree placement, tree type, tree nelts, tree init,
       return error_mark_node;
     }
 
+  /* The type allocated must be complete.  If the new-type-id was
+     "T[N]" then we are just checking that "T" is complete here, but
+     that is equivalent, since the value of "N" doesn't matter.  */
+  if (!complete_type_or_else (type, NULL_TREE))
+    return error_mark_node;
+
   rval = build_new_1 (placement, type, nelts, init, use_global_new);
   if (rval == error_mark_node)
     return error_mark_node;
@@ -2228,6 +2294,7 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
      executing any other code in the loop.
      This is also the containing expression returned by this function.  */
   tree controller = NULL_TREE;
+  tree tmp;
 
   /* We should only have 1-D arrays here.  */
   gcc_assert (TREE_CODE (type) != ARRAY_TYPE);
@@ -2241,8 +2308,8 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
 
   tbase = create_temporary_var (ptype);
   tbase_init = build_modify_expr (tbase, NOP_EXPR,
-                                 fold_build2 (PLUS_EXPR, ptype,
-                                              base,
+                                 fold_build2 (POINTER_PLUS_EXPR, ptype,
+                                              fold_convert (ptype, base),
                                               virtual_size));
   DECL_REGISTER (tbase) = 1;
   controller = build3 (BIND_EXPR, void_type_node, tbase,
@@ -2252,9 +2319,10 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
   body = build1 (EXIT_EXPR, void_type_node,
                 build2 (EQ_EXPR, boolean_type_node, tbase,
                         fold_convert (ptype, base)));
+  tmp = fold_build1 (NEGATE_EXPR, sizetype, size_exp);
   body = build_compound_expr
     (body, build_modify_expr (tbase, NOP_EXPR,
-                             build2 (MINUS_EXPR, ptype, tbase, size_exp)));
+                             build2 (POINTER_PLUS_EXPR, ptype, tbase, tmp)));
   body = build_compound_expr
     (body, build_delete (ptype, tbase, sfk_complete_destructor,
                         LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1));
@@ -2477,7 +2545,7 @@ build_vec_init (tree base, tree maxindex, tree init,
      When copying from array to another, when the array elements have
      only trivial copy constructors, we should use __builtin_memcpy
      rather than generating a loop.  That way, we could take advantage
-     of whatever cleverness the back-end has for dealing with copies
+     of whatever cleverness the back end has for dealing with copies
      of blocks of memory.  */
 
   is_global = begin_init_stmts (&stmt_expr, &compound_stmt);
@@ -2790,6 +2858,7 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
     }
   else
     {
+      tree head = NULL_TREE;
       tree do_delete = NULL_TREE;
       tree ifexp;
 
@@ -2803,8 +2872,9 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
        {
          /* We will use ADDR multiple times so we must save it.  */
          addr = save_expr (addr);
+         head = get_target_expr (build_headof (addr));
          /* Delete the object.  */
-         do_delete = build_builtin_delete_call (addr);
+         do_delete = build_builtin_delete_call (head);
          /* Otherwise, treat this like a complete object destructor
             call.  */
          auto_delete = sfk_complete_destructor;
@@ -2843,6 +2913,10 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
       if (do_delete)
        expr = build2 (COMPOUND_EXPR, void_type_node, expr, do_delete);
 
+      /* We need to calculate this before the dtor changes the vptr.  */
+      if (head)
+       expr = build2 (COMPOUND_EXPR, void_type_node, head, expr);
+
       if (flags & LOOKUP_DESTRUCTOR)
        /* Explicit destructor call; don't check for null pointer.  */
        ifexp = integer_one_node;
@@ -2975,10 +3049,11 @@ build_vec_delete (tree base, tree maxindex,
          base = TARGET_EXPR_SLOT (base_init);
        }
       type = strip_array_types (TREE_TYPE (type));
-      cookie_addr = build2 (MINUS_EXPR,
+      cookie_addr = fold_build1 (NEGATE_EXPR, sizetype, TYPE_SIZE_UNIT (sizetype));
+      cookie_addr = build2 (POINTER_PLUS_EXPR,
                            build_pointer_type (sizetype),
                            base,
-                           TYPE_SIZE_UNIT (sizetype));
+                           cookie_addr);
       maxindex = build_indirect_ref (cookie_addr, NULL);
     }
   else if (TREE_CODE (type) == ARRAY_TYPE)