r191629 - Implement C++1y sized deallocation (n3778). This is not enabled by -std=c++1y;

Richard Smith richard-llvm at metafoo.co.uk
Sat Sep 28 21:40:38 PDT 2013


Author: rsmith
Date: Sat Sep 28 23:40:38 2013
New Revision: 191629

URL: http://llvm.org/viewvc/llvm-project?rev=191629&view=rev
Log:
Implement C++1y sized deallocation (n3778). This is not enabled by -std=c++1y;
instead, it's enabled by the -cc1 flag -fsized-deallocation, until we sort out
the backward-compatibility issues.

Added:
    cfe/trunk/test/CodeGenCXX/cxx1y-sized-deallocation.cpp
    cfe/trunk/test/SemaCXX/cxx1y-sized-deallocation.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/Basic/LangOptions.def
    cfe/trunk/include/clang/Driver/CC1Options.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=191629&r1=191628&r2=191629&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Sat Sep 28 23:40:38 2013
@@ -1775,8 +1775,10 @@ public:
   ///    void *operator new[](size_t);
   ///    void *operator new[](size_t, const std::nothrow_t &) noexcept;
   ///    void operator delete(void *) noexcept;
+  ///    void operator delete(void *, std::size_t) noexcept;      [C++1y]
   ///    void operator delete(void *, const std::nothrow_t &) noexcept;
   ///    void operator delete[](void *) noexcept;
+  ///    void operator delete[](void *, std::size_t) noexcept;    [C++1y]
   ///    void operator delete[](void *, const std::nothrow_t &) noexcept;
   /// These functions have special behavior under C++1y [expr.new]:
   ///    An implementation is allowed to omit a call to a replaceable global

Modified: cfe/trunk/include/clang/Basic/LangOptions.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.def?rev=191629&r1=191628&r2=191629&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/LangOptions.def (original)
+++ cfe/trunk/include/clang/Basic/LangOptions.def Sat Sep 28 23:40:38 2013
@@ -123,6 +123,7 @@ LANGOPT(CUDA              , 1, 0, "CUDA"
 LANGOPT(OpenMP            , 1, 0, "OpenMP support")
 
 LANGOPT(AssumeSaneOperatorNew , 1, 1, "implicit __attribute__((malloc)) for C++'s new operators")
+LANGOPT(SizedDeallocation , 1, 0, "enable sized deallocation functions")
 BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision")
 BENIGN_LANGOPT(DumpRecordLayouts , 1, 0, "dumping the layout of IRgen'd records")
 BENIGN_LANGOPT(DumpRecordLayoutsSimple , 1, 0, "dumping the layout of IRgen'd records in a simple form")

Modified: cfe/trunk/include/clang/Driver/CC1Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=191629&r1=191628&r2=191629&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td (original)
+++ cfe/trunk/include/clang/Driver/CC1Options.td Sat Sep 28 23:40:38 2013
@@ -474,6 +474,8 @@ def fdeprecated_macro : Flag<["-"], "fde
   HelpText<"Defines the __DEPRECATED macro">;
 def fno_deprecated_macro : Flag<["-"], "fno-deprecated-macro">,
   HelpText<"Undefines the __DEPRECATED macro">;
+def fsized_deallocation : Flag<["-"], "fsized-deallocation">,
+  HelpText<"Enable C++1y sized global deallocation functions">;
 
 //===----------------------------------------------------------------------===//
 // Header Search Options

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=191629&r1=191628&r2=191629&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sat Sep 28 23:40:38 2013
@@ -4133,12 +4133,16 @@ public:
                               bool Diagnose = true);
   void DeclareGlobalNewDelete();
   void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return,
-                                       QualType Argument,
+                                       QualType Param1,
+                                       QualType Param2 = QualType(),
                                        bool addMallocAttr = false);
 
   bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
                                 DeclarationName Name, FunctionDecl* &Operator,
                                 bool Diagnose = true);
