]> granicus.if.org Git - clang/commitdiff
C++1y sized deallocation: if we have a use, but not a definition, of a sized
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 5 Nov 2013 09:12:18 +0000 (09:12 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 5 Nov 2013 09:12:18 +0000 (09:12 +0000)
deallocation function (and the corresponding unsized deallocation function has
been declared), emit a weak discardable definition of the function that
forwards to the corresponding unsized deallocation.

This allows a C++ standard library implementation to provide both a sized and
an unsized deallocation function, where the unsized one does not just call the
sized one, for instance by putting both in the same object file within an
archive.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@194055 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
lib/AST/Decl.cpp
lib/CodeGen/CGClass.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/CodeGenFunction.h
lib/CodeGen/CodeGenModule.cpp
lib/Frontend/CompilerInvocation.cpp
test/CodeGenCXX/cxx1y-sized-deallocation.cpp
www/cxx_status.html

index e390a66c9ceb32064b764e92706b5116e98147ca..278ceb50eaf926b1685982702c8608bfdd325f5d 100644 (file)
@@ -1793,6 +1793,11 @@ public:
   ///    allocation function. [...]
   bool isReplaceableGlobalAllocationFunction() const;
 
+  /// \brief Determine whether this function is a sized global deallocation
+  /// function in C++1y. If so, find and return the corresponding unsized
+  /// deallocation function.
+  FunctionDecl *getCorrespondingUnsizedGlobalDeallocationFunction() const;
+
   /// Compute the language linkage.
   LanguageLinkage getLanguageLinkage() const;
 
index 5077c35acb6278572cbcdc22fe19cbebb10906d2..e81444ebe7332172097c0bdf302f602d2b1c7544 100644 (file)
@@ -2354,7 +2354,8 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
   // '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())
+  if (Ctx.getLangOpts().SizedDeallocation &&
+      Ctx.hasSameType(Ty, Ctx.getSizeType()))
     return true;
   if (!Ty->isReferenceType())
     return false;
@@ -2366,6 +2367,37 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
   return RD && isNamed(RD, "nothrow_t") && isNamespaceStd(RD->getDeclContext());
 }
 
+FunctionDecl *
+FunctionDecl::getCorrespondingUnsizedGlobalDeallocationFunction() const {
+  ASTContext &Ctx = getASTContext();
+  if (!Ctx.getLangOpts().SizedDeallocation)
+    return 0;
+
+  if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName)
+    return 0;
+  if (getDeclName().getCXXOverloadedOperator() != OO_Delete &&
+      getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
+    return 0;
+  if (isa<CXXRecordDecl>(getDeclContext()))
+    return 0;
+  assert(getDeclContext()->getRedeclContext()->isTranslationUnit());
+
+  if (getNumParams() != 2 || isVariadic() ||
+      !Ctx.hasSameType(getType()->castAs<FunctionProtoType>()->getArgType(1),
+                       Ctx.getSizeType()))
+    return 0;
+
+  // This is a sized deallocation function. Find the corresponding unsized
+  // deallocation function.
+  lookup_const_result R = getDeclContext()->lookup(getDeclName());
+  for (lookup_const_result::iterator RI = R.begin(), RE = R.end(); RI != RE;
+       ++RI)
+    if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*RI))
+      if (FD->getNumParams() == 1 && !FD->isVariadic())
+        return FD;
+  return 0;
+}
+
 LanguageLinkage FunctionDecl::getLanguageLinkage() const {
   return getLanguageLinkageTemplate(*this);
 }
index af8cbbc48c24c1834ad9b90952f5916df119a355..4848d7565d40b22f231799bd7c934a3776e8d64c 100644 (file)
@@ -2180,7 +2180,7 @@ void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) {
     return;
   }
 
-  EmitFunctionBody(Args);
+  EmitFunctionBody(Args, cast<FunctionDecl>(CurGD.getDecl())->getBody());
 }
 
 void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) {
index 221d132ee0b4ec2ae44c3c955cd3f24b75c5d1bc..4a427d540f67b65b989a597e8f513ac8ae9075cd 100644 (file)
@@ -1824,8 +1824,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
     return LV;
   }
 
-  if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(ND))
-    return EmitFunctionDeclLValue(*this, E, fn);
+  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
+    return EmitFunctionDeclLValue(*this, E, FD);
 
   llvm_unreachable("Unhandled DeclRefExpr");
 }
index 3ec890383c95d4b0ec183849dd6aaa634039d946..ce1b44559dcc733cd33dcfe0083447e4b9d66ce7 100644 (file)
@@ -643,13 +643,12 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
     DI->EmitLocation(Builder, StartLoc);
 }
 
-void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args) {
-  const FunctionDecl *FD = cast<FunctionDecl>(CurGD.getDecl());
-  assert(FD->getBody());
-  if (const CompoundStmt *S = dyn_cast<CompoundStmt>(FD->getBody()))
+void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args,
+                                       const Stmt *Body) {
+  if (const CompoundStmt *S = dyn_cast<CompoundStmt>(Body))
     EmitCompoundStmtWithoutScope(*S);
   else
-    EmitStmt(FD->getBody());
+    EmitStmt(Body);
 }
 
 /// Tries to mark the given function nounwind based on the
@@ -672,6 +671,17 @@ static void TryMarkNoThrow(llvm::Function *F) {
   F->setDoesNotThrow();
 }
 
