Skip to content

Commit e7a818f

Browse files
committed
MS ABI: Insert copy-constructors into the CatchableType
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 llvm-svn: 231499
1 parent eafe552 commit e7a818f

File tree

10 files changed

+161
-35
lines changed

10 files changed

+161
-35
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2193,6 +2193,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
21932193
/// it is not used.
21942194
bool DeclMustBeEmitted(const Decl *D);
21952195

2196+
const CXXConstructorDecl *
2197+
getCopyConstructorForExceptionObject(CXXRecordDecl *RD);
2198+
2199+
void addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
2200+
CXXConstructorDecl *CD);
2201+
21962202
void setManglingNumber(const NamedDecl *ND, unsigned Number);
21972203
unsigned getManglingNumber(const NamedDecl *ND) const;
21982204

clang/include/clang/AST/Mangle.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,8 @@ class MicrosoftMangleContext : public MangleContext {
203203
virtual void mangleCXXCatchableTypeArray(QualType T, uint32_t NumEntries,
204204
raw_ostream &Out) = 0;
205205

206-
virtual void mangleCXXCatchableType(QualType T, uint32_t Size,
207-
raw_ostream &Out) = 0;
206+
virtual void mangleCXXCatchableType(QualType T, const CXXConstructorDecl *CD,
207+
uint32_t Size, raw_ostream &Out) = 0;
208208

209209
virtual void mangleCXXRTTIBaseClassDescriptor(
210210
const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset,

clang/lib/AST/ASTContext.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8189,6 +8189,19 @@ MangleNumberingContext *ASTContext::createMangleNumberingContext() const {
81898189
return ABI->createMangleNumberingContext();
81908190
}
81918191

8192+
const CXXConstructorDecl *
8193+
ASTContext::getCopyConstructorForExceptionObject(CXXRecordDecl *RD) {
8194+
return ABI->getCopyConstructorForExceptionObject(
8195+
cast<CXXRecordDecl>(RD->getFirstDecl()));
8196+
}
8197+
8198+
void ASTContext::addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
8199+
CXXConstructorDecl *CD) {
8200+
return ABI->addCopyConstructorForExceptionObject(
8201+
cast<CXXRecordDecl>(RD->getFirstDecl()),
8202+
cast<CXXConstructorDecl>(CD->getFirstDecl()));
8203+
}
8204+
81928205
void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) {
81938206
ParamIndices[D] = index;
81948207
}

clang/lib/AST/CXXABI.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
namespace clang {
2121

2222
class ASTContext;
23+
class CXXConstructorDecl;
2324
class MemberPointerType;
2425
class MangleNumberingContext;
2526

@@ -41,6 +42,14 @@ class CXXABI {
4142

4243
/// Returns a new mangling number context for this C++ ABI.
4344
virtual MangleNumberingContext *createMangleNumberingContext() const = 0;
45+
46+
/// Adds a mapping from class to copy constructor for this C++ ABI.
47+
virtual void addCopyConstructorForExceptionObject(CXXRecordDecl *,
48+
CXXConstructorDecl *) = 0;
49+
50+
/// Retrieves the mapping from class to copy constructor for this C++ ABI.
51+
virtual const CXXConstructorDecl *
52+
getCopyConstructorForExceptionObject(CXXRecordDecl *) = 0;
4453
};
4554

4655
/// Creates an instance of a C++ ABI class.

clang/lib/AST/ItaniumCXXABI.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,14 @@ class ItaniumCXXABI : public CXXABI {
133133
return Layout.getNonVirtualSize() == PointerSize;
134134
}
135135

136+
const CXXConstructorDecl *
137+
getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override {
138+
return nullptr;
139+
}
140+
141+
void addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
142+
CXXConstructorDecl *CD) override {}
143+
136144
MangleNumberingContext *createMangleNumberingContext() const override {
137145
return new ItaniumNumberingContext();
138146
}

clang/lib/AST/MicrosoftCXXABI.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ class MicrosoftNumberingContext : public MangleNumberingContext {
6363

6464
class MicrosoftCXXABI : public CXXABI {
6565
ASTContext &Context;
66+
llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> RecordToCopyCtor;
67+
6668
public:
6769
MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { }
6870

@@ -82,13 +84,26 @@ class MicrosoftCXXABI : public CXXABI {
8284
return false;
8385

8486
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
85-
87+
8688
// In the Microsoft ABI, classes can have one or two vtable pointers.
87-
CharUnits PointerSize =
88-
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
89+
CharUnits PointerSize =
90+
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
8991
return Layout.getNonVirtualSize() == PointerSize ||
9092
Layout.getNonVirtualSize() == PointerSize * 2;
91-
}
93+
}
94+
95+
const CXXConstructorDecl *
96+
getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override {
97+
return RecordToCopyCtor[RD];
98+
}
99+
100+
void
101+
addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
102+
CXXConstructorDecl *CD) override {
103+
assert(CD != nullptr);
104+
assert(RecordToCopyCtor[RD] == nullptr || RecordToCopyCtor[RD] == CD);
105+
RecordToCopyCtor[RD] = CD;
106+
}
92107

