]> granicus.if.org Git - clang/commitdiff
MS ABI: Insert copy-constructors into the CatchableType
authorDavid Majnemer <david.majnemer@gmail.com>
Fri, 6 Mar 2015 18:53:55 +0000 (18:53 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Fri, 6 Mar 2015 18:53:55 +0000 (18:53 +0000)
Find all unambiguous public classes of the exception object's class type
and reference all of their copy constructors.  Yes, this is not
conforming but it is necessary in order to implement their ABI.  This is
because the copy constructor is actually referenced by the metadata
describing which catch handlers are eligible to handle the exception
object.

N.B.  This doesn't yet handle the copy constructor closure case yet,
that work is ongoing.

Differential Revision: http://reviews.llvm.org/D8101

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

include/clang/AST/ASTContext.h
include/clang/AST/Mangle.h
lib/AST/ASTContext.cpp
lib/AST/CXXABI.h
lib/AST/ItaniumCXXABI.cpp
lib/AST/MicrosoftCXXABI.cpp
lib/AST/MicrosoftMangle.cpp
lib/CodeGen/MicrosoftCXXABI.cpp
lib/Sema/SemaExprCXX.cpp
test/CodeGenCXX/microsoft-abi-throw.cpp

index 9b22aa4a83fd13f28a3c96e2f12f2312a40a47bf..de6b8c668de30697b06b97717c564da34977b87b 100644 (file)
@@ -2193,6 +2193,12 @@ public:
   /// it is not used.
   bool DeclMustBeEmitted(const Decl *D);
 
+  const CXXConstructorDecl *
+  getCopyConstructorForExceptionObject(CXXRecordDecl *RD);
+
+  void addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
+                                            CXXConstructorDecl *CD);
+
   void setManglingNumber(const NamedDecl *ND, unsigned Number);
   unsigned getManglingNumber(const NamedDecl *ND) const;
 
index be5c2e2855d93c86474787943c683fb2ad07ef5c..ef030d26b4f6d58e69fa38864b2db57a151a7de9 100644 (file)
@@ -203,8 +203,8 @@ public:
   virtual void mangleCXXCatchableTypeArray(QualType T, uint32_t NumEntries,
                                            raw_ostream &Out) = 0;
 
-  virtual void mangleCXXCatchableType(QualType T, uint32_t Size,
-                                      raw_ostream &Out) = 0;
+  virtual void mangleCXXCatchableType(QualType T, const CXXConstructorDecl *CD,
+                                      uint32_t Size, raw_ostream &Out) = 0;
 
   virtual void mangleCXXRTTIBaseClassDescriptor(
       const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset,
index fc40f7e8e2387de6013c1433986946b198d3f491..9cfc97b926d32ca11c8d4cf912a11f8e614736ae 100644 (file)
@@ -8189,6 +8189,19 @@ MangleNumberingContext *ASTContext::createMangleNumberingContext() const {
   return ABI->createMangleNumberingContext();
 }
 
+const CXXConstructorDecl *
+ASTContext::getCopyConstructorForExceptionObject(CXXRecordDecl *RD) {
+  return ABI->getCopyConstructorForExceptionObject(
+      cast<CXXRecordDecl>(RD->getFirstDecl()));
+}
+
+void ASTContext::addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
+                                                      CXXConstructorDecl *CD) {
+  return ABI->addCopyConstructorForExceptionObject(
+      cast<CXXRecordDecl>(RD->getFirstDecl()),
+      cast<CXXConstructorDecl>(CD->getFirstDecl()));
+}
+
 void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) {
   ParamIndices[D] = index;
 }
