From: Douglas Gregor Date: Mon, 3 Jan 2011 21:13:47 +0000 (+0000) Subject: Unwrap template argument packs when checking the template arguments of X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bacb9493770ff19cfd8f7bc46a075f14b4d08159;p=clang Unwrap template argument packs when checking the template arguments of a class template partial specialiation, and look through pack expansions when checking the conditions of C++0x [temp.class.spec]p8. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122774 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 2d349bc34c..b5dfe0a480 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2910,10 +2910,6 @@ public: bool EnteringContext, TemplateTy &Template); - bool CheckClassTemplatePartialSpecializationArgs( - TemplateParameterList *TemplateParams, - llvm::SmallVectorImpl &TemplateArgs); - DeclResult ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 6384e53e80..c3cfbb8c25 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3915,34 +3915,31 @@ static bool CheckTemplateSpecializationScope(Sema &S, return false; } - -/// \brief Check the non-type template arguments of a class template -/// partial specialization according to C++ [temp.class.spec]p9. -/// -/// \param TemplateParams the template parameters of the primary class -/// template. -/// -/// \param TemplateArg the template arguments of the class template -/// partial specialization. -/// -/// \returns true if there was an error, false otherwise. -bool Sema::CheckClassTemplatePartialSpecializationArgs( - TemplateParameterList *TemplateParams, - llvm::SmallVectorImpl &TemplateArgs) { - const TemplateArgument *ArgList = TemplateArgs.data(); - - for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { - NonTypeTemplateParmDecl *Param - = dyn_cast(TemplateParams->getParam(I)); - if (!Param) + +/// \brief Subroutine of Sema::CheckClassTemplatePartialSpecializationArgs +/// that checks non-type template partial specialization arguments. +static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S, + NonTypeTemplateParmDecl *Param, + const TemplateArgument *Args, + unsigned NumArgs) { + for (unsigned I = 0; I != NumArgs; ++I) { + if (Args[I].getKind() == TemplateArgument::Pack) { + if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param, + Args[I].pack_begin(), + Args[I].pack_size())) + return true; + continue; - - Expr *ArgExpr = ArgList[I].getAsExpr(); + } + + Expr *ArgExpr = Args[I].getAsExpr(); if (!ArgExpr) { continue; } - // FIXME: Variadic templates. Unwrap argument packs. + // We can have a pack expansion of any of the above. + if (PackExpansionExpr *Expansion = dyn_cast(ArgExpr)) + ArgExpr = Expansion->getPattern(); // C++ [temp.class.spec]p8: // A non-type argument is non-specialized if it is the name of a @@ -3964,24 +3961,53 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs( // specialization except when the argument expression is a // simple identifier. if (ArgExpr->isTypeDependent() || ArgExpr->isValueDependent()) { - Diag(ArgExpr->getLocStart(), + S.Diag(ArgExpr->getLocStart(), diag::err_dependent_non_type_arg_in_partial_spec) << ArgExpr->getSourceRange(); return true; } - + // -- The type of a template parameter corresponding to a // specialized non-type argument shall not be dependent on a // parameter of the specialization. if (Param->getType()->isDependentType()) { - Diag(ArgExpr->getLocStart(), + S.Diag(ArgExpr->getLocStart(), diag::err_dependent_typed_non_type_arg_in_partial_spec) << Param->getType() << ArgExpr->getSourceRange(); - Diag(Param->getLocation(), diag::note_template_param_here); + S.Diag(Param->getLocation(), diag::note_template_param_here); return true; } } + + return false; +} + +/// \brief Check the non-type template arguments of a class template +/// partial specialization according to C++ [temp.class.spec]p9. +/// +/// \param TemplateParams the template parameters of the primary class +/// template. +/// +/// \param TemplateArg the template arguments of the class template +/// partial specialization. +/// +/// \returns true if there was an error, false otherwise. +static bool CheckClassTemplatePartialSpecializationArgs(Sema &S, + TemplateParameterList *TemplateParams, + llvm::SmallVectorImpl &TemplateArgs) { + const TemplateArgument *ArgList = TemplateArgs.data(); + + for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { + NonTypeTemplateParmDecl *Param + = dyn_cast(TemplateParams->getParam(I)); + if (!Param) + continue; + + if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param, + &ArgList[I], 1)) + return true; + } return false; } @@ -4145,7 +4171,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Find the class template (partial) specialization declaration that // corresponds to these arguments. if (isPartialSpecialization) { - if (CheckClassTemplatePartialSpecializationArgs( + if (CheckClassTemplatePartialSpecializationArgs(*this, ClassTemplate->getTemplateParameters(), Converted)) return true; diff --git a/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp b/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp new file mode 100644 index 0000000000..14152cf339 --- /dev/null +++ b/test/CXX/temp/temp.decls/temp.class.spec/p8-0x.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +template struct X1; + +template +struct X1<0, Values+1 ...>; // expected-error{{non-type template argument depends on a template parameter of the partial specialization}} + +