forked from OSchip/llvm-project
MS ABI: Implement copy-ctor closures, finish implementing throw
This adds support for copy-constructor closures. These are generated when the C++ runtime has to call a copy-constructor with a particular calling convention or with default arguments substituted in to the call. Because the runtime has no mechanism to call the function with a different calling convention or know-how to evaluate the default arguments at run-time, we create a thunk which will do all the appropriate work and package it in a way the runtime can use. Differential Revision: http://reviews.llvm.org/D8225 llvm-svn: 231952
This commit is contained in:
parent
4320495319
commit
dfa6d2067c
|
@ -2201,6 +2201,12 @@ public:
|
|||
void addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
|
||||
CXXConstructorDecl *CD);
|
||||
|
||||
void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
|
||||
unsigned ParmIdx, Expr *DAE);
|
||||
|
||||
Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
|
||||
unsigned ParmIdx);
|
||||
|
||||
void setManglingNumber(const NamedDecl *ND, unsigned Number);
|
||||
unsigned getManglingNumber(const NamedDecl *ND) const;
|
||||
|
||||
|
|
|
@ -204,9 +204,9 @@ public:
|
|||
raw_ostream &Out) = 0;
|
||||
|
||||
virtual void mangleCXXCatchableType(QualType T, const CXXConstructorDecl *CD,
|
||||
uint32_t Size, uint32_t NVOffset,
|
||||
int32_t VBPtrOffset, uint32_t VBIndex,
|
||||
raw_ostream &Out) = 0;
|
||||
CXXCtorType CT, uint32_t Size,
|
||||
uint32_t NVOffset, int32_t VBPtrOffset,
|
||||
uint32_t VBIndex, raw_ostream &Out) = 0;
|
||||
|
||||
virtual void mangleCXXRTTIBaseClassDescriptor(
|
||||
const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset,
|
||||
|
|
|
@ -22,9 +22,11 @@ namespace clang {
|
|||
|
||||
/// \brief C++ constructor types.
|
||||
enum CXXCtorType {
|
||||
Ctor_Complete, ///< Complete object ctor
|
||||
Ctor_Base, ///< Base object ctor
|
||||
Ctor_Comdat ///< The COMDAT used for ctors
|
||||
Ctor_Complete, ///< Complete object ctor
|
||||
Ctor_Base, ///< Base object ctor
|
||||
Ctor_Comdat, ///< The COMDAT used for ctors
|
||||
Ctor_CopyingClosure, ///< Copying closure variant of a ctor
|
||||
Ctor_DefaultClosure, ///< Default closure variant of a ctor
|
||||
};
|
||||
|
||||
/// \brief C++ destructor types.
|
||||
|
|
|
@ -8210,6 +8210,18 @@ void ASTContext::addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
|
|||
cast<CXXConstructorDecl>(CD->getFirstDecl()));
|
||||
}
|
||||
|
||||
void ASTContext::addDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
|
||||
unsigned ParmIdx, Expr *DAE) {
|
||||
ABI->addDefaultArgExprForConstructor(
|
||||
cast<CXXConstructorDecl>(CD->getFirstDecl()), ParmIdx, DAE);
|
||||
}
|
||||
|
||||
Expr *ASTContext::getDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
|
||||
unsigned ParmIdx) {
|
||||
return ABI->getDefaultArgExprForConstructor(
|
||||
cast<CXXConstructorDecl>(CD->getFirstDecl()), ParmIdx);
|
||||
}
|
||||
|
||||
void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) {
|
||||
ParamIndices[D] = index;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace clang {
|
|||
|
||||
class ASTContext;
|
||||
class CXXConstructorDecl;
|
||||
class Expr;
|
||||
class MemberPointerType;
|
||||
class MangleNumberingContext;
|
||||
|
||||
|
@ -50,6 +51,12 @@ public:
|
|||
/// Retrieves the mapping from class to copy constructor for this C++ ABI.
|
||||
virtual const CXXConstructorDecl *
|
||||
getCopyConstructorForExceptionObject(CXXRecordDecl *) = 0;
|
||||
|
||||
virtual void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
|
||||
unsigned ParmIdx, Expr *DAE) = 0;
|
||||
|
||||
virtual Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
|
||||
unsigned ParmIdx) = 0;
|
||||
};
|
||||
|
||||
/// Creates an instance of a C++ ABI class.
|
||||
|
|
|
@ -141,6 +141,14 @@ public:
|
|||
void addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
|
||||
CXXConstructorDecl *CD) override {}
|
||||
|
||||
void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
|
||||
unsigned ParmIdx, Expr *DAE) override {}
|
||||
|
||||
Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
|
||||
unsigned ParmIdx) override {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MangleNumberingContext *createMangleNumberingContext() const override {
|
||||
return new ItaniumNumberingContext();
|
||||
}
|
||||
|
|
|
@ -3442,6 +3442,9 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) {
|
|||
case Ctor_Comdat:
|
||||
Out << "C5";
|
||||
break;
|
||||
case Ctor_DefaultClosure:
|
||||
case Ctor_CopyingClosure:
|
||||
llvm_unreachable("closure constructors don't exist for the Itanium ABI!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,8 @@ public:
|
|||
class MicrosoftCXXABI : public CXXABI {
|
||||
ASTContext &Context;
|
||||
llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> RecordToCopyCtor;
|
||||
llvm::SmallDenseMap<std::pair<const CXXConstructorDecl *, unsigned>, Expr *>
|
||||
CtorToDefaultArgExpr;
|
||||
|
||||
public:
|
||||
MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { }
|
||||
|
@ -92,6 +94,16 @@ public:
|
|||
Layout.getNonVirtualSize() == PointerSize * 2;
|
||||
}
|
||||
|
||||
void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
|
||||
unsigned ParmIdx, Expr *DAE) override {
|
||||
CtorToDefaultArgExpr[std::make_pair(CD, ParmIdx)] = DAE;
|
||||
}
|
||||
|
||||
Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
|
||||
unsigned ParmIdx) override {
|
||||
return CtorToDefaultArgExpr[std::make_pair(CD, ParmIdx)];
|
||||
}
|
||||
|
||||
const CXXConstructorDecl *
|
||||
getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override {
|
||||
return RecordToCopyCtor[RD];
|
||||
|
|
|
@ -67,11 +67,15 @@ static const DeclContext *getEffectiveParentContext(const DeclContext *DC) {
|
|||
return getEffectiveDeclContext(cast<Decl>(DC));
|
||||
}
|
||||
|
||||
static const FunctionDecl *getStructor(const FunctionDecl *fn) {
|
||||
if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate())
|
||||
return ftd->getTemplatedDecl();
|
||||
static const FunctionDecl *getStructor(const NamedDecl *ND) {
|
||||
if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(ND))
|
||||
return FTD->getTemplatedDecl();
|
||||
|
||||
return fn;
|
||||
const auto *FD = cast<FunctionDecl>(ND);
|
||||
if (const auto *FTD = FD->getPrimaryTemplate())
|
||||
return FTD->getTemplatedDecl();
|
||||
|
||||
return FD;
|
||||
}
|
||||
|
||||
static bool isLambda(const NamedDecl *ND) {
|
||||
|
@ -115,7 +119,7 @@ public:
|
|||
void mangleCXXCatchableTypeArray(QualType T, uint32_t NumEntries,
|
||||
raw_ostream &Out) override;
|
||||
void mangleCXXCatchableType(QualType T, const CXXConstructorDecl *CD,
|
||||
uint32_t Size, uint32_t NVOffset,
|
||||
CXXCtorType CT, uint32_t Size, uint32_t NVOffset,
|
||||
int32_t VBPtrOffset, uint32_t VBIndex,
|
||||
raw_ostream &Out) override;
|
||||
void mangleCXXRTTI(QualType T, raw_ostream &Out) override;
|
||||
|
@ -223,6 +227,12 @@ public:
|
|||
PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
|
||||
64) {}
|
||||
|
||||
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_,
|
||||
const CXXConstructorDecl *D, CXXCtorType Type)
|
||||
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
|
||||
PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
|
||||
64) {}
|
||||
|
||||
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_,
|
||||
const CXXDestructorDecl *D, CXXDtorType Type)
|
||||
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
|
||||
|
@ -284,6 +294,7 @@ private:
|
|||
void mangleDecayedArrayType(const ArrayType *T);
|
||||
void mangleArrayType(const ArrayType *T);
|
||||
void mangleFunctionClass(const FunctionDecl *FD);
|
||||
void mangleCallingConvention(CallingConv CC);
|
||||
void mangleCallingConvention(const FunctionType *T);
|
||||
void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean);
|
||||
void mangleExpression(const Expr *E);
|
||||
|
@ -770,12 +781,18 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
|
|||
llvm_unreachable("Can't mangle Objective-C selector names here!");
|
||||
|
||||
case DeclarationName::CXXConstructorName:
|
||||
if (ND == Structor) {
|
||||
assert(StructorType == Ctor_Complete &&
|
||||
"Should never be asked to mangle a ctor other than complete");
|
||||
if (Structor == getStructor(ND)) {
|
||||
if (StructorType == Ctor_CopyingClosure) {
|
||||
Out << "?_O";
|
||||
return;
|
||||
}
|
||||
if (StructorType == Ctor_DefaultClosure) {
|
||||
Out << "?_F";
|
||||
return;
|
||||
}
|
||||
}
|
||||
Out << "?0";
|
||||
break;
|
||||
return;
|
||||
|
||||
case DeclarationName::CXXDestructorName:
|
||||
if (ND == Structor)
|
||||
|
@ -1566,12 +1583,22 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
|
|||
SourceRange Range;
|
||||
if (D) Range = D->getSourceRange();
|
||||
|
||||
bool IsStructor = false, HasThisQuals = ForceThisQuals;
|
||||
bool IsStructor = false, HasThisQuals = ForceThisQuals, IsCtorClosure = false;
|
||||
CallingConv CC = T->getCallConv();
|
||||
if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(D)) {
|
||||
if (MD->isInstance())
|
||||
HasThisQuals = true;
|
||||
if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD))
|
||||
if (isa<CXXDestructorDecl>(MD)) {
|
||||
IsStructor = true;
|
||||
} else if (isa<CXXConstructorDecl>(MD)) {
|
||||
IsStructor = true;
|
||||
IsCtorClosure = (StructorType == Ctor_CopyingClosure ||
|
||||
StructorType == Ctor_DefaultClosure) &&
|
||||
getStructor(MD) == Structor;
|
||||
if (IsCtorClosure)
|
||||
CC = getASTContext().getDefaultCallingConvention(
|
||||
/*IsVariadic=*/false, /*IsCXXMethod=*/true);
|
||||
}
|
||||
}
|
||||
|
||||
// If this is a C++ instance method, mangle the CVR qualifiers for the
|
||||
|
@ -1583,7 +1610,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
|
|||
mangleQualifiers(Quals, /*IsMember=*/false);
|
||||
}
|
||||
|
||||
mangleCallingConvention(T);
|
||||
mangleCallingConvention(CC);
|
||||
|
||||
// <return-type> ::= <type>
|
||||
// ::= @ # structors (they have no declared return type)
|
||||
|
@ -1597,6 +1624,28 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
|
|||
Out << (PointersAre64Bit ? "PEAXI@Z" : "PAXI@Z");
|
||||
return;
|
||||
}
|
||||
if (IsCtorClosure) {
|
||||
// Default constructor closure and copy constructor closure both return
|
||||
// void.
|
||||
Out << 'X';
|
||||
|
||||
if (StructorType == Ctor_DefaultClosure) {
|
||||
// Default constructor closure always has no arguments.
|
||||
Out << 'X';
|
||||
} else if (StructorType == Ctor_CopyingClosure) {
|
||||
// Copy constructor closure always takes an unqualified reference.
|
||||
mangleArgumentType(getASTContext().getLValueReferenceType(
|
||||
Proto->getParamType(0)
|
||||
->getAs<LValueReferenceType>()
|
||||
->getPointeeType(),
|
||||
/*SpelledAsLValue=*/true),
|
||||
Range);
|
||||
} else {
|
||||
llvm_unreachable("unexpected constructor closure!");
|
||||
}
|
||||
Out << "@Z";
|
||||
return;
|
||||
}
|
||||
Out << '@';
|
||||
} else {
|
||||
QualType ResultType = Proto->getReturnType();
|
||||
|
@ -1689,7 +1738,7 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) {
|
|||
} else
|
||||
Out << 'Y';
|
||||
}
|
||||
void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) {
|
||||
void MicrosoftCXXNameMangler::mangleCallingConvention(CallingConv CC) {
|
||||
// <calling-convention> ::= A # __cdecl
|
||||
// ::= B # __export __cdecl
|
||||
// ::= C # __pascal
|
||||
|
@ -1706,7 +1755,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) {
|
|||
// that keyword. (It didn't actually export them, it just made them so
|
||||
// that they could be in a DLL and somebody from another module could call
|
||||
// them.)
|
||||
CallingConv CC = T->getCallConv();
|
||||
|
||||
switch (CC) {
|
||||
default:
|
||||
llvm_unreachable("Unsupported CC for mangling");
|
||||
|
@ -1720,6 +1769,9 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) {
|
|||
case CC_X86VectorCall: Out << 'Q'; break;
|
||||
}
|
||||
}
|
||||
void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) {
|
||||
mangleCallingConvention(T->getCallConv());
|
||||
}
|
||||
void MicrosoftCXXNameMangler::mangleThrowSpecification(
|
||||
const FunctionProtoType *FT) {
|
||||
// <throw-spec> ::= Z # throw(...) (default)
|
||||
|
@ -2310,8 +2362,9 @@ void MicrosoftMangleContextImpl::mangleCXXCatchableTypeArray(
|
|||
}
|
||||
|
||||
void MicrosoftMangleContextImpl::mangleCXXCatchableType(
|
||||
QualType T, const CXXConstructorDecl *CD, uint32_t Size, uint32_t NVOffset,
|
||||
int32_t VBPtrOffset, uint32_t VBIndex, raw_ostream &Out) {
|
||||
QualType T, const CXXConstructorDecl *CD, CXXCtorType CT, uint32_t Size,
|
||||
uint32_t NVOffset, int32_t VBPtrOffset, uint32_t VBIndex,
|
||||
raw_ostream &Out) {
|
||||
MicrosoftCXXNameMangler Mangler(*this, Out);
|
||||
Mangler.getStream() << "_CT";
|
||||
|
||||
|
@ -2328,7 +2381,7 @@ void MicrosoftMangleContextImpl::mangleCXXCatchableType(
|
|||
llvm::SmallString<64> CopyCtorMangling;
|
||||
if (CD) {
|
||||
llvm::raw_svector_ostream Stream(CopyCtorMangling);
|
||||
mangleCXXCtor(CD, Ctor_Complete, Stream);
|
||||
mangleCXXCtor(CD, CT, Stream);
|
||||
}
|
||||
Mangler.getStream() << CopyCtorMangling.substr(1);
|
||||
|
||||
|
@ -2411,7 +2464,7 @@ void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) {
|
|||
void MicrosoftMangleContextImpl::mangleCXXCtor(const CXXConstructorDecl *D,
|
||||
CXXCtorType Type,
|
||||
raw_ostream &Out) {
|
||||
MicrosoftCXXNameMangler mangler(*this, Out);
|
||||
MicrosoftCXXNameMangler mangler(*this, Out, D, Type);
|
||||
mangler.mangle(D);
|
||||
}
|
||||
|
||||
|
|
|
@ -346,6 +346,22 @@ CodeGenTypes::arrangeMSMemberPointerThunk(const CXXMethodDecl *MD) {
|
|||
FTP->getExtInfo(), RequiredArgs(1));
|
||||
}
|
||||
|
||||
const CGFunctionInfo &
|
||||
CodeGenTypes::arrangeMSCopyCtorClosure(const CXXConstructorDecl *CD) {
|
||||
CanQual<FunctionProtoType> FTP = GetFormalType(CD);
|
||||
SmallVector<CanQualType, 2> ArgTys;
|
||||
const CXXRecordDecl *RD = CD->getParent();
|
||||
ArgTys.push_back(GetThisType(Context, RD));
|
||||
ArgTys.push_back(*FTP->param_type_begin());
|
||||
if (RD->getNumVBases() > 0)
|
||||
ArgTys.push_back(Context.IntTy);
|
||||
CallingConv CC = Context.getDefaultCallingConvention(
|
||||
/*IsVariadic=*/false, /*IsCXXMethod=*/true);
|
||||
return arrangeLLVMFunctionInfo(Context.VoidTy, /*instanceMethod=*/true,
|
||||
/*chainCall=*/false, ArgTys,
|
||||
FunctionType::ExtInfo(CC), RequiredArgs::All);
|
||||
}
|
||||
|
||||
/// Arrange a call as unto a free function, except possibly with an
|
||||
/// additional number of formal parameters considered required.
|
||||
static const CGFunctionInfo &
|
||||
|
|
|
@ -82,6 +82,9 @@ inline StructorType getFromCtorType(CXXCtorType T) {
|
|||
return StructorType::Base;
|
||||
case Ctor_Comdat:
|
||||
llvm_unreachable("not expecting a COMDAT");
|
||||
case Ctor_CopyingClosure:
|
||||
case Ctor_DefaultClosure:
|
||||
llvm_unreachable("not expecting a closure");
|
||||
}
|
||||
llvm_unreachable("not a CXXCtorType");
|
||||
}
|
||||
|
@ -261,6 +264,7 @@ public:
|
|||
const FunctionProtoType *type,
|
||||
RequiredArgs required);
|
||||
const CGFunctionInfo &arrangeMSMemberPointerThunk(const CXXMethodDecl *MD);
|
||||
const CGFunctionInfo &arrangeMSCopyCtorClosure(const CXXConstructorDecl *CD);
|
||||
|
||||
const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionProtoType> Ty);
|
||||
const CGFunctionInfo &arrangeFreeFunctionType(CanQual<FunctionNoProtoType> Ty);
|
||||
|
|
|
@ -635,6 +635,8 @@ public:
|
|||
return Fn;
|
||||
}
|
||||
|
||||
llvm::Function *getAddrOfCXXCopyCtorClosure(const CXXConstructorDecl *CD);
|
||||
|
||||
llvm::Constant *getCatchableType(QualType T,
|
||||
uint32_t NVOffset = 0,
|
||||
int32_t VBPtrOffset = -1,
|
||||
|
@ -3220,6 +3222,103 @@ void MicrosoftCXXABI::emitCXXStructor(const CXXMethodDecl *MD,
|
|||
emitCXXDestructor(CGM, cast<CXXDestructorDecl>(MD), Type);
|
||||
}
|
||||
|
||||
llvm::Function *
|
||||
MicrosoftCXXABI::getAddrOfCXXCopyCtorClosure(const CXXConstructorDecl *CD) {
|
||||
// Calculate the mangled name.
|
||||
SmallString<256> ThunkName;
|
||||
llvm::raw_svector_ostream Out(ThunkName);
|
||||
getMangleContext().mangleCXXCtor(CD, Ctor_CopyingClosure, Out);
|
||||
Out.flush();
|
||||
|
||||
// If the thunk has been generated previously, just return it.
|
||||
if (llvm::GlobalValue *GV = CGM.getModule().getNamedValue(ThunkName))
|
||||
return cast<llvm::Function>(GV);
|
||||
|
||||
// Create the llvm::Function.
|
||||
const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeMSCopyCtorClosure(CD);
|
||||
llvm::FunctionType *ThunkTy = CGM.getTypes().GetFunctionType(FnInfo);
|
||||
const CXXRecordDecl *RD = CD->getParent();
|
||||
QualType RecordTy = getContext().getRecordType(RD);
|
||||
llvm::Function *ThunkFn = llvm::Function::Create(
|
||||
ThunkTy, getLinkageForRTTI(RecordTy), ThunkName.str(), &CGM.getModule());
|
||||
|
||||
// Start codegen.
|
||||
CodeGenFunction CGF(CGM);
|
||||
CGF.CurGD = GlobalDecl(CD, Ctor_Complete);
|
||||
|
||||
// Build FunctionArgs.
|
||||
FunctionArgList FunctionArgs;
|
||||
|
||||
// A copy constructor always starts with a 'this' pointer as its first
|
||||
// argument.
|
||||
buildThisParam(CGF, FunctionArgs);
|
||||
|
||||
// Following the 'this' pointer is a reference to the source object that we
|
||||
// are copying from.
|
||||
ImplicitParamDecl SrcParam(
|
||||
getContext(), nullptr, SourceLocation(), &getContext().Idents.get("src"),
|
||||
getContext().getLValueReferenceType(RecordTy,
|
||||
/*SpelledAsLValue=*/true));
|
||||
FunctionArgs.push_back(&SrcParam);
|
||||
|
||||
// Copy constructors for classes which utilize virtual bases have an
|
||||
// additional parameter which indicates whether or not it is being delegated
|
||||
// to by a more derived constructor.
|
||||
ImplicitParamDecl IsMostDerived(getContext(), nullptr, SourceLocation(),
|
||||
&getContext().Idents.get("is_most_derived"),
|
||||
getContext().IntTy);
|
||||
// Only add the parameter to the list if thie class has virtual bases.
|
||||
if (RD->getNumVBases() > 0)
|
||||
FunctionArgs.push_back(&IsMostDerived);
|
||||
|
||||
// Start defining the function.
|
||||
CGF.StartFunction(GlobalDecl(), FnInfo.getReturnType(), ThunkFn, FnInfo,
|
||||
FunctionArgs, CD->getLocation(), SourceLocation());
|
||||
EmitThisParam(CGF);
|
||||
llvm::Value *This = getThisValue(CGF);
|
||||
|
||||
llvm::Value *SrcVal =
|
||||
CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&SrcParam), "src");
|
||||
|
||||
CallArgList Args;
|
||||
|
||||
// Push the this ptr.
|
||||
Args.add(RValue::get(This), CD->getThisType(getContext()));
|
||||
|
||||
// Push the src ptr.
|
||||
Args.add(RValue::get(SrcVal), SrcParam.getType());
|
||||
|
||||
// Add the rest of the default arguments.
|
||||
std::vector<Stmt *> ArgVec;
|
||||
for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I)
|
||||
ArgVec.push_back(getContext().getDefaultArgExprForConstructor(CD, I));
|
||||
|
||||
CodeGenFunction::RunCleanupsScope Cleanups(CGF);
|
||||
|
||||
const auto *FPT = CD->getType()->castAs<FunctionProtoType>();
|
||||
ConstExprIterator ArgBegin(ArgVec.data()), ArgEnd(&*ArgVec.end());
|
||||
CGF.EmitCallArgs(Args, FPT, ArgBegin, ArgEnd, CD, 1);
|
||||
|
||||
// Insert any ABI-specific implicit constructor arguments.
|
||||
unsigned ExtraArgs = addImplicitConstructorArgs(CGF, CD, Ctor_Complete,
|
||||
/*ForVirtualBase=*/false,
|
||||
/*Delegating=*/false, Args);
|
||||
|
||||
// Call the destructor with our arguments.
|
||||
llvm::Value *CalleeFn = CGM.getAddrOfCXXStructor(CD, StructorType::Complete);
|
||||
const CGFunctionInfo &CalleeInfo = CGM.getTypes().arrangeCXXConstructorCall(
|
||||
Args, CD, Ctor_Complete, ExtraArgs);
|
||||
CGF.EmitCall(CalleeInfo, CalleeFn, ReturnValueSlot(), Args, CD);
|
||||
|
||||
Cleanups.ForceCleanup();
|
||||
|
||||
// Emit the ret instruction, remove any temporary instructions created for the
|
||||
// aid of CodeGen.
|
||||
CGF.FinishFunction(SourceLocation());
|
||||
|
||||
return ThunkFn;
|
||||
}
|
||||
|
||||
llvm::Constant *MicrosoftCXXABI::getCatchableType(QualType T,
|
||||
uint32_t NVOffset,
|
||||
int32_t VBPtrOffset,
|
||||
|
@ -3229,27 +3328,43 @@ llvm::Constant *MicrosoftCXXABI::getCatchableType(QualType T,
|
|||
CXXRecordDecl *RD = T->getAsCXXRecordDecl();
|
||||
const CXXConstructorDecl *CD =
|
||||
RD ? CGM.getContext().getCopyConstructorForExceptionObject(RD) : nullptr;
|
||||
CXXCtorType CT = Ctor_Complete;
|
||||
if (CD) {
|
||||
CallingConv ExpectedCallingConv = getContext().getDefaultCallingConvention(
|
||||
/*IsVariadic=*/false, /*IsCXXMethod=*/true);
|
||||
CallingConv ActualCallingConv =
|
||||
CD->getType()->getAs<FunctionProtoType>()->getCallConv();
|
||||
if (ExpectedCallingConv != ActualCallingConv || CD->getNumParams() != 1)
|
||||
CT = Ctor_CopyingClosure;
|
||||
}
|
||||
|
||||
uint32_t Size = getContext().getTypeSizeInChars(T).getQuantity();
|
||||
SmallString<256> MangledName;
|
||||
{
|
||||
llvm::raw_svector_ostream Out(MangledName);
|
||||
getMangleContext().mangleCXXCatchableType(T, CD, Size, NVOffset,
|
||||
getMangleContext().mangleCXXCatchableType(T, CD, CT, Size, NVOffset,
|
||||
VBPtrOffset, VBIndex, Out);
|
||||
}
|
||||
if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName))
|
||||
return getImageRelativeConstant(GV);
|
||||
|
||||
// The TypeDescriptor is used by the runtime to determine of a catch handler
|
||||
// The TypeDescriptor is used by the runtime to determine if a catch handler
|
||||
// is appropriate for the exception object.
|
||||
llvm::Constant *TD = getImageRelativeConstant(getAddrOfRTTIDescriptor(T));
|
||||
|
||||
// The runtime is responsible for calling the copy constructor if the
|
||||
// exception is caught by value.
|
||||
llvm::Constant *CopyCtor =
|
||||
CD ? llvm::ConstantExpr::getBitCast(
|
||||
CGM.getAddrOfCXXStructor(CD, StructorType::Complete),
|
||||
CGM.Int8PtrTy)
|
||||
: llvm::Constant::getNullValue(CGM.Int8PtrTy);
|
||||
llvm::Constant *CopyCtor;
|
||||
if (CD) {
|
||||
if (CT == Ctor_CopyingClosure)
|
||||
CopyCtor = getAddrOfCXXCopyCtorClosure(CD);
|
||||
else
|
||||
CopyCtor = CGM.getAddrOfCXXStructor(CD, StructorType::Complete);
|
||||
|
||||
CopyCtor = llvm::ConstantExpr::getBitCast(CopyCtor, CGM.Int8PtrTy);
|
||||
} else {
|
||||
CopyCtor = llvm::Constant::getNullValue(CGM.Int8PtrTy);
|
||||
}
|
||||
CopyCtor = getImageRelativeConstant(CopyCtor);
|
||||
|
||||
bool IsScalar = !RD;
|
||||
|
|
|
@ -782,14 +782,51 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
|
|||
}
|
||||
}
|
||||
|
||||
// The MSVC ABI creates a list of all types which can catch the exception
|
||||
// object. This list also references the appropriate copy constructor to call
|
||||
// if the object is caught by value and has a non-trivial copy constructor.
|
||||
if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
|
||||
// We are only interested in the public, unambiguous bases contained within
|
||||
// the exception object. Bases which are ambiguous or otherwise
|
||||
// inaccessible are not catchable types.
|
||||
llvm::SmallVector<CXXRecordDecl *, 2> UnambiguousPublicSubobjects;
|
||||
getUnambiguousPublicSubobjects(RD, UnambiguousPublicSubobjects);
|
||||
|
||||
for (CXXRecordDecl *Subobject : UnambiguousPublicSubobjects) {
|
||||
if (CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0)) {
|
||||
MarkFunctionReferenced(E->getExprLoc(), CD);
|
||||
if (!CD->isTrivial())
|
||||
Context.addCopyConstructorForExceptionObject(Subobject, CD);
|
||||
// Attempt to lookup the copy constructor. Various pieces of machinery
|
||||
// will spring into action, like template instantiation, which means this
|
||||
// cannot be a simple walk of the class's decls. Instead, we must perform
|
||||
// lookup and overload resolution.
|
||||
CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0);
|
||||
if (!CD)
|
||||
continue;
|
||||
|
||||
// Mark the constructor referenced as it is used by this throw expression.
|
||||
MarkFunctionReferenced(E->getExprLoc(), CD);
|
||||
|
||||
// Skip this copy constructor if it is trivial, we don't need to record it
|
||||
// in the catchable type data.
|
||||
if (CD->isTrivial())
|
||||
continue;
|
||||
|
||||
// The copy constructor is non-trivial, create a mapping from this class
|
||||
// type to this constructor.
|
||||
// N.B. The selection of copy constructor is not sensitive to this
|
||||
// particular throw-site. Lookup will be performed at the catch-site to
|
||||
// ensure that the copy constructor is, in fact, accessible (via
|
||||
// friendship or any other means).
|
||||
Context.addCopyConstructorForExceptionObject(Subobject, CD);
|
||||
|
||||
// We don't keep the instantiated default argument expressions around so
|
||||
// we must rebuild them here.
|
||||
for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) {
|
||||
// Skip any default arguments that we've already instantiated.
|
||||
if (Context.getDefaultArgExprForConstructor(CD, I))
|
||||
continue;
|
||||
|
||||
Expr *DefaultArg =
|
||||
BuildCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I)).get();
|
||||
Context.addDefaultArgExprForConstructor(CD, I, DefaultArg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -emit-llvm -o - -triple=i386-pc-win32 %s -fcxx-exceptions | FileCheck %s
|
||||
// RUN: %clang_cc1 -emit-llvm -o - -triple=i386-pc-win32 -std=c++11 %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@@@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*) }, section ".xdata", comdat
|
||||
|
@ -12,6 +12,9 @@
|
|||
// CHECK-DAG: @"_CT??_R0?AUV@@@81044" = 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 }, section ".xdata", 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@@Z44", %eh.CatchableType* @"_CT??_R0?AUM@@@818", %eh.CatchableType* @"_CT??_R0?AUV@@@81044"] }, section ".xdata", 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*) }, section ".xdata", comdat
|
||||
// CHECK-DAG: @"_CT??_R0?AUDefault@@@8??_ODefault@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor13* @"\01??_R0?AUDefault@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.Default*, %struct.Default*)* @"\01??_ODefault@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat
|
||||
// CHECK-DAG: @"_CT??_R0?AUVariadic@@@8??_OVariadic@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor14* @"\01??_R0?AUVariadic@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.Variadic*, %struct.Variadic*)* @"\01??_OVariadic@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat
|
||||
// CHECK-DAG: @"_CT??_R0?AUTemplateWithDefault@@@8??$?_OH@TemplateWithDefault@@QAEXAAU0@@Z1" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 0, i8* bitcast (%rtti.TypeDescriptor25* @"\01??_R0?AUTemplateWithDefault@@@8" to i8*), i32 0, i32 -1, i32 0, i32 1, i8* bitcast (void (%struct.TemplateWithDefault*, %struct.TemplateWithDefault*)* @"\01??$?_OH@TemplateWithDefault@@QAEXAAU0@@Z" to i8*) }, section ".xdata", comdat
|
||||
|
||||
|
||||
struct N { ~N(); };
|
||||
|
@ -35,3 +38,52 @@ void g(const int *const *y) {
|
|||
// CHECK: call void @_CxxThrowException(i8* %{{.*}}, %eh.ThrowInfo* @_TIC2PAPBH)
|
||||
throw y;
|
||||
}
|
||||
|
||||
struct Default {
|
||||
Default(Default &, int = 42);
|
||||
};
|
||||
|
||||
// CHECK-LABEL: @"\01??_ODefault@@QAEXAAU0@@Z"
|
||||
// CHECK: %[[src_addr:.*]] = alloca
|
||||
// CHECK: %[[this_addr:.*]] = alloca
|
||||
// CHECK: store {{.*}} %src, {{.*}} %[[src_addr]], align 4
|
||||
// CHECK: store {{.*}} %this, {{.*}} %[[this_addr]], align 4
|
||||
// CHECK: %[[this:.*]] = load {{.*}} %[[this_addr]]
|
||||
// CHECK: %[[src:.*]] = load {{.*}} %[[src_addr]]
|
||||
// CHECK: call x86_thiscallcc {{.*}} @"\01??0Default@@QAE@AAU0@H@Z"({{.*}} %[[this]], {{.*}} %[[src]], i32 42)
|
||||
// CHECK: ret void
|
||||
|
||||
void h(Default &d) {
|
||||
throw d;
|
||||
}
|
||||
|
||||
struct Variadic {
|
||||
Variadic(Variadic &, ...);
|
||||
};
|
||||
|
||||
void i(Variadic &v) {
|
||||
throw v;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @"\01??_OVariadic@@QAEXAAU0@@Z"
|
||||
// CHECK: %[[src_addr:.*]] = alloca
|
||||
// CHECK: %[[this_addr:.*]] = alloca
|
||||
// CHECK: store {{.*}} %src, {{.*}} %[[src_addr:.*]], align
|
||||
// CHECK: store {{.*}} %this, {{.*}} %[[this_addr:.*]], align
|
||||
// CHECK: %[[this:.*]] = load {{.*}} %[[this_addr]]
|
||||
// CHECK: %[[src:.*]] = load {{.*}} %[[src_addr]]
|
||||
// CHECK: %call = call {{.*}} @"\01??0Variadic@@QAA@AAU0@ZZ"({{.*}} %[[this]], {{.*}} %[[src]])
|
||||
// CHECK: ret void
|
||||
|
||||
struct TemplateWithDefault {
|
||||
template <typename T>
|
||||
static int f() {
|
||||
return 0;
|
||||
}
|
||||
template <typename T = int>
|
||||
TemplateWithDefault(TemplateWithDefault &, T = f<T>());
|
||||
};
|
||||
|
||||
void j(TemplateWithDefault &twd) {
|
||||
throw twd;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue