From d0ad2949fadacc45814935ab2f2f71306ad94ef9 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 23 Dec 2010 01:24:45 +0000 Subject: [PATCH] Implement the rest of C++0x [temp.deduct.type]p9, which specifies that the presence of a pack expansion anywhere except at the end of a template-argument-list causes the entire template-argument-list to be a non-deduced context. llvm-svn: 122461 --- clang/lib/Sema/SemaTemplateDeduction.cpp | 60 ++++++++++++++++++- .../temp.deduct/temp.deduct.type/p2-0x.cpp | 2 +- .../temp.deduct/temp.deduct.type/p9-0x.cpp | 25 ++++++++ 3 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 79cbc5ab029c..ad649c067c69 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1059,6 +1059,33 @@ static TemplateParameter makeTemplateParameter(Decl *D) { return TemplateParameter(cast(D)); } +/// \brief Determine whether the given set of template arguments has a pack +/// expansion that is not the last template argument. +static bool hasPackExpansionBeforeEnd(const TemplateArgument *Args, + unsigned NumArgs) { + unsigned ArgIdx = 0; + while (ArgIdx < NumArgs) { + const TemplateArgument &Arg = Args[ArgIdx]; + + // Unwrap argument packs. + if (Args[ArgIdx].getKind() == TemplateArgument::Pack) { + Args = Arg.pack_begin(); + NumArgs = Arg.pack_size(); + ArgIdx = 0; + continue; + } + + ++ArgIdx; + if (ArgIdx == NumArgs) + return false; + + if (Arg.isPackExpansion()) + return true; + } + + return false; +} + static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, @@ -1071,9 +1098,9 @@ DeduceTemplateArguments(Sema &S, // If the template argument list of P contains a pack expansion that is not // the last template argument, the entire template argument list is a // non-deduced context. - // FIXME: Implement this. - - + if (hasPackExpansionBeforeEnd(Params, NumParams)) + return Sema::TDK_Success; + // C++0x [temp.deduct.type]p9: // If P has a form that contains or , then each argument Pi of the // respective template argument list P is compared with the corresponding @@ -3052,6 +3079,15 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, = cast(T); MarkUsedTemplateParameters(SemaRef, Spec->getTemplateName(), OnlyDeduced, Depth, Used); + + // C++0x [temp.deduct.type]p9: + // If the template argument list of P contains a pack expansion that is not + // the last template argument, the entire template argument list is a + // non-deduced context. + if (OnlyDeduced && + hasPackExpansionBeforeEnd(Spec->getArgs(), Spec->getNumArgs())) + break; + for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Depth, Used); @@ -3078,6 +3114,15 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, if (!OnlyDeduced) MarkUsedTemplateParameters(SemaRef, Spec->getQualifier(), OnlyDeduced, Depth, Used); + + // C++0x [temp.deduct.type]p9: + // If the template argument list of P contains a pack expansion that is not + // the last template argument, the entire template argument list is a + // non-deduced context. + if (OnlyDeduced && + hasPackExpansionBeforeEnd(Spec->getArgs(), Spec->getNumArgs())) + break; + for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Depth, Used); @@ -3181,6 +3226,14 @@ void Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, unsigned Depth, llvm::SmallVectorImpl &Used) { + // C++0x [temp.deduct.type]p9: + // If the template argument list of P contains a pack expansion that is not + // the last template argument, the entire template argument list is a + // non-deduced context. + if (OnlyDeduced && + hasPackExpansionBeforeEnd(TemplateArgs.data(), TemplateArgs.size())) + return; + for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, Depth, Used); @@ -3196,6 +3249,7 @@ Sema::MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, Deduced.clear(); Deduced.resize(TemplateParams->size()); + // FIXME: Variadic templates. FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I) ::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(), diff --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp index ad8a81c1dea2..198f11fe5298 100644 --- a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp +++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp @@ -18,6 +18,6 @@ struct same_tuple, tuple > { static const bool value = true; }; -//int same_tuple_check1[same_tuple, tuple>::value? -1 : 1]; +int same_tuple_check1[same_tuple, tuple>::value? -1 : 1]; int same_tuple_check2[same_tuple, tuple>::value? 1 : -1]; diff --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp new file mode 100644 index 000000000000..ebfcd3808e6d --- /dev/null +++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +template struct tuple; + +namespace PackExpansionNotAtEnd { + template + struct tuple_same_with_int { + static const bool value = false; + }; + + template + struct tuple_same_with_int, tuple> { + static const bool value = true; + }; + + int tuple_same_with_int_1[tuple_same_with_int, + tuple + >::value? 1 : -1]; + + template struct UselessPartialSpec; + + template // expected-note{{non-deducible template parameter 'Tail'}} + struct UselessPartialSpec; // expected-warning{{class template partial specialization contains template parameters that can not be deduced; this partial specialization will never be used}} +}