]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
call.c (build_new_op): Fix copy error.
authorJason Merrill <jason@yorick.cygnus.com>
Sat, 15 Nov 1997 08:36:08 +0000 (08:36 +0000)
committerJason Merrill <jason@gcc.gnu.org>
Sat, 15 Nov 1997 08:36:08 +0000 (03:36 -0500)
* call.c (build_new_op): Fix copy error.
(build_op_new_call): New fn.
(build_op_delete_call): New fn.
* cp-tree.h: Declare them.
* init.c (build_new): Use them.  Support placement delete.
(build_x_delete): Use build_op_delete_call.
(build_delete): Likewise.
* decl2.c (delete_sanity): Likewise.
(coerce_delete_type): Don't complain about placement delete.

Support placement delete.

From-SVN: r16500

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/decl2.c
gcc/cp/init.c

index cf9198285ff759974ff57bcf34856272e6298aa2..597d7350550d0b3fe23ee11c372dc36f407543eb 100644 (file)
@@ -1,3 +1,15 @@
+Sat Nov 15 00:30:51 1997  Jason Merrill  <jason@yorick.cygnus.com>
+
+       * call.c (build_new_op): Fix copy error.
+       (build_op_new_call): New fn.
+       (build_op_delete_call): New fn.
+       * cp-tree.h: Declare them.
+       * init.c (build_new): Use them.  Support placement delete.
+       (build_x_delete): Use build_op_delete_call.
+       (build_delete): Likewise.
+       * decl2.c (delete_sanity): Likewise.
+       (coerce_delete_type): Don't complain about placement delete.
+
 Thu Nov 13 01:52:36 1997  Jason Merrill  <jason@yorick.cygnus.com>
 
        * call.c (build_new_function_call): Remove unused 'obj' parm.
index f787b55a23cd79e5796d5be39641c71e83be7a75..e3086dda3952b152dbca4c9ad5a79753ade07aa2 100644 (file)
@@ -4861,8 +4861,8 @@ build_new_op (code, flags, arg1, arg2, arg3)
              templates = scratch_tree_cons (NULL_TREE, fn, templates);
              candidates 
                = add_template_candidate (candidates, fn, NULL_TREE,
-                                         this_arglist,  TREE_TYPE
-                                         (fnname), LOOKUP_NORMAL); 
+                                         this_arglist,  TREE_TYPE (fnname),
+                                         flags); 
            }
          else
            candidates = add_function_candidate
@@ -5071,6 +5071,143 @@ builtin:
     }
 }
 