93108
MangleNumberingContext *createMangleNumberingContext() const override {
94109
return new MicrosoftNumberingContext();

clang/lib/AST/MicrosoftMangle.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
114114
uint32_t NumEntries, raw_ostream &Out) override;
115115
void mangleCXXCatchableTypeArray(QualType T, uint32_t NumEntries,
116116
raw_ostream &Out) override;
117-
void mangleCXXCatchableType(QualType T, uint32_t Size,
118-
raw_ostream &Out) override;
117+
void mangleCXXCatchableType(QualType T, const CXXConstructorDecl *CD,
118+
uint32_t Size, raw_ostream &Out) override;
119119
void mangleCXXRTTI(QualType T, raw_ostream &Out) override;
120120
void mangleCXXRTTIName(QualType T, raw_ostream &Out) override;
121121
void mangleCXXRTTIBaseClassDescriptor(const CXXRecordDecl *Derived,
@@ -2307,13 +2307,25 @@ void MicrosoftMangleContextImpl::mangleCXXCatchableTypeArray(
23072307
Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
23082308
}
23092309

2310-
void MicrosoftMangleContextImpl::mangleCXXCatchableType(QualType T,
2311-
uint32_t Size,
2312-
raw_ostream &Out) {
2310+
void MicrosoftMangleContextImpl::mangleCXXCatchableType(
2311+
QualType T, const CXXConstructorDecl *CD, uint32_t Size, raw_ostream &Out) {
23132312
MicrosoftCXXNameMangler Mangler(*this, Out);
2314-
Mangler.getStream() << "_CT??_R0";
2315-
Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
2316-
Mangler.getStream() << "@8";
2313+
Mangler.getStream() << "_CT";
2314+
2315+
llvm::SmallString<64> RTTIMangling;
2316+
{
2317+
llvm::raw_svector_ostream Stream(RTTIMangling);
2318+
mangleCXXRTTI(T, Stream);
2319+
}
2320+
Mangler.getStream() << RTTIMangling.substr(1);
2321+
2322+
llvm::SmallString<64> CopyCtorMangling;
2323+
if (CD) {
2324+
llvm::raw_svector_ostream Stream(CopyCtorMangling);
2325+
mangleCXXCtor(CD, Ctor_Complete, Stream);
2326+
}
2327+
Mangler.getStream() << CopyCtorMangling.substr(1);
2328+
23172329
Mangler.getStream() << Size;
23182330
}
23192331

clang/lib/CodeGen/MicrosoftCXXABI.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "CGCXXABI.h"
1818
#include "CGVTables.h"
1919
#include "CodeGenModule.h"
20+
#include "CodeGenTypes.h"
2021
#include "TargetInfo.h"
2122
#include "clang/AST/Decl.h"
2223
#include "clang/AST/DeclCXX.h"
@@ -3225,11 +3226,14 @@ llvm::Constant *MicrosoftCXXABI::getCatchableType(QualType T,
32253226
uint32_t VBIndex) {
32263227
assert(!T->isReferenceType());
32273228

3229+
CXXRecordDecl *RD = T->getAsCXXRecordDecl();
3230+
const CXXConstructorDecl *CD =
3231+
RD ? CGM.getContext().getCopyConstructorForExceptionObject(RD) : nullptr;
32283232
uint32_t Size = getContext().getTypeSizeInChars(T).getQuantity();
32293233
SmallString<256> MangledName;
32303234
{
32313235
llvm::raw_svector_ostream Out(MangledName);
3232-
getMangleContext().mangleCXXCatchableType(T, Size, Out);
3236+
getMangleContext().mangleCXXCatchableType(T, CD, Size, Out);
32333237
}
32343238
if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName))
32353239
return getImageRelativeConstant(GV);
@@ -3241,16 +3245,15 @@ llvm::Constant *MicrosoftCXXABI::getCatchableType(QualType T,
32413245
// The runtime is responsible for calling the copy constructor if the
32423246
// exception is caught by value.
32433247
llvm::Constant *CopyCtor =
3244-
getImageRelativeConstant(llvm::Constant::getNullValue(CGM.Int8PtrTy));
3248+
CD ? llvm::ConstantExpr::getBitCast(
3249+
CGM.getAddrOfCXXStructor(CD, StructorType::Complete),
3250+
CGM.Int8PtrTy)
3251+
: llvm::Constant::getNullValue(CGM.Int8PtrTy);
3252+
CopyCtor = getImageRelativeConstant(CopyCtor);
32453253

3246-
bool IsScalar = true;
3254+
bool IsScalar = !RD;
32473255
bool HasVirtualBases = false;
32483256
bool IsStdBadAlloc = false; // std::bad_alloc is special for some reason.
3249-
if (T->getAsCXXRecordDecl()) {
3250-
IsScalar = false;
3251-
// TODO: Fill in the CopyCtor here! This is not trivial due to
3252-
// copy-constructors possessing things like default arguments.
3253-
}
32543257
QualType PointeeType = T;
32553258
if (T->isPointerType())
32563259
PointeeType = T->getPointeeType();

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,55 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
657657
CXXThrowExpr(Ex, Context.VoidTy, OpLoc, IsThrownVarInScope);
658658
}
659659

660+
static void
661+
collectPublicBases(CXXRecordDecl *RD,
662+
llvm::DenseMap<CXXRecordDecl *, unsigned> &SubobjectsSeen,
663+
llvm::SmallPtrSetImpl<CXXRecordDecl *> &VBases,
664+
llvm::SetVector<CXXRecordDecl *> &PublicSubobjectsSeen,
665+
bool ParentIsPublic) {
666+
for (const CXXBaseSpecifier &BS : RD->bases()) {
667+
CXXRecordDecl *BaseDecl = BS.getType()->getAsCXXRecordDecl();
668+
bool NewSubobject;
669+
// Virtual bases constitute the same subobject. Non-virtual bases are
670+
// always distinct subobjects.
671+
if (BS.isVirtual())
672+
NewSubobject = VBases.insert(BaseDecl).second;
673+
else
674+
NewSubobject = true;
675+
676+
if (NewSubobject)
677+
++SubobjectsSeen[BaseDecl];
678+
679+
// Only add subobjects which have public access throughout the entire chain.
680+
bool PublicPath = ParentIsPublic && BS.getAccessSpecifier() == AS_public;
681+
if (PublicPath)
682+
PublicSubobjectsSeen.insert(BaseDecl);
683+
684+
// Recurse on to each base subobject.
685+
collectPublicBases(BaseDecl, SubobjectsSeen, VBases, PublicSubobjectsSeen,
686+
PublicPath);
687+
}
688+
}
689+
690+
static void getUnambiguousPublicSubobjects(
691+
CXXRecordDecl *RD, llvm::SmallVectorImpl<CXXRecordDecl *> &Objects) {
692+
llvm::DenseMap<CXXRecordDecl *, unsigned> SubobjectsSeen;
693+
llvm::SmallSet<CXXRecordDecl *, 2> VBases;
694+
llvm::SetVector<CXXRecordDecl *> PublicSubobjectsSeen;
695+
SubobjectsSeen[RD] = 1;
696+
PublicSubobjectsSeen.insert(RD);
697+
collectPublicBases(RD, SubobjectsSeen, VBases, PublicSubobjectsSeen,
698+
/*ParentIsPublic=*/true);
699+
700+
for (CXXRecordDecl *PublicSubobject : PublicSubobjectsSeen) {
701+
// Skip ambiguous objects.
702+
if (SubobjectsSeen[PublicSubobject] > 1)
703+
continue;
704+
705+
Objects.push_back(PublicSubobject);
706+
}
707+
}
708+
660709
/// CheckCXXThrowOperand - Validate the operand of a throw.
661710
ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
662711
bool IsThrownVarInScope) {
@@ -723,18 +772,29 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
723772
return E;
724773

725774
// If the class has a destructor, we must be able to call it.
726-
if (RD->hasIrrelevantDestructor())
727-
return E;
775+
if (!RD->hasIrrelevantDestructor()) {
776+
if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) {
777+
MarkFunctionReferenced(E->getExprLoc(), Destructor);
778+
CheckDestructorAccess(E->getExprLoc(), Destructor,
779+
PDiag(diag::err_access_dtor_exception) << Ty);
780+
if (DiagnoseUseOfDecl(Destructor, E->getExprLoc()))
781+
return ExprError();
782+
}
783+
}
728784

