forked from OSchip/llvm-project
Fix an instantiation bug with nested generic lambdas and conversion to fptrs.
This patch fixes the typelocs of the conversion-operator and the conversion-operator-name and adds the parameters of the call operator to the FunctionProtoTypeLoc of the respective entities. Thus, when the template declarations (conversion operators) undergo deduction and instantiation/transformation/substitution - they add themselves to the local instantiation scope if needed. This patch supports the following: auto L = [](auto b) { return [](auto a) ->decltype(a) { return a; }; }; int (*fp)(int) = L(8); Richard LGTM'd this patch: http://llvm-reviews.chandlerc.com/D1831 Thanks! llvm-svn: 193294
This commit is contained in:
parent
e0bc980500
commit
66605d40a7
|
@ -866,39 +866,110 @@ static void addFunctionPointerConversion(Sema &S,
|
|||
CXXRecordDecl *Class,
|
||||
CXXMethodDecl *CallOperator) {
|
||||
// Add the conversion to function pointer.
|
||||
const FunctionProtoType *Proto
|
||||
= CallOperator->getType()->getAs<FunctionProtoType>();
|
||||
QualType FunctionPtrTy;
|
||||
QualType FunctionTy;
|
||||
const FunctionProtoType *CallOpProto =
|
||||
CallOperator->getType()->getAs<FunctionProtoType>();
|
||||
const FunctionProtoType::ExtProtoInfo CallOpExtInfo =
|
||||
CallOpProto->getExtProtoInfo();
|
||||
QualType PtrToFunctionTy;
|
||||
QualType InvokerFunctionTy;
|
||||
{
|
||||
FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
|
||||
FunctionProtoType::ExtProtoInfo InvokerExtInfo = CallOpExtInfo;
|
||||
CallingConv CC = S.Context.getDefaultCallingConvention(
|
||||
Proto->isVariadic(), /*IsCXXMethod=*/false);
|
||||
ExtInfo.ExtInfo = ExtInfo.ExtInfo.withCallingConv(CC);
|
||||
ExtInfo.TypeQuals = 0;
|
||||
FunctionTy = S.Context.getFunctionType(Proto->getResultType(),
|
||||
Proto->getArgTypes(), ExtInfo);
|
||||
FunctionPtrTy = S.Context.getPointerType(FunctionTy);
|
||||
CallOpProto->isVariadic(), /*IsCXXMethod=*/false);
|
||||
InvokerExtInfo.ExtInfo = InvokerExtInfo.ExtInfo.withCallingConv(CC);
|
||||
InvokerExtInfo.TypeQuals = 0;
|
||||
assert(InvokerExtInfo.RefQualifier == RQ_None &&
|
||||
"Lambda's call operator should not have a reference qualifier");
|
||||
InvokerFunctionTy = S.Context.getFunctionType(CallOpProto->getResultType(),
|
||||
CallOpProto->getArgTypes(), InvokerExtInfo);
|
||||
PtrToFunctionTy = S.Context.getPointerType(InvokerFunctionTy);
|
||||
}
|
||||
|
||||
FunctionProtoType::ExtProtoInfo ExtInfo(S.Context.getDefaultCallingConvention(
|
||||
// Create the type of the conversion function.
|
||||
FunctionProtoType::ExtProtoInfo ConvExtInfo(
|
||||
S.Context.getDefaultCallingConvention(
|
||||
/*IsVariadic=*/false, /*IsCXXMethod=*/true));
|
||||
ExtInfo.TypeQuals = Qualifiers::Const;
|
||||
QualType ConvTy = S.Context.getFunctionType(FunctionPtrTy, None, ExtInfo);
|
||||
// The conversion function is always const.
|
||||
ConvExtInfo.TypeQuals = Qualifiers::Const;
|
||||
QualType ConvTy =
|
||||
S.Context.getFunctionType(PtrToFunctionTy, None, ConvExtInfo);
|
||||
|
||||
SourceLocation Loc = IntroducerRange.getBegin();
|
||||
DeclarationName Name
|
||||
DeclarationName ConversionName
|
||||
= S.Context.DeclarationNames.getCXXConversionFunctionName(
|
||||
S.Context.getCanonicalType(FunctionPtrTy));
|
||||
DeclarationNameLoc NameLoc;
|
||||
NameLoc.NamedType.TInfo = S.Context.getTrivialTypeSourceInfo(FunctionPtrTy,
|
||||
Loc);
|
||||
S.Context.getCanonicalType(PtrToFunctionTy));
|
||||
DeclarationNameLoc ConvNameLoc;
|
||||
// Construct a TypeSourceInfo for the conversion function, and wire
|
||||
// all the parameters appropriately for the FunctionProtoTypeLoc
|
||||
// so that everything works during transformation/instantiation of
|
||||
// generic lambdas.
|
||||
// The main reason for wiring up the parameters of the conversion
|
||||
// function with that of the call operator is so that constructs
|
||||
// like the following work:
|
||||
// auto L = [](auto b) { <-- 1
|
||||
// return [](auto a) -> decltype(a) { <-- 2
|
||||
// return a;
|
||||
// };
|
||||
// };
|
||||
// int (*fp)(int) = L(5);
|
||||
// Because the trailing return type can contain DeclRefExprs that refer
|
||||
// to the original call operator's variables, we hijack the call
|
||||
// operators ParmVarDecls below.
|
||||
TypeSourceInfo *ConvNamePtrToFunctionTSI =
|
||||
S.Context.getTrivialTypeSourceInfo(PtrToFunctionTy, Loc);
|
||||
ConvNameLoc.NamedType.TInfo = ConvNamePtrToFunctionTSI;
|
||||
|
||||
// The conversion function is a conversion to a pointer-to-function.
|
||||
TypeSourceInfo *ConvTSI = S.Context.getTrivialTypeSourceInfo(ConvTy, Loc);
|
||||
FunctionProtoTypeLoc ConvTL =
|
||||
ConvTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>();
|
||||
// Get the result of the conversion function which is a pointer-to-function.
|
||||
PointerTypeLoc PtrToFunctionTL =
|
||||
ConvTL.getResultLoc().getAs<PointerTypeLoc>();
|
||||
// Do the same for the TypeSourceInfo that is used to name the conversion
|
||||
// operator.
|
||||
PointerTypeLoc ConvNamePtrToFunctionTL =
|
||||
ConvNamePtrToFunctionTSI->getTypeLoc().getAs<PointerTypeLoc>();
|
||||
|
||||
// Get the underlying function types that the conversion function will
|
||||
// be converting to (should match the type of the call operator).
|
||||
FunctionProtoTypeLoc CallOpConvTL =
|
||||
PtrToFunctionTL.getPointeeLoc().getAs<FunctionProtoTypeLoc>();
|
||||
FunctionProtoTypeLoc CallOpConvNameTL =
|
||||
ConvNamePtrToFunctionTL.getPointeeLoc().getAs<FunctionProtoTypeLoc>();
|
||||
|
||||
// Wire up the FunctionProtoTypeLocs with the call operator's parameters.
|
||||
// These parameter's are essentially used to transform the name and
|
||||
// the type of the conversion operator. By using the same parameters
|
||||
// as the call operator's we don't have to fix any back references that
|
||||
// the trailing return type of the call operator's uses (such as
|
||||
// decltype(some_type<decltype(a)>::type{} + decltype(a){}) etc.)
|
||||
// - we can simply use the return type of the call operator, and
|
||||
// everything should work.
|
||||
SmallVector<ParmVarDecl *, 4> InvokerParams;
|
||||
for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) {
|
||||
ParmVarDecl *From = CallOperator->getParamDecl(I);
|
||||
|
||||
InvokerParams.push_back(ParmVarDecl::Create(S.Context,
|
||||
// Temporarily add to the TU. This is set to the invoker below.
|
||||
S.Context.getTranslationUnitDecl(),
|
||||
From->getLocStart(),
|
||||
From->getLocation(),
|
||||
From->getIdentifier(),
|
||||
From->getType(),
|
||||
From->getTypeSourceInfo(),
|
||||
From->getStorageClass(),
|
||||
/*DefaultArg=*/0));
|
||||
CallOpConvTL.setArg(I, From);
|
||||
CallOpConvNameTL.setArg(I, From);
|
||||
}
|
||||
|
||||
CXXConversionDecl *Conversion
|
||||
= CXXConversionDecl::Create(S.Context, Class, Loc,
|
||||
DeclarationNameInfo(Name, Loc, NameLoc),
|
||||
DeclarationNameInfo(ConversionName,
|
||||
Loc, ConvNameLoc),
|
||||
ConvTy,
|
||||
S.Context.getTrivialTypeSourceInfo(ConvTy,
|
||||
Loc),
|
||||
ConvTSI,
|
||||
/*isInline=*/true, /*isExplicit=*/false,
|
||||
/*isConstexpr=*/false,
|
||||
CallOperator->getBody()->getLocEnd());
|
||||
|
@ -912,7 +983,7 @@ static void addFunctionPointerConversion(Sema &S,
|
|||
CallOperator->getDescribedFunctionTemplate();
|
||||
FunctionTemplateDecl *ConversionTemplate =
|
||||
FunctionTemplateDecl::Create(S.Context, Class,
|
||||
Loc, Name,
|
||||
Loc, ConversionName,
|
||||
TemplateCallOperator->getTemplateParameters(),
|
||||
Conversion);
|
||||
ConversionTemplate->setAccess(AS_public);
|
||||
|
@ -923,7 +994,8 @@ static void addFunctionPointerConversion(Sema &S,
|
|||
Class->addDecl(Conversion);
|
||||
// Add a non-static member function that will be the result of
|
||||
// the conversion with a certain unique ID.
|
||||
Name = &S.Context.Idents.get(getLambdaStaticInvokerName());
|
||||
DeclarationName InvokerName = &S.Context.Idents.get(
|
||||
getLambdaStaticInvokerName());
|
||||
// FIXME: Instead of passing in the CallOperator->getTypeSourceInfo()
|
||||
// we should get a prebuilt TrivialTypeSourceInfo from Context
|
||||
// using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc
|
||||
|
@ -931,34 +1003,28 @@ static void addFunctionPointerConversion(Sema &S,
|
|||
// loop below and then use its Params to set Invoke->setParams(...) below.
|
||||
// This would avoid the 'const' qualifier of the calloperator from
|
||||
// contaminating the type of the invoker, which is currently adjusted
|
||||
// in SemaTemplateDeduction.cpp:DeduceTemplateArguments.
|
||||
// in SemaTemplateDeduction.cpp:DeduceTemplateArguments. Fixing the
|
||||
// trailing return type of the invoker would require a visitor to rebuild
|
||||
// the trailing return type and adjusting all back DeclRefExpr's to refer
|
||||
// to the new static invoker parameters - not the call operator's.
|
||||
CXXMethodDecl *Invoke
|
||||
= CXXMethodDecl::Create(S.Context, Class, Loc,
|
||||
DeclarationNameInfo(Name, Loc), FunctionTy,
|
||||
CallOperator->getTypeSourceInfo(),
|
||||
DeclarationNameInfo(InvokerName, Loc),
|
||||
InvokerFunctionTy,
|
||||
CallOperator->getTypeSourceInfo(),
|
||||
SC_Static, /*IsInline=*/true,
|
||||
/*IsConstexpr=*/false,
|
||||
CallOperator->getBody()->getLocEnd());
|
||||
SmallVector<ParmVarDecl *, 4> InvokeParams;
|
||||
for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) {
|
||||
ParmVarDecl *From = CallOperator->getParamDecl(I);
|
||||
InvokeParams.push_back(ParmVarDecl::Create(S.Context, Invoke,
|
||||
From->getLocStart(),
|
||||
From->getLocation(),
|
||||
From->getIdentifier(),
|
||||
From->getType(),
|
||||
From->getTypeSourceInfo(),
|
||||
From->getStorageClass(),
|
||||
/*DefaultArg=*/0));
|
||||
}
|
||||
Invoke->setParams(InvokeParams);
|
||||
for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I)
|
||||
InvokerParams[I]->setOwningFunction(Invoke);
|
||||
Invoke->setParams(InvokerParams);
|
||||
Invoke->setAccess(AS_private);
|
||||
Invoke->setImplicit(true);
|
||||
if (Class->isGenericLambda()) {
|
||||
FunctionTemplateDecl *TemplateCallOperator =
|
||||
CallOperator->getDescribedFunctionTemplate();
|
||||
FunctionTemplateDecl *StaticInvokerTemplate = FunctionTemplateDecl::Create(
|
||||
S.Context, Class, Loc, Name,
|
||||
S.Context, Class, Loc, InvokerName,
|
||||
TemplateCallOperator->getTemplateParameters(),
|
||||
Invoke);
|
||||
StaticInvokerTemplate->setAccess(AS_private);
|
||||
|
|
|
@ -585,6 +585,50 @@ template<class T> void foo(T) {
|
|||
template void foo(int);
|
||||
} // end ns nested_generic_lambdas_123
|
||||
|
||||
namespace nested_fptr_235 {
|
||||
int test()
|
||||
{
|
||||
auto L = [](auto b) {
|
||||
return [](auto a) ->decltype(a) { return a; };
|
||||
};
|
||||
int (*fp)(int) = L(8);
|
||||
fp(5);
|
||||
L(3);
|
||||
char (*fc)(char) = L('a');
|
||||
fc('b');
|
||||
L('c');
|
||||
double (*fd)(double) = L(3.14);
|
||||
fd(3.14);
|
||||
fd(6.26);
|
||||
return 0;
|
||||
}
|
||||
int run = test();
|
||||
}
|
||||
|
||||
|
||||
namespace fptr_with_decltype_return_type {
|
||||
template<class F, class ... Ts> using FirstType = F;
|
||||
template<class F, class ... Rest> F& FirstArg(F& f, Rest& ... r) { return f; };
|
||||
template<class ... Ts> auto vfun(Ts&& ... ts) {
|
||||
print(ts...);
|
||||
return FirstArg(ts...);
|
||||
}
|
||||
int test()
|
||||
{
|
||||
{
|
||||
auto L = [](auto ... As) {
|
||||
return [](auto b) ->decltype(b) {
|
||||
vfun([](decltype(As) a) -> decltype(a) { return a; } ...)(FirstType<decltype(As)...>{});
|
||||
return decltype(b){};
|
||||
};
|
||||
};
|
||||
auto LL = L(1, 'a', 3.14, "abc");
|
||||
LL("dim");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int run = test();
|
||||
}
|
||||
|
||||
} // end ns nested_non_capturing_lambda_tests
|
||||
|
||||
|
|
Loading…
Reference in New Issue