forked from OSchip/llvm-project
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:
parent
4ca97c3b9e
commit
91772d1d76
|
@ -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">;
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
|
|
Loading…
Reference in New Issue