[cfe-commits] r85447 - in /cfe/trunk: include/clang/AST/DeclTemplate.h include/clang/Basic/DiagnosticSemaKinds.td lib/AST/DeclTemplate.cpp lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CXX/temp/temp.decls/temp.class.spec/p6.cpp
Douglas Gregor
dgregor at apple.com
Wed Oct 28 17:04:12 PDT 2009
Author: dgregor
Date: Wed Oct 28 19:04:11 2009
New Revision: 85447
URL: http://llvm.org/viewvc/llvm-project?rev=85447&view=rev
Log:
Implement support for semantic checking and template instantiation of
class template partial specializations of member templates. Also,
fixes a silly little bug in the marking of "used" template parameters
in member templates. Fixes PR5236.
Modified:
cfe/trunk/include/clang/AST/DeclTemplate.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/AST/DeclTemplate.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp
Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=85447&r1=85446&r2=85447&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Wed Oct 28 19:04:11 2009
@@ -91,6 +91,13 @@
/// arguments or if there is a parameter pack.
unsigned getMinRequiredArguments() const;
+ /// \brief Get the depth of this template parameter list in the set of
+ /// template parameter lists.
+ ///
+ /// The first template parameter list in a declaration will have depth 0,
+ /// the second template parameter list will have depth 1, etc.
+ unsigned getDepth() const;
+
SourceLocation getTemplateLoc() const { return TemplateLoc; }
SourceLocation getLAngleLoc() const { return LAngleLoc; }
SourceLocation getRAngleLoc() const { return RAngleLoc; }
@@ -859,6 +866,12 @@
InheritedDefault = Inherited;
}
+ /// \brief Retrieve the depth of the template parameter.
+ unsigned getDepth() const;
+
+ /// \brief Retrieve the index of the template parameter.
+ unsigned getIndex() const;
+
/// \brief Returns whether this is a parameter pack.
bool isParameterPack() const { return ParameterPack; }
@@ -1150,6 +1163,14 @@
/// \brief The list of template parameters
TemplateParameterList* TemplateParams;
+ /// \brief The class template partial specialization from which this
+ /// class template partial specialization was instantiated.
+ ///
+ /// The boolean value will be true to indicate that this class template
+ /// partial specialization was specialized at this level.
+ llvm::PointerIntPair<ClassTemplatePartialSpecializationDecl *, 1, bool>
+ InstantiatedFromMember;
+
ClassTemplatePartialSpecializationDecl(ASTContext &Context,
DeclContext *DC, SourceLocation L,
TemplateParameterList *Params,
@@ -1160,7 +1181,7 @@
ClassTemplatePartialSpecialization,
DC, L, SpecializedTemplate, Builder,
PrevDecl),
- TemplateParams(Params) { }
+ TemplateParams(Params), InstantiatedFromMember(0, false) { }
public:
static ClassTemplatePartialSpecializationDecl *
@@ -1175,6 +1196,70 @@
return TemplateParams;
}
+ /// \brief Retrieve the member class template partial specialization from
+ /// which this particular class template partial specialization was
+ /// instantiated.
+ ///
+ /// \code
+ /// template<typename T>
+ /// struct Outer {
+ /// template<typename U> struct Inner;
+ /// template<typename U> struct Inner<U*> { }; // #1
+ /// };
+ ///
+ /// Outer<float>::Inner<int*> ii;
+ /// \endcode
+ ///
+ /// In this example, the instantiation of \c Outer<float>::Inner<int*> will
+ /// end up instantiating the partial specialization
+ /// \c Outer<float>::Inner<U*>, which itself was instantiated from the class
+ /// template partial specialization \c Outer<T>::Inner<U*>. Given
+ /// \c Outer<float>::Inner<U*>, this function would return
+ /// \c Outer<T>::Inner<U*>.
+ ClassTemplatePartialSpecializationDecl *getInstantiatedFromMember() {
+ ClassTemplatePartialSpecializationDecl *First
+ = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
+ return First->InstantiatedFromMember.getPointer();
+ }
+
+ void setInstantiatedFromMember(
+ ClassTemplatePartialSpecializationDecl *PartialSpec) {
+ ClassTemplatePartialSpecializationDecl *First
+ = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
+ First->InstantiatedFromMember.setPointer(PartialSpec);
+ }
+
+ /// \brief Determines whether this class template partial specialization
+ /// template was a specialization of a member partial specialization.
+ ///
+ /// In the following example, the member template partial specialization
+ /// \c X<int>::Inner<T*> is a member specialization.
+ ///
+ /// \code
+ /// template<typename T>
+ /// struct X {
+ /// template<typename U> struct Inner;
+ /// template<typename U> struct Inner<U*>;
+ /// };
+ ///
+ /// template<> template<typename T>
+ /// struct X<int>::Inner<T*> { /* ... */ };
+ /// \endcode
+ bool isMemberSpecialization() {
+ ClassTemplatePartialSpecializationDecl *First
+ = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
+ return First->InstantiatedFromMember.getInt();
+ }
+
+ /// \brief Note that this member template is a specialization.
+ void setMemberSpecialization() {
+ ClassTemplatePartialSpecializationDecl *First
+ = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration());
+ assert(First->InstantiatedFromMember.getPointer() &&
+ "Only member templates can be member template specializations");
+ return First->InstantiatedFromMember.setInt(true);
+ }
+
// FIXME: Add Profile support!
static bool classof(const Decl *D) {
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=85447&r1=85446&r2=85447&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Oct 28 19:04:11 2009
@@ -1014,7 +1014,11 @@
def err_partial_spec_ordering_ambiguous : Error<
"ambiguous partial specializations of %0">;
def note_partial_spec_match : Note<"partial specialization matches %0">;
-
+def err_partial_spec_redeclared : Error<
+ "class template partial specialization %0 cannot be redeclared">;
+def note_prev_partial_spec_here : Note<
+ "previous declaration of class template partial specialization %0 is here">;
+
// C++ Function template specializations
def err_function_template_spec_no_match : Error<
"no function template matches function template specialization %0">;
Modified: cfe/trunk/lib/AST/DeclTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=85447&r1=85446&r2=85447&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Wed Oct 28 19:04:11 2009
@@ -67,6 +67,21 @@
return NumRequiredArgs;
}
+unsigned TemplateParameterList::getDepth() const {
+ if (size() == 0)
+ return 0;
+
+ const NamedDecl *FirstParm = getParam(0);
+ if (const TemplateTypeParmDecl *TTP
+ = dyn_cast<TemplateTypeParmDecl>(FirstParm))
+ return TTP->getDepth();
+ else if (const NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(FirstParm))
+ return NTTP->getDepth();
+ else
+ return cast<TemplateTemplateParmDecl>(FirstParm)->getDepth();
+}
+
//===----------------------------------------------------------------------===//
// TemplateDecl Implementation
//===----------------------------------------------------------------------===//
@@ -229,6 +244,14 @@
return new (C) TemplateTypeParmDecl(DC, L, Id, Typename, Type, ParameterPack);
}
+unsigned TemplateTypeParmDecl::getDepth() const {
+ return TypeForDecl->getAs<TemplateTypeParmType>()->getDepth();
+}
+
+unsigned TemplateTypeParmDecl::getIndex() const {
+ return TypeForDecl->getAs<TemplateTypeParmType>()->getIndex();
+}
+
//===----------------------------------------------------------------------===//
// NonTypeTemplateParmDecl Method Implementations
//===----------------------------------------------------------------------===//
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=85447&r1=85446&r2=85447&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Oct 28 19:04:11 2009
@@ -2869,6 +2869,7 @@
void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
bool OnlyDeduced,
+ unsigned Depth,
llvm::SmallVectorImpl<bool> &Used);
void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
llvm::SmallVectorImpl<bool> &Deduced);
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=85447&r1=85446&r2=85447&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Oct 28 19:04:11 2009
@@ -2880,8 +2880,6 @@
Converted.flatSize());
// 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
@@ -2901,6 +2899,11 @@
}
Specialization = Partial;
+ // If we are providing an explicit specialization of a member class
+ // template specialization, make a note of that.
+ if (PrevPartial && PrevPartial->getInstantiatedFromMember())
+ PrevPartial->setMemberSpecialization();
+
// 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
@@ -2908,6 +2911,7 @@
llvm::SmallVector<bool, 8> DeducibleParams;
DeducibleParams.resize(TemplateParams->size());
MarkUsedTemplateParameters(Partial->getTemplateArgs(), true,
+ TemplateParams->getDepth(),
DeducibleParams);
unsigned NumNonDeducible = 0;
for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I)
Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=85447&r1=85446&r2=85447&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Oct 28 19:04:11 2009
@@ -1690,6 +1690,7 @@
static void
MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
bool OnlyDeduced,
+ unsigned Level,
llvm::SmallVectorImpl<bool> &Deduced);
/// \brief Determine whether the function template \p FT1 is at least as
@@ -1782,18 +1783,22 @@
case TPOC_Call: {
unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs());
for (unsigned I = 0; I != NumParams; ++I)
- ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false,
+ ::MarkUsedTemplateParameters(S, Proto2->getArgType(I), false,
+ TemplateParams->getDepth(),
UsedParameters);
break;
}
case TPOC_Conversion:
- ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false,
+ ::MarkUsedTemplateParameters(S, Proto2->getResultType(), false,
+ TemplateParams->getDepth(),
UsedParameters);
break;
case TPOC_Other:
- ::MarkUsedTemplateParameters(S, FD2->getType(), false, UsedParameters);
+ ::MarkUsedTemplateParameters(S, FD2->getType(), false,
+ TemplateParams->getDepth(),
+ UsedParameters);
break;
}
@@ -2065,6 +2070,7 @@
MarkUsedTemplateParameters(Sema &SemaRef,
const TemplateArgument &TemplateArg,
bool OnlyDeduced,
+ unsigned Depth,
llvm::SmallVectorImpl<bool> &Used);
/// \brief Mark the template parameters that are used by the given
@@ -2073,6 +2079,7 @@
MarkUsedTemplateParameters(Sema &SemaRef,
const Expr *E,
bool OnlyDeduced,
+ unsigned Depth,
llvm::SmallVectorImpl<bool> &Used) {
// FIXME: if !OnlyDeduced, we have to walk the whole subexpression to
// find other occurrences of template parameters.
@@ -2085,7 +2092,8 @@
if (!NTTP)
return;
- Used[NTTP->getIndex()] = true;
+ if (NTTP->getDepth() == Depth)
+ Used[NTTP->getIndex()] = true;
}
/// \brief Mark the template parameters that are used by the given
@@ -2094,13 +2102,15 @@
MarkUsedTemplateParameters(Sema &SemaRef,
NestedNameSpecifier *NNS,
bool OnlyDeduced,
+ unsigned Depth,
llvm::SmallVectorImpl<bool> &Used) {
if (!NNS)
return;
- MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Used);
+ MarkUsedTemplateParameters(SemaRef, NNS->getPrefix(), OnlyDeduced, Depth,
+ Used);
MarkUsedTemplateParameters(SemaRef, QualType(NNS->getAsType(), 0),
- OnlyDeduced, Used);
+ OnlyDeduced, Depth, Used);
}
/// \brief Mark the template parameters that are used by the given
@@ -2109,16 +2119,20 @@
MarkUsedTemplateParameters(Sema &SemaRef,
TemplateName Name,
bool OnlyDeduced,
+ unsigned Depth,
llvm::SmallVectorImpl<bool> &Used) {
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
if (TemplateTemplateParmDecl *TTP
- = dyn_cast<TemplateTemplateParmDecl>(Template))
- Used[TTP->getIndex()] = true;
+ = dyn_cast<TemplateTemplateParmDecl>(Template)) {
+ if (TTP->getDepth() == Depth)
+ Used[TTP->getIndex()] = true;
+ }
return;
}
if (DependentTemplateName *DTN = Name.getAsDependentTemplateName())
- MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced, Used);
+ MarkUsedTemplateParameters(SemaRef, DTN->getQualifier(), OnlyDeduced,
+ Depth, Used);
}
/// \brief Mark the template parameters that are used by the given
@@ -2126,6 +2140,7 @@
static void
MarkUsedTemplateParameters(Sema &SemaRef, QualType T,
bool OnlyDeduced,
+ unsigned Depth,
llvm::SmallVectorImpl<bool> &Used) {
if (T.isNull())
return;
@@ -2140,6 +2155,7 @@
MarkUsedTemplateParameters(SemaRef,
cast<PointerType>(T)->getPointeeType(),
OnlyDeduced,
+ Depth,
Used);
break;
@@ -2147,6 +2163,7 @@
MarkUsedTemplateParameters(SemaRef,
cast<BlockPointerType>(T)->getPointeeType(),
OnlyDeduced,
+ Depth,
Used);
break;
@@ -2155,69 +2172,74 @@
MarkUsedTemplateParameters(SemaRef,
cast<ReferenceType>(T)->getPointeeType(),
OnlyDeduced,
+ Depth,
Used);
break;
case Type::MemberPointer: {
const MemberPointerType *MemPtr = cast<MemberPointerType>(T.getTypePtr());
MarkUsedTemplateParameters(SemaRef, MemPtr->getPointeeType(), OnlyDeduced,
- Used);
+ Depth, Used);
MarkUsedTemplateParameters(SemaRef, QualType(MemPtr->getClass(), 0),
- OnlyDeduced, Used);
+ OnlyDeduced, Depth, Used);
break;
}
case Type::DependentSizedArray:
MarkUsedTemplateParameters(SemaRef,
cast<DependentSizedArrayType>(T)->getSizeExpr(),
- OnlyDeduced, Used);
+ OnlyDeduced, Depth, Used);
// Fall through to check the element type
case Type::ConstantArray:
case Type::IncompleteArray:
MarkUsedTemplateParameters(SemaRef,
cast<ArrayType>(T)->getElementType(),
- OnlyDeduced, Used);
+ OnlyDeduced, Depth, Used);
break;
case Type::Vector:
case Type::ExtVector:
MarkUsedTemplateParameters(SemaRef,
cast<VectorType>(T)->getElementType(),
- OnlyDeduced, Used);
+ OnlyDeduced, Depth, Used);
break;
case Type::DependentSizedExtVector: {
const DependentSizedExtVectorType *VecType
= cast<DependentSizedExtVectorType>(T);
MarkUsedTemplateParameters(SemaRef, VecType->getElementType(), OnlyDeduced,
- Used);
+ Depth, Used);
MarkUsedTemplateParameters(SemaRef, VecType->getSizeExpr(), OnlyDeduced,
- Used);
+ Depth, Used);
break;
}
case Type::FunctionProto: {
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
MarkUsedTemplateParameters(SemaRef, Proto->getResultType(), OnlyDeduced,
- Used);
+ Depth, Used);
for (unsigned I = 0, N = Proto->getNumArgs(); I != N; ++I)
MarkUsedTemplateParameters(SemaRef, Proto->getArgType(I), OnlyDeduced,
- Used);
+ Depth, Used);
break;
}
- case Type::TemplateTypeParm:
- Used[cast<TemplateTypeParmType>(T)->getIndex()] = true;
+ case Type::TemplateTypeParm: {
+ const TemplateTypeParmType *TTP = cast<TemplateTypeParmType>(T);
+ if (TTP->getDepth() == Depth)
+ Used[TTP->getIndex()] = true;
break;
+ }
case Type::TemplateSpecialization: {
const TemplateSpecializationType *Spec
= cast<TemplateSpecializationType>(T);
MarkUsedTemplateParameters(SemaRef, Spec->getTemplateName(), OnlyDeduced,
- Used);
+ Depth, Used);
for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
- MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Used);
+ MarkUsedTemplateParameters(SemaRef, Spec->getArg(I), OnlyDeduced, Depth,
+ Used);
break;
}
@@ -2225,14 +2247,14 @@
if (!OnlyDeduced)
MarkUsedTemplateParameters(SemaRef,
cast<ComplexType>(T)->getElementType(),
- OnlyDeduced, Used);
+ OnlyDeduced, Depth, Used);
break;
case Type::Typename:
if (!OnlyDeduced)
MarkUsedTemplateParameters(SemaRef,
cast<TypenameType>(T)->getQualifier(),
- OnlyDeduced, Used);
+ OnlyDeduced, Depth, Used);
break;
// None of these types have any template parameters in them.
@@ -2259,6 +2281,7 @@
MarkUsedTemplateParameters(Sema &SemaRef,
const TemplateArgument &TemplateArg,
bool OnlyDeduced,
+ unsigned Depth,
llvm::SmallVectorImpl<bool> &Used) {
switch (TemplateArg.getKind()) {
case TemplateArgument::Null:
@@ -2267,25 +2290,27 @@
case TemplateArgument::Type:
MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsType(), OnlyDeduced,
- Used);
+ Depth, Used);
break;
case TemplateArgument::Declaration:
if (TemplateTemplateParmDecl *TTP
- = dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl()))
- Used[TTP->getIndex()] = true;
+ = dyn_cast<TemplateTemplateParmDecl>(TemplateArg.getAsDecl())) {
+ if (TTP->getDepth() == Depth)
+ Used[TTP->getIndex()] = true;
+ }
break;
case TemplateArgument::Expression:
MarkUsedTemplateParameters(SemaRef, TemplateArg.getAsExpr(), OnlyDeduced,
- Used);
+ Depth, Used);
break;
case TemplateArgument::Pack:
for (TemplateArgument::pack_iterator P = TemplateArg.pack_begin(),
PEnd = TemplateArg.pack_end();
P != PEnd; ++P)
- MarkUsedTemplateParameters(SemaRef, *P, OnlyDeduced, Used);
+ MarkUsedTemplateParameters(SemaRef, *P, OnlyDeduced, Depth, Used);
break;
}
}
@@ -2301,10 +2326,11 @@
/// deduced.
void
Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
- bool OnlyDeduced,
+ bool OnlyDeduced, unsigned Depth,
llvm::SmallVectorImpl<bool> &Used) {
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
- ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced, Used);
+ ::MarkUsedTemplateParameters(*this, TemplateArgs[I], OnlyDeduced,
+ Depth, Used);
}
/// \brief Marks all of the template parameters that will be deduced by a
@@ -2319,5 +2345,5 @@
FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
for (unsigned I = 0, N = Function->getNumParams(); I != N; ++I)
::MarkUsedTemplateParameters(*this, Function->getParamDecl(I)->getType(),
- true, Deduced);
+ true, TemplateParams->getDepth(), Deduced);
}
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=85447&r1=85446&r2=85447&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Wed Oct 28 19:04:11 2009
@@ -981,61 +981,72 @@
}
}
- if (Matched.size() == 1) {
- // -- If exactly one matching specialization is found, the
- // instantiation is generated from that specialization.
- Pattern = Matched[0].first;
- ClassTemplateSpec->setInstantiationOf(Matched[0].first, Matched[0].second);
- } else if (Matched.size() > 1) {
- // -- If more than one matching specialization is found, the
- // partial order rules (14.5.4.2) are used to determine
- // whether one of the specializations is more specialized
- // than the others. If none of the specializations is more
- // specialized than all of the other matching
- // specializations, then the use of the class template is
- // ambiguous and the program is ill-formed.
+ if (Matched.size() >= 1) {
llvm::SmallVector<MatchResult, 4>::iterator Best = Matched.begin();
- for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1,
- PEnd = Matched.end();
- P != PEnd; ++P) {
- if (getMoreSpecializedPartialSpecialization(P->first, Best->first)
- == P->first)
- Best = P;
- }
-
- // Determine if the best partial specialization is more specialized than
- // the others.
- bool Ambiguous = false;
- for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
- PEnd = Matched.end();
- P != PEnd; ++P) {
- if (P != Best &&
- getMoreSpecializedPartialSpecialization(P->first, Best->first)
- != Best->first) {
- Ambiguous = true;
- break;
+ if (Matched.size() == 1) {
+ // -- If exactly one matching specialization is found, the
+ // instantiation is generated from that specialization.
+ // We don't need to do anything for this.
+ } else {
+ // -- If more than one matching specialization is found, the
+ // partial order rules (14.5.4.2) are used to determine
+ // whether one of the specializations is more specialized
+ // than the others. If none of the specializations is more
+ // specialized than all of the other matching
+ // specializations, then the use of the class template is
+ // ambiguous and the program is ill-formed.
+ for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1,
+ PEnd = Matched.end();
+ P != PEnd; ++P) {
+ if (getMoreSpecializedPartialSpecialization(P->first, Best->first)
+ == P->first)
+ Best = P;
}
- }
-
- if (Ambiguous) {
- // Partial ordering did not produce a clear winner. Complain.
- ClassTemplateSpec->setInvalidDecl();
- Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous)
- << ClassTemplateSpec;
- // Print the matching partial specializations.
+ // Determine if the best partial specialization is more specialized than
+ // the others.
+ bool Ambiguous = false;
for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
PEnd = Matched.end();
- P != PEnd; ++P)
- Diag(P->first->getLocation(), diag::note_partial_spec_match)
- << getTemplateArgumentBindingsText(P->first->getTemplateParameters(),
- *P->second);
+ P != PEnd; ++P) {
+ if (P != Best &&
+ getMoreSpecializedPartialSpecialization(P->first, Best->first)
+ != Best->first) {
+ Ambiguous = true;
+ break;
+ }
+ }
+
+ if (Ambiguous) {
+ // Partial ordering did not produce a clear winner. Complain.
+ ClassTemplateSpec->setInvalidDecl();
+ Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous)
+ << ClassTemplateSpec;
+
+ // Print the matching partial specializations.
+ for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
+ PEnd = Matched.end();
+ P != PEnd; ++P)
+ Diag(P->first->getLocation(), diag::note_partial_spec_match)
+ << getTemplateArgumentBindingsText(P->first->getTemplateParameters(),
+ *P->second);
- return true;
+ return true;
+ }
}
// Instantiate using the best class template partial specialization.
- Pattern = Best->first;
+ ClassTemplatePartialSpecializationDecl *OrigPartialSpec = Best->first;
+ while (OrigPartialSpec->getInstantiatedFromMember()) {
+ // If we've found an explicit specialization of this class template,
+ // stop here and use that as the pattern.
+ if (OrigPartialSpec->isMemberSpecialization())
+ break;
+
+ OrigPartialSpec = OrigPartialSpec->getInstantiatedFromMember();
+ }
+
+ Pattern = OrigPartialSpec;
ClassTemplateSpec->setInstantiationOf(Best->first, Best->second);
} else {
// -- If no matches are found, the instantiation is generated
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=85447&r1=85446&r2=85447&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed Oct 28 19:04:11 2009
@@ -82,6 +82,10 @@
TemplateParameterList *
SubstTemplateParams(TemplateParameterList *List);
+
+ bool InstantiateClassTemplatePartialSpecialization(
+ ClassTemplateDecl *ClassTemplate,
+ ClassTemplatePartialSpecializationDecl *PartialSpec);
};
}
@@ -389,6 +393,21 @@
return 0;
}
+namespace {
+ class SortDeclByLocation {
+ SourceManager &SourceMgr;
+
+ public:
+ explicit SortDeclByLocation(SourceManager &SourceMgr)
+ : SourceMgr(SourceMgr) { }
+
+ bool operator()(const Decl *X, const Decl *Y) const {
+ return SourceMgr.isBeforeInTranslationUnit(X->getLocation(),
+ Y->getLocation());
+ }
+ };
+}
+
Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
@@ -413,13 +432,52 @@
SemaRef.Context.getTypeDeclType(RecordInst);
Owner->addDecl(Inst);
+
+ // First, we sort the partial specializations by location, so
+ // that we instantiate them in the order they were declared.
+ llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+ for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
+ P = D->getPartialSpecializations().begin(),
+ PEnd = D->getPartialSpecializations().end();
+ P != PEnd; ++P)
+ PartialSpecs.push_back(&*P);
+ std::sort(PartialSpecs.begin(), PartialSpecs.end(),
+ SortDeclByLocation(SemaRef.SourceMgr));
+
+ // Instantiate all of the partial specializations of this member class
+ // template.
+ for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I)
+ InstantiateClassTemplatePartialSpecialization(Inst, PartialSpecs[I]);
+
return Inst;
}
Decl *
TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D) {
- assert(false &&"Partial specializations of member templates are unsupported");
+ ClassTemplateDecl *ClassTemplate = D->getSpecializedTemplate();
+
+ // Lookup the already-instantiated declaration in the instantiation
+ // of the class template and return that.
+ DeclContext::lookup_result Found
+ = Owner->lookup(ClassTemplate->getDeclName());
+ if (Found.first == Found.second)
+ return 0;
+
+ ClassTemplateDecl *InstClassTemplate
+ = dyn_cast<ClassTemplateDecl>(*Found.first);
+ if (!InstClassTemplate)
+ return 0;
+
+ Decl *DCanon = D->getCanonicalDecl();
+ for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
+ P = InstClassTemplate->getPartialSpecializations().begin(),
+ PEnd = InstClassTemplate->getPartialSpecializations().end();
+ P != PEnd; ++P) {
+ if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon)
+ return &*P;
+ }
+
return 0;
}
@@ -431,7 +489,7 @@
TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return NULL;
-
+
FunctionDecl *Instantiated = 0;
if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(D->getTemplatedDecl()))
Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod,
@@ -945,6 +1003,130 @@
return InstL;
}
+/// \brief Instantiate the declaration of a class template partial
+/// specialization.
+///
+/// \param ClassTemplate the (instantiated) class template that is partially
+// specialized by the instantiation of \p PartialSpec.
+///
+/// \param PartialSpec the (uninstantiated) class template partial
+/// specialization that we are instantiating.
+///
+/// \returns true if there was an error, false otherwise.
+bool
+TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
+ ClassTemplateDecl *ClassTemplate,
+ ClassTemplatePartialSpecializationDecl *PartialSpec) {
+ // Substitute into the template parameters of the class template partial
+ // specialization.
+ TemplateParameterList *TempParams = PartialSpec->getTemplateParameters();
+ TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return true;
+
+ // Substitute into the template arguments of the class template partial
+ // specialization.
+ const TemplateArgumentList &PartialSpecTemplateArgs
+ = PartialSpec->getTemplateInstantiationArgs();
+ llvm::SmallVector<TemplateArgument, 4> InstTemplateArgs;
+ for (unsigned I = 0, N = PartialSpecTemplateArgs.size(); I != N; ++I) {
+ TemplateArgument Inst = SemaRef.Subst(PartialSpecTemplateArgs[I],
+ TemplateArgs);
+ if (Inst.isNull())
+ return true;
+
+ InstTemplateArgs.push_back(Inst);
+ }
+
+
+ // Check that the template argument list is well-formed for this
+ // class template.
+ TemplateArgumentListBuilder Converted(ClassTemplate->getTemplateParameters(),
+ InstTemplateArgs.size());
+ if (SemaRef.CheckTemplateArgumentList(ClassTemplate,
+ PartialSpec->getLocation(),
+ /*FIXME:*/PartialSpec->getLocation(),
+ InstTemplateArgs.data(),
+ InstTemplateArgs.size(),
+ /*FIXME:*/PartialSpec->getLocation(),
+ false,
+ Converted))
+ return true;
+
+ // Figure out where to insert this class template partial specialization
+ // in the member template's set of class template partial specializations.
+ llvm::FoldingSetNodeID ID;
+ ClassTemplatePartialSpecializationDecl::Profile(ID,
+ Converted.getFlatArguments(),
+ Converted.flatSize(),
+ SemaRef.Context);
+ void *InsertPos = 0;
+ ClassTemplateSpecializationDecl *PrevDecl
+ = ClassTemplate->getPartialSpecializations().FindNodeOrInsertPos(ID,
+ InsertPos);
+
+ // Build the canonical type that describes the converted template
+ // arguments of the class template partial specialization.
+ QualType CanonType
+ = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate),
+ Converted.getFlatArguments(),
+ Converted.flatSize());
+
+ // Build the fully-sugared type for this class template
+ // specialization as the user wrote in the specialization
+ // itself. This means that we'll pretty-print the type retrieved
+ // from the specialization's declaration the way that the user
+ // actually wrote the specialization, rather than formatting the
+ // name based on the "canonical" representation used to store the
+ // template arguments in the specialization.
+ QualType WrittenTy
+ = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate),
+ InstTemplateArgs.data(),
+ InstTemplateArgs.size(),
+ CanonType);
+
+ if (PrevDecl) {
+ // We've already seen a partial specialization with the same template
+ // parameters and template arguments. This can happen, for example, when
+ // substituting the outer template arguments ends up causing two
+ // class template partial specializations of a member class template
+ // to have identical forms, e.g.,
+ //
+ // template<typename T, typename U>
+ // struct Outer {
+ // template<typename X, typename Y> struct Inner;
+ // template<typename Y> struct Inner<T, Y>;
+ // template<typename Y> struct Inner<U, Y>;
+ // };
+ //
+ // Outer<int, int> outer; // error: the partial specializations of Inner
+ // // have the same signature.
+ SemaRef.Diag(PartialSpec->getLocation(), diag::err_partial_spec_redeclared)
+ << WrittenTy;
+ SemaRef.Diag(PrevDecl->getLocation(), diag::note_prev_partial_spec_here)
+ << SemaRef.Context.getTypeDeclType(PrevDecl);
+ return true;
+ }
+
+
+ // Create the class template partial specialization declaration.
+ ClassTemplatePartialSpecializationDecl *InstPartialSpec
+ = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, Owner,
+ PartialSpec->getLocation(),
+ InstParams,
+ ClassTemplate,
+ Converted,
+ 0);
+ InstPartialSpec->setInstantiatedFromMember(PartialSpec);
+ InstPartialSpec->setTypeAsWritten(WrittenTy);
+
+ // Add this partial specialization to the set of class template partial
+ // specializations.
+ ClassTemplate->getPartialSpecializations().InsertNode(InstPartialSpec,
+ InsertPos);
+ return false;
+}
+
/// \brief Does substitution on the type of the given function, including
/// all of the function parameters.
///
@@ -1391,6 +1573,22 @@
return false;
}
+static bool
+isInstantiationOf(ClassTemplatePartialSpecializationDecl *Pattern,
+ ClassTemplatePartialSpecializationDecl *Instance) {
+ Pattern
+ = cast<ClassTemplatePartialSpecializationDecl>(Pattern->getCanonicalDecl());
+ do {
+ Instance = cast<ClassTemplatePartialSpecializationDecl>(
+ Instance->getCanonicalDecl());
+ if (Pattern == Instance)
+ return true;
+ Instance = Instance->getInstantiatedFromMember();
+ } while (Instance);
+
+ return false;
+}
+
static bool isInstantiationOf(CXXRecordDecl *Pattern,
CXXRecordDecl *Instance) {
Pattern = Pattern->getCanonicalDecl();
@@ -1481,6 +1679,11 @@
if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(Other))
return isInstantiationOf(cast<FunctionTemplateDecl>(D), Temp);
+ if (ClassTemplatePartialSpecializationDecl *PartialSpec
+ = dyn_cast<ClassTemplatePartialSpecializationDecl>(Other))
+ return isInstantiationOf(cast<ClassTemplatePartialSpecializationDecl>(D),
+ PartialSpec);
+
if (FieldDecl *Field = dyn_cast<FieldDecl>(Other)) {
if (!Field->getDeclName()) {
// This is an unnamed field.
Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp?rev=85447&r1=85446&r2=85447&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p6.cpp Wed Oct 28 19:04:11 2009
@@ -1,5 +1,6 @@
// RUN: clang-cc -fsyntax-only -verify %s
+// Test class template partial specializations of member templates.
template<typename T>
struct X0 {
template<typename U> struct Inner0 {
@@ -16,5 +17,39 @@
static const unsigned value = 2;
};
-// FIXME: Test instantiation of these partial specializations (once they are
-// implemented).
+int array0[X0<int>::Inner0<int>::value == 0? 1 : -1];
+int array1[X0<int>::Inner0<int*>::value == 1? 1 : -1];
+int array2[X0<int>::Inner0<const int*>::value == 2? 1 : -1];
+
+// Make sure we can provide out-of-line class template partial specializations
+// for member templates (and instantiate them).
+template<class T> struct A {
+ struct C {
+ template<class T2> struct B;
+ };
+};
+
+// partial specialization of A<T>::C::B<T2>
+template<class T> template<class T2> struct A<T>::C::B<T2*> { };
+
+A<short>::C::B<int*> absip;
+
+// Check for conflicts during template instantiation.
+template<typename T, typename U>
+struct Outer {
+ template<typename X, typename Y> struct Inner;
+ template<typename Y> struct Inner<T, Y> {}; // expected-note{{previous}}
+ template<typename Y> struct Inner<U, Y> {}; // expected-error{{cannot be redeclared}}
+};
+
+Outer<int, int> outer; // expected-note{{instantiation}}
+
+// Test specialization of class template partial specialization members.
+template<> template<typename Z>
+struct X0<float>::Inner0<Z*> {
+ static const unsigned value = 3;
+};
+
+int array3[X0<float>::Inner0<int>::value == 0? 1 : -1];
+int array4[X0<float>::Inner0<int*>::value == 3? 1 : -1];
+int array5[X0<float>::Inner0<const int*>::value == 2? 1 : -1];
More information about the cfe-commits
mailing list