diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index f13b14bd0f1bcf654c87552f4899c5271b3d39bb..3c621dafab9dc33e02337e8dab5356fe25827c5f 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/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 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, 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. @@ -911,13 +917,36 @@ namespace { } ExprResult TransformLambdaScope(LambdaExpr *E, - CXXMethodDecl *CallOperator) { - CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(), - TSK_ImplicitInstantiation); - return TreeTransform<TemplateInstantiator>:: - TransformLambdaScope(E, CallOperator); + CXXMethodDecl *NewCallOperator) { + CXXMethodDecl *const OldCallOperator = E->getCallOperator(); + // In the generic lambda case, we set the NewTemplate to be considered + // an "instantiation" of the OldTemplate. + if (FunctionTemplateDecl *const NewCallOperatorTemplate = + NewCallOperator->getDescribedFunctionTemplate()) { + + FunctionTemplateDecl *const OldCallOperatorTemplate = + OldCallOperator->getDescribedFunctionTemplate(); + NewCallOperatorTemplate->setInstantiatedFromMemberTemplate( + OldCallOperatorTemplate); + // Mark the NewCallOperatorTemplate a specialization. + NewCallOperatorTemplate->setMemberSpecialization(); + } else + // For a non-generic lambda we set the NewCallOperator to + // be an instantiation of the OldCallOperator. + NewCallOperator->setInstantiationOfMemberFunction(OldCallOperator, + TSK_ImplicitInstantiation); + + return inherited::TransformLambdaScope(E, NewCallOperator); + } + TemplateParameterList *TransformTemplateParameterList( + TemplateParameterList *OrigTPL) { + if (!OrigTPL || !OrigTPL->size()) return OrigTPL; + + DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext(); + TemplateDeclInstantiator DeclInstantiator(getSema(), + /* DeclContext *Owner */ Owner, TemplateArgs); + return DeclInstantiator.SubstTemplateParams(OrigTPL); } - private: ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm, SourceLocation loc, diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index d1512c271c0166773ebcf1fba5230205f12d2ba9..3989c56ccd8d63b5bad4cba2496db83b749028b4 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4174,6 +4174,25 @@ DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC, NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs) { DeclContext *ParentDC = D->getDeclContext(); + // FIXME: Parmeters of pointer to functions (y below) that are themselves + // parameters (p below) can have their ParentDC set to the translation-unit + // - thus we can not consistently check if the ParentDC of such a parameter + // is Dependent or/and a FunctionOrMethod. + // For e.g. this code, during Template argument deduction tries to + // find an instantiated decl for (T y) when the ParentDC for y is + // the translation unit. + // e.g. template <class T> void Foo(auto (*p)(T y) -> decltype(y())) {} + // float baz(float(*)()) { return 0.0; } + // Foo(baz); + // The better fix here is perhaps to ensure that a ParmVarDecl, by the time + // it gets here, always has a FunctionOrMethod as its ParentDC?? + // For now: + // - as long as we have a ParmVarDecl whose parent is non-dependent and + // whose type is not instantiation dependent, do nothing to the decl + // - otherwise find its instantiated decl. + if (isa<ParmVarDecl>(D) && !ParentDC->isDependentContext() && + !cast<ParmVarDecl>(D)->getType()->isInstantiationDependentType()) + return D; if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) || (ParentDC->isFunctionOrMethod() && ParentDC->isDependentContext()) || diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 97e12d77a194258b6a84a996df755e5a7a6ffddf..3ac13bb08a6b4f51d89a9f3670482b869a9137f2 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -593,6 +593,11 @@ public: /// \brief Transform the captures and body of a lambda expression. ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator); + TemplateParameterList *TransformTemplateParameterList( + TemplateParameterList *TPL) { + return TPL; + } + ExprResult TransformAddressOfOperand(Expr *E); ExprResult TransformDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E, bool IsAddressOfOperand); @@ -8267,48 +8272,100 @@ template<typename Derived> 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(); + // Transform the template parameters, and add them to the current + // instantiation scope. The null case is handled correctly. + LSI->GLTemplateParameterList = getDerived().TransformTemplateParameterList( + E->getTemplateParameterList()); + + // Check to see if the TypeSourceInfo of the call operator needs to + // be transformed, and if so do the transformation in the + // CurrentInstantiationScope. + + TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo(); + FunctionProtoTypeLoc OldCallOpFPTL = + OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>(); + TypeSourceInfo *NewCallOpTSI = 0; + + const bool CallOpWasAlreadyTransformed = + getDerived().AlreadyTransformed(OldCallOpTSI->getType()); + + // Use the Old Call Operator's TypeSourceInfo if it is already transformed. + if (CallOpWasAlreadyTransformed) + NewCallOpTSI = OldCallOpTSI; + else { + // Transform the TypeSourceInfo of the Original Lambda's Call Operator. + // The transformation MUST be done in the CurrentInstantiationScope since + // it introduces a mapping of the original to the newly created + // transformed parameters. + + TypeLocBuilder NewCallOpTLBuilder; + QualType NewCallOpType = TransformFunctionProtoType(NewCallOpTLBuilder, + OldCallOpFPTL, + 0, 0); + NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, + NewCallOpType); + } + // Extract the ParmVarDecls from the NewCallOpTSI and add them to + // the vector below - this will be used to synthesize the + // NewCallOperator. Additionally, add the parameters of the untransformed + // lambda call operator to the CurrentInstantiationScope. + SmallVector<ParmVarDecl *, 4> Params; + { + FunctionProtoTypeLoc NewCallOpFPTL = + NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>(); + ParmVarDecl **NewParamDeclArray = NewCallOpFPTL.getParmArray(); + const unsigned NewNumArgs = NewCallOpFPTL.getNumArgs(); + + for (unsigned I = 0; I < NewNumArgs; ++I) { + // If this call operator's type does not require transformation, + // the parameters do not get added to the current instantiation scope, + // - so ADD them! This allows the following to compile when the enclosing + // template is specialized and the entire lambda expression has to be + // transformed. + // 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 (CallOpWasAlreadyTransformed) + getDerived().transformedLocalDecl(NewParamDeclArray[I], + NewParamDeclArray[I]); + // Add to Params array, so these parameters can be used to create + // the newly transformed call operator. + Params.push_back(NewParamDeclArray[I]); + } } - // Transform the type of the lambda parameters and start the definition of - // the lambda itself. - TypeSourceInfo *MethodTy - = TransformType(E->getCallOperator()->getTypeSourceInfo()); - if (!MethodTy) + + 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); - // Transform lambda parameters. - SmallVector<QualType, 4> ParamTypes; - SmallVector<ParmVarDecl *, 4> Params; - if (getDerived().TransformFunctionTypeParams(E->getLocStart(), - E->getCallOperator()->param_begin(), - 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); + LSI->CallOperator = NewCallOperator; + + getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); - return getDerived().TransformLambdaScope(E, CallOperator); + return getDerived().TransformLambdaScope(E, NewCallOperator); } template<typename Derived> diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp index a43a98bb18f859a939a46d630561c6d238e9e9bc..92dd7ad1876c54aeaf50314782899dc8571fd5f2 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp @@ -29,20 +29,3 @@ void test() { } -namespace nested_generic_lambdas { -void test() { - auto L = [](auto a) -> int { - auto M = [](auto b, decltype(a) b2) -> int { //expected-error{{unimplemented}} - return 1; - }; - M(a, a); - }; - L(3); //expected-note{{in instantiation of}} -} -template<class T> void foo(T) { - auto L = [](auto a) { return a; }; //expected-error{{unimplemented}} -} -template void foo(int); //expected-note{{in instantiation of}} -} - - diff --git a/test/SemaCXX/cxx1y-generic-lambdas.cpp b/test/SemaCXX/cxx1y-generic-lambdas.cpp index b66825a536dc3939b7df65135325df5f42847984..64b9ff14215e2bad5d004786f043045e190001af 100644 --- a/test/SemaCXX/cxx1y-generic-lambdas.cpp +++ b/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 @@ void test() { //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,516 @@ namespace generic_lambda_as_default_argument_ok { 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 + +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 + + +namespace nested_generic_lambdas_123 { +void test() { + auto L = [](auto a) -> int { + auto M = [](auto b, decltype(a) b2) -> int { + return 1; + }; + M(a, a); + }; + L(3); +} +template<class T> void foo(T) { + auto L = [](auto a) { return a; }; +} +template void foo(int); +} // end ns nested_generic_lambdas_123 + + +} // end ns nested_non_capturing_lambda_tests + +namespace PR17476 { +struct string { + string(const char *__s) { } + string &operator+=(const string &__str) { return *this; } +}; + +template <class T> +void finalizeDefaultAtomValues() { + auto startEnd = [](const char * sym) -> void { + string start("__"); + start += sym; + }; + startEnd("preinit_array"); +} + +void f() { finalizeDefaultAtomValues<char>(); } + +} + +namespace PR17476_variant { +struct string { + string(const char *__s) { } + string &operator+=(const string &__str) { return *this; } +}; + +template <class T> +void finalizeDefaultAtomValues() { + auto startEnd = [](const T *sym) -> void { + string start("__"); + start += sym; + }; + startEnd("preinit_array"); +} + +void f() { finalizeDefaultAtomValues<char>(); } + +} \ No newline at end of file