Hi doug.gregor, rsmith, eli.friedman, jdennett,
This patch teaches TreeTransform how to transform generic lambdas. It does not
include capturing.
I have a question in the patch that I would appreciate some clarity on.
Please see test file for reasonably extensive examples such as:
<code>
auto L = [](auto ... a) {
auto M = [](decltype(a) ... b) {
auto N = [](auto c) -> void {
int x = 0;
x = sizeof...(a);
x = sizeof...(b);
x = sizeof(c);
};
N('a');
N(N);
N(FirstType<Ts...>{});
return N;
};
M(a...);
return M;
};
auto M = L(L, ts...);
decltype(L(L, ts...)) (*fp)(decltype(L), decltype(ts) ...) = L;
fp(L, ts...);
decltype(L(L, ts...)(L, ts...)) (*fp2)(decltype(L), decltype(ts) ...) =
L(L, ts...);
fp2 = fp(L, ts...);
void (*fp3)(char) = fp2(L, ts...);
fp3('a');
</code>
http://llvm-reviews.chandlerc.com/D1784
Files:
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Sema/TreeTransform.h
test/SemaCXX/cxx1y-generic-lambdas.cpp
Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -14,6 +14,7 @@
#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/LangOptions.h"
@@ -130,6 +131,11 @@
assert(Function->getPrimaryTemplate() && "No function template?");
if (Function->getPrimaryTemplate()->isMemberSpecialization())
break;
+
+ // If this function is a generic lambda specialization, we are done.
+ if (isGenericLambdaCallOperatorSpecialization(Function))
+ break;
+
} else if (FunctionTemplateDecl *FunTmpl
= Function->getDescribedFunctionTemplate()) {
// Add the "injected" template arguments.
@@ -912,12 +918,54 @@
ExprResult TransformLambdaScope(LambdaExpr *E,
CXXMethodDecl *CallOperator) {
- CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(),
- TSK_ImplicitInstantiation);
- return TreeTransform<TemplateInstantiator>::
- TransformLambdaScope(E, CallOperator);
+ // I think Doug tried to explain why this link is done, but
+ // I was hoping to get a little more clarity.
+ // If a lambda is undergoing transformation for instance:
+ // template<class T> void foo(T t) {
+ // auto L1 = [](T a) { return a; };
+ // auto L2 = [](char b) { return b; };
+ // auto L3 = [](auto c) { return c; };
+ // }
+ // Its not entirely clear to me how these are
+ // instantiations/related to the untransformed
+ // original call operator.
+ FunctionTemplateDecl *const NewCallOperatorTemplate =
+ CallOperator->getDescribedFunctionTemplate();
+ FunctionTemplateDecl *const OldCallOperatorTemplate =
+ E->getCallOperator()->getDescribedFunctionTemplate();
+ if (!NewCallOperatorTemplate)
+ CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(),
+ TSK_ImplicitInstantiation);
+ else {
+ // FVQUESTION? What exactly should go here? currently by leaving it blank
+ // nothing seems to break. The below clearly does not (and should not
+ // conceptually??) work.
+#ifdef FV_DOES_NOT_WORK
+ // Record this function template specialization.
+ ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
+ CallOperator->setFunctionTemplateSpecialization(
+ OldCallOperatorTemplate,
+ TemplateArgumentList::CreateCopy(SemaRef.Context,
+ Innermost.begin(),
+ Innermost.size()),
+ /*InsertPos=*/0);
+#endif
+ }
+ return inherited::TransformLambdaScope(E, CallOperator);
}
-
+ TemplateParameterList *TransformTemplateParameterList(
+ TemplateParameterList *OrigTPL) {
+ TemplateParameterList *NewTPL = 0;
+ if (OrigTPL) {
+ if (!OrigTPL->size()) return OrigTPL; // size 0, do nothing
+
+ DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
+ TemplateDeclInstantiator DeclInstantiator(getSema(),
+ /* DeclContext *Owner */ Owner, TemplateArgs);
+ NewTPL = DeclInstantiator.SubstTemplateParams(OrigTPL);
+ }
+ return NewTPL;
+ }
private:
ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,
SourceLocation loc,
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -12,6 +12,7 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/DependentDiagnostic.h"
@@ -4171,6 +4172,30 @@
NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs) {
DeclContext *ParentDC = D->getDeclContext();
+
+ // If we have a parameter from a non-dependent context with a non-dependent
+ // type it obviously can not be mapped to a different instantiated decl.
+ // Consider the code below, with explicit return types, when N gets
+ // specialized ...:
+ // template<class T> void fooT(T t) {
+ // auto L = [](auto a) -> void {
+ // auto M = [](char b) -> void {
+ // auto N = [](auto c) -> void {
+ // int x = sizeof(a) + sizeof(b) +
+ // sizeof(c);
+ // };
+ // N('a');
+ // };
+ // };
+ // L(3.14);
+ // }
+ // fooT('a');
+ // ... without this check below, findInstantiationOf fails with
+ // an assertion violation.
+ if (isa<ParmVarDecl>(D) && !ParentDC->isDependentContext() &&
+ !cast<ParmVarDecl>(D)->getType()->isDependentType())
+ return D;
+
if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) ||
isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) ||
(ParentDC->isFunctionOrMethod() && ParentDC->isDependentContext()) ||
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -594,6 +594,14 @@
/// \brief Transform the captures and body of a lambda expression.
ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator);
+ TemplateParameterList *TransformTemplateParameterList(
+ TemplateParameterList *TPL) {
+ // FVQUESTION: Currently not implemented - Check with Doug/Richard
+ // what sort of semantics we want the default one to have?
+
+ return 0;
+ }
+
ExprResult TransformAddressOfOperand(Expr *E);
ExprResult TransformDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E,
bool IsAddressOfOperand);
@@ -4561,6 +4569,19 @@
QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
DecltypeTypeLoc TL) {
const DecltypeType *T = TL.getTypePtr();
+ // Don't transform a decltype construct that has already been transformed
+ // into a non-dependent type.
+ // Allows the following to compile:
+ // auto L = [](auto a) {
+ // return [](auto b) ->decltype(a) {
+ // return b;
+ // };
+ //};
+ if (!T->isInstantiationDependentType() && !T->isVariablyModifiedType()) {
+ DecltypeTypeLoc NewTL = TLB.push<DecltypeTypeLoc>(TL.getType());
+ NewTL.setNameLoc(TL.getNameLoc());
+ return NewTL.getType();
+ }
// decltype expressions are not potentially evaluated contexts
EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated, 0,
@@ -8252,24 +8273,27 @@
ExprResult
TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
- // FIXME: Implement nested generic lambda transformations.
- if (E->isGenericLambda()) {
- getSema().Diag(E->getIntroducerRange().getBegin(),
- diag::err_glambda_not_fully_implemented)
- << " template transformation of generic lambdas not implemented yet";
- return ExprError();
+ getSema().PushLambdaScope();
+ LambdaScopeInfo *LSI = getSema().getCurLambda();
+ TemplateParameterList *const OrigTPL = E->getTemplateParameterList();
+ TemplateParameterList *NewTPL = 0;
+ // Transform the template parameters, and add them to the
+ // current instantiation scope.
+ if (OrigTPL) {
+ NewTPL = getDerived().TransformTemplateParameterList(OrigTPL);
}
- // Transform the type of the lambda parameters and start the definition of
- // the lambda itself.
- TypeSourceInfo *MethodTy
- = TransformType(E->getCallOperator()->getTypeSourceInfo());
- if (!MethodTy)
+ LSI->GLTemplateParameterList = NewTPL;
+ // Transform the type of the lambda parameters and start the definition of
+ // the lambda itself.
+ TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo();
+ TypeSourceInfo *NewCallOpTSI = TransformType(OldCallOpTSI);
+ if (!NewCallOpTSI)
return ExprError();
// Create the local class that will describe the lambda.
CXXRecordDecl *Class
= getSema().createLambdaClosureType(E->getIntroducerRange(),
- MethodTy,
+ NewCallOpTSI,
/*KnownDependent=*/false);
getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
@@ -8281,19 +8305,49 @@
E->getCallOperator()->param_size(),
0, ParamTypes, &Params))
return ExprError();
- getSema().PushLambdaScope();
- LambdaScopeInfo *LSI = getSema().getCurLambda();
- // TODO: Fix for nested lambdas
- LSI->GLTemplateParameterList = 0;
+
// Build the call operator.
- CXXMethodDecl *CallOperator
+ CXXMethodDecl *NewCallOperator
= getSema().startLambdaDefinition(Class, E->getIntroducerRange(),
- MethodTy,
+ NewCallOpTSI,
E->getCallOperator()->getLocEnd(),
Params);
- getDerived().transformAttrs(E->getCallOperator(), CallOperator);
-
- return getDerived().TransformLambdaScope(E, CallOperator);
+ LSI->CallOperator = NewCallOperator;
+ // Fix the Decl Contexts of the parameters within the cal op function
+ // prototype.
+ getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
+
+ TypeLoc NewCallOpTL = NewCallOpTSI->getTypeLoc();
+ FunctionProtoTypeLoc NewFPTL = NewCallOpTL.castAs<FunctionProtoTypeLoc>();
+ ParmVarDecl **NewParamDeclArray = NewFPTL.getParmArray();
+ const unsigned NewNumArgs = NewFPTL.getNumArgs();
+ for (unsigned I = 0; I < NewNumArgs; ++I) {
+ NewParamDeclArray[I]->setOwningFunction(NewCallOperator);
+ }
+ // If this is a non-generic lambda, the parameters do not get added to the
+ // current instantiation scope, so add them. This feels kludgey.
+ // Anyway, it allows the following to compile when the enclosing template
+ // is specialized and the entire lambda expression has to be
+ // transformed. Without this FindInstantiatedDecl causes an assertion.
+ // template<class T> void foo(T t) {
+ // auto L = [](auto a) {
+ // auto M = [](char b) { <-- note: non-generic lambda
+ // auto N = [](auto c) {
+ // int x = sizeof(a);
+ // x = sizeof(b); <-- specifically this line
+ // x = sizeof(c);
+ // };
+ // };
+ // };
+ // }
+ // foo('a');
+ //
+ if (!E->isGenericLambda()) {
+ for (unsigned I = 0; I < NewNumArgs; ++I)
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(
+ NewParamDeclArray[I], NewParamDeclArray[I]);
+ }
+ return getDerived().TransformLambdaScope(E, NewCallOperator);
}
template<typename Derived>
Index: test/SemaCXX/cxx1y-generic-lambdas.cpp
===================================================================
--- test/SemaCXX/cxx1y-generic-lambdas.cpp
+++ test/SemaCXX/cxx1y-generic-lambdas.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks %s
+// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -emit-llvm -o - %s
// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS
// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
@@ -99,10 +99,8 @@
//expected-note{{candidate}}
}
}
-
}
-
namespace return_type_deduction_ok {
auto l = [](auto a) ->auto { return a; }(2);
auto l2 = [](auto a) ->decltype(auto) { return a; }(2);
@@ -114,3 +112,464 @@
void test(int i = [](auto a)->int { return a; }(3)) {
}
}
+
+namespace nested_non_capturing_lambda_tests {
+template<class ... Ts> void print(Ts ...) { }
+int test() {
+{
+ auto L = [](auto a) {
+ return [](auto b) {
+ return b;
+ };
+ };
+ auto M = L(3);
+ M(4.15);
+ }
+{
+ int i = 10; //expected-note{{declared here}}
+ auto L = [](auto a) {
+ return [](auto b) { //expected-note{{begins here}}
+ i = b; //expected-error{{cannot be implicitly captured}}
+ return b;
+ };
+ };
+ auto M = L(3);
+ M(4.15); //expected-note{{instantiation}}
+ }
+ {
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ return [](auto b) ->decltype(a) {
+ print("b = ", b, "\n");
+ return b;
+ };
+ };
+ auto M = L(3);
+ M(4.15);
+ }
+
+{
+ auto L = [](auto a) ->decltype(a) {
+ print("a = ", a, "\n");
+ return [](auto b) ->decltype(a) { //expected-error{{no viable conversion}}\
+ //expected-note{{candidate template ignored}}
+ print("b = ", b, "\n");
+ return b;
+ };
+ };
+ auto M = L(3); //expected-note{{in instantiation of}}
+ }
+{
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ return [](auto ... b) ->decltype(a) {
+ print("b = ", b ..., "\n");
+ return 4;
+ };
+ };
+ auto M = L(3);
+ M(4.15, 3, "fv");
+}
+
+{
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ return [](auto ... b) ->decltype(a) {
+ print("b = ", b ..., "\n");
+ return 4;
+ };
+ };
+ auto M = L(3);
+ int (*fp)(double, int, const char*) = M;
+ fp(4.15, 3, "fv");
+}
+
+{
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ return [](char b) {
+ return [](auto ... c) ->decltype(b) {
+ print("c = ", c ..., "\n");
+ return 42;
+ };
+ };
+ };
+ L(4);
+ auto M = L(3);
+ M('a');
+ auto N = M('x');
+ N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+ char (*np)(const char*, int, const char*, double, const char*, int) = N;
+ np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+}
+
+
+{
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ return [](decltype(a) b) {
+ return [](auto ... c) ->decltype(b) {
+ print("c = ", c ..., "\n");
+ return 42;
+ };
+ };
+ };
+ L('4');
+ auto M = L('3');
+ M('a');
+ auto N = M('x');
+ N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+ char (*np)(const char*, int, const char*, double, const char*, int) = N;
+ np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+}
+
+
+{
+ struct X {
+ static void foo(double d) { }
+ void test() {
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ foo(a);
+ return [](decltype(a) b) {
+ foo(b);
+ foo(sizeof(a) + sizeof(b));
+ return [](auto ... c) ->decltype(b) {
+ print("c = ", c ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return 42;
+ };
+ };
+ };
+ L('4');
+ auto M = L('3');
+ M('a');
+ auto N = M('x');
+ N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+ char (*np)(const char*, int, const char*, double, const char*, int) = N;
+ np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+ }
+};
+X x;
+x.test();
+}
+// Make sure we can escape the function
+{
+ struct X {
+ static void foo(double d) { }
+ auto test() {
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ foo(a);
+ return [](decltype(a) b) {
+ foo(b);
+ foo(sizeof(a) + sizeof(b));
+ return [](auto ... c) ->decltype(b) {
+ print("c = ", c ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return 42;
+ };
+ };
+ };
+ return L;
+ }
+};
+ X x;
+ auto L = x.test();
+ L('4');
+ auto M = L('3');
+ M('a');
+ auto N = M('x');
+ N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+ char (*np)(const char*, int, const char*, double, const char*, int) = N;
+ np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+}
+
+{
+ struct X {
+ static void foo(double d) { }
+ auto test() {
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ foo(a);
+ return [](decltype(a) b) {
+ foo(b);
+ foo(sizeof(a) + sizeof(b));
+ return [](auto ... c) {
+ print("c = ", c ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
+ print("d = ", d ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return decltype(a){};
+ };
+ };
+ };
+ };
+ return L;
+ }
+};
+ X x;
+ auto L = x.test();
+ L('4');
+ auto M = L('3');
+ M('a');
+ auto N = M('x');
+ auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+ char (*np)(const char*, int, const char*, double, const char*, int) = O;
+ np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+ int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}
+
+}
+} // end test()
+
+namespace wrapped_within_templates {
+
+namespace explicit_return {
+template<class T> int fooT(T t) {
+ auto L = [](auto a) -> void {
+ auto M = [](char b) -> void {
+ auto N = [](auto c) -> void {
+ int x = 0;
+ x = sizeof(a);
+ x = sizeof(b);
+ x = sizeof(c);
+ };
+ N('a');
+ N(decltype(a){});
+ };
+ };
+ L(t);
+ L(3.14);
+ return 0;
+}
+
+int run = fooT('a') + fooT(3.14);
+
+} // end explicit_return
+
+namespace implicit_return_deduction {
+template<class T> auto fooT(T t) {
+ auto L = [](auto a) {
+ auto M = [](char b) {
+ auto N = [](auto c) {
+ int x = 0;
+ x = sizeof(a);
+ x = sizeof(b);
+ x = sizeof(c);
+ };
+ N('a');
+ N(decltype(a){});
+ };
+ };
+ L(t);
+ L(3.14);
+ return 0;
+}
+
+int run = fooT('a') + fooT(3.14);
+
+template<class ... Ts> void print(Ts ... ts) { }
+
+template<class F, class ... Rest> using first = F;
+
+template<class ... Ts> auto fooV(Ts ... ts) {
+ auto L = [](auto ... a) {
+ auto M = [](decltype(a) ... b) {
+ auto N = [](auto c) {
+ int x = 0;
+ x = sizeof...(a);
+ x = sizeof...(b);
+ x = sizeof(c);
+ };
+ N('a');
+ N(N);
+ N(first<Ts...>{});
+ };
+ M(a...);
+ print("a = ", a..., "\n");
+ };
+ L(L, ts...);
+ print("ts = ", ts..., "\n");
+ return 0;
+}
+
+int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});
+
+} //implicit_return_deduction
+
+
+} //wrapped_within_templates
+
+namespace at_ns_scope {
+ void foo(double d) { }
+ auto test() {
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ foo(a);
+ return [](decltype(a) b) {
+ foo(b);
+ foo(sizeof(a) + sizeof(b));
+ return [](auto ... c) {
+ print("c = ", c ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
+ print("d = ", d ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return decltype(a){};
+ };
+ };
+ };
+ };
+ return L;
+ }
+auto L = test();
+auto L_test = L('4');
+auto M = L('3');
+auto M_test = M('a');
+auto N = M('x');
+auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+char (*np)(const char*, int, const char*, double, const char*, int) = O;
+auto NP_result = np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}
+
+
+
+}
+
+namespace variadic_tests_1 {
+template<class ... Ts> void print(Ts ... ts) { }
+
+template<class F, class ... Rest> using FirstType = F;
+template<class F, class ... Rest> F& FirstArg(F& f, Rest...) { return f; }
+
+template<class ... Ts> int fooV(Ts ... ts) {
+ auto L = [](auto ... a) -> void {
+ auto M = [](decltype(a) ... b) -> void {
+ auto N = [](auto c) -> void {
+ int x = 0;
+ x = sizeof...(a);
+ x = sizeof...(b);
+ x = sizeof(c);
+ };
+ N('a');
+ N(N);
+ N(FirstType<Ts...>{});
+ };
+ M(a...);
+ print("a = ", a..., "\n");
+ };
+ L(L, ts...);
+ print("ts = ", ts..., "\n");
+ return 0;
+}
+
+int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});
+
+namespace more_variadic_1 {
+
+template<class ... Ts> int fooV(Ts ... ts) {
+ auto L = [](auto ... a) {
+ auto M = [](decltype(a) ... b) -> void {
+ auto N = [](auto c) -> void {
+ int x = 0;
+ x = sizeof...(a);
+ x = sizeof...(b);
+ x = sizeof(c);
+ };
+ N('a');
+ N(N);
+ N(FirstType<Ts...>{});
+ };
+ M(a...);
+ return M;
+ };
+ auto M = L(L, ts...);
+ decltype(L(L, ts...)) (*fp)(decltype(L), decltype(ts) ...) = L;
+ void (*fp2)(decltype(L), decltype(ts) ...) = L(L, ts...);
+
+ {
+ auto L = [](auto ... a) {
+ auto M = [](decltype(a) ... b) {
+ auto N = [](auto c) -> void {
+ int x = 0;
+ x = sizeof...(a);
+ x = sizeof...(b);
+ x = sizeof(c);
+ };
+ N('a');
+ N(N);
+ N(FirstType<Ts...>{});
+ return N;
+ };
+ M(a...);
+ return M;
+ };
+ auto M = L(L, ts...);
+ decltype(L(L, ts...)) (*fp)(decltype(L), decltype(ts) ...) = L;
+ fp(L, ts...);
+ decltype(L(L, ts...)(L, ts...)) (*fp2)(decltype(L), decltype(ts) ...) = L(L, ts...);
+ fp2 = fp(L, ts...);
+ void (*fp3)(char) = fp2(L, ts...);
+ fp3('a');
+ }
+ return 0;
+}
+
+int run2 = fooV(3.14, " ", '4', 5) + fooV("BC", 3, 2.77, 'A', float{}, short{}, unsigned{});
+
+
+} //end ns more_variadic_1
+
+} // end ns variadic_tests_1
+
+
+#ifdef WORKS_ONCE_INFINITE_LINKAGE_RECURSION_OF_NESTED_LAMBDAS_COMMITTED
+namespace at_ns_scope_within_class_member {
+ struct X {
+ static void foo(double d) { }
+ auto test() {
+ auto L = [](auto a) {
+ print("a = ", a, "\n");
+ foo(a);
+ return [](decltype(a) b) {
+ foo(b);
+ foo(sizeof(a) + sizeof(b));
+ return [](auto ... c) {
+ print("c = ", c ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}}
+ print("d = ", d ..., "\n");
+ foo(decltype(b){});
+ foo(sizeof(decltype(a)*) + sizeof(decltype(b)*));
+ return decltype(a){};
+ };
+ };
+ };
+ };
+ return L;
+ }
+};
+X x;
+auto L = x.test();
+auto L_test = L('4');
+auto M = L('3');
+auto M_test = M('a');
+auto N = M('x');
+auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+char (*np)(const char*, int, const char*, double, const char*, int) = O;
+auto NP_result = np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456);
+int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}}
+
+} //end at_ns_scope_within_class_member
+#endif
+
+} // 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