+/* Build up a call to operator new.  This has to be handled differently
+   from other operators in the way lookup is handled; first members are
+   considered, then globals.  CODE is either NEW_EXPR or VEC_NEW_EXPR.
+   TYPE is the type to be created.  ARGS are any new-placement args.
+   FLAGS are the usual overloading flags.  */
+
+tree
+build_op_new_call (code, type, args, flags)
+     enum tree_code code;
+     tree type, args;
+     int flags;
+{
+  tree fnname = ansi_opname[code];
+
+  if (IS_AGGR_TYPE (type) && ! (flags & LOOKUP_GLOBAL)
+      && (TYPE_GETS_NEW (type) & (1 << (code == VEC_NEW_EXPR))))
+    {
+      tree dummy = build1 (NOP_EXPR, build_pointer_type (type),
+                          error_mark_node);
+      dummy = build_indirect_ref (dummy, "new");
+      return build_method_call (dummy, fnname, args, NULL_TREE, flags);
+    }
+  else
+    return build_new_function_call (lookup_name_nonclass (fnname), args);
+}
+
+/* Build a call to operator delete.  This has to be handled very specially,
+   because the restrictions on what signatures match are different from all
+   other call instances.  For a normal delete, only a delete taking (void *)
+   or (void *, size_t) is accepted.  For a placement delete, only an exact
+   match with the placement new is accepted.
+
+   CODE is either DELETE_EXPR or VEC_DELETE_EXPR.
+   ADDR is the pointer to be deleted.  For placement delete, it is also
+     used to determine what the corresponding new looked like.
+   SIZE is the size of the memory block to be deleted.
+   FLAGS are the usual overloading flags.  */
+
+tree
+build_op_delete_call (code, addr, size, flags)
+     enum tree_code code;
+     tree addr, size;
+     int flags;
+{
+  tree fn, fns, fnname, fntype, argtypes, args, type;
+  int placement;
+
+  if (addr == error_mark_node)
+    return error_mark_node;
+
+  type = TREE_TYPE (TREE_TYPE (addr));
+  fnname = ansi_opname[code];
+
+  if (IS_AGGR_TYPE (type) && ! (flags & LOOKUP_GLOBAL))
+    /* Here we make assumptions about how instantiate_type works.  This comes
+       out as a simple TREE_LIST, so it looks like overloaded globals to
+       instantiate_type; this works out fine.  If something changes we
+       might have to build this up like build_offset_ref does.  */
+    fns = lookup_fnfields (TYPE_BINFO (type), fnname, 0);
+  else
+    fns = NULL_TREE;
+
+  if (fns == NULL_TREE)
+    fns = lookup_name_nonclass (fnname);
+
+  /* We can recognize a placement delete because of LOOKUP_SPECULATIVELY;
+     if we are doing placement delete we do nothing if we don't find a
+     matching op delete.  */
+  placement = !!(flags & LOOKUP_SPECULATIVELY);
+  if (placement)
+    {
+      /* If placement, we are coming from build_new, and we know that addr
+        is the allocation expression, so extract the info we need from it.
+        Obviously, if the build_new process changes this may have to
+        change as well.  */
+      /* The SAVE_EXPR.  */
+      tree t = TREE_OPERAND (addr, 0);
+      /* The CALL_EXPR.  */
+      t = TREE_OPERAND (t, 0);
+      /* The function.  */
+      argtypes = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
+      /* The second parm type.  */
+      argtypes = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (argtypes)));
+      /* The second argument.  */
+      args = TREE_CHAIN (TREE_OPERAND (t, 1));
+    }
+  else
+    {
+      /* First try it without the size argument.  */
+      argtypes = void_list_node;
+      args = NULL_TREE;
+    }
+
+  argtypes = tree_cons (NULL_TREE, ptr_type_node, argtypes);
+  fntype = build_function_type (void_type_node, argtypes);
+
+  /* Strip const and volatile from addr.  */
+  if (type != TYPE_MAIN_VARIANT (type))
+    addr = cp_convert (build_pointer_type (TYPE_MAIN_VARIANT (type)), addr);
+
+  /* instantiate_type will always return a plain function; pretend it's
+     overloaded.  */
+  if (TREE_CODE (fns) == FUNCTION_DECL)
+    fns = scratch_tree_cons (NULL_TREE, fns, NULL_TREE);
+
+  fn = instantiate_type (fntype, fns, 0);
+
+  if (fn != error_mark_node)
+    {
+      if (TREE_PURPOSE (fns))
+       /* TREE_PURPOSE is only set for lists of member functions.  */
+       enforce_access (TREE_PURPOSE (fns), fn);
+      return build_function_call (fn, expr_tree_cons (NULL_TREE, addr, args));
+    }
+
+  if (placement)
+    return NULL_TREE;
+
+  /* Normal delete; now try to find a match including the size argument.  */
+  argtypes = tree_cons (NULL_TREE, ptr_type_node,
+                       tree_cons (NULL_TREE, sizetype, void_list_node));
+  fntype = build_function_type (void_type_node, argtypes);
+
+  fn = instantiate_type (fntype, fns, 0);
+
+  if (fn != error_mark_node)
+    return build_function_call
+      (fn, expr_tree_cons (NULL_TREE, addr,
+                          build_expr_list (NULL_TREE, size)));
+
+  cp_error ("no suitable operator delete for `%T'", type);
+  return error_mark_node;
+}
+
+/* If the current scope isn't allowed to access FUNCTION along
+   BASETYPE_PATH, give an error.  */
+
 static void
 enforce_access (basetype_path, function)
      tree basetype_path, function;
