diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-07-25 03:56:55 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-07-25 03:56:55 +0000 |
commit | 612409ece080e814f79e06772c690d603f45fbd6 (patch) | |
tree | 537d937d27dae8aec0b0bdf586cd8f2dfaaa9d59 /test | |
parent | 6f36366c85dc81d67d70efdeeea4cfc382053feb (diff) |
PR12057: Allow variadic template pack expansions to cross lambda boundaries.
Rather than adding a ContainsUnexpandedParameterPack bit to essentially every
AST node, we tunnel the bit directly up to the surrounding lambda expression
when we reach a context where an unexpanded pack can not normally appear.
Thus any statement or declaration within a lambda can now potentially contain
an unexpanded parameter pack.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160705 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test')
-rw-r--r-- | test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm | 19 | ||||
-rw-r--r-- | test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/lambda-expressions.cpp | 76 |
3 files changed, 96 insertions, 3 deletions
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm b/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm index 6a6e0d9c90..0db2bf5646 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/blocks.mm @@ -89,6 +89,8 @@ namespace overloading { namespace PR13117 { struct A { + template<typename ... Args> static void f(Args...); + template<typename ... Args> static void f1() { (void)^(Args args) { // expected-error{{block contains unexpanded parameter pack 'Args'}} @@ -97,9 +99,24 @@ namespace PR13117 { template<typename ... Args> static void f2() { - (void)[](Args args) { // expected-error{{lambda contains unexpanded parameter pack 'Args'}} + // FIXME: Allow this. + f( + ^(Args args) // expected-error{{block contains unexpanded parameter pack 'Args'}} + { } + ... // expected-error{{pack expansion does not contain any unexpanded parameter packs}} + ); + } + + template<typename ... Args> static void f3() + { + (void)[](Args args) { // expected-error{{expression contains unexpanded parameter pack 'Args'}} }; } + + template<typename ... Args> static void f4() + { + f([](Args args) { } ...); + } }; void g() { diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp index 174db257c8..82fc04a48f 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp @@ -9,8 +9,8 @@ void print(T first, Ts... rest) { } template<typename... Ts> -void unsupported(Ts ...values) { - auto unsup = [values] {}; // expected-error{{unexpanded function parameter pack capture is unsupported}} +void unexpanded_capture(Ts ...values) { + auto unexp = [values] {}; // expected-error{{initializer contains unexpanded parameter pack 'values'}} } template<typename... Ts> diff --git a/test/SemaCXX/lambda-expressions.cpp b/test/SemaCXX/lambda-expressions.cpp index f5eee6a529..198f8cf1fe 100644 --- a/test/SemaCXX/lambda-expressions.cpp +++ b/test/SemaCXX/lambda-expressions.cpp @@ -145,3 +145,79 @@ namespace ModifyingCapture { }; } } + +namespace VariadicPackExpansion { + template<typename T, typename U> using Fst = T; + template<typename...Ts> bool g(Fst<bool, Ts> ...bools); + template<typename...Ts> bool f(Ts &&...ts) { + return g<Ts...>([&ts] { + if (!ts) + return false; + --ts; + return true; + } () ...); + } + void h() { + int a = 5, b = 2, c = 3; + while (f(a, b, c)) { + } + } + + struct sink { + template<typename...Ts> sink(Ts &&...) {} + }; + + template<typename...Ts> void local_class() { + sink { + [] (Ts t) { + struct S : Ts { + void f(Ts t) { + Ts &that = *this; + that = t; + } + Ts g() { return *this; }; + }; + S s; + s.f(t); + return s; + } (Ts()).g() ... + }; + }; + struct X {}; struct Y {}; + template void local_class<X, Y>(); + + template<typename...Ts> void nested(Ts ...ts) { + f( + // Each expansion of this lambda implicitly captures all of 'ts', because + // the inner lambda also expands 'ts'. + [&] { + return ts + [&] { return f(ts...); } (); + } () ... + ); + } + template void nested(int, int, int); + + template<typename...Ts> void nested2(Ts ...ts) { // expected-note 2{{here}} + // Capture all 'ts', use only one. + f([&ts...] { return ts; } ()...); + // Capture each 'ts', use it. + f([&ts] { return ts; } ()...); + // Capture all 'ts', use all of them. + f([&ts...] { return (int)f(ts...); } ()); + // Capture each 'ts', use all of them. Ill-formed. In more detail: + // + // We instantiate two lambdas here; the first captures ts$0, the second + // captures ts$1. Both of them reference both ts parameters, so both are + // ill-formed because ts can't be implicitly captured. + // + // FIXME: This diagnostic does not explain what's happening. We should + // specify which 'ts' we're referring to in its diagnostic name. We should + // also say which slice of the pack expansion is being performed in the + // instantiation backtrace. + f([&ts] { return (int)f(ts...); } ()...); // \ + // expected-error 2{{'ts' cannot be implicitly captured}} \ + // expected-note 2{{lambda expression begins here}} + } + template void nested2(int); // ok + template void nested2(int, int); // expected-note {{in instantiation of}} +} |