Author: rsmith Date: Wed Feb 3 14:40:30 2016 New Revision: 259688 URL: http://llvm.org/viewvc/llvm-project?rev=259688&view=rev Log: Ensure that we substitute into the declaration of a template parameter pack (that is not a pack expansion) during template argument deduction, even if we deduced that the pack would be empty.
Added: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=259688&r1=259687&r2=259688&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Feb 3 14:40:30 2016 @@ -2119,8 +2119,25 @@ ConvertDeducedTemplateArgument(Sema &S, PackedArgsBuilder.push_back(Output.pop_back_val()); } - // FIXME: If the pack is empty and this is a template template parameter, - // we still need to substitute into the parameter itself. + // If the pack is empty, we still need to substitute into the parameter + // itself, in case that substitution fails. For non-type parameters, we did + // this above. For type parameters, no substitution is ever required. + auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param); + if (TTP && PackedArgsBuilder.empty()) { + // Set up a template instantiation context. + LocalInstantiationScope Scope(S); + Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template, + TTP, Output, + Template->getSourceRange()); + if (Inst.isInvalid()) + return true; + + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Output.data(), Output.size()); + if (!S.SubstDecl(TTP, S.CurContext, + MultiLevelTemplateArgumentList(TemplateArgs))) + return true; + } // Create the resulting argument pack. Output.push_back( @@ -2808,11 +2825,22 @@ Sema::FinishTemplateArgumentDeduction(Fu Builder.push_back(TemplateArgument( llvm::makeArrayRef(ExplicitArgs, NumExplicitArgs))); - // Forget the partially-substituted pack; it's substitution is now + // Forget the partially-substituted pack; its substitution is now // complete. CurrentInstantiationScope->ResetPartiallySubstitutedPack(); } else { - Builder.push_back(TemplateArgument::getEmptyPack()); + // Go through the motions of checking the empty argument pack against + // the parameter pack. + DeducedTemplateArgument DeducedPack(TemplateArgument::getEmptyPack()); + if (ConvertDeducedTemplateArgument(*this, Param, DeducedPack, + FunctionTemplate, Info, true, + Builder)) { + Info.Param = makeTemplateParameter(Param); + // FIXME: These template arguments are temporary. Free them! + Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(), + Builder.size())); + return TDK_SubstitutionFailure; + } } continue; } Added: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp?rev=259688&view=auto ============================================================================== --- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp (added) +++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp Wed Feb 3 14:40:30 2016 @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s + +struct Q { typedef int type; }; + +// "The substitution occurs in all types and expressions that are used in [...] +// template parameter declarations." In particular, we must substitute into the +// type of a parameter pack that is not a pack expansion, even if we know the +// corresponding argument pack is empty. +template<typename T, typename T::type...> void a(T); +int &a(...); +int &a_disabled = a(0); +int &a_enabled = a(Q()); // expected-error {{cannot bind to a temporary of type 'void'}} + +template<typename T, template<typename T::type> class ...X> void b(T); +int &b(...); +int &b_disabled = b(0); +int &b_enabled = b(Q()); // expected-error {{cannot bind to a temporary of type 'void'}} + +template<typename T, template<typename T::type...> class ...X> void c(T); +int &c(...); +int &c_disabled = c(0); +int &c_enabled = c(Q()); // expected-error {{cannot bind to a temporary of type 'void'}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits