diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-12-23 01:24:45 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-12-23 01:24:45 +0000 |
commit | 7b976ece336d209977b25b5c28ee09c2d2146e6a (patch) | |
tree | 6cab951effd2c0c8c5d0435c35eccf29bdd5d6eb | |
parent | c6ed729f669044f5072a49d79041f455d971ece3 (diff) |
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122461 91177308-0d34-0410-b5e6-96231b3b80d8
3 files changed, 83 insertions, 4 deletions
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 79cbc5ab02..ad649c067c 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -1059,6 +1059,33 @@ static TemplateParameter makeTemplateParameter(Decl *D) { return TemplateParameter(cast<TemplateTemplateParmDecl>(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 <T> or <i>, 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<TemplateSpecializationType>(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<bool> &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/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp index ad8a81c1de..198f11fe52 100644 --- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp +++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp @@ -18,6 +18,6 @@ struct same_tuple<tuple<Types1...>, tuple<Types1...> > { static const bool value = true; }; -//int same_tuple_check1[same_tuple<tuple<int, float>, tuple<int, double>>::value? -1 : 1]; +int same_tuple_check1[same_tuple<tuple<int, float>, tuple<int, double>>::value? -1 : 1]; int same_tuple_check2[same_tuple<tuple<float, double>, tuple<float, double>>::value? 1 : -1]; diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp new file mode 100644 index 0000000000..ebfcd3808e --- /dev/null +++ b/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<typename ...Types> struct tuple; + +namespace PackExpansionNotAtEnd { + template<typename T, typename U> + struct tuple_same_with_int { + static const bool value = false; + }; + + template<typename ...Types> + struct tuple_same_with_int<tuple<Types...>, tuple<Types..., int>> { + static const bool value = true; + }; + + int tuple_same_with_int_1[tuple_same_with_int<tuple<int, float, double>, + tuple<int, float, double, int> + >::value? 1 : -1]; + + template<typename ... Types> struct UselessPartialSpec; + + template<typename ... Types, // expected-note{{non-deducible template parameter 'Types'}} + typename Tail> // expected-note{{non-deducible template parameter 'Tail'}} + struct UselessPartialSpec<Types..., Tail>; // expected-warning{{class template partial specialization contains template parameters that can not be deduced; this partial specialization will never be used}} +} |