index b931a5cd21bea2ca0fb39009c7503d5b27f5ed69..47b9fe6062eff0a2b3980010f5815eb7f346d64d 100644 (file)
@@ -1957,6 +1957,8 @@ extern tree type_decays_to                        PROTO((tree));
 extern tree build_user_type_conversion         PROTO((tree, tree, int));
 extern tree build_new_function_call            PROTO((tree, tree));
 extern tree build_new_op                       PROTO((enum tree_code, int, tree, tree, tree));
+extern tree build_op_new_call                  PROTO((enum tree_code, tree, tree, int));
+extern tree build_op_delete_call               PROTO((enum tree_code, tree, tree, int));
 extern int can_convert                         PROTO((tree, tree));
 extern int can_convert_arg                     PROTO((tree, tree, tree));
 
index 583b7d403ad5418f9bce97596efab5d6948a60d1..fbe5c80bf097c86f2f52e15774b2fa53fe32afe0 100644 (file)
@@ -1310,8 +1310,8 @@ delete_sanity (exp, size, doing_vec, use_global_delete)
        {
          /* Only do access checking here; we'll be calling op delete
             from the destructor.  */
-         tree tmp = build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, t,
-                                    size_zero_node, NULL_TREE);
+         tree tmp = build_op_delete_call (DELETE_EXPR, t,
+                                          size_zero_node, LOOKUP_NORMAL);
          if (tmp == error_mark_node)
            return error_mark_node;
        }
@@ -2403,6 +2403,7 @@ coerce_delete_type (type)
       || TREE_VALUE (arg_types) != ptr_type_node)
     e2 = 1, error ("`operator delete' takes type `void *' as first parameter");
 
+#if 0
   if (arg_types
       && TREE_CHAIN (arg_types)
       && TREE_CHAIN (arg_types) != void_list_node)
@@ -2434,8 +2435,12 @@ coerce_delete_type (type)
        arg_types = tree_cons (NULL_TREE, ptr_type_node, TREE_CHAIN (arg_types));
     }
   else e3 |= e1;
+#endif
 
-  if (e3)
+  if (e2)
+    arg_types = tree_cons (NULL_TREE, ptr_type_node,
+                          arg_types ? TREE_CHAIN (arg_types): NULL_TREE);
+  if (e2 || e1)
     type = build_function_type (void_type_node, arg_types);
 
   return type;
index c1df1d978f5a551aaa87355cca0d182bb94766b3..c5604e14681d6fc14b31d4c57aefd949bfc222ef 100644 (file)
@@ -2493,18 +2493,9 @@ build_new (placement, decl, init, use_global_new)
     }
 
   /* Allocate the object.  */
-  if (! use_global_new && TYPE_LANG_SPECIFIC (true_type)
-      && (TYPE_GETS_NEW (true_type) & (1 << has_array)))
-    rval = build_opfncall (code, LOOKUP_NORMAL,
-                          build_pointer_type (true_type), size, placement);
-  else if (placement)
-    {
-      rval = build_opfncall (code, LOOKUP_GLOBAL|LOOKUP_COMPLAIN,
-                            ptr_type_node, size, placement);
-      rval = cp_convert (build_pointer_type (true_type), rval);
-    }
-  else if (! has_array && flag_this_is_variable > 0
-          && TYPE_NEEDS_CONSTRUCTING (true_type) && init != void_type_node)
+  
+  if (! has_array && ! placement && flag_this_is_variable > 0
+      && TYPE_NEEDS_CONSTRUCTING (true_type) && init != void_type_node)
     {
       if (init == NULL_TREE || TREE_CODE (init) == TREE_LIST)
        rval = NULL_TREE;
@@ -2516,10 +2507,10 @@ build_new (placement, decl, init, use_global_new)
     }
   else
     {
-      rval = build_builtin_call (build_pointer_type (true_type),
-                                has_array ? BIVN : BIN,
-                                build_expr_list (NULL_TREE, size));
-      TREE_CALLS_NEW (rval) = 1;
+      rval = build_op_new_call
+       (code, true_type, expr_tree_cons (NULL_TREE, size, placement),
+        LOOKUP_NORMAL | (use_global_new * LOOKUP_GLOBAL));
+      rval = cp_convert (build_pointer_type (true_type), rval);
     }
 
   if (flag_exceptions && rval)