index 8e9e358525e8c6e0688691b2f118a4581c5612a1..62c96f901e64952eb0d31ac744bd31fddb347f11 100644 (file)
@@ -20,6 +20,7 @@
 namespace clang {
 
 class ASTContext;
+class CXXConstructorDecl;
 class MemberPointerType;
 class MangleNumberingContext;
 
@@ -41,6 +42,14 @@ public:
 
   /// Returns a new mangling number context for this C++ ABI.
   virtual MangleNumberingContext *createMangleNumberingContext() const = 0;
+
+  /// Adds a mapping from class to copy constructor for this C++ ABI.
+  virtual void addCopyConstructorForExceptionObject(CXXRecordDecl *,
+                                                    CXXConstructorDecl *) = 0;
+
+  /// Retrieves the mapping from class to copy constructor for this C++ ABI.
+  virtual const CXXConstructorDecl *
+  getCopyConstructorForExceptionObject(CXXRecordDecl *) = 0;
 };
 
 /// Creates an instance of a C++ ABI class.
index 378121c8e5b9b89d1d2847a4c9e84d64237f4bb7..13d4dbf1f4617aa8ab9181bb2add95ffba0011ed 100644 (file)
@@ -133,6 +133,14 @@ public:
     return Layout.getNonVirtualSize() == PointerSize;
   }
 
+  const CXXConstructorDecl *
+  getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override {
+    return nullptr;
+  }
+
+  void addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
+                                            CXXConstructorDecl *CD) override {}
+
   MangleNumberingContext *createMangleNumberingContext() const override {
     return new ItaniumNumberingContext();
   }
index 0603d3b7b9b5f3fbab104d67250f6a0756d0f091..71b21bff77ccd0891c7e2a4a04a7944f360925ed 100644 (file)
@@ -63,6 +63,8 @@ public:
 
 class MicrosoftCXXABI : public CXXABI {
   ASTContext &Context;
+  llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> RecordToCopyCtor;
+
 public:
   MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { }
 
@@ -82,13 +84,26 @@ public:
       return false;
 
     const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
-    
+
     // In the Microsoft ABI, classes can have one or two vtable pointers.
-    CharUnits PointerSize = 
-      Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+    CharUnits PointerSize =
+        Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
     return Layout.getNonVirtualSize() == PointerSize ||
       Layout.getNonVirtualSize() == PointerSize * 2;
-  }    
+  }
+
+  const CXXConstructorDecl *
+  getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override {
+    return RecordToCopyCtor[RD];
+  }
+
+  void
+  addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
+                                       CXXConstructorDecl *CD) override {
+    assert(CD != nullptr);
+    assert(RecordToCopyCtor[RD] == nullptr || RecordToCopyCtor[RD] == CD);
+    RecordToCopyCtor[RD] = CD;
+  }
 
   MangleNumberingContext *createMangleNumberingContext() const override {
     return new MicrosoftNumberingContext();
index 29af2cb9c2c781be23832f2df5efb72985ca267f..3f660c9f69e8736af049381465d8c1bead8af859 100644 (file)
@@ -114,8 +114,8 @@ public:
                           uint32_t NumEntries, raw_ostream &Out) override;
   void mangleCXXCatchableTypeArray(QualType T, uint32_t NumEntries,
                                    raw_ostream &Out) override;
