forked from OSchip/llvm-project
[CodeGen] Fix ExtParameterInfo bugs in C++ CodeGen code.
This patch makes use of the prefix/suffix ABI argument distinction that was introduced in r295870, so that we now emit ExtParameterInfo at the correct offset for member calls that have added ABI arguments. I don't see a good way to test the generated param info, since we don't actually seem to use it in CGFunctionInfo outside of Swift. Any suggestions/thoughts for how to better test this are welcome. :) This patch also fixes a small bug with inheriting constructors: if we decide not to pass args into an base class ctor, we would still generate ExtParameterInfo as though we did. The added test-case is for that behavior. llvm-svn: 296024
This commit is contained in:
parent
66b4e21534
commit
d0a9e807f3
|
@ -362,18 +362,31 @@ getExtParameterInfosForCall(const FunctionProtoType *proto,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Arrange a call to a C++ method, passing the given arguments.
|
/// Arrange a call to a C++ method, passing the given arguments.
|
||||||
|
///
|
||||||
|
/// ExtraPrefixArgs is the number of ABI-specific args passed after the `this`
|
||||||
|
/// parameter.
|
||||||
|
/// ExtraSuffixArgs is the number of ABI-specific args passed at the end of
|
||||||
|
/// args.
|
||||||
|
/// PassProtoArgs indicates whether `args` has args for the parameters in the
|
||||||
|
/// given CXXConstructorDecl.
|
||||||
const CGFunctionInfo &
|
const CGFunctionInfo &
|
||||||
CodeGenTypes::arrangeCXXConstructorCall(const CallArgList &args,
|
CodeGenTypes::arrangeCXXConstructorCall(const CallArgList &args,
|
||||||
const CXXConstructorDecl *D,
|
const CXXConstructorDecl *D,
|
||||||
CXXCtorType CtorKind,
|
CXXCtorType CtorKind,
|
||||||
unsigned ExtraArgs) {
|
unsigned ExtraPrefixArgs,
|
||||||
|
unsigned ExtraSuffixArgs,
|
||||||
|
bool PassProtoArgs) {
|
||||||
// FIXME: Kill copy.
|
// FIXME: Kill copy.
|
||||||
SmallVector<CanQualType, 16> ArgTypes;
|
SmallVector<CanQualType, 16> ArgTypes;
|
||||||
for (const auto &Arg : args)
|
for (const auto &Arg : args)
|
||||||
ArgTypes.push_back(Context.getCanonicalParamType(Arg.Ty));
|
ArgTypes.push_back(Context.getCanonicalParamType(Arg.Ty));
|
||||||
|
|
||||||
|
// +1 for implicit this, which should always be args[0].
|
||||||
|
unsigned TotalPrefixArgs = 1 + ExtraPrefixArgs;
|
||||||
|
|
||||||
CanQual<FunctionProtoType> FPT = GetFormalType(D);
|
CanQual<FunctionProtoType> FPT = GetFormalType(D);
|
||||||
RequiredArgs Required = RequiredArgs::forPrototypePlus(FPT, 1 + ExtraArgs, D);
|
RequiredArgs Required =
|
||||||
|
RequiredArgs::forPrototypePlus(FPT, TotalPrefixArgs + ExtraSuffixArgs, D);
|
||||||
GlobalDecl GD(D, CtorKind);
|
GlobalDecl GD(D, CtorKind);
|
||||||
CanQualType ResultType = TheCXXABI.HasThisReturn(GD)
|
CanQualType ResultType = TheCXXABI.HasThisReturn(GD)
|
||||||
? ArgTypes.front()
|
? ArgTypes.front()
|
||||||
|
@ -382,8 +395,14 @@ CodeGenTypes::arrangeCXXConstructorCall(const CallArgList &args,
|
||||||
: Context.VoidTy;
|
: Context.VoidTy;
|
||||||
|
|
||||||
FunctionType::ExtInfo Info = FPT->getExtInfo();
|
FunctionType::ExtInfo Info = FPT->getExtInfo();
|
||||||
auto ParamInfos = getExtParameterInfosForCall(FPT.getTypePtr(), 1 + ExtraArgs,
|
llvm::SmallVector<FunctionProtoType::ExtParameterInfo, 16> ParamInfos;
|
||||||
ArgTypes.size());
|
// If the prototype args are elided, we should only have ABI-specific args,
|
||||||
|
// which never have param info.
|
||||||
|
if (PassProtoArgs && FPT->hasExtParameterInfos()) {
|
||||||
|
// ABI-specific suffix arguments are treated the same as variadic arguments.
|
||||||
|
addExtParameterInfosForCall(ParamInfos, FPT.getTypePtr(), TotalPrefixArgs,
|
||||||
|
ArgTypes.size());
|
||||||
|
}
|
||||||
return arrangeLLVMFunctionInfo(ResultType, /*instanceMethod=*/true,
|
return arrangeLLVMFunctionInfo(ResultType, /*instanceMethod=*/true,
|
||||||
/*chainCall=*/false, ArgTypes, Info,
|
/*chainCall=*/false, ArgTypes, Info,
|
||||||
ParamInfos, Required);
|
ParamInfos, Required);
|
||||||
|
@ -627,15 +646,20 @@ CodeGenTypes::arrangeBuiltinFunctionDeclaration(CanQualType resultType,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Arrange a call to a C++ method, passing the given arguments.
|
/// Arrange a call to a C++ method, passing the given arguments.
|
||||||
|
///
|
||||||
|
/// numPrefixArgs is the number of ABI-specific prefix arguments we have. It
|
||||||
|
/// does not count `this`.
|
||||||
const CGFunctionInfo &
|
const CGFunctionInfo &
|
||||||
CodeGenTypes::arrangeCXXMethodCall(const CallArgList &args,
|
CodeGenTypes::arrangeCXXMethodCall(const CallArgList &args,
|
||||||
const FunctionProtoType *proto,
|
const FunctionProtoType *proto,
|
||||||
RequiredArgs required) {
|
RequiredArgs required,
|
||||||
unsigned numRequiredArgs =
|
unsigned numPrefixArgs) {
|
||||||
(proto->isVariadic() ? required.getNumRequiredArgs() : args.size());
|
assert(numPrefixArgs + 1 <= args.size() &&
|
||||||
unsigned numPrefixArgs = numRequiredArgs - proto->getNumParams();
|
"Emitting a call with less args than the required prefix?");
|
||||||
|
// Add one to account for `this`. It's a bit awkward here, but we don't count
|
||||||
|
// `this` in similar places elsewhere.
|
||||||
auto paramInfos =
|
auto paramInfos =
|
||||||
getExtParameterInfosForCall(proto, numPrefixArgs, args.size());
|
getExtParameterInfosForCall(proto, numPrefixArgs + 1, args.size());
|
||||||
|
|
||||||
// FIXME: Kill copy.
|
// FIXME: Kill copy.
|
||||||
auto argTypes = getArgTypesForCall(Context, args);
|
auto argTypes = getArgTypesForCall(Context, args);
|
||||||
|
|
|
@ -1979,7 +1979,7 @@ static bool canEmitDelegateCallArgs(CodeGenFunction &CGF,
|
||||||
|
|
||||||
// Likewise if they're inalloca.
|
// Likewise if they're inalloca.
|
||||||
const CGFunctionInfo &Info =
|
const CGFunctionInfo &Info =
|
||||||
CGF.CGM.getTypes().arrangeCXXConstructorCall(Args, Ctor, Type, 0);
|
CGF.CGM.getTypes().arrangeCXXConstructorCall(Args, Ctor, Type, 0, 0);
|
||||||
if (Info.usesInAlloca())
|
if (Info.usesInAlloca())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2021,10 +2021,11 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PassPrototypeArgs = true;
|
||||||
// Check whether we can actually emit the constructor before trying to do so.
|
// Check whether we can actually emit the constructor before trying to do so.
|
||||||
if (auto Inherited = D->getInheritedConstructor()) {
|
if (auto Inherited = D->getInheritedConstructor()) {
|
||||||
if (getTypes().inheritingCtorHasParams(Inherited, Type) &&
|
PassPrototypeArgs = getTypes().inheritingCtorHasParams(Inherited, Type);
|
||||||
!canEmitDelegateCallArgs(*this, D, Type, Args)) {
|
if (PassPrototypeArgs && !canEmitDelegateCallArgs(*this, D, Type, Args)) {
|
||||||
EmitInlinedInheritingCXXConstructorCall(D, Type, ForVirtualBase,
|
EmitInlinedInheritingCXXConstructorCall(D, Type, ForVirtualBase,
|
||||||
Delegating, Args);
|
Delegating, Args);
|
||||||
return;
|
return;
|
||||||
|
@ -2040,7 +2041,7 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
|
||||||
llvm::Constant *CalleePtr =
|
llvm::Constant *CalleePtr =
|
||||||
CGM.getAddrOfCXXStructor(D, getFromCtorType(Type));
|
CGM.getAddrOfCXXStructor(D, getFromCtorType(Type));
|
||||||
const CGFunctionInfo &Info = CGM.getTypes().arrangeCXXConstructorCall(
|
const CGFunctionInfo &Info = CGM.getTypes().arrangeCXXConstructorCall(
|
||||||
Args, D, Type, ExtraArgs.Prefix + ExtraArgs.Suffix);
|
Args, D, Type, ExtraArgs.Prefix, ExtraArgs.Suffix, PassPrototypeArgs);
|
||||||
CGCallee Callee = CGCallee::forDirect(CalleePtr, D);
|
CGCallee Callee = CGCallee::forDirect(CalleePtr, D);
|
||||||
EmitCall(Info, Callee, ReturnValueSlot(), Args);
|
EmitCall(Info, Callee, ReturnValueSlot(), Args);
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,15 @@
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
using namespace CodeGen;
|
using namespace CodeGen;
|
||||||
|
|
||||||
static RequiredArgs
|
namespace {
|
||||||
|
struct MemberCallInfo {
|
||||||
|
RequiredArgs ReqArgs;
|
||||||
|
// Number of prefix arguments for the call. Ignores the `this` pointer.
|
||||||
|
unsigned PrefixSize;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemberCallInfo
|
||||||
commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, const CXXMethodDecl *MD,
|
commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, const CXXMethodDecl *MD,
|
||||||
llvm::Value *This, llvm::Value *ImplicitParam,
|
llvm::Value *This, llvm::Value *ImplicitParam,
|
||||||
QualType ImplicitParamTy, const CallExpr *CE,
|
QualType ImplicitParamTy, const CallExpr *CE,
|
||||||
|
@ -48,6 +56,7 @@ commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, const CXXMethodDecl *MD,
|
||||||
|
|
||||||
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
|
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
|
||||||
RequiredArgs required = RequiredArgs::forPrototypePlus(FPT, Args.size(), MD);
|
RequiredArgs required = RequiredArgs::forPrototypePlus(FPT, Args.size(), MD);
|
||||||
|
unsigned PrefixSize = Args.size() - 1;
|
||||||
|
|
||||||
// And the rest of the call args.
|
// And the rest of the call args.
|
||||||
if (RtlArgs) {
|
if (RtlArgs) {
|
||||||
|
@ -65,7 +74,7 @@ commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, const CXXMethodDecl *MD,
|
||||||
FPT->getNumParams() == 0 &&
|
FPT->getNumParams() == 0 &&
|
||||||
"No CallExpr specified for function with non-zero number of arguments");
|
"No CallExpr specified for function with non-zero number of arguments");
|
||||||
}
|
}
|
||||||
return required;
|
return {required, PrefixSize};
|
||||||
}
|
}
|
||||||
|
|
||||||
RValue CodeGenFunction::EmitCXXMemberOrOperatorCall(
|
RValue CodeGenFunction::EmitCXXMemberOrOperatorCall(
|
||||||
|
@ -75,9 +84,10 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorCall(
|
||||||
const CallExpr *CE, CallArgList *RtlArgs) {
|
const CallExpr *CE, CallArgList *RtlArgs) {
|
||||||
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
|
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
|
||||||
CallArgList Args;
|
CallArgList Args;
|
||||||
RequiredArgs required = commonEmitCXXMemberOrOperatorCall(
|
MemberCallInfo CallInfo = commonEmitCXXMemberOrOperatorCall(
|
||||||
*this, MD, This, ImplicitParam, ImplicitParamTy, CE, Args, RtlArgs);
|
*this, MD, This, ImplicitParam, ImplicitParamTy, CE, Args, RtlArgs);
|
||||||
auto &FnInfo = CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required);
|
auto &FnInfo = CGM.getTypes().arrangeCXXMethodCall(
|
||||||
|
Args, FPT, CallInfo.ReqArgs, CallInfo.PrefixSize);
|
||||||
return EmitCall(FnInfo, Callee, ReturnValue, Args);
|
return EmitCall(FnInfo, Callee, ReturnValue, Args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,7 +435,8 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
|
||||||
|
|
||||||
// And the rest of the call args
|
// And the rest of the call args
|
||||||
EmitCallArgs(Args, FPT, E->arguments());
|
EmitCallArgs(Args, FPT, E->arguments());
|
||||||
return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required),
|
return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required,
|
||||||
|
/*PrefixSize=*/0),
|
||||||
Callee, ReturnValue, Args);
|
Callee, ReturnValue, Args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -284,6 +284,7 @@ void CodeGenFunction::EmitCallAndReturnForThunk(llvm::Constant *CalleePtr,
|
||||||
if (isa<CXXDestructorDecl>(MD))
|
if (isa<CXXDestructorDecl>(MD))
|
||||||
CGM.getCXXABI().adjustCallArgsForDestructorThunk(*this, CurGD, CallArgs);
|
CGM.getCXXABI().adjustCallArgsForDestructorThunk(*this, CurGD, CallArgs);
|
||||||
|
|
||||||
|
unsigned PrefixArgs = CallArgs.size() - 1;
|
||||||
// Add the rest of the arguments.
|
// Add the rest of the arguments.
|
||||||
for (const ParmVarDecl *PD : MD->parameters())
|
for (const ParmVarDecl *PD : MD->parameters())
|
||||||
EmitDelegateCallArg(CallArgs, PD, SourceLocation());
|
EmitDelegateCallArg(CallArgs, PD, SourceLocation());
|
||||||
|
@ -292,7 +293,7 @@ void CodeGenFunction::EmitCallAndReturnForThunk(llvm::Constant *CalleePtr,
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
const CGFunctionInfo &CallFnInfo = CGM.getTypes().arrangeCXXMethodCall(
|
const CGFunctionInfo &CallFnInfo = CGM.getTypes().arrangeCXXMethodCall(
|
||||||
CallArgs, FPT, RequiredArgs::forPrototypePlus(FPT, 1, MD));
|
CallArgs, FPT, RequiredArgs::forPrototypePlus(FPT, 1, MD), PrefixArgs);
|
||||||
assert(CallFnInfo.getRegParm() == CurFnInfo->getRegParm() &&
|
assert(CallFnInfo.getRegParm() == CurFnInfo->getRegParm() &&
|
||||||
CallFnInfo.isNoReturn() == CurFnInfo->isNoReturn() &&
|
CallFnInfo.isNoReturn() == CurFnInfo->isNoReturn() &&
|
||||||
CallFnInfo.getCallingConvention() == CurFnInfo->getCallingConvention());
|
CallFnInfo.getCallingConvention() == CurFnInfo->getCallingConvention());
|
||||||
|
|
|
@ -303,11 +303,14 @@ public:
|
||||||
const CGFunctionInfo &arrangeCXXConstructorCall(const CallArgList &Args,
|
const CGFunctionInfo &arrangeCXXConstructorCall(const CallArgList &Args,
|
||||||
const CXXConstructorDecl *D,
|
const CXXConstructorDecl *D,
|
||||||
CXXCtorType CtorKind,
|
CXXCtorType CtorKind,
|
||||||
unsigned ExtraArgs);
|
unsigned ExtraPrefixArgs,
|
||||||
|
unsigned ExtraSuffixArgs,
|
||||||
|
bool PassProtoArgs = true);
|
||||||
|
|
||||||
const CGFunctionInfo &arrangeCXXMethodCall(const CallArgList &args,
|
const CGFunctionInfo &arrangeCXXMethodCall(const CallArgList &args,
|
||||||
const FunctionProtoType *type,
|
const FunctionProtoType *type,
|
||||||
RequiredArgs required);
|
RequiredArgs required,
|
||||||
|
unsigned numPrefixArgs);
|
||||||
const CGFunctionInfo &arrangeMSMemberPointerThunk(const CXXMethodDecl *MD);
|
const CGFunctionInfo &arrangeMSMemberPointerThunk(const CXXMethodDecl *MD);
|
||||||
const CGFunctionInfo &arrangeMSCtorClosure(const CXXConstructorDecl *CD,
|
const CGFunctionInfo &arrangeMSCtorClosure(const CXXConstructorDecl *CD,
|
||||||
CXXCtorType CT);
|
CXXCtorType CT);
|
||||||
|
|
|
@ -3934,7 +3934,7 @@ MicrosoftCXXABI::getAddrOfCXXCtorClosure(const CXXConstructorDecl *CD,
|
||||||
CGM.getAddrOfCXXStructor(CD, StructorType::Complete);
|
CGM.getAddrOfCXXStructor(CD, StructorType::Complete);
|
||||||
CGCallee Callee = CGCallee::forDirect(CalleePtr, CD);
|
CGCallee Callee = CGCallee::forDirect(CalleePtr, CD);
|
||||||
const CGFunctionInfo &CalleeInfo = CGM.getTypes().arrangeCXXConstructorCall(
|
const CGFunctionInfo &CalleeInfo = CGM.getTypes().arrangeCXXConstructorCall(
|
||||||
Args, CD, Ctor_Complete, ExtraArgs.Prefix + ExtraArgs.Suffix);
|
Args, CD, Ctor_Complete, ExtraArgs.Prefix, ExtraArgs.Suffix);
|
||||||
CGF.EmitCall(CalleeInfo, Callee, ReturnValueSlot(), Args);
|
CGF.EmitCall(CalleeInfo, Callee, ReturnValueSlot(), Args);
|
||||||
|
|
||||||
Cleanups.ForceCleanup();
|
Cleanups.ForceCleanup();
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// RUN: %clang_cc1 -triple x86_64-apple -emit-llvm -fobjc-arc -o - %s
|
// RUN: %clang_cc1 -triple x86_64-apple -emit-llvm -fobjc-arc -o - %s -std=c++11 | FileCheck %s --check-prefix=ITANIUM
|
||||||
// RUN: %clang_cc1 -triple x86_64-windows -emit-llvm -fobjc-arc -o - %s
|
// RUN: %clang_cc1 -triple x86_64-windows -emit-llvm -fobjc-arc -o - %s -std=c++11
|
||||||
//
|
//
|
||||||
// Test caess where we weren't properly adding parameter infos declarations,
|
// Test cases where we weren't properly adding extended parameter info, which
|
||||||
// which caused assertions to fire. Hence, no CHECKs.
|
// caused assertions to fire. Hence, minimal CHECKs.
|
||||||
|
|
||||||
struct VirtualBase {
|
struct VirtualBase {
|
||||||
VirtualBase(__attribute__((ns_consumed)) id x);
|
VirtualBase(__attribute__((ns_consumed)) id x);
|
||||||
|
@ -13,3 +13,25 @@ struct WithVirtualBase : virtual VirtualBase {
|
||||||
|
|
||||||
WithVirtualBase::WithVirtualBase(__attribute__((ns_consumed)) id x)
|
WithVirtualBase::WithVirtualBase(__attribute__((ns_consumed)) id x)
|
||||||
: VirtualBase(x) {}
|
: VirtualBase(x) {}
|
||||||
|
|
||||||
|
|
||||||
|
struct VirtualBase2 {
|
||||||
|
VirtualBase2(__attribute__((ns_consumed)) id x, void *y);
|
||||||
|
};
|
||||||
|
|
||||||
|
// In this case, we don't actually end up passing the `id` param from
|
||||||
|
// WithVirtualBaseLast's ctor to WithVirtualBaseMid's. So, we shouldn't emit
|
||||||
|
// ext param info for `id` to `Mid`. Itanium-only check since MSABI seems to
|
||||||
|
// emit the construction code inline.
|
||||||
|
struct WithVirtualBaseMid : virtual VirtualBase2 {
|
||||||
|
// Ensure we only pass in `this` and a vtable. Otherwise this test is useless.
|
||||||
|
// ITANIUM: define {{.*}} void @_ZN18WithVirtualBaseMidCI212VirtualBase2EP11objc_objectPv({{.*}}, {{.*}})
|
||||||
|
using VirtualBase2::VirtualBase2;
|
||||||
|
};
|
||||||
|
struct WithVirtualBaseLast : WithVirtualBaseMid {
|
||||||
|
using WithVirtualBaseMid::WithVirtualBaseMid;
|
||||||
|
};
|
||||||
|
|
||||||
|
void callLast(__attribute__((ns_consumed)) id x) {
|
||||||
|
WithVirtualBaseLast{x, (void*)0};
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue