forked from OSchip/llvm-project
Revert r184205 and associated patches while investigating issue with broken buildbot (possible interaction with LTO)
<rdar://problem/14209661> llvm-svn: 184384
This commit is contained in:
parent
11b3ba7176
commit
19cee1871e
|
@ -97,12 +97,8 @@ public:
|
||||||
return *MangleCtx;
|
return *MangleCtx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the given constructor or destructor is one of the
|
/// Returns true if the given instance method is one of the
|
||||||
/// kinds that the ABI says returns 'this' (only applies when called
|
/// kinds that the ABI says returns 'this'.
|
||||||
/// non-virtually for destructors).
|
|
||||||
///
|
|
||||||
/// There currently is no way to indicate if a destructor returns 'this'
|
|
||||||
/// when called virtually, and code generation does not support the case.
|
|
||||||
virtual bool HasThisReturn(GlobalDecl GD) const { return false; }
|
virtual bool HasThisReturn(GlobalDecl GD) const { return false; }
|
||||||
|
|
||||||
/// Returns true if the given record type should be returned indirectly.
|
/// Returns true if the given record type should be returned indirectly.
|
||||||
|
@ -218,10 +214,10 @@ public:
|
||||||
const CXXRecordDecl *BaseClassDecl) = 0;
|
const CXXRecordDecl *BaseClassDecl) = 0;
|
||||||
|
|
||||||
/// Build the signature of the given constructor variant by adding
|
/// Build the signature of the given constructor variant by adding
|
||||||
/// any required parameters. For convenience, ArgTys has been initialized
|
/// any required parameters. For convenience, ResTy has been
|
||||||
/// with the type of 'this' and ResTy has been initialized with the type of
|
/// initialized to 'void', and ArgTys has been initialized with the
|
||||||
/// 'this' if HasThisReturn(GlobalDecl(Ctor, T)) is true or 'void' otherwise
|
/// type of 'this' (although this may be changed by the ABI) and
|
||||||
/// (although both may be changed by the ABI).
|
/// will have the formal parameters added to it afterwards.
|
||||||
///
|
///
|
||||||
/// If there are ever any ABIs where the implicit parameters are
|
/// If there are ever any ABIs where the implicit parameters are
|
||||||
/// intermixed with the formal parameters, we can address those
|
/// intermixed with the formal parameters, we can address those
|
||||||
|
@ -235,10 +231,9 @@ public:
|
||||||
const CXXRecordDecl *RD);
|
const CXXRecordDecl *RD);
|
||||||
|
|
||||||
/// Build the signature of the given destructor variant by adding
|
/// Build the signature of the given destructor variant by adding
|
||||||
/// any required parameters. For convenience, ArgTys has been initialized
|
/// any required parameters. For convenience, ResTy has been
|
||||||
/// with the type of 'this' and ResTy has been initialized with the type of
|
/// initialized to 'void' and ArgTys has been initialized with the
|
||||||
/// 'this' if HasThisReturn(GlobalDecl(Dtor, T)) is true or 'void' otherwise
|
/// type of 'this' (although this may be changed by the ABI).
|
||||||
/// (although both may be changed by the ABI).
|
|
||||||
virtual void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
|
virtual void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
|
||||||
CXXDtorType T,
|
CXXDtorType T,
|
||||||
CanQualType &ResTy,
|
CanQualType &ResTy,
|
||||||
|
@ -249,8 +244,7 @@ public:
|
||||||
/// possibly some extra data for constructors and destructors.
|
/// possibly some extra data for constructors and destructors.
|
||||||
///
|
///
|
||||||
/// ABIs may also choose to override the return type, which has been
|
/// ABIs may also choose to override the return type, which has been
|
||||||
/// initialized with the type of 'this' if HasThisReturn(CGF.CurGD) is true or
|
/// initialized with the formal return type of the function.
|
||||||
/// the formal return type of the function otherwise.
|
|
||||||
virtual void BuildInstanceFunctionParams(CodeGenFunction &CGF,
|
virtual void BuildInstanceFunctionParams(CodeGenFunction &CGF,
|
||||||
QualType &ResTy,
|
QualType &ResTy,
|
||||||
FunctionArgList &Params) = 0;
|
FunctionArgList &Params) = 0;
|
||||||
|
@ -259,20 +253,21 @@ public:
|
||||||
virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;
|
virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;
|
||||||
|
|
||||||
/// Emit the constructor call. Return the function that is called.
|
/// Emit the constructor call. Return the function that is called.
|
||||||
virtual void EmitConstructorCall(CodeGenFunction &CGF,
|
virtual llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
|
||||||
const CXXConstructorDecl *D,
|
const CXXConstructorDecl *D,
|
||||||
CXXCtorType Type,
|
CXXCtorType Type, bool ForVirtualBase,
|
||||||
bool ForVirtualBase, bool Delegating,
|
bool Delegating,
|
||||||
llvm::Value *This,
|
llvm::Value *This,
|
||||||
CallExpr::const_arg_iterator ArgBeg,
|
CallExpr::const_arg_iterator ArgBeg,
|
||||||
CallExpr::const_arg_iterator ArgEnd) = 0;
|
CallExpr::const_arg_iterator ArgEnd) = 0;
|
||||||
|
|
||||||
/// Emit the ABI-specific virtual destructor call.
|
/// Emit the ABI-specific virtual destructor call.
|
||||||
virtual void EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
virtual RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||||
const CXXDestructorDecl *Dtor,
|
const CXXDestructorDecl *Dtor,
|
||||||
CXXDtorType DtorType,
|
CXXDtorType DtorType,
|
||||||
SourceLocation CallLoc,
|
SourceLocation CallLoc,
|
||||||
llvm::Value *This) = 0;
|
ReturnValueSlot ReturnValue,
|
||||||
|
llvm::Value *This) = 0;
|
||||||
|
|
||||||
/// Emit any tables needed to implement virtual inheritance. For Itanium,
|
/// Emit any tables needed to implement virtual inheritance. For Itanium,
|
||||||
/// this emits virtual table tables. For the MSVC++ ABI, this emits virtual
|
/// this emits virtual table tables. For the MSVC++ ABI, this emits virtual
|
||||||
|
|
|
@ -200,10 +200,7 @@ CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D,
|
||||||
CXXCtorType ctorKind) {
|
CXXCtorType ctorKind) {
|
||||||
SmallVector<CanQualType, 16> argTypes;
|
SmallVector<CanQualType, 16> argTypes;
|
||||||
argTypes.push_back(GetThisType(Context, D->getParent()));
|
argTypes.push_back(GetThisType(Context, D->getParent()));
|
||||||
|
CanQualType resultType = Context.VoidTy;
|
||||||
GlobalDecl GD(D, ctorKind);
|
|
||||||
CanQualType resultType =
|
|
||||||
TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy;
|
|
||||||
|
|
||||||
TheCXXABI.BuildConstructorSignature(D, ctorKind, resultType, argTypes);
|
TheCXXABI.BuildConstructorSignature(D, ctorKind, resultType, argTypes);
|
||||||
|
|
||||||
|
@ -228,10 +225,7 @@ CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D,
|
||||||
CXXDtorType dtorKind) {
|
CXXDtorType dtorKind) {
|
||||||
SmallVector<CanQualType, 2> argTypes;
|
SmallVector<CanQualType, 2> argTypes;
|
||||||
argTypes.push_back(GetThisType(Context, D->getParent()));
|
argTypes.push_back(GetThisType(Context, D->getParent()));
|
||||||
|
CanQualType resultType = Context.VoidTy;
|
||||||
GlobalDecl GD(D, dtorKind);
|
|
||||||
CanQualType resultType =
|
|
||||||
TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy;
|
|
||||||
|
|
||||||
TheCXXABI.BuildDestructorSignature(D, dtorKind, resultType, argTypes);
|
TheCXXABI.BuildDestructorSignature(D, dtorKind, resultType, argTypes);
|
||||||
|
|
||||||
|
@ -1639,6 +1633,18 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
|
||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check whether 'this' argument of a callsite matches 'this' of the caller.
|
||||||
|
static bool checkThisPointer(llvm::Value *ThisArg, llvm::Value *This) {
|
||||||
|
if (ThisArg == This)
|
||||||
|
return true;
|
||||||
|
// Check whether ThisArg is a bitcast of This.
|
||||||
|
llvm::BitCastInst *Bitcast;
|
||||||
|
if ((Bitcast = dyn_cast<llvm::BitCastInst>(ThisArg)) &&
|
||||||
|
Bitcast->getOperand(0) == This)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
|
void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
|
||||||
bool EmitRetDbgLoc) {
|
bool EmitRetDbgLoc) {
|
||||||
// Functions with no result always return void.
|
// Functions with no result always return void.
|
||||||
|
@ -1735,6 +1741,19 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
|
||||||
llvm_unreachable("Invalid ABI kind for return argument");
|
llvm_unreachable("Invalid ABI kind for return argument");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this function returns 'this', the last instruction is a CallInst
|
||||||
|
// that returns 'this', and 'this' argument of the CallInst points to
|
||||||
|
// the same object as CXXThisValue, use the return value from the CallInst.
|
||||||
|
// We will not need to keep 'this' alive through the callsite. It also enables
|
||||||
|
// optimizations in the backend, such as tail call optimization.
|
||||||
|
if (CalleeWithThisReturn && CGM.getCXXABI().HasThisReturn(CurGD)) {
|
||||||
|
llvm::BasicBlock *IP = Builder.GetInsertBlock();
|
||||||
|
llvm::CallInst *Callsite;
|
||||||
|
if (!IP->empty() && (Callsite = dyn_cast<llvm::CallInst>(&IP->back())) &&
|
||||||
|
Callsite->getCalledFunction() == CalleeWithThisReturn &&
|
||||||
|
checkThisPointer(Callsite->getOperand(0), CXXThisValue))
|
||||||
|
RV = Builder.CreateBitCast(Callsite, RetAI.getCoerceToType());
|
||||||
|
}
|
||||||
llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid();
|
llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid();
|
||||||
if (!RetDbgLoc.isUnknown())
|
if (!RetDbgLoc.isUnknown())
|
||||||
Ret->setDebugLoc(RetDbgLoc);
|
Ret->setDebugLoc(RetDbgLoc);
|
||||||
|
|
|
@ -1662,8 +1662,11 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-trivial constructors are handled in an ABI-specific manner.
|
// Non-trivial constructors are handled in an ABI-specific manner.
|
||||||
CGM.getCXXABI().EmitConstructorCall(*this, D, Type, ForVirtualBase,
|
llvm::Value *Callee = CGM.getCXXABI().EmitConstructorCall(*this, D, Type,
|
||||||
Delegating, This, ArgBeg, ArgEnd);
|
ForVirtualBase, Delegating, This, ArgBeg, ArgEnd);
|
||||||
|
if (CGM.getCXXABI().HasThisReturn(CurGD) &&
|
||||||
|
CGM.getCXXABI().HasThisReturn(GlobalDecl(D, Type)))
|
||||||
|
CalleeWithThisReturn = Callee;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1755,6 +1758,9 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
|
||||||
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType);
|
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType);
|
||||||
EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),
|
EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),
|
||||||
Callee, ReturnValueSlot(), DelegateArgs, Ctor);
|
Callee, ReturnValueSlot(), DelegateArgs, Ctor);
|
||||||
|
if (CGM.getCXXABI().HasThisReturn(CurGD) &&
|
||||||
|
CGM.getCXXABI().HasThisReturn(GlobalDecl(Ctor, CtorType)))
|
||||||
|
CalleeWithThisReturn = Callee;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -1821,6 +1827,9 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
|
||||||
EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
|
EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
|
||||||
VTT, getContext().getPointerType(getContext().VoidPtrTy),
|
VTT, getContext().getPointerType(getContext().VoidPtrTy),
|
||||||
0, 0);
|
0, 0);
|
||||||
|
if (CGM.getCXXABI().HasThisReturn(CurGD) &&
|
||||||
|
CGM.getCXXABI().HasThisReturn(GlobalDecl(DD, Type)))
|
||||||
|
CalleeWithThisReturn = Callee;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
|
@ -280,15 +280,16 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
|
||||||
// We also don't emit a virtual call if the base expression has a record type
|
// We also don't emit a virtual call if the base expression has a record type
|
||||||
// because then we know what the type is.
|
// because then we know what the type is.
|
||||||
bool UseVirtualCall = CanUseVirtualCall && !DevirtualizedMethod;
|
bool UseVirtualCall = CanUseVirtualCall && !DevirtualizedMethod;
|
||||||
llvm::Value *Callee;
|
|
||||||
|
|
||||||
|
llvm::Value *Callee;
|
||||||
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) {
|
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) {
|
||||||
assert(CE->arg_begin() == CE->arg_end() &&
|
|
||||||
"Destructor shouldn't have explicit parameters");
|
|
||||||
assert(ReturnValue.isNull() && "Destructor shouldn't have return value");
|
|
||||||
if (UseVirtualCall) {
|
if (UseVirtualCall) {
|
||||||
CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor, Dtor_Complete,
|
assert(CE->arg_begin() == CE->arg_end() &&
|
||||||
CE->getExprLoc(), This);
|
"Virtual destructor shouldn't have explicit parameters");
|
||||||
|
return CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor,
|
||||||
|
Dtor_Complete,
|
||||||
|
CE->getExprLoc(),
|
||||||
|
ReturnValue, This);
|
||||||
} else {
|
} else {
|
||||||
if (getLangOpts().AppleKext &&
|
if (getLangOpts().AppleKext &&
|
||||||
MD->isVirtual() &&
|
MD->isVirtual() &&
|
||||||
|
@ -301,16 +302,12 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
|
||||||
cast<CXXDestructorDecl>(DevirtualizedMethod);
|
cast<CXXDestructorDecl>(DevirtualizedMethod);
|
||||||
Callee = CGM.GetAddrOfFunction(GlobalDecl(DDtor, Dtor_Complete), Ty);
|
Callee = CGM.GetAddrOfFunction(GlobalDecl(DDtor, Dtor_Complete), Ty);
|
||||||
}
|
}
|
||||||
EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This,
|
|
||||||
/*ImplicitParam=*/0, QualType(), 0, 0);
|
|
||||||
}
|
}
|
||||||
return RValue::get(0);
|
} else if (const CXXConstructorDecl *Ctor =
|
||||||
}
|
dyn_cast<CXXConstructorDecl>(MD)) {
|
||||||
|
|
||||||
if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
|
|
||||||
Callee = CGM.GetAddrOfFunction(GlobalDecl(Ctor, Ctor_Complete), Ty);
|
Callee = CGM.GetAddrOfFunction(GlobalDecl(Ctor, Ctor_Complete), Ty);
|
||||||
} else if (UseVirtualCall) {
|
} else if (UseVirtualCall) {
|
||||||
Callee = BuildVirtualCall(MD, This, Ty);
|
Callee = BuildVirtualCall(MD, This, Ty);
|
||||||
} else {
|
} else {
|
||||||
if (getLangOpts().AppleKext &&
|
if (getLangOpts().AppleKext &&
|
||||||
MD->isVirtual() &&
|
MD->isVirtual() &&
|
||||||
|
@ -1416,7 +1413,8 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
|
||||||
// FIXME: Provide a source location here.
|
// FIXME: Provide a source location here.
|
||||||
CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
|
CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
|
||||||
CGF.CGM.getCXXABI().EmitVirtualDestructorCall(CGF, Dtor, DtorType,
|
CGF.CGM.getCXXABI().EmitVirtualDestructorCall(CGF, Dtor, DtorType,
|
||||||
SourceLocation(), Ptr);
|
SourceLocation(),
|
||||||
|
ReturnValueSlot(), Ptr);
|
||||||
|
|
||||||
if (UseGlobalDelete) {
|
if (UseGlobalDelete) {
|
||||||
CGF.PopCleanupBlock();
|
CGF.PopCleanupBlock();
|
||||||
|
|
|
@ -287,9 +287,8 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
|
||||||
GlobalDecl GD, const ThunkInfo &Thunk) {
|
GlobalDecl GD, const ThunkInfo &Thunk) {
|
||||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
|
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
|
||||||
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
|
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
|
||||||
|
QualType ResultType = FPT->getResultType();
|
||||||
QualType ThisType = MD->getThisType(getContext());
|
QualType ThisType = MD->getThisType(getContext());
|
||||||
QualType ResultType =
|
|
||||||
CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getResultType();
|
|
||||||
|
|
||||||
FunctionArgList FunctionArgs;
|
FunctionArgList FunctionArgs;
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,8 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
|
||||||
AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),
|
AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),
|
||||||
LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1),
|
LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1),
|
||||||
FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0),
|
FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0),
|
||||||
DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false),
|
DebugInfo(0), DisableDebugInfo(false), CalleeWithThisReturn(0),
|
||||||
|
DidCallStackSave(false),
|
||||||
IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),
|
IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),
|
||||||
NumReturnExprs(0), NumSimpleReturnExprs(0),
|
NumReturnExprs(0), NumSimpleReturnExprs(0),
|
||||||
CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0),
|
CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0),
|
||||||
|
@ -661,12 +662,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
|
||||||
QualType ResTy = FD->getResultType();
|
QualType ResTy = FD->getResultType();
|
||||||
|
|
||||||
CurGD = GD;
|
CurGD = GD;
|
||||||
const CXXMethodDecl *MD;
|
if (isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isInstance())
|
||||||
if ((MD = dyn_cast<CXXMethodDecl>(FD)) && MD->isInstance()) {
|
|
||||||
if (CGM.getCXXABI().HasThisReturn(GD))
|
|
||||||
ResTy = MD->getThisType(getContext());
|
|
||||||
CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args);
|
CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args);
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i)
|
for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i)
|
||||||
Args.push_back(FD->getParamDecl(i));
|
Args.push_back(FD->getParamDecl(i));
|
||||||
|
@ -675,6 +672,10 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
|
||||||
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
|
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
|
||||||
CurEHLocation = BodyRange.getEnd();
|
CurEHLocation = BodyRange.getEnd();
|
||||||
|
|
||||||
|
// CalleeWithThisReturn keeps track of the last callee inside this function
|
||||||
|
// that returns 'this'. Before starting the function, we set it to null.
|
||||||
|
CalleeWithThisReturn = 0;
|
||||||
|
|
||||||
// Emit the standard function prologue.
|
// Emit the standard function prologue.
|
||||||
StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin());
|
StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin());
|
||||||
|
|
||||||
|
@ -726,6 +727,9 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
|
||||||
|
|
||||||
// Emit the standard function epilogue.
|
// Emit the standard function epilogue.
|
||||||
FinishFunction(BodyRange.getEnd());
|
FinishFunction(BodyRange.getEnd());
|
||||||
|
// CalleeWithThisReturn keeps track of the last callee inside this function
|
||||||
|
// that returns 'this'. After finishing the function, we set it to null.
|
||||||
|
CalleeWithThisReturn = 0;
|
||||||
|
|
||||||
// If we haven't marked the function nothrow through other means, do
|
// If we haven't marked the function nothrow through other means, do
|
||||||
// a quick pass now to see if we can.
|
// a quick pass now to see if we can.
|
||||||
|
|
|
@ -798,6 +798,10 @@ private:
|
||||||
CGDebugInfo *DebugInfo;
|
CGDebugInfo *DebugInfo;
|
||||||
bool DisableDebugInfo;
|
bool DisableDebugInfo;
|
||||||
|
|
||||||
|
/// If the current function returns 'this', use the field to keep track of
|
||||||
|
/// the callee that returns 'this'.
|
||||||
|
llvm::Value *CalleeWithThisReturn;
|
||||||
|
|
||||||
/// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
|
/// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
|
||||||
/// calling llvm.stacksave for multiple VLAs in the same scope.
|
/// calling llvm.stacksave for multiple VLAs in the same scope.
|
||||||
bool DidCallStackSave;
|
bool DidCallStackSave;
|
||||||
|
|
|
@ -722,14 +722,6 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
|
||||||
if (!IsIncompleteFunction)
|
if (!IsIncompleteFunction)
|
||||||
SetLLVMFunctionAttributes(FD, getTypes().arrangeGlobalDeclaration(GD), F);
|
SetLLVMFunctionAttributes(FD, getTypes().arrangeGlobalDeclaration(GD), F);
|
||||||
|
|
||||||
if (getCXXABI().HasThisReturn(GD)) {
|
|
||||||
assert(!F->arg_empty() &&
|
|
||||||
F->arg_begin()->getType()
|
|
||||||
->canLosslesslyBitCastTo(F->getReturnType()) &&
|
|
||||||
"unexpected this return");
|
|
||||||
F->addAttribute(1, llvm::Attribute::Returned);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only a few attributes are set on declarations; these may later be
|
// Only a few attributes are set on declarations; these may later be
|
||||||
// overridden by a definition.
|
// overridden by a definition.
|
||||||
|
|
||||||
|
|
|
@ -119,17 +119,20 @@ public:
|
||||||
|
|
||||||
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
|
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
|
||||||
|
|
||||||
void EmitConstructorCall(CodeGenFunction &CGF,
|
llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
|
||||||
const CXXConstructorDecl *D, CXXCtorType Type,
|
const CXXConstructorDecl *D,
|
||||||
bool ForVirtualBase, bool Delegating,
|
CXXCtorType Type, bool ForVirtualBase,
|
||||||
|
bool Delegating,
|
||||||
llvm::Value *This,
|
llvm::Value *This,
|
||||||
CallExpr::const_arg_iterator ArgBeg,
|
CallExpr::const_arg_iterator ArgBeg,
|
||||||
CallExpr::const_arg_iterator ArgEnd);
|
CallExpr::const_arg_iterator ArgEnd);
|
||||||
|
|
||||||
void EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||||
const CXXDestructorDecl *Dtor,
|
const CXXDestructorDecl *Dtor,
|
||||||
CXXDtorType DtorType, SourceLocation CallLoc,
|
CXXDtorType DtorType,
|
||||||
llvm::Value *This);
|
SourceLocation CallLoc,
|
||||||
|
ReturnValueSlot ReturnValue,
|
||||||
|
llvm::Value *This);
|
||||||
|
|
||||||
void EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage,
|
void EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage,
|
||||||
const CXXRecordDecl *RD);
|
const CXXRecordDecl *RD);
|
||||||
|
@ -165,11 +168,21 @@ class ARMCXXABI : public ItaniumCXXABI {
|
||||||
public:
|
public:
|
||||||
ARMCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM, /*ARM*/ true) {}
|
ARMCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM, /*ARM*/ true) {}
|
||||||
|
|
||||||
bool HasThisReturn(GlobalDecl GD) const {
|
void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
|
||||||
return (isa<CXXConstructorDecl>(GD.getDecl()) || (
|
CXXCtorType T,
|
||||||
isa<CXXDestructorDecl>(GD.getDecl()) &&
|
CanQualType &ResTy,
|
||||||
GD.getDtorType() != Dtor_Deleting));
|
SmallVectorImpl<CanQualType> &ArgTys);
|
||||||
}
|
|
||||||
|
void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
|
||||||
|
CXXDtorType T,
|
||||||
|
CanQualType &ResTy,
|
||||||
|
SmallVectorImpl<CanQualType> &ArgTys);
|
||||||
|
|
||||||
|
void BuildInstanceFunctionParams(CodeGenFunction &CGF,
|
||||||
|
QualType &ResTy,
|
||||||
|
FunctionArgList &Params);
|
||||||
|
|
||||||
|
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
|
||||||
|
|
||||||
void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy);
|
void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy);
|
||||||
|
|
||||||
|
@ -181,6 +194,15 @@ public:
|
||||||
QualType ElementType);
|
QualType ElementType);
|
||||||
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr,
|
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr,
|
||||||
CharUnits cookieSize);
|
CharUnits cookieSize);
|
||||||
|
|
||||||
|
/// \brief Returns true if the given instance method is one of the
|
||||||
|
/// kinds that the ARM ABI says returns 'this'.
|
||||||
|
bool HasThisReturn(GlobalDecl GD) const {
|
||||||
|
const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(GD.getDecl());
|
||||||
|
if (!MD) return false;
|
||||||
|
return ((isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Deleting) ||
|
||||||
|
(isa<CXXConstructorDecl>(MD)));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -735,14 +757,22 @@ void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
|
||||||
SmallVectorImpl<CanQualType> &ArgTys) {
|
SmallVectorImpl<CanQualType> &ArgTys) {
|
||||||
ASTContext &Context = getContext();
|
ASTContext &Context = getContext();
|
||||||
|
|
||||||
// 'this' parameter is already there, as well as 'this' return if
|
// 'this' is already there.
|
||||||
// HasThisReturn(GlobalDecl(Ctor, Type)) is true
|
|
||||||
|
|
||||||
// Check if we need to add a VTT parameter (which has type void **).
|
// Check if we need to add a VTT parameter (which has type void **).
|
||||||
if (Type == Ctor_Base && Ctor->getParent()->getNumVBases() != 0)
|
if (Type == Ctor_Base && Ctor->getParent()->getNumVBases() != 0)
|
||||||
ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy));
|
ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The ARM ABI does the same as the Itanium ABI, but returns 'this'.
|
||||||
|
void ARMCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
|
||||||
|
CXXCtorType Type,
|
||||||
|
CanQualType &ResTy,
|
||||||
|
SmallVectorImpl<CanQualType> &ArgTys) {
|
||||||
|
ItaniumCXXABI::BuildConstructorSignature(Ctor, Type, ResTy, ArgTys);
|
||||||
|
ResTy = ArgTys[0];
|
||||||
|
}
|
||||||
|
|
||||||
/// The generic ABI passes 'this', plus a VTT if it's destroying a
|
/// The generic ABI passes 'this', plus a VTT if it's destroying a
|
||||||
/// base subobject.
|
/// base subobject.
|
||||||
void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
|
void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
|
||||||
|
@ -751,14 +781,25 @@ void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
|
||||||
SmallVectorImpl<CanQualType> &ArgTys) {
|
SmallVectorImpl<CanQualType> &ArgTys) {
|
||||||
ASTContext &Context = getContext();
|
ASTContext &Context = getContext();
|
||||||
|
|
||||||
// 'this' parameter is already there, as well as 'this' return if
|
// 'this' is already there.
|
||||||
// HasThisReturn(GlobalDecl(Dtor, Type)) is true
|
|
||||||
|
|
||||||
// Check if we need to add a VTT parameter (which has type void **).
|
// Check if we need to add a VTT parameter (which has type void **).
|
||||||
if (Type == Dtor_Base && Dtor->getParent()->getNumVBases() != 0)
|
if (Type == Dtor_Base && Dtor->getParent()->getNumVBases() != 0)
|
||||||
ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy));
|
ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The ARM ABI does the same as the Itanium ABI, but returns 'this'
|
||||||
|
/// for non-deleting destructors.
|
||||||
|
void ARMCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
|
||||||
|
CXXDtorType Type,
|
||||||
|
CanQualType &ResTy,
|
||||||
|
SmallVectorImpl<CanQualType> &ArgTys) {
|
||||||
|
ItaniumCXXABI::BuildDestructorSignature(Dtor, Type, ResTy, ArgTys);
|
||||||
|
|
||||||
|
if (Type != Dtor_Deleting)
|
||||||
|
ResTy = ArgTys[0];
|
||||||
|
}
|
||||||
|
|
||||||
void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
|
void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
|
||||||
QualType &ResTy,
|
QualType &ResTy,
|
||||||
FunctionArgList &Params) {
|
FunctionArgList &Params) {
|
||||||
|
@ -782,6 +823,16 @@ void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ARMCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
|
||||||
|
QualType &ResTy,
|
||||||
|
FunctionArgList &Params) {
|
||||||
|
ItaniumCXXABI::BuildInstanceFunctionParams(CGF, ResTy, Params);
|
||||||
|
|
||||||
|
// Return 'this' from certain constructors and destructors.
|
||||||
|
if (HasThisReturn(CGF.CurGD))
|
||||||
|
ResTy = Params[0]->getType();
|
||||||
|
}
|
||||||
|
|
||||||
void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
|
void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
|
||||||
/// Initialize the 'this' slot.
|
/// Initialize the 'this' slot.
|
||||||
EmitThisParam(CGF);
|
EmitThisParam(CGF);
|
||||||
|
@ -792,23 +843,21 @@ void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
|
||||||
= CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getVTTDecl(CGF)),
|
= CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getVTTDecl(CGF)),
|
||||||
"vtt");
|
"vtt");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// If this is a function that the ABI specifies returns 'this', initialize
|
void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
|
||||||
/// the return slot to 'this' at the start of the function.
|
ItaniumCXXABI::EmitInstanceFunctionProlog(CGF);
|
||||||
///
|
|
||||||
/// Unlike the setting of return types, this is done within the ABI
|
/// Initialize the return slot to 'this' at the start of the
|
||||||
/// implementation instead of by clients of CGCXXABI because:
|
/// function.
|
||||||
/// 1) getThisValue is currently protected
|
|
||||||
/// 2) in theory, an ABI could implement 'this' returns some other way;
|
|
||||||
/// HasThisReturn only specifies a contract, not the implementation
|
|
||||||
if (HasThisReturn(CGF.CurGD))
|
if (HasThisReturn(CGF.CurGD))
|
||||||
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
|
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
|
llvm::Value *ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
|
||||||
const CXXConstructorDecl *D,
|
const CXXConstructorDecl *D,
|
||||||
CXXCtorType Type,
|
CXXCtorType Type, bool ForVirtualBase,
|
||||||
bool ForVirtualBase, bool Delegating,
|
bool Delegating,
|
||||||
llvm::Value *This,
|
llvm::Value *This,
|
||||||
CallExpr::const_arg_iterator ArgBeg,
|
CallExpr::const_arg_iterator ArgBeg,
|
||||||
CallExpr::const_arg_iterator ArgEnd) {
|
CallExpr::const_arg_iterator ArgEnd) {
|
||||||
|
@ -818,15 +867,17 @@ void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
|
||||||
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
|
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
|
||||||
|
|
||||||
// FIXME: Provide a source location here.
|
// FIXME: Provide a source location here.
|
||||||
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(),
|
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
|
||||||
This, VTT, VTTTy, ArgBeg, ArgEnd);
|
VTT, VTTTy, ArgBeg, ArgEnd);
|
||||||
|
return Callee;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||||
const CXXDestructorDecl *Dtor,
|
const CXXDestructorDecl *Dtor,
|
||||||
CXXDtorType DtorType,
|
CXXDtorType DtorType,
|
||||||
SourceLocation CallLoc,
|
SourceLocation CallLoc,
|
||||||
llvm::Value *This) {
|
ReturnValueSlot ReturnValue,
|
||||||
|
llvm::Value *This) {
|
||||||
assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
|
assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
|
||||||
|
|
||||||
const CGFunctionInfo *FInfo
|
const CGFunctionInfo *FInfo
|
||||||
|
@ -834,8 +885,8 @@ void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||||
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
|
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
|
||||||
llvm::Value *Callee = CGF.BuildVirtualCall(Dtor, DtorType, This, Ty);
|
llvm::Value *Callee = CGF.BuildVirtualCall(Dtor, DtorType, This, Ty);
|
||||||
|
|
||||||
CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This,
|
return CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValue, This,
|
||||||
/*ImplicitParam=*/0, QualType(), 0, 0);
|
/*ImplicitParam=*/0, QualType(), 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItaniumCXXABI::EmitVirtualInheritanceTables(
|
void ItaniumCXXABI::EmitVirtualInheritanceTables(
|
||||||
|
|
|
@ -30,8 +30,6 @@ class MicrosoftCXXABI : public CGCXXABI {
|
||||||
public:
|
public:
|
||||||
MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {}
|
MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {}
|
||||||
|
|
||||||
bool HasThisReturn(GlobalDecl GD) const;
|
|
||||||
|
|
||||||
bool isReturnTypeIndirect(const CXXRecordDecl *RD) const {
|
bool isReturnTypeIndirect(const CXXRecordDecl *RD) const {
|
||||||
// Structures that are not C++03 PODs are always indirect.
|
// Structures that are not C++03 PODs are always indirect.
|
||||||
return !RD->isPOD();
|
return !RD->isPOD();
|
||||||
|
@ -76,17 +74,20 @@ public:
|
||||||
|
|
||||||
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
|
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
|
||||||
|
|
||||||
void EmitConstructorCall(CodeGenFunction &CGF,
|
llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
|
||||||
const CXXConstructorDecl *D, CXXCtorType Type,
|
const CXXConstructorDecl *D,
|
||||||
bool ForVirtualBase, bool Delegating,
|
CXXCtorType Type, bool ForVirtualBase,
|
||||||
|
bool Delegating,
|
||||||
llvm::Value *This,
|
llvm::Value *This,
|
||||||
CallExpr::const_arg_iterator ArgBeg,
|
CallExpr::const_arg_iterator ArgBeg,
|
||||||
CallExpr::const_arg_iterator ArgEnd);
|
CallExpr::const_arg_iterator ArgEnd);
|
||||||
|
|
||||||
void EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||||
const CXXDestructorDecl *Dtor,
|
const CXXDestructorDecl *Dtor,
|
||||||
CXXDtorType DtorType, SourceLocation CallLoc,
|
CXXDtorType DtorType,
|
||||||
llvm::Value *This);
|
SourceLocation CallLoc,
|
||||||
|
ReturnValueSlot ReturnValue,
|
||||||
|
llvm::Value *This);
|
||||||
|
|
||||||
void EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage,
|
void EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage,
|
||||||
const CXXRecordDecl *RD);
|
const CXXRecordDecl *RD);
|
||||||
|
@ -129,6 +130,7 @@ public:
|
||||||
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF,
|
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF,
|
||||||
llvm::Value *allocPtr,
|
llvm::Value *allocPtr,
|
||||||
CharUnits cookieSize);
|
CharUnits cookieSize);
|
||||||
|
static bool needThisReturn(GlobalDecl GD);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
llvm::Constant *getZeroInt() {
|
llvm::Constant *getZeroInt() {
|
||||||
|
@ -312,15 +314,19 @@ MicrosoftCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
|
||||||
return CGF.Builder.CreateNSWAdd(VBPtrOffset, VBPtrToNewBase);
|
return CGF.Builder.CreateNSWAdd(VBPtrOffset, VBPtrToNewBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MicrosoftCXXABI::HasThisReturn(GlobalDecl GD) const {
|
bool MicrosoftCXXABI::needThisReturn(GlobalDecl GD) {
|
||||||
return isa<CXXConstructorDecl>(GD.getDecl());
|
const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl());
|
||||||
|
return isa<CXXConstructorDecl>(MD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
|
void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
|
||||||
CXXCtorType Type,
|
CXXCtorType Type,
|
||||||
CanQualType &ResTy,
|
CanQualType &ResTy,
|
||||||
SmallVectorImpl<CanQualType> &ArgTys) {
|
SmallVectorImpl<CanQualType> &ArgTys) {
|
||||||
// 'this' parameter and 'this' return are already in place
|
// 'this' is already in place
|
||||||
|
|
||||||
|
// Ctor returns this ptr
|
||||||
|
ResTy = ArgTys[0];
|
||||||
|
|
||||||
const CXXRecordDecl *Class = Ctor->getParent();
|
const CXXRecordDecl *Class = Ctor->getParent();
|
||||||
if (Class->getNumVBases()) {
|
if (Class->getNumVBases()) {
|
||||||
|
@ -378,7 +384,6 @@ void MicrosoftCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
|
||||||
CanQualType &ResTy,
|
CanQualType &ResTy,
|
||||||
SmallVectorImpl<CanQualType> &ArgTys) {
|
SmallVectorImpl<CanQualType> &ArgTys) {
|
||||||
// 'this' is already in place
|
// 'this' is already in place
|
||||||
|
|
||||||
// TODO: 'for base' flag
|
// TODO: 'for base' flag
|
||||||
|
|
||||||
if (Type == Dtor_Deleting) {
|
if (Type == Dtor_Deleting) {
|
||||||
|
@ -399,6 +404,9 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
|
||||||
QualType &ResTy,
|
QualType &ResTy,
|
||||||
FunctionArgList &Params) {
|
FunctionArgList &Params) {
|
||||||
BuildThisParam(CGF, Params);
|
BuildThisParam(CGF, Params);
|
||||||
|
if (needThisReturn(CGF.CurGD)) {
|
||||||
|
ResTy = Params[0]->getType();
|
||||||
|
}
|
||||||
|
|
||||||
ASTContext &Context = getContext();
|
ASTContext &Context = getContext();
|
||||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
|
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
|
||||||
|
@ -423,17 +431,9 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
|
||||||
|
|
||||||
void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
|
void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
|
||||||
EmitThisParam(CGF);
|
EmitThisParam(CGF);
|
||||||
|
if (needThisReturn(CGF.CurGD)) {
|
||||||
/// If this is a function that the ABI specifies returns 'this', initialize
|
|
||||||
/// the return slot to 'this' at the start of the function.
|
|
||||||
///
|
|
||||||
/// Unlike the setting of return types, this is done within the ABI
|
|
||||||
/// implementation instead of by clients of CGCXXABI because:
|
|
||||||
/// 1) getThisValue is currently protected
|
|
||||||
/// 2) in theory, an ABI could implement 'this' returns some other way;
|
|
||||||
/// HasThisReturn only specifies a contract, not the implementation
|
|
||||||
if (HasThisReturn(CGF.CurGD))
|
|
||||||
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
|
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
|
||||||
|
}
|
||||||
|
|
||||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
|
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
|
||||||
if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
|
if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
|
||||||
|
@ -455,10 +455,9 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
|
llvm::Value *MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
|
||||||
const CXXConstructorDecl *D,
|
const CXXConstructorDecl *D,
|
||||||
CXXCtorType Type,
|
CXXCtorType Type, bool ForVirtualBase,
|
||||||
bool ForVirtualBase,
|
|
||||||
bool Delegating,
|
bool Delegating,
|
||||||
llvm::Value *This,
|
llvm::Value *This,
|
||||||
CallExpr::const_arg_iterator ArgBeg,
|
CallExpr::const_arg_iterator ArgBeg,
|
||||||
|
@ -475,14 +474,17 @@ void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
|
||||||
|
|
||||||
// FIXME: Provide a source location here.
|
// FIXME: Provide a source location here.
|
||||||
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
|
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
|
||||||
ImplicitParam, ImplicitParamTy, ArgBeg, ArgEnd);
|
ImplicitParam, ImplicitParamTy,
|
||||||
|
ArgBeg, ArgEnd);
|
||||||
|
return Callee;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||||
const CXXDestructorDecl *Dtor,
|
const CXXDestructorDecl *Dtor,
|
||||||
CXXDtorType DtorType,
|
CXXDtorType DtorType,
|
||||||
SourceLocation CallLoc,
|
SourceLocation CallLoc,
|
||||||
llvm::Value *This) {
|
ReturnValueSlot ReturnValue,
|
||||||
|
llvm::Value *This) {
|
||||||
assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
|
assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
|
||||||
|
|
||||||
// We have only one destructor in the vftable but can get both behaviors
|
// We have only one destructor in the vftable but can get both behaviors
|
||||||
|
@ -497,8 +499,8 @@ void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||||
= llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(CGF.getLLVMContext()),
|
= llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(CGF.getLLVMContext()),
|
||||||
DtorType == Dtor_Deleting);
|
DtorType == Dtor_Deleting);
|
||||||
|
|
||||||
CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This,
|
return CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValue, This,
|
||||||
ImplicitParam, Context.BoolTy, 0, 0);
|
ImplicitParam, Context.BoolTy, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const VBTableVector &
|
const VBTableVector &
|
||||||
|
|
|
@ -52,19 +52,19 @@ namespace test1 {
|
||||||
a.bar();
|
a.bar();
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* returned %this, i32 %i) unnamed_addr
|
// CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* %this, i32 %i) unnamed_addr
|
||||||
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
|
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
|
||||||
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
|
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
|
||||||
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
|
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
|
||||||
// CHECK: {{%.*}} = call [[A]]* @_ZN5test11AC2Ei(
|
// CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AC2Ei(
|
||||||
// CHECK: ret [[A]]* [[THIS1]]
|
// CHECK: ret [[A]]* [[THIS2]]
|
||||||
|
|
||||||
// CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* returned %this) unnamed_addr
|
// CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* %this) unnamed_addr
|
||||||
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
|
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
|
||||||
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
|
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
|
||||||
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
|
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
|
||||||
// CHECK: {{%.*}} = call [[A]]* @_ZN5test11AD2Ev(
|
// CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AD2Ev(
|
||||||
// CHECK: ret [[A]]* [[THIS1]]
|
// CHECK: ret [[A]]* [[THIS2]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Awkward virtual cases.
|
// Awkward virtual cases.
|
||||||
|
|
|
@ -1,119 +1,60 @@
|
||||||
//RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-unknown-linux | FileCheck --check-prefix=CHECKGEN %s
|
//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck %s
|
||||||
//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck --check-prefix=CHECKARM %s
|
|
||||||
//RUN: %clang_cc1 %s -emit-llvm -o - -DPR12784_WORKAROUND -triple=x86_64-pc-win32 -cxx-abi microsoft | FileCheck --check-prefix=CHECKMS %s
|
|
||||||
|
|
||||||
// FIXME: Add checks to ensure that Microsoft destructors do not return 'this'
|
// For constructors/desctructors that return 'this', if there exists a callsite
|
||||||
// once PR12784 is resolved
|
// that returns 'this' and is immediately before the return instruction, make
|
||||||
|
// sure we are using the return value from the callsite.
|
||||||
|
// rdar://12818789
|
||||||
|
|
||||||
// Make sure we attach the 'returned' attribute to the 'this' parameter of
|
// CHECK: define linkonce_odr [[A:%.*]] @_ZN11ObjectCacheC1Ev([[A]] %this) unnamed_addr
|
||||||
// constructors and destructors which return this (and only these cases)
|
// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN11ObjectCacheC2Ev(
|
||||||
|
// CHECK-NEXT: ret [[A]] [[THIS1]]
|
||||||
|
|
||||||
class A {
|
// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheEC1EPS0_MS0_FvPS1_E([[A]] %this
|
||||||
|
// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheEC2EPS0_MS0_FvPS1_E(
|
||||||
|
// CHECK-NEXT: ret [[A]] [[THIS1]]
|
||||||
|
|
||||||
|
// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED1Ev([[A]] %this) unnamed_addr
|
||||||
|
// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheED2Ev(
|
||||||
|
// CHECK-NEXT: ret [[A]] [[THIS1]]
|
||||||
|
|
||||||
|
// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED2Ev([[A]] %this) unnamed_addr
|
||||||
|
// CHECK: [[THIS1:%.*]] = call [[B:%.*]] @_ZN9TimerBaseD2Ev(
|
||||||
|
// CHECK-NEXT: [[THIS2:%.*]] = bitcast [[B]] [[THIS1]] to [[A]]
|
||||||
|
// CHECK-NEXT: ret [[A]] [[THIS2]]
|
||||||
|
|
||||||
|
class TimerBase {
|
||||||
public:
|
public:
|
||||||
A();
|
TimerBase();
|
||||||
~A();
|
virtual ~TimerBase();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TimerFiredClass> class Timer : public TimerBase {
|
||||||
|
public:
|
||||||
|
typedef void (TimerFiredClass::*TimerFiredFunction)(Timer*);
|
||||||
|
|
||||||
|
Timer(TimerFiredClass* o, TimerFiredFunction f)
|
||||||
|
: m_object(o), m_function(f) { }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int x_;
|
virtual void fired() { (m_object->*m_function)(this); }
|
||||||
|
|
||||||
|
TimerFiredClass* m_object;
|
||||||
|
TimerFiredFunction m_function;
|
||||||
};
|
};
|
||||||
|
|
||||||
class B : public A {
|
class ObjectCache {
|
||||||
public:
|
public:
|
||||||
B(int *i);
|
explicit ObjectCache();
|
||||||
~B();
|
~ObjectCache();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int *i_;
|
Timer<ObjectCache> m_notificationPostTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
B::B(int *i) : i_(i) { }
|
inline ObjectCache::ObjectCache() : m_notificationPostTimer(this, 0) { }
|
||||||
#ifndef PR12784_WORKAROUND
|
inline ObjectCache::~ObjectCache() { }
|
||||||
B::~B() { }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// CHECKGEN: define void @_ZN1BC1EPi(%class.B* %this, i32* %i)
|
ObjectCache *test() {
|
||||||
// CHECKGEN: define void @_ZN1BC2EPi(%class.B* %this, i32* %i)
|
ObjectCache *dd = new ObjectCache();
|
||||||
// CHECKGEN: define void @_ZN1BD1Ev(%class.B* %this)
|
return dd;
|
||||||
// CHECKGEN: define void @_ZN1BD2Ev(%class.B* %this)
|
|
||||||
|
|
||||||
// CHECKARM: define %class.B* @_ZN1BC1EPi(%class.B* returned %this, i32* %i)
|
|
||||||
// CHECKARM: define %class.B* @_ZN1BC2EPi(%class.B* returned %this, i32* %i)
|
|
||||||
// CHECKARM: define %class.B* @_ZN1BD1Ev(%class.B* returned %this)
|
|
||||||
// CHECKARM: define %class.B* @_ZN1BD2Ev(%class.B* returned %this)
|
|
||||||
|
|
||||||
// CHECKMS: define %class.B* @"\01??0B@@QEAA@PEAH@Z"(%class.B* returned %this, i32* %i)
|
|
||||||
|
|
||||||
class C : public A, public B {
|
|
||||||
public:
|
|
||||||
C(int *i, char *c);
|
|
||||||
virtual ~C();
|
|
||||||
private:
|
|
||||||
char *c_;
|
|
||||||
};
|
|
||||||
|
|
||||||
C::C(int *i, char *c) : B(i), c_(c) { }
|
|
||||||
#ifndef PR12784_WORKAROUND
|
|
||||||
C::~C() { }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// CHECKGEN: define void @_ZN1CC1EPiPc(%class.C* %this, i32* %i, i8* %c)
|
|
||||||
// CHECKGEN: define void @_ZN1CC2EPiPc(%class.C* %this, i32* %i, i8* %c)
|
|
||||||
// CHECKGEN: define void @_ZN1CD0Ev(%class.C* %this)
|
|
||||||
// CHECKGEN: define void @_ZN1CD1Ev(%class.C* %this)
|
|
||||||
// CHECKGEN: define void @_ZN1CD2Ev(%class.C* %this)
|
|
||||||
|
|
||||||
// CHECKARM: define %class.C* @_ZN1CC1EPiPc(%class.C* returned %this, i32* %i, i8* %c)
|
|
||||||
// CHECKARM: define %class.C* @_ZN1CC2EPiPc(%class.C* returned %this, i32* %i, i8* %c)
|
|
||||||
// CHECKARM: define void @_ZN1CD0Ev(%class.C* %this)
|
|
||||||
// CHECKARM: define %class.C* @_ZN1CD1Ev(%class.C* returned %this)
|
|
||||||
// CHECKARM: define %class.C* @_ZN1CD2Ev(%class.C* returned %this)
|
|
||||||
|
|
||||||
// CHECKMS: define %class.C* @"\01??0C@@QEAA@PEAHPEAD@Z"(%class.C* returned %this, i32* %i, i8* %c)
|
|
||||||
|
|
||||||
class D : public virtual A {
|
|
||||||
public:
|
|
||||||
D();
|
|
||||||
~D();
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef PR12784_WORKAROUND
|
|
||||||
D::D() { }
|
|
||||||
D::~D() { }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// CHECKGEN: define void @_ZN1DC1Ev(%class.D* %this)
|
|
||||||
// CHECKGEN: define void @_ZN1DC2Ev(%class.D* %this, i8** %vtt)
|
|
||||||
// CHECKGEN: define void @_ZN1DD1Ev(%class.D* %this)
|
|
||||||
// CHECKGEN: define void @_ZN1DD2Ev(%class.D* %this, i8** %vtt)
|
|
||||||
|
|
||||||
// CHECKARM: define %class.D* @_ZN1DC1Ev(%class.D* returned %this)
|
|
||||||
// CHECKARM: define %class.D* @_ZN1DC2Ev(%class.D* returned %this, i8** %vtt)
|
|
||||||
// CHECKARM: define %class.D* @_ZN1DD1Ev(%class.D* returned %this)
|
|
||||||
// CHECKARM: define %class.D* @_ZN1DD2Ev(%class.D* returned %this, i8** %vtt)
|
|
||||||
|
|
||||||
class E {
|
|
||||||
public:
|
|
||||||
E();
|
|
||||||
virtual ~E();
|
|
||||||
};
|
|
||||||
|
|
||||||
E* gete();
|
|
||||||
|
|
||||||
void test_destructor() {
|
|
||||||
const E& e1 = E();
|
|
||||||
E* e2 = gete();
|
|
||||||
e2->~E();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECKARM: define void @_Z15test_destructorv()
|
|
||||||
|
|
||||||
// Verify that virtual calls to destructors are not marked with a 'returned'
|
|
||||||
// this parameter at the call site...
|
|
||||||
// CHECKARM: [[VFN:%.*]] = getelementptr inbounds %class.E* (%class.E*)**
|
|
||||||
// CHECKARM: [[THUNK:%.*]] = load %class.E* (%class.E*)** [[VFN]]
|
|
||||||
// CHECKARM: call %class.E* [[THUNK]](%class.E* %
|
|
||||||
|
|
||||||
// ...but static calls create declarations with 'returned' this
|
|
||||||
// CHECKARM: {{%.*}} = call %class.E* @_ZN1ED1Ev(%class.E* %
|
|
||||||
|
|
||||||
// CHECKARM: declare %class.E* @_ZN1ED1Ev(%class.E* returned)
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace no_elide_base {
|
||||||
Derived(const Other &O);
|
Derived(const Other &O);
|
||||||
};
|
};
|
||||||
|
|
||||||
// CHECK: define {{.*}} @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* returned %this, %"struct.no_elide_base::Other"* %O) unnamed_addr
|
// CHECK: define {{.*}} @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* %this, %"struct.no_elide_base::Other"* %O) unnamed_addr
|
||||||
Derived::Derived(const Other &O)
|
Derived::Derived(const Other &O)
|
||||||
// CHECK: call {{.*}} @_ZNK13no_elide_base5OthercvNS_4BaseEEv
|
// CHECK: call {{.*}} @_ZNK13no_elide_base5OthercvNS_4BaseEEv
|
||||||
// CHECK: call {{.*}} @_ZN13no_elide_base4BaseC2ERKS0_
|
// CHECK: call {{.*}} @_ZN13no_elide_base4BaseC2ERKS0_
|
||||||
|
|
|
@ -3,5 +3,5 @@
|
||||||
struct A { virtual void a(); };
|
struct A { virtual void a(); };
|
||||||
A x(A& y) { return y; }
|
A x(A& y) { return y; }
|
||||||
|
|
||||||
// CHECK: define linkonce_odr {{.*}} @_ZN1AC1ERKS_(%struct.A* {{.*}}%this, %struct.A*) unnamed_addr
|
// CHECK: define linkonce_odr {{.*}} @_ZN1AC1ERKS_(%struct.A* %this, %struct.A*) unnamed_addr
|
||||||
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2)
|
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2)
|
||||||
|
|
|
@ -5,7 +5,6 @@ struct B { A<int> x; };
|
||||||
void a() {
|
void a() {
|
||||||
B b;
|
B b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECK: call {{.*}} @_ZN1BC1Ev
|
// CHECK: call {{.*}} @_ZN1BC1Ev
|
||||||
// CHECK: define linkonce_odr {{.*}} @_ZN1BC1Ev(%struct.B* {{.*}}%this) unnamed_addr
|
// CHECK: define linkonce_odr {{.*}} @_ZN1BC1Ev(%struct.B* %this) unnamed_addr
|
||||||
// CHECK: call {{.*}} @_ZN1AIiEC1Ev
|
// CHECK: call {{.*}} @_ZN1AIiEC1Ev
|
||||||
|
|
|
@ -82,7 +82,7 @@ namespace test7 {
|
||||||
X(U*, typename int_c<(meta<T>::value + meta<U>::value)>::type *) { }
|
X(U*, typename int_c<(meta<T>::value + meta<U>::value)>::type *) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
// CHECK: define weak_odr {{.*}} @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsr4metaIS3_EE5valueEE4typeE(
|
// CHECK: define weak_odr {{.*}} @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsr4metaIS3_EE5valueEE4typeE(%"struct.test7::X"* %this, double*, float*) unnamed_addr
|
||||||
template X<int>::X(double*, float*);
|
template X<int>::X(double*, float*);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ namespace test8 {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void f(int_c<meta<T>::type::value>) { }
|
void f(int_c<meta<T>::type::value>) { }
|
||||||
|
|
||||||
// CHECK: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsr4metaIT_E4typeE5valueEEE(
|
// CHECK: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsr4metaIT_E4typeE5valueEEE
|
||||||
template void f<int>(int_c<sizeof(int)>);
|
template void f<int>(int_c<sizeof(int)>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ class A {
|
||||||
void no_constructor_destructor_infinite_recursion() {
|
void no_constructor_destructor_infinite_recursion() {
|
||||||
A a;
|
A a;
|
||||||
|
|
||||||
// CHECK: define linkonce_odr x86_thiscallcc %"class.basic::A"* @"\01??0A@basic@@QAE@XZ"(%"class.basic::A"* returned %this)
|
// CHECK: define linkonce_odr x86_thiscallcc %"class.basic::A"* @"\01??0A@basic@@QAE@XZ"(%"class.basic::A"* %this)
|
||||||
// CHECK: [[THIS_ADDR:%[.0-9A-Z_a-z]+]] = alloca %"class.basic::A"*, align 4
|
// CHECK: [[THIS_ADDR:%[.0-9A-Z_a-z]+]] = alloca %"class.basic::A"*, align 4
|
||||||
// CHECK-NEXT: store %"class.basic::A"* %this, %"class.basic::A"** [[THIS_ADDR]], align 4
|
// CHECK-NEXT: store %"class.basic::A"* %this, %"class.basic::A"** [[THIS_ADDR]], align 4
|
||||||
// CHECK-NEXT: [[T1:%[.0-9A-Z_a-z]+]] = load %"class.basic::A"** [[THIS_ADDR]]
|
// CHECK-NEXT: [[T1:%[.0-9A-Z_a-z]+]] = load %"class.basic::A"** [[THIS_ADDR]]
|
||||||
|
@ -34,7 +34,7 @@ struct B {
|
||||||
|
|
||||||
// Tests that we can define constructors outside the class (PR12784).
|
// Tests that we can define constructors outside the class (PR12784).
|
||||||
B::B() {
|
B::B() {
|
||||||
// CHECK: define x86_thiscallcc %"struct.basic::B"* @"\01??0B@basic@@QAE@XZ"(%"struct.basic::B"* returned %this)
|
// CHECK: define x86_thiscallcc %"struct.basic::B"* @"\01??0B@basic@@QAE@XZ"(%"struct.basic::B"* %this)
|
||||||
// CHECK: ret
|
// CHECK: ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ struct B : A {
|
||||||
};
|
};
|
||||||
|
|
||||||
B::B() {
|
B::B() {
|
||||||
// CHECK: define x86_thiscallcc %"struct.constructors::B"* @"\01??0B@constructors@@QAE@XZ"(%"struct.constructors::B"* returned %this)
|
// CHECK: define x86_thiscallcc %"struct.constructors::B"* @"\01??0B@constructors@@QAE@XZ"(%"struct.constructors::B"* %this)
|
||||||
// CHECK: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}})
|
// CHECK: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}})
|
||||||
// CHECK: ret
|
// CHECK: ret
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ struct C : virtual A {
|
||||||
};
|
};
|
||||||
|
|
||||||
C::C() {
|
C::C() {
|
||||||
// CHECK: define x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* returned %this, i32 %is_most_derived)
|
// CHECK: define x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* %this, i32 %is_most_derived)
|
||||||
// TODO: make sure this works in the Release build too;
|
// TODO: make sure this works in the Release build too;
|
||||||
// CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
|
// CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
|
||||||
// CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
|
// CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
|
||||||
|
@ -179,7 +179,7 @@ struct D : C {
|
||||||
};
|
};
|
||||||
|
|
||||||
D::D() {
|
D::D() {
|
||||||
// CHECK: define x86_thiscallcc %"struct.constructors::D"* @"\01??0D@constructors@@QAE@XZ"(%"struct.constructors::D"* returned %this, i32 %is_most_derived) unnamed_addr
|
// CHECK: define x86_thiscallcc %"struct.constructors::D"* @"\01??0D@constructors@@QAE@XZ"(%"struct.constructors::D"* %this, i32 %is_most_derived) unnamed_addr
|
||||||
// CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
|
// CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
|
||||||
// CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
|
// CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
|
||||||
// CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0
|
// CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0
|
||||||
|
@ -204,7 +204,7 @@ struct E : virtual C {
|
||||||
};
|
};
|
||||||
|
|
||||||
E::E() {
|
E::E() {
|
||||||
// CHECK: define x86_thiscallcc %"struct.constructors::E"* @"\01??0E@constructors@@QAE@XZ"(%"struct.constructors::E"* returned %this, i32 %is_most_derived) unnamed_addr
|
// CHECK: define x86_thiscallcc %"struct.constructors::E"* @"\01??0E@constructors@@QAE@XZ"(%"struct.constructors::E"* %this, i32 %is_most_derived) unnamed_addr
|
||||||
// CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
|
// CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
|
||||||
// CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
|
// CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
|
||||||
// CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0
|
// CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0
|
||||||
|
|
|
@ -18,34 +18,34 @@ int main() {
|
||||||
|
|
||||||
// basic_iostream's complete dtor calls its base dtor, then its
|
// basic_iostream's complete dtor calls its base dtor, then its
|
||||||
// virtual base's dtor.
|
// virtual base's dtor.
|
||||||
// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED1Ev(%struct.basic_iostream* {{.*}}%this) unnamed_addr
|
// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED1Ev(%struct.basic_iostream* %this) unnamed_addr
|
||||||
// CHECK: call {{.*}} @_ZN14basic_iostreamIcED2Ev
|
// CHECK: call {{.*}} @_ZN14basic_iostreamIcED2Ev
|
||||||
// CHECK: call {{.*}} @_ZN9basic_iosD2Ev
|
// CHECK: call {{.*}} @_ZN9basic_iosD2Ev
|
||||||
|
|
||||||
// basic_iostream's base dtor calls its non-virtual base dtor.
|
// basic_iostream's base dtor calls its non-virtual base dtor.
|
||||||
// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED2Ev(%struct.basic_iostream* {{.*}}%this, i8** %vtt) unnamed_addr
|
// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED2Ev(%struct.basic_iostream* %this, i8** %vtt) unnamed_addr
|
||||||
// CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev
|
// CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev
|
||||||
// CHECK: }
|
// CHECK: }
|
||||||
|
|
||||||
// basic_iostream's deleting dtor calls its complete dtor, then
|
// basic_iostream's deleting dtor calls its complete dtor, then
|
||||||
// operator delete().
|
// operator delete().
|
||||||
// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* {{.*}}%this) unnamed_addr
|
// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* %this) unnamed_addr
|
||||||
// CHECK: call {{.*}} @_ZN14basic_iostreamIcED1Ev
|
// CHECK: call {{.*}} @_ZN14basic_iostreamIcED1Ev
|
||||||
// CHECK: call {{.*}} @_ZdlPv
|
// CHECK: call {{.*}} @_ZdlPv
|
||||||
|
|
||||||
// basic_istream's complete dtor calls the base dtor,
|
// basic_istream's complete dtor calls the base dtor,
|
||||||
// then its virtual base's base dtor.
|
// then its virtual base's base dtor.
|
||||||
// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* {{.*}}%this) unnamed_addr
|
// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* %this) unnamed_addr
|
||||||
// CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev
|
// CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev
|
||||||
// CHECK: call {{.*}} @_ZN9basic_iosD2Ev
|
// CHECK: call {{.*}} @_ZN9basic_iosD2Ev
|
||||||
|
|
||||||
// basic_istream's deleting dtor calls the complete dtor, then
|
// basic_istream's deleting dtor calls the complete dtor, then
|
||||||
// operator delete().
|
// operator delete().
|
||||||
// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* {{.*}}%this) unnamed_addr
|
// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* %this) unnamed_addr
|
||||||
// CHECK: call {{.*}} @_ZN13basic_istreamIcED1Ev
|
// CHECK: call {{.*}} @_ZN13basic_istreamIcED1Ev
|
||||||
// CHECK: call {{.*}} @_ZdlPv
|
// CHECK: call {{.*}} @_ZdlPv
|
||||||
|
|
||||||
// basic_istream's base dtor is a no-op.
|
// basic_istream's base dtor is a no-op.
|
||||||
// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* {{.*}}%this, i8** %vtt) unnamed_addr
|
// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* %this, i8** %vtt) unnamed_addr
|
||||||
// CHECK-NOT: call
|
// CHECK-NOT: call
|
||||||
// CHECK: }
|
// CHECK: }
|
||||||
|
|
Loading…
Reference in New Issue