+  FunctionDecl *FindUsualDeallocationFunction(SourceLocation StartLoc,
+                                              bool CanProvideSize,
+                                              DeclarationName Name);
 
   /// ActOnCXXDelete - Parsed a C++ 'delete' expression
   ExprResult ActOnCXXDelete(SourceLocation StartLoc,

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=191629&r1=191628&r2=191629&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Sat Sep 28 23:40:38 2013
@@ -2310,8 +2310,11 @@ bool FunctionDecl::isReplaceableGlobalAl
     return true;
 
   // Otherwise, we're looking for a second parameter whose type is
-  // 'const std::nothrow_t &'.
+  // 'const std::nothrow_t &', or, in C++1y, 'std::size_t'.
   QualType Ty = FPT->getArgType(1);
+  ASTContext &Ctx = getASTContext();
+  if (Ctx.getLangOpts().SizedDeallocation && Ty == Ctx.getSizeType())
+    return true;
   if (!Ty->isReferenceType())
     return false;
   Ty = Ty->getPointeeType();

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=191629&r1=191628&r2=191629&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Sat Sep 28 23:40:38 2013
@@ -1292,6 +1292,7 @@ static void ParseLangArgs(LangOptions &O
   Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
   Opts.NoMathBuiltin = Args.hasArg(OPT_fno_math_builtin);
   Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
+  Opts.SizedDeallocation = Args.hasArg(OPT_fsized_deallocation);
   Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions);
   Opts.AccessControl = !Args.hasArg(OPT_fno_access_control);
   Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=191629&r1=191628&r2=191629&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Sat Sep 28 23:40:38 2013
@@ -1539,16 +1539,23 @@ bool Sema::CheckAllocatedType(QualType A
 
 /// \brief Determine whether the given function is a non-placement
 /// deallocation function.
-static bool isNonPlacementDeallocationFunction(FunctionDecl *FD) {
+static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) {
   if (FD->isInvalidDecl())
     return false;
 
   if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
     return Method->isUsualDeallocationFunction();
 
-  return ((FD->getOverloadedOperator() == OO_Delete ||
-           FD->getOverloadedOperator() == OO_Array_Delete) &&
-          FD->getNumParams() == 1);
+  if (FD->getOverloadedOperator() != OO_Delete &&
+      FD->getOverloadedOperator() != OO_Array_Delete)
+    return false;
+
+  if (FD->getNumParams() == 1)
+    return true;
+
+  return S.getLangOpts().SizedDeallocation && FD->getNumParams() == 2 &&
+         S.Context.hasSameUnqualifiedType(FD->getParamDecl(1)->getType(),
+                                          S.Context.getSizeType());
 }
 
 /// FindAllocationFunctions - Finds the overloads of operator new and delete
@@ -1723,9 +1730,28 @@ bool Sema::FindAllocationFunctions(Sourc
                              DEnd = FoundDelete.end();
          D != DEnd; ++D) {
       if (FunctionDecl *Fn = dyn_cast<FunctionDecl>((*D)->getUnderlyingDecl()))
-        if (isNonPlacementDeallocationFunction(Fn))
+        if (isNonPlacementDeallocationFunction(*this, Fn))
           Matches.push_back(std::make_pair(D.getPair(), Fn));
     }
+
+    // C++1y [expr.new]p22:
+    //   For a non-placement allocation function, the normal deallocation
+    //   function lookup is used
+    // C++1y [expr.delete]p?:
+    //   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, then the
+    //   selected deallocation function shall be the one with two parameters.
+    //   Otherwise, the selected deallocation function shall be the function
+    //   with one parameter.
+    if (getLangOpts().SizedDeallocation && Matches.size() == 2) {
+      if (Matches[0].second->getNumParams() == 1)
+        Matches.erase(Matches.begin());
+      else
+        Matches.erase(Matches.begin() + 1);
+      assert(Matches[0].second->getNumParams() == 2 &&
+             "found an unexpected uusal deallocation function");
+    }
   }
 
   // C++ [expr.new]p20:
@@ -1742,12 +1768,13 @@ bool Sema::FindAllocationFunctions(Sourc
     //   selected as a match for the allocation function, the program
     //   is ill-formed.
     if (!PlaceArgs.empty() && getLangOpts().CPlusPlus11 &&
-        isNonPlacementDeallocationFunction(OperatorDelete)) {
+        isNonPlacementDeallocationFunction(*this, OperatorDelete)) {
       Diag(StartLoc, diag::err_placement_new_non_placement_delete)
         << SourceRange(PlaceArgs.front()->getLocStart(),
                        PlaceArgs.back()->getLocEnd());
-      Diag(OperatorDelete->getLocation(), diag::note_previous_decl)
-        << DeleteName;
+      if (!OperatorDelete->isImplicit())
+        Diag(OperatorDelete->getLocation(), diag::note_previous_decl)
+          << DeleteName;
     } else {
       CheckAllocationAccess(StartLoc, Range, FoundDelete.getNamingClass(),
                             Matches[0].first);
@@ -1874,13 +1901,19 @@ bool Sema::FindAllocationOverload(Source
 ///   void* operator new[](std::size_t) throw(std::bad_alloc);
 ///   void operator delete(void *) throw();
 ///   void operator delete[](void *) throw();
-///   // C++0x:
+///   // C++11:
 ///   void* operator new(std::size_t);
 ///   void* operator new[](std::size_t);
-///   void operator delete(void *);
-///   void operator delete[](void *);
+///   void operator delete(void *) noexcept;
+///   void operator delete[](void *) noexcept;
+///   // C++1y:
+///   void* operator new(std::size_t);
+///   void* operator new[](std::size_t);
+///   void operator delete(void *) noexcept;
+///   void operator delete[](void *) noexcept;
+///   void operator delete(void *, std::size_t) noexcept;
+///   void operator delete[](void *, std::size_t) noexcept;
 /// @endcode
-/// C++0x operator delete is implicitly noexcept.
 /// Note that the placement and nothrow forms of new are *not* implicitly
 /// declared. Their use requires including \<new\>.
 void Sema::DeclareGlobalNewDelete() {
@@ -1897,11 +1930,18 @@ void Sema::DeclareGlobalNewDelete() {
   //     void* operator new[](std::size_t) throw(std::bad_alloc);
   //     void  operator delete(void*) throw();
   //     void  operator delete[](void*) throw();
-  //     C++0x:
+  //     C++11:
+  //     void* operator new(std::size_t);
+  //     void* operator new[](std::size_t);
+  //     void  operator delete(void*) noexcept;
+  //     void  operator delete[](void*) noexcept;
+  //     C++1y:
   //     void* operator new(std::size_t);
   //     void* operator new[](std::size_t);
-  //     void  operator delete(void*);
-  //     void  operator delete[](void*);
+  //     void  operator delete(void*) noexcept;
+  //     void  operator delete[](void*) noexcept;
+  //     void  operator delete(void*, std::size_t) noexcept;
+  //     void  operator delete[](void*, std::size_t) noexcept;
   //
   //   These implicit declarations introduce only the function names operator
   //   new, operator new[], operator delete, operator delete[].
@@ -1910,8 +1950,6 @@ void Sema::DeclareGlobalNewDelete() {
   // "std" or "bad_alloc" as necessary to form the exception specification.
   // However, we do not make these implicit declarations visible to name
   // lookup.
-  // Note that the C++0x versions of operator delete are deallocation functions,
-  // and thus are implicitly noexcept.
   if (!StdBadAlloc && !getLangOpts().CPlusPlus11) {
     // The "std::bad_alloc" class has not yet been declared, so build it
     // implicitly.
@@ -1931,24 +1969,34 @@ void Sema::DeclareGlobalNewDelete() {
 
   DeclareGlobalAllocationFunction(
       Context.DeclarationNames.getCXXOperatorName(OO_New),
-      VoidPtr, SizeT, AssumeSaneOperatorNew);
+      VoidPtr, SizeT, QualType(), AssumeSaneOperatorNew);
   DeclareGlobalAllocationFunction(
       Context.DeclarationNames.getCXXOperatorName(OO_Array_New),
-      VoidPtr, SizeT, AssumeSaneOperatorNew);
+      VoidPtr, SizeT, QualType(), AssumeSaneOperatorNew);
   DeclareGlobalAllocationFunction(
       Context.DeclarationNames.getCXXOperatorName(OO_Delete),
       Context.VoidTy, VoidPtr);
   DeclareGlobalAllocationFunction(
       Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete),
       Context.VoidTy, VoidPtr);
+  if (getLangOpts().SizedDeallocation) {
+    DeclareGlobalAllocationFunction(
+        Context.DeclarationNames.getCXXOperatorName(OO_Delete),
+        Context.VoidTy, VoidPtr, Context.getSizeType());
+    DeclareGlobalAllocationFunction(
+        Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete),
+        Context.VoidTy, VoidPtr, Context.getSizeType());
+  }
 }
 
 /// DeclareGlobalAllocationFunction - Declares a single implicit global
 /// allocation function if it doesn't already exist.
 void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
-                                           QualType Return, QualType Argument,
+                                           QualType Return,
+                                           QualType Param1, QualType Param2,
                                            bool AddMallocAttr) {
   DeclContext *GlobalCtx = Context.getTranslationUnitDecl();
+  unsigned NumParams = Param2.isNull() ? 1 : 2;
 
   // Check if this function is already declared.
   DeclContext::lookup_result R = GlobalCtx->lookup(Name);
@@ -1957,12 +2005,18 @@ void Sema::DeclareGlobalAllocationFuncti
     // Only look at non-template functions, as it is the predefined,
     // non-templated allocation function we are trying to declare here.
     if (FunctionDecl *Func = dyn_cast<FunctionDecl>(*Alloc)) {
-      if (Func->getNumParams() == 1) {
-        QualType InitialParamType =
-          Context.getCanonicalType(
-            Func->getParamDecl(0)->getType().getUnqualifiedType());
+      if (Func->getNumParams() == NumParams) {
+        QualType InitialParam1Type =
+            Context.getCanonicalType(Func->getParamDecl(0)
+                                         ->getType().getUnqualifiedType());
+        QualType InitialParam2Type =
+            NumParams == 2
+                ? Context.getCanonicalType(Func->getParamDecl(1)
+                                               ->getType().getUnqualifiedType())
+                : QualType();
         // FIXME: Do we need to check for default arguments here?
-        if (InitialParamType == Argument) {
+        if (InitialParam1Type == Param1 &&
+            (NumParams == 1 || InitialParam2Type == Param2)) {
           if (AddMallocAttr && !Func->hasAttr<MallocAttr>())
             Func->addAttr(::new (Context) MallocAttr(SourceLocation(),
                                                      Context));
@@ -1997,7 +2051,10 @@ void Sema::DeclareGlobalAllocationFuncti
                                 EST_BasicNoexcept : EST_DynamicNone;
   }
 
-  QualType FnType = Context.getFunctionType(Return, Argument, EPI);
+  QualType Params[] = { Param1, Param2 };
+
+  QualType FnType = Context.getFunctionType(
+      Return, ArrayRef<QualType>(Params, NumParams), EPI);
   FunctionDecl *Alloc =
     FunctionDecl::Create(Context, GlobalCtx, SourceLocation(),
                          SourceLocation(), Name,
@@ -2007,11 +2064,13 @@ void Sema::DeclareGlobalAllocationFuncti
   if (AddMallocAttr)
     Alloc->addAttr(::new (Context) MallocAttr(SourceLocation(), Context));
 
-  ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
-                                           SourceLocation(), 0,
-                                           Argument, /*TInfo=*/0,
-                                           SC_None, 0);
-  Alloc->setParams(Param);
+  ParmVarDecl *ParamDecls[2];
+  for (unsigned I = 0; I != NumParams; ++I)
+    ParamDecls[I] = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
+                                        SourceLocation(), 0,
+                                        Params[I], /*TInfo=*/0,
+                                        SC_None, 0);
+  Alloc->setParams(ArrayRef<ParmVarDecl*>(ParamDecls, NumParams));
 
   // FIXME: Also add this declaration to the IdentifierResolver, but
   // make sure it is at the end of the chain to coincide with the
@@ -2019,6 +2078,48 @@ void Sema::DeclareGlobalAllocationFuncti
   Context.getTranslationUnitDecl()->addDecl(Alloc);
 }
 
+FunctionDecl *Sema::FindUsualDeallocationFunction(SourceLocation StartLoc,
+                                                  bool CanProvideSize,
+                                                  DeclarationName Name) {
+  DeclareGlobalNewDelete();
+
+  LookupResult FoundDelete(*this, Name, StartLoc, LookupOrdinaryName);
+  LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl());
+
+  // C++ [expr.new]p20:
+  //   [...] Any non-placement deallocation function matches a
+  //   non-placement allocation function. [...]
+  llvm::SmallVector<FunctionDecl*, 2> Matches;
+  for (LookupResult::iterator D = FoundDelete.begin(),
+                           DEnd = FoundDelete.end();
+       D != DEnd; ++D) {
+    if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*D))
+      if (isNonPlacementDeallocationFunction(*this, Fn))
+        Matches.push_back(Fn);
+  }
+
+  // C++1y [expr.delete]p?:
+  //   If the type is complete and 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, then the selected deallocation function shall be the one
+  //   with two parameters.  Otherwise, the selected deallocation function
+  //   shall be the function with one parameter.
+  if (getLangOpts().SizedDeallocation && Matches.size() == 2) {
+    unsigned NumArgs = CanProvideSize ? 2 : 1;
+    if (Matches[0]->getNumParams() != NumArgs)
+      Matches.erase(Matches.begin());
+    else
+      Matches.erase(Matches.begin() + 1);
+    assert(Matches[0]->getNumParams() == NumArgs &&
+           "found an unexpected uusal deallocation function");
+  }
+
+  assert(Matches.size() == 1 &&
+         "unexpectedly have multiple usual deallocation functions");
+  return Matches.front();
+}
+
 bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
                                     DeclarationName Name,
                                     FunctionDecl* &Operator, bool Diagnose) {
@@ -2093,17 +2194,7 @@ bool Sema::FindDeallocationFunction(Sour
   }
 
   // Look for a global declaration.
-  DeclareGlobalNewDelete();
-  DeclContext *TUDecl = Context.getTranslationUnitDecl();
-
-  CXXNullPtrLiteralExpr Null(Context.VoidPtrTy, SourceLocation());
-  Expr *DeallocArgs[1] = { &Null };
-  if (FindAllocationOverload(StartLoc, SourceRange(), Name,
-                             DeallocArgs, TUDecl, !Diagnose,
-                             Operator, Diagnose))
-    return true;
-
-  assert(Operator && "Did not find a deallocation function!");
+  Operator = FindUsualDeallocationFunction(StartLoc, true, Name);
   return false;
 }
 
@@ -2291,20 +2382,13 @@ Sema::ActOnCXXDelete(SourceLocation Star
 
     }
 
-    if (!OperatorDelete) {
+    if (!OperatorDelete)
       // Look for a global declaration.
-      DeclareGlobalNewDelete();
-      DeclContext *TUDecl = Context.getTranslationUnitDecl();
-      Expr *Arg = Ex.get();
-      if (!Context.hasSameType(Arg->getType(), Context.VoidPtrTy))
-        Arg = ImplicitCastExpr::Create(Context, Context.VoidPtrTy,
-                                       CK_BitCast, Arg, 0, VK_RValue);
-      Expr *DeallocArgs[1] = { Arg };
-      if (FindAllocationOverload(StartLoc, SourceRange(), DeleteName,
-                                 DeallocArgs, TUDecl, /*AllowMissing=*/false,
-                                 OperatorDelete))
-        return ExprError();
-    }
+      OperatorDelete = FindUsualDeallocationFunction(
+          StartLoc, !RequireCompleteType(StartLoc, Pointee, 0) &&
+                    (!ArrayForm || UsualArrayDeleteWantsSize ||
+                     Pointee.isDestructedType()),
+          DeleteName);
 
     MarkFunctionReferenced(StartLoc, OperatorDelete);
     

Added: cfe/trunk/test/CodeGenCXX/cxx1y-sized-deallocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx1y-sized-deallocation.cpp?rev=191629&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/cxx1y-sized-deallocation.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/cxx1y-sized-deallocation.cpp Sat Sep 28 23:40:38 2013
@@ -0,0 +1,83 @@
+// RUN: %clang_cc1 -std=c++1y -fsized-deallocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++1y %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefix=CHECK-UNSIZED
+
+// CHECK-UNSIZED-NOT: _ZdlPvm
+// CHECK-UNSIZED-NOT: _ZdaPvm
+
+typedef decltype(sizeof(0)) size_t;
+
+typedef int A;
+struct B { int n; };
+struct C { ~C() {} };
+struct D { D(); virtual ~D() {} };
+struct E {
+  void *operator new(size_t);
+  void *operator new[](size_t);
+  void operator delete(void *) noexcept;
+  void operator delete[](void *) noexcept;
+};
+struct F {
+  void *operator new(size_t);
+  void *operator new[](size_t);
+  void operator delete(void *, size_t) noexcept;
+  void operator delete[](void *, size_t) noexcept;
+};
+
+template<typename T> T get();
+
+template<typename T>
+void del() {
+  ::delete get<T*>();
+  ::delete[] get<T*>();
+}
+
+template void del<A>();
+template void del<B>();
+template void del<C>();
+template void del<D>();
+template void del<E>();
+template void del<F>();
+
+D::D() {}
+
+// CHECK-LABEL: define weak_odr void @_Z3delIiEvv()
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 4)
+// CHECK: call void @_ZdaPv(i8* %{{[^ ]*}})
+
+// CHECK-LABEL: define weak_odr void @_Z3delI1BEvv()
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 4)
+// CHECK: call void @_ZdaPv(i8* %{{[^ ]*}})
+
+// CHECK-LABEL: define weak_odr void @_Z3delI1CEvv()
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 1)
+// CHECK: mul i64 1, %{{[^ ]*}}
+// CHECK: add i64 %{{[^ ]*}}, 8
+// CHECK: call void @_ZdaPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}})
+
+// CHECK-LABEL: define weak_odr void @_Z3delI1DEvv()
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 8)
+// CHECK: mul i64 8, %{{[^ ]*}}
+// CHECK: add i64 %{{[^ ]*}}, 8
+// CHECK: call void @_ZdaPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}})
+
+// CHECK-LABEL: define weak_odr void @_Z3delI1EEvv()
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 1)
+// CHECK: call void @_ZdaPv(i8* %{{[^ ]*}})
+
+// CHECK-LABEL: define weak_odr void @_Z3delI1FEvv()
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 1)
+// CHECK: mul i64 1, %{{[^ ]*}}
+// CHECK: add i64 %{{[^ ]*}}, 8
+// CHECK: call void @_ZdaPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}})
+
+// CHECK-LABEL: define void @_Z10member_delv()
+// CHECK-NOT: Zdl
+// CHECK: call void %{{[^ ]*}}(%{{[^ ]*}}* %
+// CHECK-NOT: Zdl
+// CHECK: }
+void member_del() {
+  delete get<D*>();
+}
+
+// CHECK-LABEL: define linkonce_odr void @_ZN1DD0Ev(%{{[^ ]*}}* %this)
+// CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 8)

Added: cfe/trunk/test/SemaCXX/cxx1y-sized-deallocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-sized-deallocation.cpp?rev=191629&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1y-sized-deallocation.cpp (added)
+++ cfe/trunk/test/SemaCXX/cxx1y-sized-deallocation.cpp Sat Sep 28 23:40:38 2013
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -std=c++1y -verify %s -fsized-deallocation -fexceptions -fcxx-exceptions
+
+using size_t = decltype(sizeof(0));
+
+void f(void *p, void *q) {
+  // OK, implicitly declared.
+  operator delete(p, 8);
+  operator delete[](q, 12);
+  static_assert(noexcept(operator delete(p, 8)), "");
+  static_assert(noexcept(operator delete[](q, 12)), "");
+}
+
+void *operator new(size_t bad, size_t idea);
+struct S { S() { throw 0; } };
+void g() {
+  new (123) S; // expected-error {{'new' expression with placement arguments refers to non-placement 'operator delete'}}
+}

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=191629&r1=191628&r2=191629&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Sat Sep 28 23:40:38 2013
@@ -476,10 +476,15 @@ available.</p>
     <tr>
       <td>C++ Sized Deallocation</td>
       <td><!--<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3778.html">-->N3778<!--</a>--></td>
-      <td class="none" align="center">No</td>
+      <td class="partial" align="center">Partial <a href="#n3778">(1)</a></td>
     </tr>
 </table>
 
+<p>
+<span id="n3778">(1): Use the experimental <tt>-Xclang -fsized-deallocation</tt>
+flag to enable this feature.</span><br>
+</p>
+
 </div>
 </body>
 </html>





More information about the cfe-commits mailing list