From 4f1b413f41afb3833bc5f645c212873f8132fe74 Mon Sep 17 00:00:00 2001 From: Faisal Vali Date: Sun, 1 Jun 2014 16:11:54 +0000 Subject: [PATCH] Fix PR18498: Support explicit template arguments with variadic generic lambdas http://llvm.org/bugs/show_bug.cgi?id=18498 This code was resulting in a crash: auto L = [](auto ... v) { }; L.operator()(3); The reason is that the partially-substituted-pack is incorrectly retained within the current-instantiation-scope during template-argument-finalization, and because lambda's are local, there parent instantiation scopes are merged, which leads to the expansion-pattern being retained in the finalized specialization. This patch ensures that once we have finalized deduction of a parameter-pack, we remove the partially-substituted-pack so that it doesn't cause CheckParameterPacksForExpansion to incorrectly inform the caller that it needs to retain the expansion pattern. Thanks to Richard Smith for the review! http://reviews.llvm.org/D2135 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@209992 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaTemplateDeduction.cpp | 12 ++- .../cxx1y-generic-lambdas-variadics.cpp | 100 ++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 7d9cec141a..f941a0992c 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -2816,9 +2816,19 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // argument, because it was explicitly-specified. Just record the // presence of this argument. Builder.push_back(Deduced[I]); + // We may have had explicitly-specified template arguments for a + // template parameter pack (that may or may not have been extended + // via additional deduced arguments). + if (Param->isParameterPack() && CurrentInstantiationScope) { + if (CurrentInstantiationScope->getPartiallySubstitutedPack() == + Param) { + // Forget the partially-substituted pack; its substitution is now + // complete. + CurrentInstantiationScope->ResetPartiallySubstitutedPack(); + } + } continue; } - // We have deduced this argument, so it still needs to be // checked and converted. diff --git a/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp b/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp new file mode 100644 index 0000000000..b0b86e3877 --- /dev/null +++ b/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp @@ -0,0 +1,100 @@ +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks %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 + +namespace explicit_argument_variadics { + + +template void print(Ts ... ) { } + +struct X { }; +struct Y { }; +struct Z { }; + +int test() { + { + auto L = [](auto ... as) { }; + L.operator()(true); + } + { + auto L = [](auto a) { }; + L.operator()(false); + } + { + auto L = [](auto a, auto b) { }; + L.operator()(false, 'a'); + } + { + auto L = [](auto a, auto b) { }; + L.operator()(false, 'a'); + } + { + auto L = [](auto a, auto b, auto ... cs) { }; + L.operator()(false, 'a'); + L.operator()(false, 'a', "jim"); + } + + { + auto L = [](auto ... As) { + }; + L.operator()(false, 3.14, "abc"); + } + { + auto L = [](auto A, auto B, auto ... As) { + }; + L.operator()(false, 3.14, "abc"); + L.operator()(false, 3.14, "abc"); //expected-warning{{implicit conversion}} + L.operator()(X{}, Y{}, 3.14, Z{}, X{}); //expected-warning{{implicit conversion}} + } + { + auto L = [](auto ... As) { + print("\nL::As = ", As ...); + return [](decltype(As) ... as, auto ... Bs) { + print("\nL::Inner::as = ", as ...); + print("\nL::Inner::Bs = ", Bs ...); + return 4; + }; + }; + auto M = L.operator()(false, 3.14, "abc"); + M(false, 6.26, "jim", true); + M.operator()(true, 6.26, "jim", false, 3.14); + } + { + auto L = [](auto A, auto ... As) { + print("\nL::As = ", As ...); + return [](decltype(As) ... as, decltype(A) a, auto ... Bs) { + print("\nL::Inner::as = ", as ...); + print("\nL::Inner::Bs = ", Bs ...); + return 4; + }; + }; + auto M = L.operator()(false, 3.14, "abc"); + M(6.26, "jim", true); + M.operator()(6.26, "jim", false, X{}, Y{}, Z{}); + } + + return 0; +} + int run = test(); +} // end ns explicit_argument_extension + + + +#ifdef PR18499_FIXED +namespace variadic_expansion { + void f(int &, char &); + + template void g(T &... t) { + f([&a(t)]()->decltype(auto) { + return a; + }() ...); + f([&a(f([&b(t)]()->decltype(auto) { return b; }()...), t)]()->decltype(auto) { + return a; + }()...); + } + + void h(int i, char c) { g(i, c); } +} +#endif + -- 2.40.0