зеркало из https://github.com/microsoft/clang-1.git
Revert r184205 and associated patches while investigating issue with broken buildbot (possible interaction with LTO)
<rdar://problem/14209661> git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184384 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
8bb8669779
Коммит
3258abc2ba
|
@ -97,12 +97,8 @@ public:
|
|||
return *MangleCtx;
|
||||
}
|
||||
|
||||
/// Returns true if the given constructor or destructor is one of the
|
||||
/// kinds that the ABI says returns 'this' (only applies when called
|
||||
/// 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.
|
||||
/// Returns true if the given instance method is one of the
|
||||
/// kinds that the ABI says returns 'this'.
|
||||
virtual bool HasThisReturn(GlobalDecl GD) const { return false; }
|
||||
|
||||
/// Returns true if the given record type should be returned indirectly.
|
||||
|
@ -218,10 +214,10 @@ public:
|
|||
const CXXRecordDecl *BaseClassDecl) = 0;
|
||||
|
||||
/// Build the signature of the given constructor variant by adding
|
||||
/// any required parameters. For convenience, ArgTys has been initialized
|
||||
/// with the type of 'this' and ResTy has been initialized with the type of
|
||||
/// 'this' if HasThisReturn(GlobalDecl(Ctor, T)) is true or 'void' otherwise
|
||||
/// (although both may be changed by the ABI).
|
||||
/// any required parameters. For convenience, ResTy has been
|
||||
/// initialized to 'void', and ArgTys has been initialized with the
|
||||
/// type of 'this' (although this may be changed by the ABI) and
|
||||
/// will have the formal parameters added to it afterwards.
|
||||
///
|
||||
/// If there are ever any ABIs where the implicit parameters are
|
||||
/// intermixed with the formal parameters, we can address those
|
||||
|
@ -235,10 +231,9 @@ public:
|
|||
const CXXRecordDecl *RD);
|
||||
|
||||
/// Build the signature of the given destructor variant by adding
|
||||
/// any required parameters. For convenience, ArgTys has been initialized
|
||||
/// with the type of 'this' and ResTy has been initialized with the type of
|
||||
/// 'this' if HasThisReturn(GlobalDecl(Dtor, T)) is true or 'void' otherwise
|
||||
/// (although both may be changed by the ABI).
|
||||
/// any required parameters. For convenience, ResTy has been
|
||||
/// initialized to 'void' and ArgTys has been initialized with the
|
||||
/// type of 'this' (although this may be changed by the ABI).
|
||||
virtual void BuildDestructorSignature(const CXXDestructorDecl *Dtor,
|
||||
CXXDtorType T,
|
||||
CanQualType &ResTy,
|
||||
|
@ -249,8 +244,7 @@ public:
|
|||
/// possibly some extra data for constructors and destructors.
|
||||
///
|
||||
/// 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
|
||||
/// the formal return type of the function otherwise.
|
||||
/// initialized with the formal return type of the function.
|
||||
virtual void BuildInstanceFunctionParams(CodeGenFunction &CGF,
|
||||
QualType &ResTy,
|
||||
FunctionArgList &Params) = 0;
|
||||
|
@ -259,20 +253,21 @@ public:
|
|||
virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;
|
||||
|
||||
/// Emit the constructor call. Return the function that is called.
|
||||
virtual void EmitConstructorCall(CodeGenFunction &CGF,
|
||||
virtual llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
|
||||
const CXXConstructorDecl *D,
|
||||
CXXCtorType Type,
|
||||
bool ForVirtualBase, bool Delegating,
|
||||
CXXCtorType Type, bool ForVirtualBase,
|
||||
bool Delegating,
|
||||
llvm::Value *This,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd) = 0;
|
||||
|
||||
/// Emit the ABI-specific virtual destructor call.
|
||||
virtual void EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
CXXDtorType DtorType,
|
||||
SourceLocation CallLoc,
|
||||
llvm::Value *This) = 0;
|
||||
virtual RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
CXXDtorType DtorType,
|
||||
SourceLocation CallLoc,
|
||||
ReturnValueSlot ReturnValue,
|
||||
llvm::Value *This) = 0;
|
||||
|
||||
/// Emit any tables needed to implement virtual inheritance. For Itanium,
|
||||
/// this emits virtual table tables. For the MSVC++ ABI, this emits virtual
|
||||
|
|
|
@ -200,10 +200,7 @@ CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D,
|
|||
CXXCtorType ctorKind) {
|
||||
SmallVector<CanQualType, 16> argTypes;
|
||||
argTypes.push_back(GetThisType(Context, D->getParent()));
|
||||
|
||||
GlobalDecl GD(D, ctorKind);
|
||||
CanQualType resultType =
|
||||
TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy;
|
||||
CanQualType resultType = Context.VoidTy;
|
||||
|
||||
TheCXXABI.BuildConstructorSignature(D, ctorKind, resultType, argTypes);
|
||||
|
||||
|
@ -228,10 +225,7 @@ CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D,
|
|||
CXXDtorType dtorKind) {
|
||||
SmallVector<CanQualType, 2> argTypes;
|
||||
argTypes.push_back(GetThisType(Context, D->getParent()));
|
||||
|
||||
GlobalDecl GD(D, dtorKind);
|
||||
CanQualType resultType =
|
||||
TheCXXABI.HasThisReturn(GD) ? argTypes.front() : Context.VoidTy;
|
||||
CanQualType resultType = Context.VoidTy;
|
||||
|
||||
TheCXXABI.BuildDestructorSignature(D, dtorKind, resultType, argTypes);
|
||||
|
||||
|
@ -1639,6 +1633,18 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
|
|||
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,
|
||||
bool EmitRetDbgLoc) {
|
||||
// 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");
|
||||
}
|
||||
|
||||
// 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();
|
||||
if (!RetDbgLoc.isUnknown())
|
||||
Ret->setDebugLoc(RetDbgLoc);
|
||||
|
|
|
@ -1662,8 +1662,11 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
|
|||
}
|
||||
|
||||
// Non-trivial constructors are handled in an ABI-specific manner.
|
||||
CGM.getCXXABI().EmitConstructorCall(*this, D, Type, ForVirtualBase,
|
||||
Delegating, This, ArgBeg, ArgEnd);
|
||||
llvm::Value *Callee = CGM.getCXXABI().EmitConstructorCall(*this, D, Type,
|
||||
ForVirtualBase, Delegating, This, ArgBeg, ArgEnd);
|
||||
if (CGM.getCXXABI().HasThisReturn(CurGD) &&
|
||||
CGM.getCXXABI().HasThisReturn(GlobalDecl(D, Type)))
|
||||
CalleeWithThisReturn = Callee;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1755,6 +1758,9 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
|
|||
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType);
|
||||
EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),
|
||||
Callee, ReturnValueSlot(), DelegateArgs, Ctor);
|
||||
if (CGM.getCXXABI().HasThisReturn(CurGD) &&
|
||||
CGM.getCXXABI().HasThisReturn(GlobalDecl(Ctor, CtorType)))
|
||||
CalleeWithThisReturn = Callee;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -1821,6 +1827,9 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
|
|||
EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
|
||||
VTT, getContext().getPointerType(getContext().VoidPtrTy),
|
||||
0, 0);
|
||||
if (CGM.getCXXABI().HasThisReturn(CurGD) &&
|
||||
CGM.getCXXABI().HasThisReturn(GlobalDecl(DD, Type)))
|
||||
CalleeWithThisReturn = Callee;
|
||||
}
|
||||
|
||||
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
|
||||
// because then we know what the type is.
|
||||
bool UseVirtualCall = CanUseVirtualCall && !DevirtualizedMethod;
|
||||
llvm::Value *Callee;
|
||||
|
||||
llvm::Value *Callee;
|
||||
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) {
|
||||
CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor, Dtor_Complete,
|
||||
CE->getExprLoc(), This);
|
||||
assert(CE->arg_begin() == CE->arg_end() &&
|
||||
"Virtual destructor shouldn't have explicit parameters");
|
||||
return CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor,
|
||||
Dtor_Complete,
|
||||
CE->getExprLoc(),
|
||||
ReturnValue, This);
|
||||
} else {
|
||||
if (getLangOpts().AppleKext &&
|
||||
MD->isVirtual() &&
|
||||
|
@ -301,16 +302,12 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
|
|||
cast<CXXDestructorDecl>(DevirtualizedMethod);
|
||||
Callee = CGM.GetAddrOfFunction(GlobalDecl(DDtor, Dtor_Complete), Ty);
|
||||
}
|
||||
EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This,
|
||||
/*ImplicitParam=*/0, QualType(), 0, 0);
|
||||
}
|
||||
return RValue::get(0);
|
||||
}
|
||||
|
||||
if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) {
|
||||
} else if (const CXXConstructorDecl *Ctor =
|
||||
dyn_cast<CXXConstructorDecl>(MD)) {
|
||||
Callee = CGM.GetAddrOfFunction(GlobalDecl(Ctor, Ctor_Complete), Ty);
|
||||
} else if (UseVirtualCall) {
|
||||
Callee = BuildVirtualCall(MD, This, Ty);
|
||||
Callee = BuildVirtualCall(MD, This, Ty);
|
||||
} else {
|
||||
if (getLangOpts().AppleKext &&
|
||||
MD->isVirtual() &&
|
||||
|
@ -1416,7 +1413,8 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
|
|||
// FIXME: Provide a source location here.
|
||||
CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
|
||||
CGF.CGM.getCXXABI().EmitVirtualDestructorCall(CGF, Dtor, DtorType,
|
||||
SourceLocation(), Ptr);
|
||||
SourceLocation(),
|
||||
ReturnValueSlot(), Ptr);
|
||||
|
||||
if (UseGlobalDelete) {
|
||||
CGF.PopCleanupBlock();
|
||||
|
|
|
@ -287,9 +287,8 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
|
|||
GlobalDecl GD, const ThunkInfo &Thunk) {
|
||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
|
||||
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
|
||||
QualType ResultType = FPT->getResultType();
|
||||
QualType ThisType = MD->getThisType(getContext());
|
||||
QualType ResultType =
|
||||
CGM.getCXXABI().HasThisReturn(GD) ? ThisType : FPT->getResultType();
|
||||
|
||||
FunctionArgList FunctionArgs;
|
||||
|
||||
|
|
|
@ -42,7 +42,8 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
|
|||
AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),
|
||||
LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1),
|
||||
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),
|
||||
NumReturnExprs(0), NumSimpleReturnExprs(0),
|
||||
CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0),
|
||||
|
@ -661,12 +662,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
|
|||
QualType ResTy = FD->getResultType();
|
||||
|
||||
CurGD = GD;
|
||||
const CXXMethodDecl *MD;
|
||||
if ((MD = dyn_cast<CXXMethodDecl>(FD)) && MD->isInstance()) {
|
||||
if (CGM.getCXXABI().HasThisReturn(GD))
|
||||
ResTy = MD->getThisType(getContext());
|
||||
if (isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isInstance())
|
||||
CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args);
|
||||
}
|
||||
|
||||
for (unsigned i = 0, e = FD->getNumParams(); i != e; ++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();
|
||||
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.
|
||||
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.
|
||||
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
|
||||
// a quick pass now to see if we can.
|
||||
|
|
|
@ -798,6 +798,10 @@ private:
|
|||
CGDebugInfo *DebugInfo;
|
||||
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
|
||||
/// calling llvm.stacksave for multiple VLAs in the same scope.
|
||||
bool DidCallStackSave;
|
||||
|
|
|
@ -722,14 +722,6 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
|
|||
if (!IsIncompleteFunction)
|
||||
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
|
||||
// overridden by a definition.
|
||||
|
||||
|
|
|
@ -119,17 +119,20 @@ public:
|
|||
|
||||
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
|
||||
|
||||
void EmitConstructorCall(CodeGenFunction &CGF,
|
||||
const CXXConstructorDecl *D, CXXCtorType Type,
|
||||
bool ForVirtualBase, bool Delegating,
|
||||
llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
|
||||
const CXXConstructorDecl *D,
|
||||
CXXCtorType Type, bool ForVirtualBase,
|
||||
bool Delegating,
|
||||
llvm::Value *This,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd);
|
||||
|
||||
void EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
CXXDtorType DtorType, SourceLocation CallLoc,
|
||||
llvm::Value *This);
|
||||
RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
CXXDtorType DtorType,
|
||||
SourceLocation CallLoc,
|
||||
ReturnValueSlot ReturnValue,
|
||||
llvm::Value *This);
|
||||
|
||||
void EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage,
|
||||
const CXXRecordDecl *RD);
|
||||
|
@ -165,11 +168,21 @@ class ARMCXXABI : public ItaniumCXXABI {
|
|||
public:
|
||||
ARMCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM, /*ARM*/ true) {}
|
||||
|
||||
bool HasThisReturn(GlobalDecl GD) const {
|
||||
return (isa<CXXConstructorDecl>(GD.getDecl()) || (
|
||||
isa<CXXDestructorDecl>(GD.getDecl()) &&
|
||||
GD.getDtorType() != Dtor_Deleting));
|
||||
}
|
||||
void BuildConstructorSignature(const CXXConstructorDecl *Ctor,
|
||||
CXXCtorType T,
|
||||
CanQualType &ResTy,
|
||||
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);
|
||||
|
||||
|
@ -181,6 +194,15 @@ public:
|
|||
QualType ElementType);
|
||||
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr,
|
||||
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) {
|
||||
ASTContext &Context = getContext();
|
||||
|
||||
// 'this' parameter is already there, as well as 'this' return if
|
||||
// HasThisReturn(GlobalDecl(Ctor, Type)) is true
|
||||
// 'this' is already there.
|
||||
|
||||
// Check if we need to add a VTT parameter (which has type void **).
|
||||
if (Type == Ctor_Base && Ctor->getParent()->getNumVBases() != 0)
|
||||
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
|
||||
/// base subobject.
|
||||
void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
|
||||
|
@ -751,14 +781,25 @@ void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
|
|||
SmallVectorImpl<CanQualType> &ArgTys) {
|
||||
ASTContext &Context = getContext();
|
||||
|
||||
// 'this' parameter is already there, as well as 'this' return if
|
||||
// HasThisReturn(GlobalDecl(Dtor, Type)) is true
|
||||
// 'this' is already there.
|
||||
|
||||
// Check if we need to add a VTT parameter (which has type void **).
|
||||
if (Type == Dtor_Base && Dtor->getParent()->getNumVBases() != 0)
|
||||
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,
|
||||
QualType &ResTy,
|
||||
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) {
|
||||
/// Initialize the 'this' slot.
|
||||
EmitThisParam(CGF);
|
||||
|
@ -792,23 +843,21 @@ void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
|
|||
= CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getVTTDecl(CGF)),
|
||||
"vtt");
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
|
||||
ItaniumCXXABI::EmitInstanceFunctionProlog(CGF);
|
||||
|
||||
/// Initialize the return slot to 'this' at the start of the
|
||||
/// function.
|
||||
if (HasThisReturn(CGF.CurGD))
|
||||
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
|
||||
}
|
||||
|
||||
void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
|
||||
llvm::Value *ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
|
||||
const CXXConstructorDecl *D,
|
||||
CXXCtorType Type,
|
||||
bool ForVirtualBase, bool Delegating,
|
||||
CXXCtorType Type, bool ForVirtualBase,
|
||||
bool Delegating,
|
||||
llvm::Value *This,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd) {
|
||||
|
@ -818,15 +867,17 @@ void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
|
|||
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
|
||||
|
||||
// FIXME: Provide a source location here.
|
||||
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(),
|
||||
This, VTT, VTTTy, ArgBeg, ArgEnd);
|
||||
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
|
||||
VTT, VTTTy, ArgBeg, ArgEnd);
|
||||
return Callee;
|
||||
}
|
||||
|
||||
void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
CXXDtorType DtorType,
|
||||
SourceLocation CallLoc,
|
||||
llvm::Value *This) {
|
||||
RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
CXXDtorType DtorType,
|
||||
SourceLocation CallLoc,
|
||||
ReturnValueSlot ReturnValue,
|
||||
llvm::Value *This) {
|
||||
assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
|
||||
|
||||
const CGFunctionInfo *FInfo
|
||||
|
@ -834,8 +885,8 @@ void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
|||
llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
|
||||
llvm::Value *Callee = CGF.BuildVirtualCall(Dtor, DtorType, This, Ty);
|
||||
|
||||
CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This,
|
||||
/*ImplicitParam=*/0, QualType(), 0, 0);
|
||||
return CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValue, This,
|
||||
/*ImplicitParam=*/0, QualType(), 0, 0);
|
||||
}
|
||||
|
||||
void ItaniumCXXABI::EmitVirtualInheritanceTables(
|
||||
|
|
|
@ -30,8 +30,6 @@ class MicrosoftCXXABI : public CGCXXABI {
|
|||
public:
|
||||
MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {}
|
||||
|
||||
bool HasThisReturn(GlobalDecl GD) const;
|
||||
|
||||
bool isReturnTypeIndirect(const CXXRecordDecl *RD) const {
|
||||
// Structures that are not C++03 PODs are always indirect.
|
||||
return !RD->isPOD();
|
||||
|
@ -76,17 +74,20 @@ public:
|
|||
|
||||
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
|
||||
|
||||
void EmitConstructorCall(CodeGenFunction &CGF,
|
||||
const CXXConstructorDecl *D, CXXCtorType Type,
|
||||
bool ForVirtualBase, bool Delegating,
|
||||
llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
|
||||
const CXXConstructorDecl *D,
|
||||
CXXCtorType Type, bool ForVirtualBase,
|
||||
bool Delegating,
|
||||
llvm::Value *This,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd);
|
||||
|
||||
void EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
CXXDtorType DtorType, SourceLocation CallLoc,
|
||||
llvm::Value *This);
|
||||
|
||||
RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
CXXDtorType DtorType,
|
||||
SourceLocation CallLoc,
|
||||
ReturnValueSlot ReturnValue,
|
||||
llvm::Value *This);
|
||||
|
||||
void EmitVirtualInheritanceTables(llvm::GlobalVariable::LinkageTypes Linkage,
|
||||
const CXXRecordDecl *RD);
|
||||
|
@ -129,6 +130,7 @@ public:
|
|||
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF,
|
||||
llvm::Value *allocPtr,
|
||||
CharUnits cookieSize);
|
||||
static bool needThisReturn(GlobalDecl GD);
|
||||
|
||||
private:
|
||||
llvm::Constant *getZeroInt() {
|
||||
|
@ -312,15 +314,19 @@ MicrosoftCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
|
|||
return CGF.Builder.CreateNSWAdd(VBPtrOffset, VBPtrToNewBase);
|
||||
}
|
||||
|
||||
bool MicrosoftCXXABI::HasThisReturn(GlobalDecl GD) const {
|
||||
return isa<CXXConstructorDecl>(GD.getDecl());
|
||||
bool MicrosoftCXXABI::needThisReturn(GlobalDecl GD) {
|
||||
const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl());
|
||||
return isa<CXXConstructorDecl>(MD);
|
||||
}
|
||||
|
||||
void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
|
||||
CXXCtorType Type,
|
||||
CanQualType &ResTy,
|
||||
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();
|
||||
if (Class->getNumVBases()) {
|
||||
|
@ -378,7 +384,6 @@ void MicrosoftCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
|
|||
CanQualType &ResTy,
|
||||
SmallVectorImpl<CanQualType> &ArgTys) {
|
||||
// 'this' is already in place
|
||||
|
||||
// TODO: 'for base' flag
|
||||
|
||||
if (Type == Dtor_Deleting) {
|
||||
|
@ -399,6 +404,9 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
|
|||
QualType &ResTy,
|
||||
FunctionArgList &Params) {
|
||||
BuildThisParam(CGF, Params);
|
||||
if (needThisReturn(CGF.CurGD)) {
|
||||
ResTy = Params[0]->getType();
|
||||
}
|
||||
|
||||
ASTContext &Context = getContext();
|
||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
|
||||
|
@ -423,17 +431,9 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
|
|||
|
||||
void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
|
||||
EmitThisParam(CGF);
|
||||
|
||||
/// 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))
|
||||
if (needThisReturn(CGF.CurGD)) {
|
||||
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
|
||||
}
|
||||
|
||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
|
||||
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,
|
||||
CXXCtorType Type,
|
||||
bool ForVirtualBase,
|
||||
CXXCtorType Type, bool ForVirtualBase,
|
||||
bool Delegating,
|
||||
llvm::Value *This,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
|
@ -475,14 +474,17 @@ void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
|
|||
|
||||
// FIXME: Provide a source location here.
|
||||
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
|
||||
ImplicitParam, ImplicitParamTy, ArgBeg, ArgEnd);
|
||||
ImplicitParam, ImplicitParamTy,
|
||||
ArgBeg, ArgEnd);
|
||||
return Callee;
|
||||
}
|
||||
|
||||
void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
CXXDtorType DtorType,
|
||||
SourceLocation CallLoc,
|
||||
llvm::Value *This) {
|
||||
RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
|
||||
const CXXDestructorDecl *Dtor,
|
||||
CXXDtorType DtorType,
|
||||
SourceLocation CallLoc,
|
||||
ReturnValueSlot ReturnValue,
|
||||
llvm::Value *This) {
|
||||
assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
|
||||
|
||||
// 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()),
|
||||
DtorType == Dtor_Deleting);
|
||||
|
||||
CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This,
|
||||
ImplicitParam, Context.BoolTy, 0, 0);
|
||||
return CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValue, This,
|
||||
ImplicitParam, Context.BoolTy, 0, 0);
|
||||
}
|
||||
|
||||
const VBTableVector &
|
||||
|
|
|
@ -52,19 +52,19 @@ namespace test1 {
|
|||
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: store [[A]]* {{.*}}, [[A]]** [[THIS]]
|
||||
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
|
||||
// CHECK: {{%.*}} = call [[A]]* @_ZN5test11AC2Ei(
|
||||
// CHECK: ret [[A]]* [[THIS1]]
|
||||
// CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AC2Ei(
|
||||
// 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: store [[A]]* {{.*}}, [[A]]** [[THIS]]
|
||||
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
|
||||
// CHECK: {{%.*}} = call [[A]]* @_ZN5test11AD2Ev(
|
||||
// CHECK: ret [[A]]* [[THIS1]]
|
||||
// CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AD2Ev(
|
||||
// CHECK: ret [[A]]* [[THIS2]]
|
||||
}
|
||||
|
||||
// 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 --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
|
||||
//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck %s
|
||||
|
||||
// FIXME: Add checks to ensure that Microsoft destructors do not return 'this'
|
||||
// once PR12784 is resolved
|
||||
// For constructors/desctructors that return 'this', if there exists a callsite
|
||||
// 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
|
||||
// constructors and destructors which return this (and only these cases)
|
||||
// CHECK: define linkonce_odr [[A:%.*]] @_ZN11ObjectCacheC1Ev([[A]] %this) unnamed_addr
|
||||
// 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:
|
||||
A();
|
||||
~A();
|
||||
TimerBase();
|
||||
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:
|
||||
int x_;
|
||||
virtual void fired() { (m_object->*m_function)(this); }
|
||||
|
||||
TimerFiredClass* m_object;
|
||||
TimerFiredFunction m_function;
|
||||
};
|
||||
|
||||
class B : public A {
|
||||
class ObjectCache {
|
||||
public:
|
||||
B(int *i);
|
||||
~B();
|
||||
explicit ObjectCache();
|
||||
~ObjectCache();
|
||||
|
||||
private:
|
||||
int *i_;
|
||||
Timer<ObjectCache> m_notificationPostTimer;
|
||||
};
|
||||
|
||||
B::B(int *i) : i_(i) { }
|
||||
#ifndef PR12784_WORKAROUND
|
||||
B::~B() { }
|
||||
#endif
|
||||
inline ObjectCache::ObjectCache() : m_notificationPostTimer(this, 0) { }
|
||||
inline ObjectCache::~ObjectCache() { }
|
||||
|
||||
// CHECKGEN: define void @_ZN1BC1EPi(%class.B* %this, i32* %i)
|
||||
// CHECKGEN: define void @_ZN1BC2EPi(%class.B* %this, i32* %i)
|
||||
// CHECKGEN: define void @_ZN1BD1Ev(%class.B* %this)
|
||||
// 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();
|
||||
ObjectCache *test() {
|
||||
ObjectCache *dd = new ObjectCache();
|
||||
return dd;
|
||||
}
|
||||
|
||||
// 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);
|
||||
};
|
||||
|
||||
// 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)
|
||||
// CHECK: call {{.*}} @_ZNK13no_elide_base5OthercvNS_4BaseEEv
|
||||
// CHECK: call {{.*}} @_ZN13no_elide_base4BaseC2ERKS0_
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
struct A { virtual void a(); };
|
||||
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)
|
||||
|
|
|
@ -5,7 +5,6 @@ struct B { A<int> x; };
|
|||
void a() {
|
||||
B b;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
|
@ -82,7 +82,7 @@ namespace test7 {
|
|||
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*);
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ namespace test8 {
|
|||
template<typename T>
|
||||
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)>);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ class A {
|
|||
void no_constructor_destructor_infinite_recursion() {
|
||||
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-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]]
|
||||
|
@ -34,7 +34,7 @@ struct B {
|
|||
|
||||
// Tests that we can define constructors outside the class (PR12784).
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -136,7 +136,7 @@ struct B : A {
|
|||
};
|
||||
|
||||
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: ret
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ struct C : virtual A {
|
|||
};
|
||||
|
||||
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;
|
||||
// CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
|
||||
// CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
|
||||
|
@ -179,7 +179,7 @@ struct D : C {
|
|||
};
|
||||
|
||||
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: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
|
||||
// CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0
|
||||
|
@ -204,7 +204,7 @@ struct E : virtual C {
|
|||
};
|
||||
|
||||
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: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
|
||||
// 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
|
||||
// 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 {{.*}} @_ZN9basic_iosD2Ev
|
||||
|
||||
// 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: }
|
||||
|
||||
// basic_iostream's deleting dtor calls its complete dtor, then
|
||||
// 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 {{.*}} @_ZdlPv
|
||||
|
||||
// basic_istream's complete dtor calls the 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 {{.*}} @_ZN9basic_iosD2Ev
|
||||
|
||||
// basic_istream's deleting dtor calls the complete dtor, then
|
||||
// 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 {{.*}} @_ZdlPv
|
||||
|
||||
// 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: }
|
||||
|
|
Загрузка…
Ссылка в новой задаче