static bool classof(const Decl *D) {
return D->getKind() == CXXRecord ||
- D->getKind() == ClassTemplateSpecialization;
+ D->getKind() == ClassTemplateSpecialization ||
+ D->getKind() == ClassTemplatePartialSpecialization;
}
static bool classof(const CXXRecordDecl *D) { return true; }
static bool classof(const ClassTemplateSpecializationDecl *D) {
DECL(Record, TagDecl)
DECL(CXXRecord, RecordDecl)
DECL(ClassTemplateSpecialization, CXXRecordDecl)
+ DECL(ClassTemplatePartialSpecialization,
+ ClassTemplateSpecializationDecl)
DECL(TemplateTypeParm, TypeDecl)
ABSTRACT_DECL(Value, NamedDecl)
DECL(EnumConstant, ValueDecl)
DECL_RANGE(ObjCContainer, ObjCContainer, ObjCInterface)
DECL_RANGE(Field, Field, ObjCAtDefsField)
DECL_RANGE(Type, Typedef, TemplateTypeParm)
-DECL_RANGE(Tag, Enum, ClassTemplateSpecialization)
-DECL_RANGE(Record, Record, ClassTemplateSpecialization)
+DECL_RANGE(Tag, Enum, ClassTemplatePartialSpecialization)
+DECL_RANGE(Record, Record, ClassTemplatePartialSpecialization)
DECL_RANGE(Value, EnumConstant, NonTypeTemplateParm)
DECL_RANGE(Function, Function, CXXConversion)
DECL_RANGE(Template, Template, TemplateTemplateParm)
class TemplateDecl;
class FunctionTemplateDecl;
class ClassTemplateDecl;
+class ClassTemplatePartialSpecializationDecl;
class TemplateTypeParmDecl;
class NonTypeTemplateParmDecl;
class TemplateTemplateParmDecl;
/// has not yet been declared, defined, or instantiated.
TSK_Undeclared = 0,
/// This template specialization was declared or defined by an
- /// explicit specialization (C++ [temp.expl.spec]).
+ /// explicit specialization (C++ [temp.expl.spec]) or partial
+ /// specialization (C++ [temp.class.spec]).
TSK_ExplicitSpecialization,
/// This template specialization was implicitly instantiated from a
/// template. (C++ [temp.inst]).
/// Really a value of type TemplateSpecializationKind.
unsigned SpecializationKind : 2;
- ClassTemplateSpecializationDecl(ASTContext &Context,
+protected:
+ ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgument *TemplateArgs,
SpecializationKind = TSK;
}
- void Profile(llvm::FoldingSetNodeID &ID) const {
- Profile(ID, TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size());
- }
-
/// \brief Sets the type of this specialization as it was written by
/// the user. This will be a class template specialization type.
void setTypeAsWritten(QualType T) {
TypeForDecl = T.getTypePtr();
}
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Profile(ID, TemplateArgs.getFlatArgumentList(), TemplateArgs.flat_size());
+ }
+
static void
Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
}
static bool classof(const Decl *D) {
- return D->getKind() == ClassTemplateSpecialization;
+ return D->getKind() == ClassTemplateSpecialization ||
+ D->getKind() == ClassTemplatePartialSpecialization;
}
static bool classof(const ClassTemplateSpecializationDecl *) {
return true;
}
+
+ static bool classof(const ClassTemplatePartialSpecializationDecl *) {
+ return true;
+ }
+};
+
+class ClassTemplatePartialSpecializationDecl
+ : public ClassTemplateSpecializationDecl
+{
+ /// \brief The list of template parameters
+ TemplateParameterList* TemplateParams;
+
+ ClassTemplatePartialSpecializationDecl(ASTContext &Context,
+ DeclContext *DC, SourceLocation L,
+ TemplateParameterList *Params,
+ ClassTemplateDecl *SpecializedTemplate,
+ TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs)
+ : ClassTemplateSpecializationDecl(Context, ClassTemplatePartialSpecialization,
+ DC, L, SpecializedTemplate, TemplateArgs,
+ NumTemplateArgs),
+ TemplateParams(Params) { }
+
+public:
+ static ClassTemplatePartialSpecializationDecl *
+ Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
+ TemplateParameterList *Params,
+ ClassTemplateDecl *SpecializedTemplate,
+ TemplateArgument *TemplateArgs, unsigned NumTemplateArgs,
+ ClassTemplatePartialSpecializationDecl *PrevDecl);
+
+ /// Get the list of template parameters
+ TemplateParameterList *getTemplateParameters() const {
+ return TemplateParams;
+ }
+
+ // FIXME: Add Profile support!
+
+ static bool classof(const Decl *D) {
+ return D->getKind() == ClassTemplatePartialSpecialization;
+ }
+
+ static bool classof(const ClassTemplatePartialSpecializationDecl *) {
+ return true;
+ }
};
/// Declaration of a class template.
/// template, including explicit specializations and instantiations.
llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations;
+ /// \brief The class template partial specializations for this class
+ /// template.
+ llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>
+ PartialSpecializations;
+
/// \brief The injected-class-name type for this class template.
QualType InjectedClassNameType;
};
return CommonPtr->Specializations;
}
+ /// \brief Retrieve the set of partial specializations of this class
+ /// template.
+ llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &
+ getPartialSpecializations() {
+ return CommonPtr->PartialSpecializations;
+ }
+
/// \brief Retrieve the type of the injected-class-name for this
/// class template.
///
"template specialization requires 'template<>'">;
def err_template_spec_extra_headers : Error<
"template specialization must have a single 'template<>' header">;
-def unsup_template_partial_spec : Error<
- "class template partial specialization is not yet supported">;
+def unsup_template_partial_spec_ordering : Error<
+ "partial ordering of class template partial specializations is not yet "
+ "supported">;
def err_template_spec_decl_out_of_scope_global : Error<
"class template specialization of %0 must occur in the global scope">;
def err_template_spec_decl_out_of_scope : Error<
// Aren't looked up?
case UsingDirective:
case ClassTemplateSpecialization:
+ case ClassTemplatePartialSpecialization:
return 0;
}
}
if (isFileContext())
return false;
+ if (isa<ClassTemplatePartialSpecializationDecl>(this))
+ return true;
+
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this))
if (Record->getDescribedClassTemplate())
return true;
// ClassTemplateSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
ClassTemplateSpecializationDecl::
-ClassTemplateSpecializationDecl(ASTContext &Context,
+ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK,
DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs)
- : CXXRecordDecl(ClassTemplateSpecialization,
+ : CXXRecordDecl(DK,
SpecializedTemplate->getTemplatedDecl()->getTagKind(),
DC, L,
// FIXME: Should we use DeclarationName for the name of
unsigned NumTemplateArgs,
ClassTemplateSpecializationDecl *PrevDecl) {
ClassTemplateSpecializationDecl *Result
- = new (Context)ClassTemplateSpecializationDecl(Context, DC, L,
+ = new (Context)ClassTemplateSpecializationDecl(Context,
+ ClassTemplateSpecialization,
+ DC, L,
SpecializedTemplate,
TemplateArgs,
NumTemplateArgs);
Context.getTypeDeclType(Result, PrevDecl);
return Result;
}
+
+//===----------------------------------------------------------------------===//
+// ClassTemplatePartialSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+ClassTemplatePartialSpecializationDecl *
+ClassTemplatePartialSpecializationDecl::
+Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
+ TemplateParameterList *Params,
+ ClassTemplateDecl *SpecializedTemplate,
+ TemplateArgument *TemplateArgs, unsigned NumTemplateArgs,
+ ClassTemplatePartialSpecializationDecl *PrevDecl) {
+ ClassTemplatePartialSpecializationDecl *Result
+ = new (Context)ClassTemplatePartialSpecializationDecl(Context,
+ DC, L, Params,
+ SpecializedTemplate,
+ TemplateArgs,
+ NumTemplateArgs);
+ Result->setSpecializationKind(TSK_ExplicitSpecialization);
+ Context.getTypeDeclType(Result, PrevDecl);
+ return Result;
+}
class TemplateArgumentList;
class TemplateParameterList;
class TemplateTemplateParmDecl;
+ class ClassTemplatePartialSpecializationDecl;
class ClassTemplateDecl;
class ObjCInterfaceDecl;
class ObjCCompatibleAliasDecl;
QualType CheckTypenameType(NestedNameSpecifier *NNS,
const IdentifierInfo &II,
SourceRange Range);
+
+ bool DeduceTemplateArguments(QualType Param, QualType Arg,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced);
+ bool DeduceTemplateArguments(const TemplateArgument &Param,
+ const TemplateArgument &Arg,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced);
+ bool DeduceTemplateArguments(const TemplateArgumentList &ParamList,
+ const TemplateArgumentList &ArgList,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced);
+ bool DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
+ const TemplateArgumentList &TemplateArgs);
//===--------------------------------------------------------------------===//
// C++ Template Instantiation
ClassTemplateDecl *ClassTemplate
= cast<ClassTemplateDecl>(Name.getAsTemplateDecl());
+ bool isPartialSpecialization = false;
+
// Check the validity of the template headers that introduce this
// template.
// FIXME: Once we have member templates, we'll need to check
return true;
}
- if (TemplateParams->size() > 0) {
- // FIXME: No support for class template partial specialization.
- Diag(TemplateParams->getTemplateLoc(), diag::unsup_template_partial_spec);
- return true;
- }
+ // FIXME: We'll need more checks, here!
+ if (TemplateParams->size() > 0)
+ isPartialSpecialization = true;
}
// Check that the specialization uses the same tag kind as the
ClassTemplate->getTemplateParameters()->size()) &&
"Converted template argument list is too short!");
- // Find the class template specialization declaration that
+ // Find the class template (partial) specialization declaration that
// corresponds to these arguments.
llvm::FoldingSetNodeID ID;
- ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0],
- ConvertedTemplateArgs.size());
+ if (isPartialSpecialization)
+ // FIXME: Template parameter list matters, too
+ ClassTemplatePartialSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size());
+ else
+ ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size());
void *InsertPos = 0;
- ClassTemplateSpecializationDecl *PrevDecl
- = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
+ ClassTemplateSpecializationDecl *PrevDecl = 0;
+
+ if (isPartialSpecialization)
+ PrevDecl
+ = ClassTemplate->getPartialSpecializations().FindNodeOrInsertPos(ID,
+ InsertPos);
+ else
+ PrevDecl
+ = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
ClassTemplateSpecializationDecl *Specialization = 0;
Specialization = PrevDecl;
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());
+ ClassTemplatePartialSpecializationDecl *PrevPartial
+ = cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl);
+ ClassTemplatePartialSpecializationDecl *Partial
+ = ClassTemplatePartialSpecializationDecl::Create(Context,
+ ClassTemplate->getDeclContext(),
+ TemplateNameLoc,
+ TemplateParams,
+ ClassTemplate,
+ &ConvertedTemplateArgs[0],
+ ConvertedTemplateArgs.size(),
+ PrevPartial);
+
+ if (PrevPartial) {
+ ClassTemplate->getPartialSpecializations().RemoveNode(PrevPartial);
+ ClassTemplate->getPartialSpecializations().GetOrInsertNode(Partial);
+ } else {
+ ClassTemplate->getPartialSpecializations().InsertNode(Partial, InsertPos);
+ }
+ Specialization = Partial;
} else {
// Create a new class template specialization declaration node for
// this explicit specialization.
// instantiation with a special diagnostic.
SourceRange Range(TemplateNameLoc, RAngleLoc);
Diag(TemplateNameLoc, diag::err_redefinition)
- << Specialization << Range;
+ << Context.getTypeDeclType(Specialization) << Range;
Diag(Def->getLocation(), diag::note_previous_definition);
Specialization->setInvalidDecl();
return true;
<< Name;
return QualType();
}
+
+// FIXME: Move to SemaTemplateDeduction.cpp
+bool
+Sema::DeduceTemplateArguments(QualType Param, QualType Arg,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ // We only want to look at the canonical types, since typedefs and
+ // sugar are not part of template argument deduction.
+ Param = Context.getCanonicalType(Param);
+ Arg = Context.getCanonicalType(Arg);
+
+ // If the parameter type is not dependent, just compare the types
+ // directly.
+ if (!Param->isDependentType())
+ return Param == Arg;
+
+ // FIXME: Use a visitor or switch to handle all of the kinds of
+ // types that the parameter may be.
+ if (const TemplateTypeParmType *TemplateTypeParm
+ = Param->getAsTemplateTypeParmType()) {
+ (void)TemplateTypeParm; // FIXME: use this
+ // The argument type can not be less qualified than the parameter
+ // type.
+ if (Param.isMoreQualifiedThan(Arg))
+ return false;
+
+ unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers();
+ QualType DeducedType = Arg.getQualifiedType(Quals);
+ // FIXME: actually save the deduced type, and check that this
+ // deduction is consistent.
+ return true;
+ }
+
+ if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
+ return false;
+
+ if (const PointerType *PointerParam = Param->getAsPointerType()) {
+ const PointerType *PointerArg = Arg->getAsPointerType();
+ if (!PointerArg)
+ return false;
+
+ return DeduceTemplateArguments(PointerParam->getPointeeType(),
+ PointerArg->getPointeeType(),
+ Deduced);
+ }
+
+ // FIXME: Many more cases to go (to go).
+ return false;
+}
+
+bool
+Sema::DeduceTemplateArguments(const TemplateArgument &Param,
+ const TemplateArgument &Arg,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ assert(Param.getKind() == Arg.getKind() &&
+ "Template argument kind mismatch during deduction");
+ switch (Param.getKind()) {
+ case TemplateArgument::Type:
+ return DeduceTemplateArguments(Param.getAsType(), Arg.getAsType(),
+ Deduced);
+
+ default:
+ return false;
+ }
+}
+
+bool
+Sema::DeduceTemplateArguments(const TemplateArgumentList &ParamList,
+ const TemplateArgumentList &ArgList,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ assert(ParamList.size() == ArgList.size());
+ for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
+ if (!DeduceTemplateArguments(ParamList[I], ArgList[I], Deduced))
+ return false;
+ }
+ return true;
+}
+
+
+bool
+Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
+ const TemplateArgumentList &TemplateArgs) {
+ llvm::SmallVector<TemplateArgument, 4> Deduced;
+ Deduced.resize(Partial->getTemplateParameters()->size());
+ return DeduceTemplateArguments(Partial->getTemplateArgs(), TemplateArgs,
+ Deduced);
+}
if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared)
return true;
- // FIXME: Push this class template instantiation onto the instantiation stack,
- // checking for recursion that exceeds a certain depth.
-
- // FIXME: Perform class template partial specialization to select the best
- // template.
ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
-
CXXRecordDecl *Pattern = Template->getTemplatedDecl();
+ const TemplateArgumentList *TemplateArgs
+ = &ClassTemplateSpec->getTemplateArgs();
+
+ // Determine whether any class template partial specializations
+ // match the given template arguments.
+ llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> Matched;
+ for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
+ Partial = Template->getPartialSpecializations().begin(),
+ PartialEnd = Template->getPartialSpecializations().end();
+ Partial != PartialEnd;
+ ++Partial) {
+ if (DeduceTemplateArguments(&*Partial, ClassTemplateSpec->getTemplateArgs()))
+ Matched.push_back(&*Partial);
+ }
+
+ if (Matched.size() == 1) {
+ Pattern = Matched[0];
+ // FIXME: set TemplateArgs to the template arguments of the
+ // partial specialization, instantiated with the deduced template
+ // arguments.
+ } else if (Matched.size() > 1) {
+ // FIXME: Implement partial ordering of class template partial
+ // specializations.
+ Diag(ClassTemplateSpec->getLocation(),
+ diag::unsup_template_partial_spec_ordering);
+ }
// Note that this is an instantiation.
ClassTemplateSpec->setSpecializationKind(
: TSK_ImplicitInstantiation);
return InstantiateClass(ClassTemplateSpec->getLocation(),
- ClassTemplateSpec, Pattern,
- ClassTemplateSpec->getTemplateArgs(),
+ ClassTemplateSpec, Pattern, *TemplateArgs,
ExplicitInstantiation);
}
// Diagnose specialization errors
struct A<double> { }; // expected-error{{template specialization requires 'template<>'}}
-template<typename T> // expected-error{{class template partial specialization is not yet supported}}
-struct A<T*> { };
-
template<> struct ::A<double>;
namespace N {
Def2<int_ref_t> *d2; // expected-note{{in instantiation of default argument for 'Def2<int &>' required here}}
-template<> struct Def1<const int, const int> { }; // expected-error{{redefinition of 'Def1'}}
+template<> struct Def1<const int, const int> { }; // expected-error{{redefinition of 'Def1<int const>'}}
template<typename T, typename T2 = T&> struct Def3;
--- /dev/null
+// RUN: clang-cc -fsyntax-only -verify %s
+template<typename T>
+struct is_pointer {
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_pointer<T*> {
+ static const bool value = true;
+};
+
+template<typename T>
+struct is_pointer<const T*> {
+ static const bool value = true;
+};
+
+int array0[is_pointer<int>::value? -1 : 1];
+int array1[is_pointer<int*>::value? 1 : -1];
+int array2[is_pointer<const int*>::value? 1 : -1]; // expected-error{{partial ordering}} \
+// expected-error{{negative}}