From: Douglas Gregor Date: Sat, 13 Jun 2009 00:26:55 +0000 (+0000) Subject: When some template parameters of a class template partial X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=031a5880e19d06624551aed9d74594356f4f9db1;p=clang When some template parameters of a class template partial specialization cannot be deduced, produce a warning noting that the affected class template partial specialization will never be used. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73274 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 5780959058..26c5fc80b8 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -770,6 +770,12 @@ def err_partial_spec_args_match_primary_template : Error< "class template partial specialization does not specialize any template " "argument; to %select{declare|define}0 the primary template, remove the " "template argument list">; +def warn_partial_specs_not_deducible : Warning< + "class template partial specialization contains " + "%select{a template parameter|template parameters}0 that can not be " + "deduced; this partial specialization will never be used">; +def note_partial_spec_unused_parameter : Note< + "non-deducible template parameter %0">; def unsup_template_partial_spec_ordering : Error< "partial ordering of class template partial specializations is not yet " "supported">; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 7e32c11129..d77036ff36 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2163,7 +2163,10 @@ public: DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, TemplateDeductionInfo &Info); - + + void MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs, + llvm::SmallVectorImpl &Deduced); + //===--------------------------------------------------------------------===// // C++ Template Instantiation // diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 54c61f6cd9..78c1a9a97a 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2328,8 +2328,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, Specialization->setLocation(TemplateNameLoc); PrevDecl = 0; } else if (isPartialSpecialization) { - // FIXME: extra checking for partial specializations - // Create a new class template partial specialization declaration node. TemplateParameterList *TemplateParams = static_cast(*TemplateParameterLists.get()); @@ -2351,6 +2349,38 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, ClassTemplate->getPartialSpecializations().InsertNode(Partial, InsertPos); } Specialization = Partial; + + // Check that all of the template parameters of the class template + // partial specialization are deducible from the template + // arguments. If not, this class template partial specialization + // will never be used. + llvm::SmallVector DeducibleParams; + DeducibleParams.resize(TemplateParams->size()); + MarkDeducedTemplateParameters(Partial->getTemplateArgs(), DeducibleParams); + unsigned NumNonDeducible = 0; + for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) + if (!DeducibleParams[I]) + ++NumNonDeducible; + + if (NumNonDeducible) { + Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible) + << (NumNonDeducible > 1) + << SourceRange(TemplateNameLoc, RAngleLoc); + for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { + if (!DeducibleParams[I]) { + NamedDecl *Param = cast(TemplateParams->getParam(I)); + if (Param->getDeclName()) + Diag(Param->getLocation(), + diag::note_partial_spec_unused_parameter) + << Param->getDeclName(); + else + Diag(Param->getLocation(), + diag::note_partial_spec_unused_parameter) + << std::string(""); + } + } + } + } else { // Create a new class template specialization declaration node for // this explicit specialization. diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 4bbfd048c2..d34019e36c 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -881,3 +881,178 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, return TDK_Success; } + +static void +MarkDeducedTemplateParameters(Sema &SemaRef, + const TemplateArgument &TemplateArg, + llvm::SmallVectorImpl &Deduced); + +/// \brief Mark the template arguments that are deduced by the given +/// expression. +static void +MarkDeducedTemplateParameters(Expr *E, llvm::SmallVectorImpl &Deduced) { + DeclRefExpr *DRE = dyn_cast(E); + if (!E) + return; + + NonTypeTemplateParmDecl *NTTP + = dyn_cast(DRE->getDecl()); + if (!NTTP) + return; + + Deduced[NTTP->getIndex()] = true; +} + +/// \brief Mark the template parameters that are deduced by the given +/// type. +static void +MarkDeducedTemplateParameters(Sema &SemaRef, QualType T, + llvm::SmallVectorImpl &Deduced) { + // Non-dependent types have nothing deducible + if (!T->isDependentType()) + return; + + T = SemaRef.Context.getCanonicalType(T); + switch (T->getTypeClass()) { + case Type::ExtQual: + MarkDeducedTemplateParameters(SemaRef, + QualType(cast(T.getTypePtr())->getBaseType(), 0), + Deduced); + break; + + case Type::Pointer: + MarkDeducedTemplateParameters(SemaRef, + cast(T.getTypePtr())->getPointeeType(), + Deduced); + break; + + case Type::BlockPointer: + MarkDeducedTemplateParameters(SemaRef, + cast(T.getTypePtr())->getPointeeType(), + Deduced); + break; + + case Type::LValueReference: + case Type::RValueReference: + MarkDeducedTemplateParameters(SemaRef, + cast(T.getTypePtr())->getPointeeType(), + Deduced); + break; + + case Type::MemberPointer: { + const MemberPointerType *MemPtr = cast(T.getTypePtr()); + MarkDeducedTemplateParameters(SemaRef, MemPtr->getPointeeType(), Deduced); + MarkDeducedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0), + Deduced); + break; + } + + case Type::DependentSizedArray: + MarkDeducedTemplateParameters( + cast(T.getTypePtr())->getSizeExpr(), + Deduced); + // Fall through to check the element type + + case Type::ConstantArray: + case Type::IncompleteArray: + MarkDeducedTemplateParameters(SemaRef, + cast(T.getTypePtr())->getElementType(), + Deduced); + break; + + case Type::Vector: + case Type::ExtVector: + MarkDeducedTemplateParameters(SemaRef, + cast(T.getTypePtr())->getElementType(), + Deduced); + break; + + case Type::FunctionProto: { + const FunctionProtoType *Proto = cast(T.getTypePtr()); + MarkDeducedTemplateParameters(SemaRef, Proto->getResultType(), Deduced); + for (unsigned I = 0, N = Proto->getNumArgs(); I != N; ++I) + MarkDeducedTemplateParameters(SemaRef, Proto->getArgType(I), Deduced); + break; + } + + case Type::TemplateTypeParm: + Deduced[cast(T.getTypePtr())->getIndex()] = true; + break; + + case Type::TemplateSpecialization: { + const TemplateSpecializationType *Spec + = cast(T.getTypePtr()); + if (TemplateDecl *Template = Spec->getTemplateName().getAsTemplateDecl()) + if (TemplateTemplateParmDecl *TTP + = dyn_cast(Template)) + Deduced[TTP->getIndex()] = true; + + for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) + MarkDeducedTemplateParameters(SemaRef, Spec->getArg(I), Deduced); + + break; + } + + // None of these types have any deducible parts. + case Type::Builtin: + case Type::FixedWidthInt: + case Type::Complex: + case Type::VariableArray: + case Type::FunctionNoProto: + case Type::Record: + case Type::Enum: + case Type::Typename: + case Type::ObjCInterface: + case Type::ObjCQualifiedInterface: + case Type::ObjCQualifiedId: +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) +#define NON_CANONICAL_TYPE(Class, Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + break; + } +} + +/// \brief Mark the template parameters that are deduced by this +/// template argument. +static void +MarkDeducedTemplateParameters(Sema &SemaRef, + const TemplateArgument &TemplateArg, + llvm::SmallVectorImpl &Deduced) { + switch (TemplateArg.getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Integral: + break; + + case TemplateArgument::Type: + MarkDeducedTemplateParameters(SemaRef, TemplateArg.getAsType(), Deduced); + break; + + case TemplateArgument::Declaration: + if (TemplateTemplateParmDecl *TTP + = dyn_cast(TemplateArg.getAsDecl())) + Deduced[TTP->getIndex()] = true; + break; + + case TemplateArgument::Expression: + MarkDeducedTemplateParameters(TemplateArg.getAsExpr(), Deduced); + break; + } +} + +/// \brief Mark the template parameters can be deduced by the given +/// template argument list. +/// +/// \param TemplateArgs the template argument list from which template +/// parameters will be deduced. +/// +/// \param Deduced a bit vector whose elements will be set to \c true +/// to indicate when the corresponding template parameter will be +/// deduced. +void +Sema::MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs, + llvm::SmallVectorImpl &Deduced) { + for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) + ::MarkDeducedTemplateParameters(*this, TemplateArgs[I], Deduced); +} diff --git a/test/SemaTemplate/temp_class_spec_neg.cpp b/test/SemaTemplate/temp_class_spec_neg.cpp index b9a12cb4de..b50bd8f634 100644 --- a/test/SemaTemplate/temp_class_spec_neg.cpp +++ b/test/SemaTemplate/temp_class_spec_neg.cpp @@ -39,3 +39,7 @@ template class TT = ::vector> // expected-error{{default template argument}} struct Test0 { }; + +template struct Test1; +template // expected-note{{non-deducible}} + struct Test1 { }; // expected-warning{{never be used}}