-  void mangleCXXCatchableType(QualType T, uint32_t Size,
-                              raw_ostream &Out) override;
+  void mangleCXXCatchableType(QualType T, const CXXConstructorDecl *CD,
+                              uint32_t Size, raw_ostream &Out) override;
   void mangleCXXRTTI(QualType T, raw_ostream &Out) override;
   void mangleCXXRTTIName(QualType T, raw_ostream &Out) override;
   void mangleCXXRTTIBaseClassDescriptor(const CXXRecordDecl *Derived,
@@ -2307,13 +2307,25 @@ void MicrosoftMangleContextImpl::mangleCXXCatchableTypeArray(
   Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
 }
 
-void MicrosoftMangleContextImpl::mangleCXXCatchableType(QualType T,
-                                                        uint32_t Size,
-                                                        raw_ostream &Out) {
+void MicrosoftMangleContextImpl::mangleCXXCatchableType(
+    QualType T, const CXXConstructorDecl *CD, uint32_t Size, raw_ostream &Out) {
   MicrosoftCXXNameMangler Mangler(*this, Out);
-  Mangler.getStream() << "_CT??_R0";
-  Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
-  Mangler.getStream() << "@8";
+  Mangler.getStream() << "_CT";
+
+  llvm::SmallString<64> RTTIMangling;
+  {
+    llvm::raw_svector_ostream Stream(RTTIMangling);
+    mangleCXXRTTI(T, Stream);
+  }
+  Mangler.getStream() << RTTIMangling.substr(1);
+
+  llvm::SmallString<64> CopyCtorMangling;
+  if (CD) {
+    llvm::raw_svector_ostream Stream(CopyCtorMangling);
+    mangleCXXCtor(CD, Ctor_Complete, Stream);
+  }
+  Mangler.getStream() << CopyCtorMangling.substr(1);
+
   Mangler.getStream() << Size;
 }
 
index dd4c274e245c3d087f551119f8619ad90fe40900..4e3d50b408ec91904c7528fbf475fa924cc99429 100644 (file)
@@ -17,6 +17,7 @@
 #include "CGCXXABI.h"
 #include "CGVTables.h"
 #include "CodeGenModule.h"
+#include "CodeGenTypes.h"
 #include "TargetInfo.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
@@ -3225,11 +3226,14 @@ llvm::Constant *MicrosoftCXXABI::getCatchableType(QualType T,
                                                   uint32_t VBIndex) {
   assert(!T->isReferenceType());
 
+  CXXRecordDecl *RD = T->getAsCXXRecordDecl();
+  const CXXConstructorDecl *CD =
+      RD ? CGM.getContext().getCopyConstructorForExceptionObject(RD) : nullptr;
   uint32_t Size = getContext().getTypeSizeInChars(T).getQuantity();
   SmallString<256> MangledName;
   {
     llvm::raw_svector_ostream Out(MangledName);
-    getMangleContext().mangleCXXCatchableType(T, Size, Out);
+    getMangleContext().mangleCXXCatchableType(T, CD, Size, Out);
   }
   if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName))
     return getImageRelativeConstant(GV);
@@ -3241,16 +3245,15 @@ llvm::Constant *MicrosoftCXXABI::getCatchableType(QualType T,
   // The runtime is responsible for calling the copy constructor if the
   // exception is caught by value.
   llvm::Constant *CopyCtor =
-      getImageRelativeConstant(llvm::Constant::getNullValue(CGM.Int8PtrTy));
+      CD ? llvm::ConstantExpr::getBitCast(
+               CGM.getAddrOfCXXStructor(CD, StructorType::Complete),
+               CGM.Int8PtrTy)
+         : llvm::Constant::getNullValue(CGM.Int8PtrTy);
+  CopyCtor = getImageRelativeConstant(CopyCtor);
 
-  bool IsScalar = true;
+  bool IsScalar = !RD;
   bool HasVirtualBases = false;
   bool IsStdBadAlloc = false; // std::bad_alloc is special for some reason.
-  if (T->getAsCXXRecordDecl()) {
-    IsScalar = false;
-    // TODO: Fill in the CopyCtor here!  This is not trivial due to
-    // copy-constructors possessing things like default arguments.
-  }
   QualType PointeeType = T;
   if (T->isPointerType())
     PointeeType = T->getPointeeType();
index 29e5150073d99f2da649aec918741fed76cd4d34..0cedf349b958e2697cea403d3033975e8de5c778 100644 (file)
@@ -657,6 +657,55 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
       CXXThrowExpr(Ex, Context.VoidTy, OpLoc, IsThrownVarInScope);
 }
 
+static void
+collectPublicBases(CXXRecordDecl *RD,
+                   llvm::DenseMap<CXXRecordDecl *, unsigned> &SubobjectsSeen,
+                   llvm::SmallPtrSetImpl<CXXRecordDecl *> &VBases,
+                   llvm::SetVector<CXXRecordDecl *> &PublicSubobjectsSeen,
+                   bool ParentIsPublic) {
+  for (const CXXBaseSpecifier &BS : RD->bases()) {
+    CXXRecordDecl *BaseDecl = BS.getType()->getAsCXXRecordDecl();
+    bool NewSubobject;
+    // Virtual bases constitute the same subobject.  Non-virtual bases are
+    // always distinct subobjects.
+    if (BS.isVirtual())
+      NewSubobject = VBases.insert(BaseDecl).second;
+    else
+      NewSubobject = true;
+
+    if (NewSubobject)
+      ++SubobjectsSeen[BaseDecl];
+
+    // Only add subobjects which have public access throughout the entire chain.
+    bool PublicPath = ParentIsPublic && BS.getAccessSpecifier() == AS_public;
+    if (PublicPath)
+      PublicSubobjectsSeen.insert(BaseDecl);
+
+    // Recurse on to each base subobject.
+    collectPublicBases(BaseDecl, SubobjectsSeen, VBases, PublicSubobjectsSeen,
+                       PublicPath);
+  }
+}
+
+static void getUnambiguousPublicSubobjects(
+    CXXRecordDecl *RD, llvm::SmallVectorImpl<CXXRecordDecl *> &Objects) {
+  llvm::DenseMap<CXXRecordDecl *, unsigned> SubobjectsSeen;
+  llvm::SmallSet<CXXRecordDecl *, 2> VBases;
+  llvm::SetVector<CXXRecordDecl *> PublicSubobjectsSeen;
+  SubobjectsSeen[RD] = 1;
+  PublicSubobjectsSeen.insert(RD);
+  collectPublicBases(RD, SubobjectsSeen, VBases, PublicSubobjectsSeen,
+                     /*ParentIsPublic=*/true);
+
+  for (CXXRecordDecl *PublicSubobject : PublicSubobjectsSeen) {
+    // Skip ambiguous objects.
+    if (SubobjectsSeen[PublicSubobject] > 1)
+      continue;
+
+    Objects.push_back(PublicSubobject);
+  }
+}
+
 /// CheckCXXThrowOperand - Validate the operand of a throw.
 ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
                                       bool IsThrownVarInScope) {
@@ -723,18 +772,29 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
     return E;
 
   // If the class has a destructor, we must be able to call it.
-  if (RD->hasIrrelevantDestructor())
-    return E;
+  if (!RD->hasIrrelevantDestructor()) {
+    if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) {
+      MarkFunctionReferenced(E->getExprLoc(), Destructor);
+      CheckDestructorAccess(E->getExprLoc(), Destructor,
+                            PDiag(diag::err_access_dtor_exception) << Ty);
+      if (DiagnoseUseOfDecl(Destructor, E->getExprLoc()))
+        return ExprError();
+    }
+  }
 
