N3778: Sized Deallocation
authorJason Merrill <jason@redhat.com>
Mon, 15 Dec 2014 18:31:40 +0000 (13:31 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 15 Dec 2014 18:31:40 +0000 (13:31 -0500)
N3778: Sized Deallocation
gcc/c-family/
* c.opt (-fsized-deallocation, -Wc++14-compat): New.
(-Wsized-deallocation): New.
* c-opts.c (c_common_post_options): -fsized-deallocation defaults
to on in C++14 and up.
gcc/cp/
* call.c (non_placement_deallocation_fn_p): A global sized
operator delete is not a usual deallocation function until C++14.
(build_op_delete_call): Choose the global sized op delete if we
know the size.
* cp-tree.h: Declare non_placement_deallocation_fn_p.
(enum cp_tree_index): Remove CPTI_GLOBAL_DELETE_FNDECL.
(global_delete_fndecl): Remove.
* decl.c (cxx_init_decl_processing): Also declare sized op deletes.
(grok_op_properties): Warn about sized dealloc without the flag.
* init.c (build_builtin_delete_call): Remove.
(build_vec_delete_1, build_delete): Don't call it.
* decl2.c (maybe_warn_sized_delete): New.
(cp_write_global_declarations): Call it.
libstdc++-v3/
* libsupc++/del_ops.cc: New.
* libsupc++/del_opvs.cc: New.
* libsupc++/Makefile.am: Add them.
* libsupc++/Makefile.in: Regenerate.
* config/abi/pre/gnu.ver: Export _ZdlPvm and _ZdaPvm.

From-SVN: r218755

20 files changed:
gcc/c-family/ChangeLog
gcc/c-family/c-opts.c
gcc/c-family/c.opt
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/init.c
gcc/doc/invoke.texi
gcc/testsuite/g++.dg/cpp1y/sized-dealloc1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/sized-dealloc2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1y/sized-dealloc3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tree-ssa/pr61034.C
libstdc++-v3/ChangeLog
libstdc++-v3/config/abi/pre/gnu.ver
libstdc++-v3/libsupc++/Makefile.am
libstdc++-v3/libsupc++/Makefile.in
libstdc++-v3/libsupc++/del_ops.cc [new file with mode: 0644]
libstdc++-v3/libsupc++/del_opvs.cc [new file with mode: 0644]

index f064370cc783ef4a507710ef658f423601ea96ea..2d0c2fe58720bc690415d18d0d50ea234234d037 100644 (file)
@@ -1,3 +1,10 @@
+2014-12-15  Jason Merrill  <jason@redhat.com>
+
+       * c.opt (-fsized-deallocation, -Wc++14-compat): New.
+       (-Wsized-deallocation): New.
+       * c-opts.c (c_common_post_options): -fsized-deallocation defaults
+       to on in C++14 and up.
+
 2014-12-11  Jason Merrill  <jason@redhat.com>
 
        * c-cppbuiltin.c (c_cpp_builtins): Enable C++14 __cpp_constexpr.
index 08a36f03c8ccef079c9f8ea149599b30d4c88582..dbb99125462712f9affebfca5cdf479ab1054d2a 100644 (file)
@@ -889,6 +889,10 @@ c_common_post_options (const char **pfilename)
   else if (warn_narrowing == -1)
     warn_narrowing = 0;
 
+  /* Global sized deallocation is new in C++14.  */
+  if (flag_sized_deallocation == -1)
+    flag_sized_deallocation = (cxx_dialect >= cxx14);
+
   if (flag_extern_tls_init)
     {
 #if !defined (ASM_OUTPUT_DEF) || !SUPPORTS_WEAK
index b9f7c6562091fb7dc8d96da5df69f2cd7332c86c..1676f65bcd2532cff0bc7ea068c4700c9c90cbd6 100644 (file)
@@ -315,6 +315,10 @@ Wc++11-compat
 C++ ObjC++ Warning Alias(Wc++0x-compat)
 Warn about C++ constructs whose meaning differs between ISO C++ 1998 and ISO C++ 2011
 
+Wc++14-compat
+C++ ObjC++ Var(warn_cxx14_compat) Warning LangEnabledBy(C++ ObjC++,Wall)
+Warn about C++ constructs whose meaning differs between ISO C++ 2011 and ISO C++ 2014
+
 Wcast-qual
 C ObjC C++ ObjC++ Var(warn_cast_qual) Warning
 Warn about casts which discard qualifiers
@@ -554,6 +558,10 @@ Wmissing-field-initializers
 C ObjC C++ ObjC++ Var(warn_missing_field_initializers) Warning EnabledBy(Wextra)
 Warn about missing fields in struct initializers
 
+Wsized-deallocation
+C++ ObjC++ Var(warn_sized_deallocation) Warning EnabledBy(Wextra)
+Warn about missing sized deallocation functions
+
 Wsizeof-pointer-memaccess
 C ObjC C++ ObjC++ Var(warn_sizeof_pointer_memaccess) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
 Warn about suspicious length parameters to certain string functions if the argument uses sizeof
@@ -1341,6 +1349,10 @@ fsigned-char
 C ObjC C++ ObjC++ LTO Var(flag_signed_char)
 Make \"char\" signed by default
 
+fsized-deallocation
+C++ ObjC++ Var(flag_sized_deallocation) Init(-1)
+Enable C++14 sized deallocation support
+
 fsquangle
 C++ ObjC++ Ignore Warn(switch %qs is no longer supported)
 
index 4eb762c91abf1289c57ba5030a033044c95e39b0..c14020dafd61d222f95f89c34988a200fd8c6077 100644 (file)
@@ -1,3 +1,20 @@
+2014-12-15  Jason Merrill  <jason@redhat.com>
+
+       N3778: Sized Deallocation
+       * call.c (non_placement_deallocation_fn_p): A global sized
+       operator delete is not a usual deallocation function until C++14.
+       (build_op_delete_call): Choose the global sized op delete if we
+       know the size.
+       * cp-tree.h: Declare non_placement_deallocation_fn_p.
+       (enum cp_tree_index): Remove CPTI_GLOBAL_DELETE_FNDECL.
+       (global_delete_fndecl): Remove.
+       * decl.c (cxx_init_decl_processing): Also declare sized op deletes.
+       (grok_op_properties): Warn about sized dealloc without the flag.
+       * init.c (build_builtin_delete_call): Remove.
+       (build_vec_delete_1, build_delete): Don't call it.
+       * decl2.c (maybe_warn_sized_delete): New.
+       (cp_write_global_declarations): Call it.
+
 2014-12-15  Paolo Carlini  <paolo.carlini@oracle.com>
 
        PR c++/58882
index 312dfdf242101a2434caa68d443ace2dd23949f7..86c78ab47f604053ad797ec7e09949ac7938c6db 100644 (file)
@@ -5733,7 +5733,7 @@ build_new_op (location_t loc, enum tree_code code, int flags,
 /* Returns true iff T, an element of an OVERLOAD chain, is a usual
    deallocation function (3.7.4.2 [basic.stc.dynamic.deallocation]).  */
 
-static bool
+bool
 non_placement_deallocation_fn_p (tree t)
 {
   /* A template instance is never a usual deallocation function,
@@ -5749,9 +5749,11 @@ non_placement_deallocation_fn_p (tree t)
      function named operator delete with exactly two parameters, the second
      of which has type std::size_t (18.2), then this function is a usual
      deallocation function.  */
+  bool global = DECL_NAMESPACE_SCOPE_P (t);
   t = FUNCTION_ARG_CHAIN (t);
   if (t == void_list_node
       || (t && same_type_p (TREE_VALUE (t), size_type_node)
+         && (!global || flag_sized_deallocation)
          && TREE_CHAIN (t) == void_list_node))
     return true;
   return false;
@@ -5883,9 +5885,39 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
               which has type std::size_t (18.2), then this function is a
               usual deallocation function."
 
-              So (void*) beats (void*, size_t).  */
-           if (FUNCTION_ARG_CHAIN (fn) == void_list_node)
-             break;
+              So in a class (void*) beats (void*, size_t).  */
+           if (DECL_CLASS_SCOPE_P (fn))
+             {
+               if (FUNCTION_ARG_CHAIN (fn) == void_list_node)
+                 break;
+             }
+           /* At global scope (in C++14 and above) the rules are different:
+
+              If deallocation function lookup finds both a usual
+              deallocation function with only a pointer parameter and a
+              usual deallocation function with both a pointer parameter
+              and a size parameter, the function to be called is selected
+              as follows:
+
+              * If the type is complete and if, for the second alternative
+              (delete array) only, the operand is a pointer to a class
+              type with a non-trivial destructor or a (possibly
+              multi-dimensional) array thereof, the function with two
+              parameters is selected.
+
+              * Otherwise, it is unspecified which of the two deallocation
+              functions is selected. */
+           else
+             {
+               bool want_size = COMPLETE_TYPE_P (type);
+               if (code == VEC_DELETE_EXPR
+                   && !TYPE_VEC_NEW_USES_COOKIE (type))
+                 /* We need a cookie to determine the array size.  */
+                 want_size = false;
+               bool have_size = (FUNCTION_ARG_CHAIN (fn) != void_list_node);
+               if (want_size == have_size)
+                 break;
+             }
          }
       }
 
index e8516606184fb43a7bdb5db22d697a3d38cd3f97..e0e7690b1889c99d1a46e73a734db9848b4d697e 100644 (file)
@@ -891,7 +891,6 @@ enum cp_tree_index
     CPTI_CONST_TYPE_INFO_TYPE,
     CPTI_TYPE_INFO_PTR_TYPE,
     CPTI_ABORT_FNDECL,
-    CPTI_GLOBAL_DELETE_FNDECL,
     CPTI_AGGR_TAG,
 
     CPTI_CTOR_IDENTIFIER,
@@ -962,7 +961,6 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 #define const_type_info_type_node      cp_global_trees[CPTI_CONST_TYPE_INFO_TYPE]
 #define type_info_ptr_type             cp_global_trees[CPTI_TYPE_INFO_PTR_TYPE]
 #define abort_fndecl                   cp_global_trees[CPTI_ABORT_FNDECL]
-#define global_delete_fndecl           cp_global_trees[CPTI_GLOBAL_DELETE_FNDECL]
 #define current_aggr                   cp_global_trees[CPTI_AGGR_TAG]
 #define nullptr_node                   cp_global_trees[CPTI_NULLPTR]
 #define nullptr_type_node              cp_global_trees[CPTI_NULLPTR_TYPE]
@@ -5185,6 +5183,7 @@ extern tree build_new_op                  (location_t, enum tree_code,
                                                 tsubst_flags_t);
 extern tree build_op_call                      (tree, vec<tree, va_gc> **,
                                                 tsubst_flags_t);
+extern bool non_placement_deallocation_fn_p    (tree);
 extern tree build_op_delete_call               (enum tree_code, tree, tree,
                                                 bool, tree, tree,
                                                 tsubst_flags_t);
index d47865287a83c2ded66aa424a465b307d842990c..bbaf3d68d9e757db46d3a27d4e363711feaddc3b 100644 (file)
@@ -159,10 +159,6 @@ static void expand_static_init (tree, tree);
 
        tree abort_fndecl;
 
-   The FUNCTION_DECL for the default `::operator delete'.
-
-       tree global_delete_fndecl;
-
    Used by RTTI
        tree type_info_type_node, tinfo_decl_id, tinfo_decl_type;
        tree tinfo_var_id;  */
@@ -3954,8 +3950,22 @@ cxx_init_decl_processing (void)
     opnew = push_cp_library_fn (VEC_NEW_EXPR, newtype, 0);
     DECL_IS_MALLOC (opnew) = 1;
     DECL_IS_OPERATOR_NEW (opnew) = 1;
-    global_delete_fndecl = push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
+    push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
     push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+    if (flag_sized_deallocation)
+      {
+       /* Also push the sized deallocation variants:
+            void operator delete(void*, std::size_t) throw();
+            void operator delete[](void*, std::size_t) throw();  */
+       tree void_ftype_ptr_size
+         = build_function_type_list (void_type_node, ptr_type_node,
+                                     size_type_node, NULL_TREE);
+       deltype = cp_build_type_attribute_variant (void_ftype_ptr_size,
+                                                  extvisattr);
+       deltype = build_exception_variant (deltype, empty_except_spec);
+       push_cp_library_fn (DELETE_EXPR, deltype, ECF_NOTHROW);
+       push_cp_library_fn (VEC_DELETE_EXPR, deltype, ECF_NOTHROW);
+      }
 
     nullptr_type_node = make_node (NULLPTR_TYPE);
     TYPE_SIZE (nullptr_type_node) = bitsize_int (GET_MODE_BITSIZE (ptr_mode));
@@ -11745,6 +11755,16 @@ grok_op_properties (tree decl, bool complain)
              error ("%qD may not be declared as static", decl);
              return false;
            }
+         if (!flag_sized_deallocation && warn_cxx14_compat)
+           {
+             tree parm = FUNCTION_ARG_CHAIN (decl);
+             if (parm && same_type_p (TREE_VALUE (parm), size_type_node)
+                 && TREE_CHAIN (parm) == void_list_node)
+               warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wc__14_compat,
+                           "%qD is a usual (non-placement) deallocation "
+                           "function in C++14 (or with -fsized-deallocation)",
+                           decl);
+           }
        }
     }
 
index f3b94a93dc5b6e2d680091ae6311355d39fcbcd5..07bdd92de93236ccbdea3fe862b20cab3b2ab3b0 100644 (file)
@@ -4308,6 +4308,47 @@ dump_tu (void)
     }
 }
 
+/* Check the deallocation functions for CODE to see if we want to warn that
+   only one was defined.  */
+
+static void
+maybe_warn_sized_delete (enum tree_code code)
+{
+  tree sized = NULL_TREE;
+  tree unsized = NULL_TREE;
+
+  for (tree ovl = IDENTIFIER_GLOBAL_VALUE (ansi_opname (code));
+       ovl; ovl = OVL_NEXT (ovl))
+    {
+      tree fn = OVL_CURRENT (ovl);
+      /* We're only interested in usual deallocation functions.  */
+      if (!non_placement_deallocation_fn_p (fn))
+       continue;
+      if (FUNCTION_ARG_CHAIN (fn) == void_list_node)
+       unsized = fn;
+      else
+       sized = fn;
+    }
+  if (DECL_INITIAL (unsized) && !DECL_INITIAL (sized))
+    warning_at (DECL_SOURCE_LOCATION (unsized), OPT_Wsized_deallocation,
+               "the program should also define %qD", sized);
+  else if (!DECL_INITIAL (unsized) && DECL_INITIAL (sized))
+    warning_at (DECL_SOURCE_LOCATION (sized), OPT_Wsized_deallocation,
+               "the program should also define %qD", unsized);
+}
+
+/* Check the global deallocation functions to see if we want to warn about
+   defining unsized without sized (or vice versa).  */
+
+static void
+maybe_warn_sized_delete ()
+{
+  if (!flag_sized_deallocation || !warn_sized_deallocation)
+    return;
+  maybe_warn_sized_delete (DELETE_EXPR);
+  maybe_warn_sized_delete (VEC_DELETE_EXPR);
+}
+
 /* This routine is called at the end of compilation.
    Its job is to create all the code needed to initialize and
    destroy the global aggregates.  We do the destruction
@@ -4638,6 +4679,8 @@ cp_write_global_declarations (void)
   FOR_EACH_VEC_SAFE_ELT (no_linkage_decls, i, decl)
     no_linkage_error (decl);
 
+  maybe_warn_sized_delete ();
+
   /* Then, do the Objective-C stuff.  This is where all the
      Objective-C module stuff gets generated (symtab,
      class/protocol/selector lists etc).  This must be done after C++
index b987ef15a0d0e044a454e89711ea2e92d9a48c1a..8a7dca32b46daed3d6f41e3ae05c436d2c5ea788 100644 (file)
@@ -39,7 +39,6 @@ static void construct_virtual_base (tree, tree);
 static void expand_aggr_init_1 (tree, tree, tree, tree, int, tsubst_flags_t);
 static void expand_default_init (tree, tree, tree, tree, int, tsubst_flags_t);
 static void perform_member_init (tree, tree);
-static tree build_builtin_delete_call (tree);
 static int member_init_ok_or_else (tree, tree, tree);
 static void expand_virtual_init (tree, tree);
 static tree sort_mem_initializers (tree, tree);
@@ -2094,15 +2093,6 @@ decl_constant_value (tree decl)
 }
 \f
 /* Common subroutines of build_new and build_vec_delete.  */
-
-/* Call the global __builtin_delete to delete ADDR.  */
-
-static tree
-build_builtin_delete_call (tree addr)
-{
-  mark_used (global_delete_fndecl);
-  return build_call_n (global_delete_fndecl, 1, addr);
-}
 \f
 /* Build and return a NEW_EXPR.  If NELTS is non-NULL, TYPE[NELTS] is
    the type of the object being allocated; otherwise, it's just TYPE.
@@ -3211,7 +3201,9 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
                  "class-specific operator delete [] will be called, "
                  "even if they are declared when the class is defined");
        }
-      return build_builtin_delete_call (base);
+      /* This size won't actually be used.  */
+      size_exp = size_one_node;
+      goto no_destructor;
     } 
 
   size_exp = size_in_bytes (type);
@@ -3967,8 +3959,6 @@ build_delete (tree otype, tree addr, special_function_kind auto_delete,
 
   if (TYPE_PTR_P (otype))
     {
-      bool complete_p = true;
-
       addr = mark_rvalue_use (addr);
 
       /* We don't want to warn about delete of void*, only other
@@ -3993,7 +3983,6 @@ build_delete (tree otype, tree addr, special_function_kind auto_delete,
                          "operator delete will be called, even if they are "
                          "declared when the class is defined");
                }
-             complete_p = false;
            }
          else if (auto_delete == sfk_deleting_destructor && warn_delnonvdtor
                   && MAYBE_CLASS_TYPE_P (type) && !CLASSTYPE_FINAL (type)
@@ -4016,9 +4005,6 @@ build_delete (tree otype, tree addr, special_function_kind auto_delete,
                }
            }
        }
-      if (VOID_TYPE_P (type) || !complete_p || !MAYBE_CLASS_TYPE_P (type))
-       /* Call the builtin operator delete.  */
-       return build_builtin_delete_call (addr);
       if (TREE_SIDE_EFFECTS (addr))
        addr = save_expr (addr);
 
@@ -4079,7 +4065,13 @@ build_delete (tree otype, tree addr, special_function_kind auto_delete,
          addr = save_expr (addr);
          head = get_target_expr (build_headof (addr));
          /* Delete the object.  */
-         do_delete = build_builtin_delete_call (head);
+         do_delete = build_op_delete_call (DELETE_EXPR,
+                                           head,
+                                           cxx_sizeof_nowarn (type),
+                                           /*global_p=*/true,
+                                           /*placement=*/NULL_TREE,
+                                           /*alloc_fn=*/NULL_TREE,
+                                           complain);
          /* Otherwise, treat this like a complete object destructor
             call.  */
          auto_delete = sfk_complete_destructor;
index eb9a64dc9baaaa3cc1554f89766dbc76305a15bd..19422d78cd13b41bbdbe269130ec8e6e6477126f 100644 (file)
@@ -187,7 +187,8 @@ in the following sections.
 -fno-nonansi-builtins  -fnothrow-opt  -fno-operator-names @gol
 -fno-optional-diags  -fpermissive @gol
 -fno-pretty-templates @gol
--frepo  -fno-rtti  -fstats  -ftemplate-backtrace-limit=@var{n} @gol
+-frepo  -fno-rtti -fsized-deallocation @gol
+-fstats  -ftemplate-backtrace-limit=@var{n} @gol
 -ftemplate-depth=@var{n} @gol
 -fno-threadsafe-statics  -fuse-cxa-atexit @gol
 -fno-weak  -nostdinc++ @gol
@@ -243,7 +244,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wbool-compare @gol
 -Wno-attributes -Wno-builtin-macro-redefined @gol
 -Wc90-c99-compat -Wc99-c11-compat @gol
--Wc++-compat -Wc++11-compat -Wcast-align  -Wcast-qual  @gol
+-Wc++-compat -Wc++11-compat -Wc++14-compat -Wcast-align  -Wcast-qual  @gol
 -Wchar-subscripts -Wclobbered  -Wcomment -Wconditionally-supported  @gol
 -Wconversion -Wcoverage-mismatch -Wdate-time -Wdelete-incomplete -Wno-cpp  @gol
 -Wno-deprecated -Wno-deprecated-declarations -Wno-designated-init @gol
@@ -2304,6 +2305,19 @@ needed. The @samp{dynamic_cast} operator can still be used for casts that
 do not require run-time type information, i.e.@: casts to @code{void *} or to
 unambiguous base classes.
 
+@item -fsized-deallocation
+@opindex fsized-deallocation
+Enable the built-in global declarations
+@smallexample
+void operator delete (void *, std::size_t) noexcept;
+void operator delete[] (void *, std::size_t) noexcept;
+@end smallexample
+as introduced in C++14.  This is useful for user-defined replacement
+deallocation functions that, for example, use the size of the object
+to make deallocation faster.  Enabled by default under
+@samp{-std=c++14} and above.  The flag @option{-Wsized-deallocation} will
+warn about places that might want to add a definition.
+
 @item -fstats
 @opindex fstats
 Emit statistics about front-end processing at the end of the compilation.
@@ -3356,7 +3370,7 @@ Options} and @ref{Objective-C and Objective-C++ Dialect Options}.
 
 @gccoptlist{-Waddress   @gol
 -Warray-bounds @r{(only with} @option{-O2}@r{)}  @gol
--Wc++11-compat  @gol
+-Wc++11-compat  -Wc++14-compat@gol
 -Wchar-subscripts  @gol
 -Wenum-compare @r{(in C/ObjC; this is on by default in C++)} @gol
 -Wimplicit-int @r{(C and Objective-C only)} @gol
@@ -4608,6 +4622,10 @@ and ISO C++ 2011, e.g., identifiers in ISO C++ 1998 that are keywords
 in ISO C++ 2011.  This warning turns on @option{-Wnarrowing} and is
 enabled by @option{-Wall}.
 
+@item -Wc++14-compat @r{(C++ and Objective-C++ only)}
+Warn about C++ constructs whose meaning differs between ISO C++ 2011
+and ISO C++ 2014.  This warning is enabled by @option{-Wall}.
+
 @item -Wcast-qual
 @opindex Wcast-qual
 @opindex Wno-cast-qual
@@ -4767,6 +4785,22 @@ This includes conversions from real to integer, and from higher precision
 real to lower precision real values.  This option is also enabled by
 @option{-Wconversion}.
 
+@item -Wsized-deallocation @r{(C++ and Objective-C++ only)}
+@opindex Wsized-deallocation
+@opindex -Wno-sized-deallocation
+Warn about a definition of an unsized deallocation function
+@smallexample
+void operator delete (void *) noexcept;
+void operator delete[] (void *) noexcept;
+@end smallexample
+without a definition of the corresponding sized deallocation function
+@smallexample
+void operator delete (void *, std::size_t) noexcept;
+void operator delete[] (void *, std::size_t) noexcept;
+@end smallexample
+or vice versa.  Enabled by @option{-Wextra} along with
+@option{-fsized-deallocation}.
+
 @item -Wsizeof-pointer-memaccess
 @opindex Wsizeof-pointer-memaccess
 @opindex Wno-sizeof-pointer-memaccess
diff --git a/gcc/testsuite/g++.dg/cpp1y/sized-dealloc1.C b/gcc/testsuite/g++.dg/cpp1y/sized-dealloc1.C
new file mode 100644 (file)
index 0000000..846fce6
--- /dev/null
@@ -0,0 +1,75 @@
+// Test for C++14 sized deallocation.  The operators delete defined below
+// should be called only in C++14 mode and above.
+// { dg-do run }
+
+extern "C" void abort();
+typedef __SIZE_TYPE__ size_t;
+#include <new>
+
+bool called;
+void operator delete[] (void *p, size_t s) throw()
+{
+  called = true;
+  operator delete[] (p);
+}
+
+void operator delete (void *p, size_t s) throw()
+{
+  called = true;
+  operator delete (p);
+}
+
+void operator delete[] (void *p, size_t s, const std::nothrow_t &) throw()
+{
+  called = true;
+  operator delete[] (p);
+}
+
+void operator delete (void *p, size_t s, const std::nothrow_t &) throw()
+{
+  called = true;
+  operator delete (p);
+}
+
+struct A { ~A(){} };
+
+struct B { };
+
+struct C;
+
+struct D { ~D(){}; D() { throw 1; } };
+
+int main()
+{
+  /* * If the type is complete and if, for the second alternative (delete
+     array) only, the operand is a pointer to a class type with a
+     non-trivial destructor or a (possibly multi-dimensional) array
+     thereof, the function with two parameters is selected.
+
+     * Otherwise, it is unspecified which of the two deallocation functions
+     is selected. */
+  delete new int;
+  if (called != (__cplusplus >= 201402L)) abort(); called = false;
+
+  delete new A;
+  if (called != (__cplusplus >= 201402L)) abort(); called = false;
+
+  delete[] new A[2];
+  if (called != (__cplusplus >= 201402L)) abort(); called = false;
+
+  delete new B;
+  if (called != (__cplusplus >= 201402L)) abort(); called = false;
+
+  /* N3778 added the sized placement deallocation functions, but the core
+     language rules don't provide any way they would be called.  */
+  try { new (std::nothrow) D; } catch (int) {}
+  if (called) abort();
+
+  try { new (std::nothrow) D[2]; } catch (int) {}
+  if (called) abort();
+
+  /* Make sure we don't try to use the size of an array that doesn't have a
+     cookie.  */
+  delete[] new B[2];
+  if (called) abort();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/sized-dealloc2.C b/gcc/testsuite/g++.dg/cpp1y/sized-dealloc2.C
new file mode 100644 (file)
index 0000000..a3ab64c
--- /dev/null
@@ -0,0 +1,5 @@
+// Test that -Wc++14-compat warns about the change in meaning.
+// { dg-options "-Wall" }
+
+typedef __SIZE_TYPE__ size_t;
+void operator delete[] (void *p, size_t s) throw(); // { dg-warning "usual" "" { target { ! c++14 } } }
diff --git a/gcc/testsuite/g++.dg/cpp1y/sized-dealloc3.C b/gcc/testsuite/g++.dg/cpp1y/sized-dealloc3.C
new file mode 100644 (file)
index 0000000..e5bfe7c
--- /dev/null
@@ -0,0 +1,3 @@
+// { dg-options "-Wsized-deallocation" }
+
+void operator delete (void *p) throw() { __builtin_free(p); } // { dg-warning "sized" "" { target c++14 } }
index fe09df31209d030b272d1a832f9dcc0bc21d2530..9ec3995afde3b7e7103db3f84708591789c344e9 100644 (file)
@@ -5,6 +5,8 @@
 
 inline void* operator new(__SIZE_TYPE__ n){ return __builtin_malloc(n); }
 inline void operator delete(void *p) { __builtin_free(p); }
+// C++14 sized deallocation function
+inline void operator delete(void *p, __SIZE_TYPE__) { __builtin_free(p); }
 struct O {
     double num;
     int count;
index 4e79925ff0fa888a94f1ea764cc3f753093ef0c5..2f8c54b2603a9f9fdffe310c9b890ee0772a48c4 100644 (file)
@@ -1,3 +1,11 @@
+2014-12-15  Jason Merrill  <jason@redhat.com>
+
+       * libsupc++/del_ops.cc: New.
+       * libsupc++/del_opvs.cc: New.
+       * libsupc++/Makefile.am: Add them.
+       * libsupc++/Makefile.in: Regenerate.
+       * config/abi/pre/gnu.ver: Export _ZdlPvm and _ZdaPvm.
+
 2014-12-13  Tim Shen  <timshen@google.com>
 
        PR libstdc++/64239
index c73ebe7a65552d49cb92c3e4aa1a9988a400d535..9b516599563955e4ad030e8b32d4d2f455cb74c0 100644 (file)
@@ -1733,6 +1733,11 @@ CXXABI_1.3.9 {
     _ZTSP[no];
     _ZTSPK[no];
 
+    # operator delete(void*, std::size_t)
+    _ZdlPvm;
+    # operator delete[](void*, std::size_t)
+    _ZdaPvm;
+
 } CXXABI_1.3.8;
 
 # Symbols in the support library (libsupc++) supporting transactional memory.
index 679d71750f29fd7d93e87e63c5371ae8c18e3796..2e60f65249ee0fdd7cef093ad0f999f2417d56eb 100644 (file)
@@ -55,8 +55,10 @@ sources = \
        bad_typeid.cc \
        class_type_info.cc \
        del_op.cc \
+       del_ops.cc \
        del_opnt.cc \
        del_opv.cc \
+       del_opvs.cc \
        del_opvnt.cc \
        dyncast.cc \
        eh_alloc.cc \
index 88b237e1275e3759a26e75ba4f06b9b6ec72078e..1c7270a69d33dac28806a8b6afd9da6b11945479 100644 (file)
@@ -93,17 +93,18 @@ LTLIBRARIES = $(noinst_LTLIBRARIES) $(toolexeclib_LTLIBRARIES)
 libsupc___la_LIBADD =
 am__objects_1 = array_type_info.lo atexit_arm.lo atexit_thread.lo \
        bad_alloc.lo bad_array_length.lo bad_array_new.lo bad_cast.lo \
-       bad_typeid.lo class_type_info.lo del_op.lo del_opnt.lo \
-       del_opv.lo del_opvnt.lo dyncast.lo eh_alloc.lo eh_arm.lo \
-       eh_aux_runtime.lo eh_call.lo eh_catch.lo eh_exception.lo \
-       eh_globals.lo eh_personality.lo eh_ptr.lo eh_term_handler.lo \
-       eh_terminate.lo eh_tm.lo eh_throw.lo eh_type.lo \
-       eh_unex_handler.lo enum_type_info.lo function_type_info.lo \
-       fundamental_type_info.lo guard.lo guard_error.lo hash_bytes.lo \
-       nested_exception.lo new_handler.lo new_op.lo new_opnt.lo \
-       new_opv.lo new_opvnt.lo pbase_type_info.lo pmem_type_info.lo \
-       pointer_type_info.lo pure.lo si_class_type_info.lo tinfo.lo \
-       tinfo2.lo vec.lo vmi_class_type_info.lo vterminate.lo
+       bad_typeid.lo class_type_info.lo del_op.lo del_ops.lo \
+       del_opnt.lo del_opv.lo del_opvs.lo del_opvnt.lo dyncast.lo \
+       eh_alloc.lo eh_arm.lo eh_aux_runtime.lo eh_call.lo eh_catch.lo \
+       eh_exception.lo eh_globals.lo eh_personality.lo eh_ptr.lo \
+       eh_term_handler.lo eh_terminate.lo eh_tm.lo eh_throw.lo \
+       eh_type.lo eh_unex_handler.lo enum_type_info.lo \
+       function_type_info.lo fundamental_type_info.lo guard.lo \
+       guard_error.lo hash_bytes.lo nested_exception.lo \
+       new_handler.lo new_op.lo new_opnt.lo new_opv.lo new_opvnt.lo \
+       pbase_type_info.lo pmem_type_info.lo pointer_type_info.lo \
+       pure.lo si_class_type_info.lo tinfo.lo tinfo2.lo vec.lo \
+       vmi_class_type_info.lo vterminate.lo
 @GLIBCXX_HOSTED_TRUE@am__objects_2 = cp-demangle.lo
 @ENABLE_VTABLE_VERIFY_TRUE@am__objects_3 = vtv_stubs.lo
 am_libsupc___la_OBJECTS = $(am__objects_1) $(am__objects_2) \
@@ -381,8 +382,10 @@ sources = \
        bad_typeid.cc \
        class_type_info.cc \
        del_op.cc \
+       del_ops.cc \
        del_opnt.cc \
        del_opv.cc \
+       del_opvs.cc \
        del_opvnt.cc \
        dyncast.cc \
        eh_alloc.cc \
diff --git a/libstdc++-v3/libsupc++/del_ops.cc b/libstdc++-v3/libsupc++/del_ops.cc
new file mode 100644 (file)
index 0000000..d97815e
--- /dev/null
@@ -0,0 +1,33 @@
+// Boilerplate support routines for -*- C++ -*- dynamic memory management.
+
+// Copyright (C) 1997-2014 Free Software Foundation, Inc.
+//
+// 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 3, or (at your option)
+// any later version.
+//
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+#include <bits/c++config.h>
+#include "new"
+
+_GLIBCXX_WEAK_DEFINITION void
+operator delete(void* ptr, std::size_t) _GLIBCXX_USE_NOEXCEPT
+{
+  ::operator delete (ptr);
+}
diff --git a/libstdc++-v3/libsupc++/del_opvs.cc b/libstdc++-v3/libsupc++/del_opvs.cc
new file mode 100644 (file)
index 0000000..11bae1e
--- /dev/null
@@ -0,0 +1,33 @@
+// Boilerplate support routines for -*- C++ -*- dynamic memory management.
+
+// Copyright (C) 1997-2014 Free Software Foundation, Inc.
+//
+// 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 3, or (at your option)
+// any later version.
+//
+// GCC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+// <http://www.gnu.org/licenses/>.
+
+#include <bits/c++config.h>
+#include "new"
+
+_GLIBCXX_WEAK_DEFINITION void
+operator delete[] (void *ptr, std::size_t) _GLIBCXX_USE_NOEXCEPT
+{
+  ::operator delete[] (ptr);
+}