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.

llvm-svn: 73274
This commit is contained in:
Douglas Gregor 2009-06-13 00:26:55 +00:00
parent 4ca97c3b9e
commit 91772d1d76
5 changed files with 221 additions and 3 deletions

View File

@ -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">;

View File

@ -2163,7 +2163,10 @@ public:
DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentList &TemplateArgs,
TemplateDeductionInfo &Info);
void MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs,
llvm::SmallVectorImpl<bool> &Deduced);
//===--------------------------------------------------------------------===//
// C++ Template Instantiation
//

View File

@ -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<TemplateParameterList*>(*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<bool, 8> 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<NamedDecl>(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("<anonymous>");
}
}
}
} else {
// Create a new class template specialization declaration node for
// this explicit specialization.

View File

@ -881,3 +881,178 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
return TDK_Success;
}
static void
MarkDeducedTemplateParameters(Sema &SemaRef,
const TemplateArgument &TemplateArg,
llvm::SmallVectorImpl<bool> &Deduced);
/// \brief Mark the template arguments that are deduced by the given
/// expression.
static void
MarkDeducedTemplateParameters(Expr *E, llvm::SmallVectorImpl<bool> &Deduced) {
DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
if (!E)
return;
NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(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<bool> &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<ExtQualType>(T.getTypePtr())->getBaseType(), 0),
Deduced);
break;
case Type::Pointer:
MarkDeducedTemplateParameters(SemaRef,
cast<PointerType>(T.getTypePtr())->getPointeeType(),
Deduced);
break;
case Type::BlockPointer:
MarkDeducedTemplateParameters(SemaRef,
cast<BlockPointerType>(T.getTypePtr())->getPointeeType(),
Deduced);
break;
case Type::LValueReference:
case Type::RValueReference:
MarkDeducedTemplateParameters(SemaRef,
cast<ReferenceType>(T.getTypePtr())->getPointeeType(),
Deduced);
break;
case Type::MemberPointer: {
const MemberPointerType *MemPtr = cast<MemberPointerType>(T.getTypePtr());
MarkDeducedTemplateParameters(SemaRef, MemPtr->getPointeeType(), Deduced);
MarkDeducedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0),
Deduced);
break;
}
case Type::DependentSizedArray:
MarkDeducedTemplateParameters(
cast<DependentSizedArrayType>(T.getTypePtr())->getSizeExpr(),
Deduced);
// Fall through to check the element type
case Type::ConstantArray:
case Type::IncompleteArray:
MarkDeducedTemplateParameters(SemaRef,
cast<ArrayType>(T.getTypePtr())->getElementType(),
Deduced);
break;
case Type::Vector:
case Type::ExtVector:
MarkDeducedTemplateParameters(SemaRef,
cast<VectorType>(T.getTypePtr())->getElementType(),
Deduced);
break;
case Type::FunctionProto: {
const FunctionProtoType *Proto = cast<FunctionProtoType>(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<TemplateTypeParmType>(T.getTypePtr())->getIndex()] = true;
break;
case Type::TemplateSpecialization: {
const TemplateSpecializationType *Spec
= cast<TemplateSpecializationType>(T.getTypePtr());
if (TemplateDecl *Template = Spec->getTemplateName().getAsTemplateDecl())
if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(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<bool> &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<TemplateTemplateParmDecl>(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<bool> &Deduced) {
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
::MarkDeducedTemplateParameters(*this, TemplateArgs[I], Deduced);
}

View File

@ -39,3 +39,7 @@ template<typename T = int, // expected-error{{default template argument}}
int N = 17, // expected-error{{default template argument}}
template<typename X> class TT = ::vector> // expected-error{{default template argument}}
struct Test0<T*, N, TT> { };
template<typename T> struct Test1;
template<typename T, typename U> // expected-note{{non-deducible}}
struct Test1<T*> { }; // expected-warning{{never be used}}