Explorar o código

C++1y sized deallocation: if we have a use, but not a definition, of a sized
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

Richard Smith %!s(int64=11) %!d(string=hai) anos
pai
achega
3cebc73895

+ 5 - 0
include/clang/AST/Decl.h

@@ -1793,6 +1793,11 @@ public:
   ///    allocation function. [...]
   ///    allocation function. [...]
   bool isReplaceableGlobalAllocationFunction() const;
   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.
   /// Compute the language linkage.
   LanguageLinkage getLanguageLinkage() const;
   LanguageLinkage getLanguageLinkage() const;
 
 

+ 33 - 1
lib/AST/Decl.cpp

@@ -2354,7 +2354,8 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
   // 'const std::nothrow_t &', or, in C++1y, 'std::size_t'.
   // 'const std::nothrow_t &', or, in C++1y, 'std::size_t'.
   QualType Ty = FPT->getArgType(1);
   QualType Ty = FPT->getArgType(1);
   ASTContext &Ctx = getASTContext();
   ASTContext &Ctx = getASTContext();
-  if (Ctx.getLangOpts().SizedDeallocation && Ty == Ctx.getSizeType())
+  if (Ctx.getLangOpts().SizedDeallocation &&
+      Ctx.hasSameType(Ty, Ctx.getSizeType()))
     return true;
     return true;
   if (!Ty->isReferenceType())
   if (!Ty->isReferenceType())
     return false;
     return false;
@@ -2366,6 +2367,37 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
   return RD && isNamed(RD, "nothrow_t") && isNamespaceStd(RD->getDeclContext());
   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 {
 LanguageLinkage FunctionDecl::getLanguageLinkage() const {
   return getLanguageLinkageTemplate(*this);
   return getLanguageLinkageTemplate(*this);
 }
 }

+ 1 - 1
lib/CodeGen/CGClass.cpp

@@ -2180,7 +2180,7 @@ void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) {
     return;
     return;
   }
   }
 
 
-  EmitFunctionBody(Args);
+  EmitFunctionBody(Args, cast<FunctionDecl>(CurGD.getDecl())->getBody());
 }
 }
 
 
 void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) {
 void CodeGenFunction::EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD) {

+ 2 - 2
lib/CodeGen/CGExpr.cpp

@@ -1824,8 +1824,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
     return LV;
     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");
   llvm_unreachable("Unhandled DeclRefExpr");
 }
 }

+ 24 - 8
lib/CodeGen/CodeGenFunction.cpp

@@ -643,13 +643,12 @@ void CodeGenFunction::StartFunction(GlobalDecl GD,
     DI->EmitLocation(Builder, StartLoc);
     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);
     EmitCompoundStmtWithoutScope(*S);
   else
   else
-    EmitStmt(FD->getBody());
+    EmitStmt(Body);
 }
 }
 
 
 /// Tries to mark the given function nounwind based on the
 /// Tries to mark the given function nounwind based on the
