summaryrefslogtreecommitdiff
path: root/test/CXX/expr/expr.prim/expr.prim.lambda
diff options
context:
space:
mode:
authorFaisal Vali <faisalv@yahoo.com>2013-08-22 01:49:11 +0000
committerFaisal Vali <faisalv@yahoo.com>2013-08-22 01:49:11 +0000
commitecb5819a9e64fb654d46a3b270a286cc570c58ff (patch)
treedad7768ace62588d236d2ce070ee5a139e6101f3 /test/CXX/expr/expr.prim/expr.prim.lambda
parentb9377d373bad7a0d76924551474665cc1fa01555 (diff)
downloadclang-ecb5819a9e64fb654d46a3b270a286cc570c58ff.tar.gz
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 <class F1, class F2> 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<decltype(Base), decltype(Recursive)> 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! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@188977 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/CXX/expr/expr.prim/expr.prim.lambda')
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp50
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp23
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp57
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp4
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp135
5 files changed, 267 insertions, 2 deletions
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
new file mode 100644
index 0000000000..fcfd9bcb7d
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/generic-lambda-unimplemented-1y.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify -emit-llvm
+namespace return_type_deduction_ok {
+// FIXME: Once return type deduction is implemented for generic lambdas
+// this will need to be updated.
+ auto l = [](auto a) ->auto { return a; }(2);
+ auto l2 = [](auto a) ->decltype(auto) { return a; }(2);
+ auto l3 = [](auto a) { return a; }(2);
+
+
+}
+
+namespace lambda_capturing {
+// FIXME: Once return type deduction is implemented for generic lambdas
+// this will need to be updated.
+void test() {
+ int i = 10;
+ auto L = [=](auto a) -> int { //expected-error{{unimplemented}}
+ return i + a;
+ };
+ L(3);
+}
+
+}
+
+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}}
+}
+}
+
+namespace conversion_operator {
+void test() {
+ auto L = [](auto a) -> int { return a; };
+ int (*fp)(int) = L; //expected-error{{no viable conversion}}
+ }
+}
+
+namespace generic_lambda_as_default_argument_ok {
+ void test(int i = [](auto a)->int { return a; }(3)) {
+
+ }
+
+}
+
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp
new file mode 100644
index 0000000000..44656a37e3
--- /dev/null
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p2-generic-lambda-1y.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y -DCXX1Y
+
+// prvalue
+void prvalue() {
+ auto&& x = [](auto a)->void { };
+ auto& y = [](auto *a)->void { }; // expected-error{{cannot bind to a temporary of type}}
+}
+
+namespace std {
+ class type_info;
+}
+
+struct P {
+ virtual ~P();
+};
+
+void unevaluated_operand(P &p, int i) {
+ // FIXME: this should only emit one error.
+ int i2 = sizeof([](auto a, auto b)->void{}(3, '4')); // expected-error{{lambda expression in an unevaluated operand}} \
+ // expected-error{{invalid application of 'sizeof'}}
+ const std::type_info &ti1 = typeid([](auto &a) -> P& { static P p; return p; }(i));
+ const std::type_info &ti2 = typeid([](auto) -> int { return i; }(i)); // expected-error{{lambda expression in an unevaluated operand}}
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp
index 79ee76f025..f8461335b7 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp
@@ -7,3 +7,60 @@ int &d = [] (int &r) -> auto & { return r; } (a);
int &e = [] (int &r) -> auto { return r; } (a); // expected-error {{cannot bind to a temporary}}
int &f = [] (int r) -> decltype(auto) { return r; } (a); // expected-error {{cannot bind to a temporary}}
int &g = [] (int r) -> decltype(auto) { return (r); } (a); // expected-warning {{reference to stack}}
+
+
+int test_explicit_auto_return()
+{
+ struct X {};
+ auto L = [](auto F, auto a) { return F(a); };
+ auto M = [](auto a) -> auto { return a; }; // OK
+ auto MRef = [](auto b) -> auto& { return b; }; //expected-warning{{reference to stack}}
+ auto MPtr = [](auto c) -> auto* { return &c; }; //expected-warning{{address of stack}}
+ auto MDeclType = [](auto&& d) -> decltype(auto) { return static_cast<decltype(d)>(d); }; //OK
+ M(3);
+
+ auto &&x = MDeclType(X{});
+ auto &&x1 = M(X{});
+ auto &&x2 = MRef(X{});//expected-note{{in instantiation of}}
+ auto &&x3 = MPtr(X{}); //expected-note{{in instantiation of}}
+ return 0;
+}
+
+int test_implicit_auto_return()
+{
+ {
+ auto M = [](auto a) { return a; };
+ struct X {};
+ X x = M(X{});
+
+ }
+}
+
+int test_multiple_returns() {
+ auto M = [](auto a) {
+ bool k;
+ if (k)
+ return a;
+ else
+ return 5; //expected-error{{deduced as 'int' here}}
+ };
+ M(3); // OK
+ M('a'); //expected-note{{in instantiation of}}
+ return 0;
+}
+int test_no_parameter_list()
+{
+ static int si = 0;
+ auto M = [] { return 5; }; // OK
+ auto M2 = [] -> auto&& { return si; }; // expected-error{{lambda requires '()'}}
+ M();
+}
+
+int test_conditional_in_return() {
+ auto Fac = [](auto f, auto n) {
+ return n <= 0 ? n : f(f, n - 1) * n;
+ };
+ // FIXME: this test causes a recursive limit - need to error more gracefully.
+ //Fac(Fac, 3);
+
+} \ No newline at end of file
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
index c69aa115be..1016cb1d30 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
-// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify
+// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify -DCPP1Y
void missing_lambda_declarator() {
[](){}();
@@ -18,7 +18,7 @@ void infer_void_return_type(int i) {
switch (x) {
case 0: return get<void>();
case 1: return;
- case 2: return { 1, 2.0 }; // expected-error{{cannot deduce lambda return type from initializer list}}
+ case 2: return { 1, 2.0 }; //expected-error{{cannot deduce}}
}
}(7);
}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p5-generic-lambda-1y.cpp
new file mode 100644
index 0000000000..c1311617ef
--- /dev/null
+++ b/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 <class F1, class F2> 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<decltype(Base), decltype(NumParams)> O(Base, NumParams);
+ int num_params = O(O, 5, 3, "abc", 3.14, 'a');
+}
+
+
+namespace overload_generic_lambda_return_type_deduction {
+ template <class F1, class F2> 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<decltype(Base), decltype(NumParams)> 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);
+ }
+}
+