-  CXXDestructorDecl *Destructor = LookupDestructor(RD);
-  if (!Destructor)
-    return E;
+  if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+    llvm::SmallVector<CXXRecordDecl *, 2> UnambiguousPublicSubobjects;
+    getUnambiguousPublicSubobjects(RD, UnambiguousPublicSubobjects);
+    for (CXXRecordDecl *Subobject : UnambiguousPublicSubobjects) {
+      if (CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0)) {
+        if (CD->isTrivial())
+          continue;
+        MarkFunctionReferenced(E->getExprLoc(), CD);
+        Context.addCopyConstructorForExceptionObject(Subobject, CD);
+      }
+    }
+  }
 
-  MarkFunctionReferenced(E->getExprLoc(), Destructor);
-  CheckDestructorAccess(E->getExprLoc(), Destructor,
-                        PDiag(diag::err_access_dtor_exception) << Ty);
-  if (DiagnoseUseOfDecl(Destructor, E->getExprLoc()))
-    return ExprError();
   return E;
 }
 
index 93d051e8ebdfc6a30f9b77d377ba2bd4cdac4826..f0151c5d39bf3bb47fb55b6ae0affa74490c1e89 100644 (file)
@@ -1,16 +1,16 @@
 // RUN: %clang_cc1 -emit-llvm -o - -triple=i386-pc-win32 %s -fcxx-exceptions | FileCheck %s
 
 // CHECK-DAG: @"\01??_R0?AUY@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUY@@\00" }, comdat
