Hi doug.gregor, rsmith,
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 these entities. So when the template declarations
(conversion operators) undergo deduction and
instantiation/transformation/substitution - they add themselves to the local
instantiation scope if needed.
auto L = [](auto b) {
return [](auto a) ->decltype(a) { return a; };
};
int (*fp)(int) = L(8);
http://llvm-reviews.chandlerc.com/D1831
Files:
lib/Sema/SemaLambda.cpp
test/SemaCXX/cxx1y-generic-lambdas.cpp
Index: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -858,39 +858,110 @@
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;
+ 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;
+ ConvExtInfo.HasTrailingReturn = CallOpExtInfo.HasTrailingReturn;
+ QualType ConvTy =
+ S.Context.getFunctionType(PtrToFunctionTy, None, ConvExtInfo);
SourceLocation Loc = IntroducerRange.getBegin();
- DeclarationName Name
+ DeclarationName ConversionOrInvokerName
= 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);
+ // Get the conversion functions TypeLoc as a FunctinoProtoTypeLoc...
+ 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(ConversionOrInvokerName,
+ Loc, ConvNameLoc),
ConvTy,
- S.Context.getTrivialTypeSourceInfo(ConvTy,
- Loc),
+ ConvTSI,
/*isInline=*/true, /*isExplicit=*/false,
/*isConstexpr=*/false,
CallOperator->getBody()->getLocEnd());
@@ -904,7 +975,7 @@
CallOperator->getDescribedFunctionTemplate();
FunctionTemplateDecl *ConversionTemplate =
FunctionTemplateDecl::Create(S.Context, Class,
- Loc, Name,
+ Loc, ConversionOrInvokerName,
TemplateCallOperator->getTemplateParameters(),
Conversion);
ConversionTemplate->setAccess(AS_public);
@@ -915,7 +986,7 @@
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());
+ ConversionOrInvokerName = &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
@@ -923,34 +994,28 @@
// 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(ConversionOrInvokerName, 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, ConversionOrInvokerName,
TemplateCallOperator->getTemplateParameters(),
Invoke);
StaticInvokerTemplate->setAccess(AS_private);
Index: test/SemaCXX/cxx1y-generic-lambdas.cpp
===================================================================
--- test/SemaCXX/cxx1y-generic-lambdas.cpp
+++ test/SemaCXX/cxx1y-generic-lambdas.cpp
@@ -585,6 +585,50 @@
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
\ No newline at end of file
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits