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,
|
CXXRecordDecl *Class,
|
||||||
CXXMethodDecl *CallOperator) {
|
CXXMethodDecl *CallOperator) {
|
||||||
// Add the conversion to function pointer.
|
// Add the conversion to function pointer.
|
||||||
const FunctionProtoType *Proto
|
const FunctionProtoType *CallOpProto =
|
||||||
= CallOperator->getType()->getAs<FunctionProtoType>();
|
CallOperator->getType()->getAs<FunctionProtoType>();
|
||||||
QualType FunctionPtrTy;
|
const FunctionProtoType::ExtProtoInfo CallOpExtInfo =
|
||||||
QualType FunctionTy;
|
CallOpProto->getExtProtoInfo();
|
||||||
|
QualType PtrToFunctionTy;
|
||||||
|
QualType InvokerFunctionTy;
|
||||||
{
|
{
|
||||||
FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
|
FunctionProtoType::ExtProtoInfo InvokerExtInfo = CallOpExtInfo;
|
||||||
CallingConv CC = S.Context.getDefaultCallingConvention(
|
CallingConv CC = S.Context.getDefaultCallingConvention(
|
||||||
Proto->isVariadic(), /*IsCXXMethod=*/false);
|
CallOpProto->isVariadic(), /*IsCXXMethod=*/false);
|
||||||
ExtInfo.ExtInfo = ExtInfo.ExtInfo.withCallingConv(CC);
|
InvokerExtInfo.ExtInfo = InvokerExtInfo.ExtInfo.withCallingConv(CC);
|
||||||
ExtInfo.TypeQuals = 0;
|
InvokerExtInfo.TypeQuals = 0;
|
||||||
FunctionTy = S.Context.getFunctionType(Proto->getResultType(),
|
assert(InvokerExtInfo.RefQualifier == RQ_None &&
|
||||||
Proto->getArgTypes(), ExtInfo);
|
"Lambda's call operator should not have a reference qualifier");
|
||||||
FunctionPtrTy = S.Context.getPointerType(FunctionTy);
|
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));
|
/*IsVariadic=*/false, /*IsCXXMethod=*/true));
|
||||||
ExtInfo.TypeQuals = Qualifiers::Const;
|
// The conversion function is always const.
|
||||||
QualType ConvTy = S.Context.getFunctionType(FunctionPtrTy, None, ExtInfo);
|
ConvExtInfo.TypeQuals = Qualifiers::Const;
|
||||||
|
QualType ConvTy =
|
||||||
|
S.Context.getFunctionType(PtrToFunctionTy, None, ConvExtInfo);
|
||||||
|
|
||||||
SourceLocation Loc = IntroducerRange.getBegin();
|
SourceLocation Loc = IntroducerRange.getBegin();
|
||||||
DeclarationName Name
|
DeclarationName ConversionName
|
||||||
= S.Context.DeclarationNames.getCXXConversionFunctionName(
|
= S.Context.DeclarationNames.getCXXConversionFunctionName(
|
||||||
S.Context.getCanonicalType(FunctionPtrTy));
|
S.Context.getCanonicalType(PtrToFunctionTy));
|
||||||
DeclarationNameLoc NameLoc;
|
DeclarationNameLoc ConvNameLoc;
|
||||||
NameLoc.NamedType.TInfo = S.Context.getTrivialTypeSourceInfo(FunctionPtrTy,
|
// Construct a TypeSourceInfo for the conversion function, and wire
|
||||||
Loc);
|
// 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 *Conversion
|
||||||
= CXXConversionDecl::Create(S.Context, Class, Loc,
|
= CXXConversionDecl::Create(S.Context, Class, Loc,
|
||||||
DeclarationNameInfo(Name, Loc, NameLoc),
|
DeclarationNameInfo(ConversionName,
|
||||||
|
Loc, ConvNameLoc),
|
||||||
ConvTy,
|
ConvTy,
|
||||||
S.Context.getTrivialTypeSourceInfo(ConvTy,
|
ConvTSI,
|
||||||
Loc),
|
|
||||||
/*isInline=*/true, /*isExplicit=*/false,
|
/*isInline=*/true, /*isExplicit=*/false,
|
||||||
/*isConstexpr=*/false,
|
/*isConstexpr=*/false,
|
||||||
CallOperator->getBody()->getLocEnd());
|
CallOperator->getBody()->getLocEnd());
|
||||||
|
@ -912,7 +983,7 @@ static void addFunctionPointerConversion(Sema &S,
|
||||||
CallOperator->getDescribedFunctionTemplate();
|
CallOperator->getDescribedFunctionTemplate();
|
||||||
FunctionTemplateDecl *ConversionTemplate =
|
FunctionTemplateDecl *ConversionTemplate =
|
||||||
FunctionTemplateDecl::Create(S.Context, Class,
|
FunctionTemplateDecl::Create(S.Context, Class,
|
||||||
Loc, Name,
|
Loc, ConversionName,
|
||||||
TemplateCallOperator->getTemplateParameters(),
|
TemplateCallOperator->getTemplateParameters(),
|
||||||
Conversion);
|
Conversion);
|
||||||
ConversionTemplate->setAccess(AS_public);
|
ConversionTemplate->setAccess(AS_public);
|
||||||
|
@ -923,7 +994,8 @@ static void addFunctionPointerConversion(Sema &S,
|
||||||
Class->addDecl(Conversion);
|
Class->addDecl(Conversion);
|
||||||
// Add a non-static member function that will be the result of
|
// Add a non-static member function that will be the result of
|
||||||
// the conversion with a certain unique ID.
|
// 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()
|
// FIXME: Instead of passing in the CallOperator->getTypeSourceInfo()
|
||||||
// we should get a prebuilt TrivialTypeSourceInfo from Context
|
// we should get a prebuilt TrivialTypeSourceInfo from Context
|
||||||
// using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc
|
// 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.
|
// loop below and then use its Params to set Invoke->setParams(...) below.
|
||||||
// This would avoid the 'const' qualifier of the calloperator from
|
// This would avoid the 'const' qualifier of the calloperator from
|
||||||
// contaminating the type of the invoker, which is currently adjusted
|
// 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 *Invoke
|
||||||
= CXXMethodDecl::Create(S.Context, Class, Loc,
|
= CXXMethodDecl::Create(S.Context, Class, Loc,
|
||||||
DeclarationNameInfo(Name, Loc), FunctionTy,
|
DeclarationNameInfo(InvokerName, Loc),
|
||||||
CallOperator->getTypeSourceInfo(),
|
InvokerFunctionTy,
|
||||||
|
CallOperator->getTypeSourceInfo(),
|
||||||
SC_Static, /*IsInline=*/true,
|
SC_Static, /*IsInline=*/true,
|
||||||
/*IsConstexpr=*/false,
|
/*IsConstexpr=*/false,
|
||||||
CallOperator->getBody()->getLocEnd());
|
CallOperator->getBody()->getLocEnd());
|
||||||
SmallVector<ParmVarDecl *, 4> InvokeParams;
|
for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I)
|
||||||
for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) {
|
InvokerParams[I]->setOwningFunction(Invoke);
|
||||||
ParmVarDecl *From = CallOperator->getParamDecl(I);
|
Invoke->setParams(InvokerParams);
|
||||||
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);
|
|
||||||
Invoke->setAccess(AS_private);
|
Invoke->setAccess(AS_private);
|
||||||
Invoke->setImplicit(true);
|
Invoke->setImplicit(true);
|
||||||
if (Class->isGenericLambda()) {
|
if (Class->isGenericLambda()) {
|
||||||
FunctionTemplateDecl *TemplateCallOperator =
|
FunctionTemplateDecl *TemplateCallOperator =
|
||||||
CallOperator->getDescribedFunctionTemplate();
|
CallOperator->getDescribedFunctionTemplate();
|
||||||
FunctionTemplateDecl *StaticInvokerTemplate = FunctionTemplateDecl::Create(
|
FunctionTemplateDecl *StaticInvokerTemplate = FunctionTemplateDecl::Create(
|
||||||
S.Context, Class, Loc, Name,
|
S.Context, Class, Loc, InvokerName,
|
||||||
TemplateCallOperator->getTemplateParameters(),
|
TemplateCallOperator->getTemplateParameters(),
|
||||||
Invoke);
|
Invoke);
|
||||||
StaticInvokerTemplate->setAccess(AS_private);
|
StaticInvokerTemplate->setAccess(AS_private);
|
||||||
|
|
|
@ -585,6 +585,50 @@ template<class T> void foo(T) {
|
||||||
template void foo(int);
|
template void foo(int);
|
||||||
} // end ns nested_generic_lambdas_123
|
} // 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
|
} // end ns nested_non_capturing_lambda_tests
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue