Again: Teach TreeTransform and family how to transform generic
lambdas nested within templates and themselves.
A previous attempt http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20130930/090049.html resulted in PR 17476, and was reverted,
The original TransformLambdaExpr (pre generic-lambdas) transformed the TypeSourceInfo of the Call operator in its own instantiation scope via TransformType. This resulted in the parameters of the call operator being mapped to their transformed counterparts in an instantiation scope that would get popped off.
Then a call to TransformFunctionParameters would add the parameters and their transformed mappings (but newly created ones!) to the current instantiation scope. This would result in a disconnect between the new call operator's TSI parameters and those used to construct the call operator declaration. This was ok in the non-generic lambda world - but would cause issues with nested transformations (when non-generic and generics were interleaved) in the generic lambda world - that I somewhat kludged around initially - but this resulted in PR17476.
The new approach seems cleaner. We only do the transformation of the TypeSourceInfo - but we make sure to do it in the current instantiation scope so we don't lose the untransformed to transformed mappings of the ParmVarDecls when they get created.
This does not yet include capturing.
Please see test file for examples.
This patch was LGTM'd by Doug:
http://llvm-reviews.chandlerc.com/D1784
llvm-svn: 193216
diff --git a/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp b/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
index b66825a..64b9ff1 100644
--- a/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
+++ b/clang/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,516 @@
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