+static void EmitSizedDeallocationFunction(CodeGenFunction &CGF,
+                                          const FunctionDecl *UnsizedDealloc) {
+  // This is a weak discardable definition of the sized deallocation function.
+  CGF.CurFn->setLinkage(llvm::Function::LinkOnceAnyLinkage);
+
+  // Call the unsized deallocation function and forward the first argument
+  // unchanged.
+  llvm::Constant *Unsized = CGF.CGM.GetAddrOfFunction(UnsizedDealloc);
+  CGF.Builder.CreateCall(Unsized, &*CGF.CurFn->arg_begin());
+}
+
 void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
                                    const CGFunctionInfo &FnInfo) {
   const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
@@ -726,9 +736,15 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
     // Implicit copy-assignment gets the same special treatment as implicit
     // copy-constructors.
     emitImplicitAssignmentOperatorBody(Args);
-  }
-  else
-    EmitFunctionBody(Args);
+  } else if (Stmt *Body = FD->getBody()) {
+    EmitFunctionBody(Args, Body);
+  } else if (FunctionDecl *UnsizedDealloc =
+                 FD->getCorrespondingUnsizedGlobalDeallocationFunction()) {
+    // Global sized deallocation functions get an implicit weak definition if
+    // they don't have an explicit definition.
+    EmitSizedDeallocationFunction(*this, UnsizedDealloc);
+  } else
+    llvm_unreachable("no definition for emitted function");
 
   // C++11 [stmt.return]p2:
   //   Flowing off the end of a function [...] results in undefined behavior in
index b07e903b49fe6948134f3b09da85a9cd59367fee..98c090fa14978f46bdc0bbea669ad85a6e4bbd64 100644 (file)
@@ -1136,7 +1136,7 @@ public:
   void EmitConstructorBody(FunctionArgList &Args);
   void EmitDestructorBody(FunctionArgList &Args);
   void emitImplicitAssignmentOperatorBody(FunctionArgList &Args);
-  void EmitFunctionBody(FunctionArgList &Args);
+  void EmitFunctionBody(FunctionArgList &Args, const Stmt *Body);
 
   void EmitForwardingCallToLambda(const CXXMethodDecl *LambdaCallOperator,
                                   CallArgList &CallArgs);
index d0f34dddca3be425af2e06faa3cf052219fa6a9b..c34f8332699e78223edbdac0bdb099d383ccb93b 100644 (file)
@@ -1406,6 +1406,12 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
     DeferredDeclsToEmit.push_back(DDI->second);
     DeferredDecls.erase(DDI);
 
+  // Otherwise, if this is a sized deallocation function, emit a weak definition
+  // for it at the end of the translation unit.
+  } else if (D && cast<FunctionDecl>(D)
+                      ->getCorrespondingUnsizedGlobalDeallocationFunction()) {
+    DeferredDeclsToEmit.push_back(GD);
+
   // Otherwise, there are cases we have to worry about where we're
   // using a declaration for which we must emit a definition but where
   // we might not find a top-level definition:
index 3da8ba7309acb69987a1b4018bba9849ec026698..a523acfc431a9ff7a8c647fb19e21586b4f240a6 100644 (file)
@@ -1093,6 +1093,9 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
   Opts.Trigraphs = !Opts.GNUMode;
 
   Opts.DollarIdents = !Opts.AsmPreprocessor;
+
+  // C++1y onwards has sized global deallocation functions.
+  Opts.SizedDeallocation = Opts.CPlusPlus1y;
 }
 
 /// Attempt to parse a visibility value out of the given argument.
@@ -1310,7 +1313,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
   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.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);
index 767878365e8dc4256a5f4e671976eac7726d5c29..642e1e07f6cdf51d1b2509b3069b598d4eb9b9a4 100644 (file)
@@ -1,5 +1,6 @@
-// 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
+// RUN: %clang_cc1 -std=c++1y %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -fsized-deallocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefix=CHECK-UNSIZED
 
 // CHECK-UNSIZED-NOT: _ZdlPvm
 // CHECK-UNSIZED-NOT: _ZdaPvm
@@ -44,6 +45,9 @@ D::D() {}
 // CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 4)
 // CHECK: call void @_ZdaPv(i8* %{{[^ ]*}})
 
+// CHECK-LABEL: define linkonce void @_ZdlPvm(i8*
+// CHECK: call void @_ZdlPv(i8* %0)
+
 // CHECK-LABEL: define weak_odr void @_Z3delI1BEvv()
 // CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 4)
 // CHECK: call void @_ZdaPv(i8* %{{[^ ]*}})
@@ -54,6 +58,9 @@ D::D() {}
 // CHECK: add i64 %{{[^ ]*}}, 8
 // CHECK: call void @_ZdaPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}})
 
+// CHECK-LABEL: define linkonce void @_ZdaPvm(i8*
+// CHECK: call void @_ZdaPv(i8* %0)
+
 // CHECK-LABEL: define weak_odr void @_Z3delI1DEvv()
 // CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 8)
 // CHECK: mul i64 8, %{{[^ ]*}}
index 1f165b957ddec876d1ebbbff546e5aa7352577c5..d2e2fc23969e214a2ec3f0915b0725242399d442 100644 (file)
@@ -401,7 +401,7 @@ ABI-incompatible change.</span>
 
 <h2 id="cxx14">C++1y implementation status</h2>
 
-<p>Clang is introducing support for the upcoming C++ language standard,
+<p>Clang implements most of the upcoming C++ language standard,
 provisionally named C++1y.  The following table describes which C++1y features
 have been implemented in Clang and in which Clang version they became
 available.</p>
@@ -476,15 +476,10 @@ 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="partial" align="center">Partial <a href="#n3778">(1)</a></td>
+      <td class="svn" align="center">SVN</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>