From fd5277c0635f74bbdbb2daa3bb95e08f39db7d63 Mon Sep 17 00:00:00 2001 From: Faisal Vali Date: Thu, 22 Aug 2013 01:49:11 +0000 Subject: Implement a rudimentary form of generic lambdas. Specifically, the following features are not included in this commit: - any sort of capturing within generic lambdas - nested lambdas - conversion operator for captureless lambdas - ensuring all visitors are generic lambda aware As an example of what compiles: template struct overload : F1, F2 { using F1::operator(); using F2::operator(); overload(F1 f1, F2 f2) : F1(f1), F2(f2) { } }; auto Recursive = [](auto Self, auto h, auto ... rest) { return 1 + Self(Self, rest...); }; auto Base = [](auto Self, auto h) { return 1; }; overload O(Base, Recursive); int num_params = O(O, 5, 3, "abc", 3.14, 'a'); Please see attached tests for more examples. Some implementation notes: - Add a new Declarator context => LambdaExprParameterContext to clang::Declarator to allow the use of 'auto' in declaring generic lambda parameters - Augment AutoType's constructor (similar to how variadic template-type-parameters ala TemplateTypeParmDecl are implemented) to accept an IsParameterPack to encode a generic lambda parameter pack. - Add various helpers to CXXRecordDecl to facilitate identifying and querying a closure class - LambdaScopeInfo (which maintains the current lambda's Sema state) was augmented to house the current depth of the template being parsed (id est the Parser calls Sema::RecordParsingTemplateParameterDepth) so that Sema::ActOnLambdaAutoParameter may use it to create the appropriate list of corresponding TemplateTypeParmDecl for each auto parameter identified within the generic lambda (also stored within the current LambdaScopeInfo). Additionally, a TemplateParameterList data-member was added to hold the invented TemplateParameterList AST node which will be much more useful once we teach TreeTransform how to transform generic lambdas. - SemaLambda.h was added to hold some common lambda utility functions (this file is likely to grow ...) - Teach Sema::ActOnStartOfFunctionDef to check whether it is being called to instantiate a generic lambda's call operator, and if so, push an appropriately prepared LambdaScopeInfo object on the stack. - Teach Sema::ActOnStartOfLambdaDefinition to set the return type of a lambda without a trailing return type to 'auto' in C++1y mode, and teach the return type deduction machinery in SemaStmt.cpp to process either C++11 and C++14 lambda's correctly depending on the flag. - various tests were added - but much more will be needed. A greatful thanks to all reviewers including Eli Friedman, James Dennett and the ever illuminating Richard Smith. And yet I am certain that I have allowed unidentified bugs to creep in; bugs, that I will do my best to slay, once identified! Thanks! llvm-svn: 188977 --- .../expr.prim.lambda/p5-generic-lambda-1y.cpp | 135 +++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 clang/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp (limited to 'clang/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp') diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp new file mode 100644 index 00000000000..c1311617efb --- /dev/null +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp @@ -0,0 +1,135 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y -DCXX1Y -emit-llvm + +namespace test_factorial { + +auto Fact = [](auto Self, unsigned n) -> unsigned { + return !n ? 1 : Self(Self, n - 1) * n; +}; + +auto six = Fact(Fact, 3); + +} + +namespace overload_generic_lambda { + template struct overload : F1, F2 { + using F1::operator(); + using F2::operator(); + overload(F1 f1, F2 f2) : F1(f1), F2(f2) { } + }; + + auto NumParams = [](auto Self, auto h, auto ... rest) -> unsigned { + return 1 + Self(Self, rest...); + }; + auto Base = [](auto Self, auto h) -> unsigned { + return 1; + }; + overload O(Base, NumParams); + int num_params = O(O, 5, 3, "abc", 3.14, 'a'); +} + + +namespace overload_generic_lambda_return_type_deduction { + template struct overload : F1, F2 { + using F1::operator(); + using F2::operator(); + overload(F1 f1, F2 f2) : F1(f1), F2(f2) { } + }; + + auto NumParams = [](auto Self, auto h, auto ... rest) { + return 1 + Self(Self, rest...); + }; + auto Base = [](auto Self, auto h) { + return 1; + }; + overload O(Base, NumParams); + int num_params = O(O, 5, 3, "abc", 3.14, 'a'); +} + +namespace test_standard_p5 { +// FIXME: This test should eventually compile without an explicit trailing return type +auto glambda = [](auto a, auto&& b) ->bool { return a < b; }; +bool b = glambda(3, 3.14); // OK + +} +namespace test_deduction_failure { + int test() { + auto g = [](auto *a) { //expected-note{{candidate template ignored}} + return a; + }; + struct X { }; + X *x; + g(x); + g(3); //expected-error{{no matching function}} + return 0; + } + +} + +namespace test_instantiation_or_sfinae_failure { +int test2() { + { + auto L = [](auto *a) { + return (*a)(a); }; //expected-error{{called object type 'double' is not a function}} + //l(&l); + double d; + L(&d); //expected-note{{in instantiation of}} + auto M = [](auto b) { return b; }; + L(&M); // ok + } + { + auto L = [](auto *a) ->decltype (a->foo()) { //expected-note2{{candidate template ignored:}} + return (*a)(a); }; + //l(&l); + double d; + L(&d); //expected-error{{no matching function for call}} + auto M = [](auto b) { return b; }; + L(&M); //expected-error{{no matching function for call}} + + } + return 0; +} + + +} + +namespace test_misc { +auto GL = [](auto a, decltype(a) b) //expected-note{{candidate function}} + -> int { return a + b; }; + +void test() { + struct X { }; + GL(3, X{}); //expected-error{{no matching function}} +} + +void test2() { + auto l = [](auto *a) -> int { + (*a)(a); return 0; }; //expected-error{{called object type 'double' is not a function}} + l(&l); + double d; + l(&d); //expected-note{{in instantiation of}} +} + +} + +namespace nested_lambdas { + int test() { + auto L = [](auto a) { + return [=](auto b) { //expected-error{{unimplemented}} + return a + b; + }; + }; + // auto M = L(3.14); + // return M('4'); + } + auto get_lambda() { + return [](auto a) { + return a; + }; + }; + + int test2() { + auto L = get_lambda(); + L(3); + } +} + -- cgit v1.2.3