-// CHECK-DAG: @"_CT??_R0?AUY@@@88" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 4, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUY@@@8" to i8*), i32 0, i32 -1, i32 0, i32 8, i8* null }, comdat
+// CHECK-DAG: @"_CT??_R0?AUY@@@8??0Y@@QAE@ABU0@@Z8" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 4, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUY@@@8" to i8*), i32 0, i32 -1, i32 0, i32 8, i8* bitcast (%struct.Y* (%struct.Y*, %struct.Y*, i32)* @"\01??0Y@@QAE@ABU0@@Z" to i8*) }, comdat
 // CHECK-DAG: @"\01??_R0?AUZ@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUZ@@\00" }, comdat
 // CHECK-DAG: @"_CT??_R0?AUZ@@@81" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUZ@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* null }, comdat
 // CHECK-DAG: @"\01??_R0?AUW@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUW@@\00" }, comdat
-// CHECK-DAG: @"_CT??_R0?AUW@@@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 4, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUW@@@8" to i8*), i32 4, i32 -1, i32 0, i32 4, i8* null }, comdat
+// CHECK-DAG: @"_CT??_R0?AUW@@@8??0W@@QAE@ABU0@@Z4" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 4, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUW@@@8" to i8*), i32 4, i32 -1, i32 0, i32 4, i8* bitcast (%struct.W* (%struct.W*, %struct.W*, i32)* @"\01??0W@@QAE@ABU0@@Z" to i8*) }, comdat
 // CHECK-DAG: @"\01??_R0?AUM@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUM@@\00" }, comdat
 // CHECK-DAG: @"_CT??_R0?AUM@@@81" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUM@@@8" to i8*), i32 8, i32 -1, i32 0, i32 1, i8* null }, comdat
 // CHECK-DAG: @"\01??_R0?AUV@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AUV@@\00" }, comdat
 // CHECK-DAG: @"_CT??_R0?AUV@@@81" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor7* @"\01??_R0?AUV@@@8" to i8*), i32 0, i32 4, i32 4, i32 1, i8* null }, comdat
-// CHECK-DAG: @"_CTA5?AUY@@" = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.5 { i32 5, [5 x %eh.CatchableType*] [%eh.CatchableType* @"_CT??_R0?AUY@@@88", %eh.CatchableType* @"_CT??_R0?AUZ@@@81", %eh.CatchableType* @"_CT??_R0?AUW@@@84", %eh.CatchableType* @"_CT??_R0?AUM@@@81", %eh.CatchableType* @"_CT??_R0?AUV@@@81"] }, comdat
+// CHECK-DAG: @"_CTA5?AUY@@" = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.5 { i32 5, [5 x %eh.CatchableType*] [%eh.CatchableType* @"_CT??_R0?AUY@@@8??0Y@@QAE@ABU0@@Z8", %eh.CatchableType* @"_CT??_R0?AUZ@@@81", %eh.CatchableType* @"_CT??_R0?AUW@@@8??0W@@QAE@ABU0@@Z4", %eh.CatchableType* @"_CT??_R0?AUM@@@81", %eh.CatchableType* @"_CT??_R0?AUV@@@81"] }, comdat
 // CHECK-DAG: @"_TI5?AUY@@" = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i8* bitcast (void (%struct.Y*)* @"\01??_DY@@QAE@XZ" to i8*), i8* null, i8* bitcast (%eh.CatchableTypeArray.5* @"_CTA5?AUY@@" to i8*) }, comdat