@@ -672,6 +671,17 @@ static void TryMarkNoThrow(llvm::Function *F) {
   F->setDoesNotThrow();
   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,
 void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
                                    const CGFunctionInfo &FnInfo) {
                                    const CGFunctionInfo &FnInfo) {
   const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
   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
     // Implicit copy-assignment gets the same special treatment as implicit
     // copy-constructors.
     // copy-constructors.
     emitImplicitAssignmentOperatorBody(Args);
     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:
   // C++11 [stmt.return]p2:
   //   Flowing off the end of a function [...] results in undefined behavior in
   //   Flowing off the end of a function [...] results in undefined behavior in

+ 1 - 1
lib/CodeGen/CodeGenFunction.h

@@ -1136,7 +1136,7 @@ public:
   void EmitConstructorBody(FunctionArgList &Args);
   void EmitConstructorBody(FunctionArgList &Args);
   void EmitDestructorBody(FunctionArgList &Args);
   void EmitDestructorBody(FunctionArgList &Args);
   void emitImplicitAssignmentOperatorBody(FunctionArgList &Args);
   void emitImplicitAssignmentOperatorBody(FunctionArgList &Args);
-  void EmitFunctionBody(FunctionArgList &Args);
+  void EmitFunctionBody(FunctionArgList &Args, const Stmt *Body);
 
 
   void EmitForwardingCallToLambda(const CXXMethodDecl *LambdaCallOperator,
   void EmitForwardingCallToLambda(const CXXMethodDecl *LambdaCallOperator,
                                   CallArgList &CallArgs);
                                   CallArgList &CallArgs);

+ 6 - 0
lib/CodeGen/CodeGenModule.cpp

@@ -1406,6 +1406,12 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
     DeferredDeclsToEmit.push_back(DDI->second);
     DeferredDeclsToEmit.push_back(DDI->second);
     DeferredDecls.erase(DDI);
     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
   // Otherwise, there are cases we have to worry about where we're
   // using a declaration for which we must emit a definition but where
   // using a declaration for which we must emit a definition but where
   // we might not find a top-level definition:
   // we might not find a top-level definition:

+ 4 - 1
lib/Frontend/CompilerInvocation.cpp

@@ -1093,6 +1093,9 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
   Opts.Trigraphs = !Opts.GNUMode;
   Opts.Trigraphs = !Opts.GNUMode;
 
 
   Opts.DollarIdents = !Opts.AsmPreprocessor;
   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.
 /// 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.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
   Opts.NoMathBuiltin = Args.hasArg(OPT_fno_math_builtin);
   Opts.NoMathBuiltin = Args.hasArg(OPT_fno_math_builtin);
   Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
   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.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions);
   Opts.AccessControl = !Args.hasArg(OPT_fno_access_control);
   Opts.AccessControl = !Args.hasArg(OPT_fno_access_control);
   Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);
   Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);

+ 9 - 2
test/CodeGenCXX/cxx1y-sized-deallocation.cpp

@@ -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: _ZdlPvm
 // CHECK-UNSIZED-NOT: _ZdaPvm
 // CHECK-UNSIZED-NOT: _ZdaPvm
@@ -44,6 +45,9 @@ D::D() {}
 // CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 4)
 // CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 4)
 // CHECK: call void @_ZdaPv(i8* %{{[^ ]*}})
 // 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-LABEL: define weak_odr void @_Z3delI1BEvv()
 // CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 4)
 // CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 4)
 // CHECK: call void @_ZdaPv(i8* %{{[^ ]*}})
 // CHECK: call void @_ZdaPv(i8* %{{[^ ]*}})
@@ -54,6 +58,9 @@ D::D() {}
 // CHECK: add i64 %{{[^ ]*}}, 8
 // CHECK: add i64 %{{[^ ]*}}, 8
 // CHECK: call void @_ZdaPvm(i8* %{{[^ ]*}}, i64 %{{[^ ]*}})
 // 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-LABEL: define weak_odr void @_Z3delI1DEvv()
 // CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 8)
 // CHECK: call void @_ZdlPvm(i8* %{{[^ ]*}}, i64 8)
 // CHECK: mul i64 8, %{{[^ ]*}}
 // CHECK: mul i64 8, %{{[^ ]*}}

+ 2 - 7
www/cxx_status.html

@@ -401,7 +401,7 @@ ABI-incompatible change.</span>
 
 
 <h2 id="cxx14">C++1y implementation status</h2>
 <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
 provisionally named C++1y.  The following table describes which C++1y features
 have been implemented in Clang and in which Clang version they became
 have been implemented in Clang and in which Clang version they became
 available.</p>
 available.</p>
@@ -476,15 +476,10 @@ available.</p>
     <tr>
     <tr>
       <td>C++ Sized Deallocation</td>
       <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><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>
     </tr>
 </table>
 </table>
 
 
-<p>
-<span id="n3778">(1): Use the experimental <tt>-Xclang -fsized-deallocation</tt>
-flag to enable this feature.</span><br>
-</p>
-
 </div>
 </div>
 </body>
 </body>
 </html>
 </html>