@@ -2719,27 +2710,27 @@ build_new (placement, decl, init, use_global_new)
         an exception and the new-expression does not contain a
         new-placement, then the deallocation function is called to free
         the memory in which the object was being constructed.  */
-      /* FIXME: handle placement delete.  */
-      if (flag_exceptions && ! placement)
+      if (flag_exceptions && alloc_expr)
        {
-         tree cleanup = alloc_expr;
+         enum tree_code dcode = has_array? VEC_DELETE_EXPR : DELETE_EXPR;
+         tree cleanup, args = NULL_TREE;
+         int flags = LOOKUP_NORMAL | (use_global_new * LOOKUP_GLOBAL);
 
          /* All cleanups must last longer than normal.  */
          int yes = suspend_momentary ();
 
-         if (! use_global_new && TYPE_LANG_SPECIFIC (true_type)
-             && (TYPE_GETS_DELETE (true_type) & (1 << has_array)))
-           cleanup = build_opfncall (has_array? VEC_DELETE_EXPR : DELETE_EXPR,
-                                     LOOKUP_NORMAL, cleanup, size, NULL_TREE);
-         else
-           cleanup = build_builtin_call
-             (void_type_node, has_array ? BIVD : BID,
-              build_expr_list (NULL_TREE, cleanup));
+         if (placement)
+           flags |= LOOKUP_SPECULATIVELY;
+
+         cleanup = build_op_delete_call (dcode, alloc_expr, size, flags);
 
          resume_momentary (yes);
-                                        
-         rval = build (TRY_CATCH_EXPR, TREE_TYPE (rval), rval, cleanup);
-         rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
+
+         if (cleanup)
+           {
+             rval = build (TRY_CATCH_EXPR, TREE_TYPE (rval), rval, cleanup);
+             rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
+           }
        }
     }
   else if (TYPE_READONLY (true_type))
@@ -3196,16 +3187,10 @@ build_x_delete (type, addr, which_delete, virtual_size)
 {
   int use_global_delete = which_delete & 1;
   int use_vec_delete = !!(which_delete & 2);
-  tree rval;
   enum tree_code code = use_vec_delete ? VEC_DELETE_EXPR : DELETE_EXPR;
+  int flags = LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL);
 
-  if (! use_global_delete && TYPE_LANG_SPECIFIC (TREE_TYPE (type))
-      && (TYPE_GETS_DELETE (TREE_TYPE (type)) & (1 << use_vec_delete)))
-    rval = build_opfncall (code, LOOKUP_NORMAL, addr, virtual_size, NULL_TREE);
-  else
-    rval = build_builtin_call (void_type_node, use_vec_delete ? BIVD : BID,
-                              build_expr_list (NULL_TREE, addr));
-  return rval;
+  return build_op_delete_call (code, addr, virtual_size, flags);
 }
 
 /* Generate a call to a destructor. TYPE is the type to cast ADDR to.
@@ -3302,18 +3287,9 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
       if (auto_delete == integer_zero_node)
        return void_zero_node;
 
-      /* Pass the size of the object down to the operator delete() in
-        addition to the ADDR.  */
-      if (TYPE_GETS_REG_DELETE (type) && !use_global_delete)
-       {
-         tree virtual_size = c_sizeof_nowarn (type);
-         return build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, addr,
-                                virtual_size, NULL_TREE);
-       }
-
-      /* Call the builtin operator delete.  */
-      return build_builtin_call (void_type_node, BID,
-                                build_expr_list (NULL_TREE, addr));
+      return build_op_delete_call
+       (DELETE_EXPR, addr, c_sizeof_nowarn (type),
+        LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL));
     }
 
   /* Below, we will reverse the order in which these calls are made.