hanchenye-llvm-project/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp

716 lines
17 KiB
C++
Raw Normal View History

// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -emit-llvm-only %s
// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING
// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS
// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
Implement conversion to function pointer for generic lambdas without captures. The general strategy is to create template versions of the conversion function and static invoker and then during template argument deduction of the conversion function, create the corresponding call-operator and static invoker specializations, and when the conversion function is marked referenced generate the body of the conversion function using the corresponding static-invoker specialization. Similarly, Codegen does something similar - when asked to emit the IR for a specialized static invoker of a generic lambda, it forwards emission to the corresponding call operator. This patch has been reviewed in person both by Doug and Richard. Richard gave me the LGTM. A few minor changes: - per Richard's request i added a simple check to gracefully inform that captures (init, explicit or default) have not been added to generic lambdas just yet (instead of the assertion violation). - I removed a few lines of code that added the call operators instantiated parameters to the currentinstantiationscope. Not only did it not handle parameter packs, but it is more relevant in the patch for nested lambdas which will follow this one, and fix that problem more comprehensively. - Doug had commented that the original implementation strategy of using the TypeSourceInfo of the call operator to create the static-invoker was flawed and allowed const as a member qualifier to creep into the type of the static-invoker. I currently kludge around it - but after my initial discussion with Doug, with a follow up session with Richard, I have added a FIXME so that a more elegant solution that involves the use of TrivialTypeSourceInfo call followed by the correct wiring of the template parameters to the functionprototypeloc is forthcoming. Thanks! llvm-svn: 191634
2013-09-29 16:45:24 +08:00
namespace explicit_call {
int test() {
auto L = [](auto a) { return a; };
L.operator()(3);
L.operator()<char>(3.14); //expected-warning{{implicit conversion}}
return 0;
}
} //end ns
namespace test_conversion_to_fptr {
void f1(int (*)(int)) { }
void f2(char (*)(int)) { } // expected-note{{candidate}}
void g(int (*)(int)) { } // #1 expected-note{{candidate}}
void g(char (*)(char)) { } // #2 expected-note{{candidate}}
void h(int (*)(int)) { } // #3
void h(char (*)(int)) { } // #4
int test() {
{
auto glambda = [](auto a) { return a; };
glambda(1);
f1(glambda); // OK
f2(glambda); // expected-error{{no matching function}}
g(glambda); // expected-error{{call to 'g' is ambiguous}}
h(glambda); // OK: calls #3 since it is convertible from ID
int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
}
{
auto L = [](auto a) { return a; };
int (*fp)(int) = L;
fp(5);
L(3);
char (*fc)(char) = L;
fc('b');
L('c');
double (*fd)(double) = L;
fd(3.14);
fd(6.26);
L(4.25);
}
{
auto L = [](auto a) ->int { return a; }; //expected-note 2{{candidate template ignored}}
int (*fp)(int) = L;
char (*fc)(char) = L; //expected-error{{no viable conversion}}
double (*fd)(double) = L; //expected-error{{no viable conversion}}
}
{
int* (*fp)(int*) = [](auto *a) -> auto* { return a; };
fp(0);
}
Implement conversion to function pointer for generic lambdas without captures. The general strategy is to create template versions of the conversion function and static invoker and then during template argument deduction of the conversion function, create the corresponding call-operator and static invoker specializations, and when the conversion function is marked referenced generate the body of the conversion function using the corresponding static-invoker specialization. Similarly, Codegen does something similar - when asked to emit the IR for a specialized static invoker of a generic lambda, it forwards emission to the corresponding call operator. This patch has been reviewed in person both by Doug and Richard. Richard gave me the LGTM. A few minor changes: - per Richard's request i added a simple check to gracefully inform that captures (init, explicit or default) have not been added to generic lambdas just yet (instead of the assertion violation). - I removed a few lines of code that added the call operators instantiated parameters to the currentinstantiationscope. Not only did it not handle parameter packs, but it is more relevant in the patch for nested lambdas which will follow this one, and fix that problem more comprehensively. - Doug had commented that the original implementation strategy of using the TypeSourceInfo of the call operator to create the static-invoker was flawed and allowed const as a member qualifier to creep into the type of the static-invoker. I currently kludge around it - but after my initial discussion with Doug, with a follow up session with Richard, I have added a FIXME so that a more elegant solution that involves the use of TrivialTypeSourceInfo call followed by the correct wiring of the template parameters to the functionprototypeloc is forthcoming. Thanks! llvm-svn: 191634
2013-09-29 16:45:24 +08:00
}
namespace more_converion_to_ptr_to_function_tests {
int test() {
{
int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
int (*fp2)(int) = [](auto b) -> int { return b; };
int (*fp3)(char) = [](auto c) -> int { return c; };
char (*fp4)(int) = [](auto d) { return d; }; //expected-error{{no viable conversion}}\
//expected-note{{candidate template ignored}}
char (*fp5)(char) = [](auto e) -> int { return e; }; //expected-error{{no viable conversion}}\
//expected-note{{candidate template ignored}}
fp2(3);
fp3('\n');
fp3('a');
return 0;
}
} // end test()
template<class ... Ts> void vfun(Ts ... ) { }
int variadic_test() {
int (*fp)(int, char, double) = [](auto ... a) -> int { vfun(a...); return 4; };
fp(3, '4', 3.14);
int (*fp2)(int, char, double) = [](auto ... a) { vfun(a...); return 4; };
fp(3, '4', 3.14);
return 2;
}
} // end ns
namespace conversion_operator {
void test() {
auto L = [](auto a) -> int { return a; };
int (*fp)(int) = L;
int (&fp2)(int) = [](auto a) { return a; }; // expected-error{{non-const lvalue}}
int (&&fp3)(int) = [](auto a) { return a; }; // expected-error{{no viable conversion}}\
//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);
auto l3 = [](auto a) { return a; }(2);
}
namespace generic_lambda_as_default_argument_ok {
void test(int i = [](auto a)->int { return a; }(3)) {
}
}
And Again: Teach TreeTransform how to transform nested generic lambdas. 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. Another attempt caused a test to fail (http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20131021/091533.html) and also had to be reverted - my apologies - in my haste, i did not run all the tests - argh! Now all the tests seem to pass - but a Fixme has been added - since I suspect Richard will find the fix a little inelegant ;) I shall try and work on a more elegant fix once I have had a chance to discuss with Richard or Doug at a later date. Hopefully the third time;s a charm *fingers crossed* 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: 193230
2013-10-23 14:44:28 +08:00
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 at_ns_scope_within_class_template_member {
struct X {
static void foo(double d) { }
template<class T = int>
auto test(T = T{}) {
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}}
And Again: Teach TreeTransform how to transform nested generic lambdas. 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. Another attempt caused a test to fail (http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20131021/091533.html) and also had to be reverted - my apologies - in my haste, i did not run all the tests - argh! Now all the tests seem to pass - but a Fixme has been added - since I suspect Richard will find the fix a little inelegant ;) I shall try and work on a more elegant fix once I have had a chance to discuss with Richard or Doug at a later date. Hopefully the third time;s a charm *fingers crossed* 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: 193230
2013-10-23 14:44:28 +08:00
} //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
namespace nested_fptr_235 {
int test()
{
auto L = [](auto b) {
return [](auto a) ->decltype(a) { return a; };
};
int (*fp)(int) = L(8);
fp(5);
L(3);
char (*fc)(char) = L('a');
fc('b');
L('c');
double (*fd)(double) = L(3.14);
fd(3.14);
fd(6.26);
return 0;
}
int run = test();
}
namespace fptr_with_decltype_return_type {
template<class F, class ... Ts> using FirstType = F;
template<class F, class ... Rest> F& FirstArg(F& f, Rest& ... r) { return f; };
template<class ... Ts> auto vfun(Ts&& ... ts) {
print(ts...);
return FirstArg(ts...);
}
int test()
{
{
auto L = [](auto ... As) {
return [](auto b) ->decltype(b) {
vfun([](decltype(As) a) -> decltype(a) { return a; } ...)(FirstType<decltype(As)...>{});
return decltype(b){};
};
};
auto LL = L(1, 'a', 3.14, "abc");
LL("dim");
}
return 0;
}
int run = test();
}
And Again: Teach TreeTransform how to transform nested generic lambdas. 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. Another attempt caused a test to fail (http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20131021/091533.html) and also had to be reverted - my apologies - in my haste, i did not run all the tests - argh! Now all the tests seem to pass - but a Fixme has been added - since I suspect Richard will find the fix a little inelegant ;) I shall try and work on a more elegant fix once I have had a chance to discuss with Richard or Doug at a later date. Hopefully the third time;s a charm *fingers crossed* 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: 193230
2013-10-23 14:44:28 +08:00
} // 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>(); }
}