729-
CXXDestructorDecl *Destructor = LookupDestructor(RD);
730-
if (!Destructor)
731-
return E;
785+
if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
786+
llvm::SmallVector<CXXRecordDecl *, 2> UnambiguousPublicSubobjects;
787+
getUnambiguousPublicSubobjects(RD, UnambiguousPublicSubobjects);
788+
for (CXXRecordDecl *Subobject : UnambiguousPublicSubobjects) {
789+
if (CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0)) {
790+
if (CD->isTrivial())
791+
continue;
792+
MarkFunctionReferenced(E->getExprLoc(), CD);
793+
Context.addCopyConstructorForExceptionObject(Subobject, CD);
794+
}
795+
}
796+
}
732797

733-
MarkFunctionReferenced(E->getExprLoc(), Destructor);
734-
CheckDestructorAccess(E->getExprLoc(), Destructor,
735-
PDiag(diag::err_access_dtor_exception) << Ty);
736-
if (DiagnoseUseOfDecl(Destructor, E->getExprLoc()))
737-
return ExprError();
738798
return E;
739799
}
740800

clang/test/CodeGenCXX/microsoft-abi-throw.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
// RUN: %clang_cc1 -emit-llvm -o - -triple=i386-pc-win32 %s -fcxx-exceptions | FileCheck %s
22

33
// 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
4-
// 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
4+
// 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
55
// 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
66
// 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
77
// 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
8-
// 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
8+
// 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
99
// 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
1010
// 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
1111
// 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
1212
// 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
13-
// 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
13+
// 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
1414
// 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
1515

1616

0 commit comments

Comments
 (0)