Support out-of-line definitions of the members of class template
partial specializations.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77606 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 66aa363..e9bcc04 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1669,9 +1669,10 @@
const TemplateArgument *Args,
unsigned NumArgs,
QualType Canon) {
- if (Canon.isNull()) {
- // Build the canonical template specialization type, since no type
- // was provided.
+ if (!Canon.isNull())
+ Canon = getCanonicalType(Canon);
+ else {
+ // Build the canonical template specialization type.
TemplateName CanonTemplate = getCanonicalTemplateName(Template);
llvm::SmallVector<TemplateArgument, 4> CanonArgs;
CanonArgs.reserve(NumArgs);
@@ -1695,16 +1696,16 @@
8);
Spec = new (Mem) TemplateSpecializationType(*this, CanonTemplate,
CanonArgs.data(), NumArgs,
- QualType());
+ Canon);
Types.push_back(Spec);
TemplateSpecializationTypes.InsertNode(Spec, InsertPos);
}
- Canon = QualType(Spec, 0);
+ if (Canon.isNull())
+ Canon = QualType(Spec, 0);
assert(Canon->isDependentType() &&
"Non-dependent template-id type must have a canonical type");
- } else
- Canon = getCanonicalType(Canon);
+ }
// Allocate the (non-canonical) template specialization type, but don't
// try to unique it: these types typically have location information that
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 4677d17..6b3ea43 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -161,6 +161,21 @@
C.Deallocate((void*)this);
}
+ClassTemplatePartialSpecializationDecl *
+ClassTemplateDecl::findPartialSpecialization(QualType T) {
+ ASTContext &Context = getASTContext();
+ typedef llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
+ partial_spec_iterator;
+ for (partial_spec_iterator P = getPartialSpecializations().begin(),
+ PEnd = getPartialSpecializations().end();
+ P != PEnd; ++P) {
+ if (Context.hasSameType(Context.getTypeDeclType(&*P), T))
+ return &*P;
+ }
+
+ return 0;
+}
+
QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) {
if (!CommonPtr->InjectedClassNameType.isNull())
return CommonPtr->InjectedClassNameType;
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index a5a2030..1580e72 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -55,14 +55,23 @@
if (ClassTemplateDecl *ClassTemplate
= dyn_cast_or_null<ClassTemplateDecl>(
SpecType->getTemplateName().getAsTemplateDecl())) {
+ QualType ContextType
+ = Context.getCanonicalType(QualType(SpecType, 0));
+
// If the type of the nested name specifier is the same as the
// injected class name of the named class template, we're entering
// into that class template definition.
QualType Injected = ClassTemplate->getInjectedClassNameType(Context);
- if (Context.hasSameType(Injected, QualType(SpecType, 0)))
+ if (Context.hasSameType(Injected, ContextType))
return ClassTemplate->getTemplatedDecl();
- // FIXME: Class template partial specializations
+ // If the type of the nested name specifier is the same as the
+ // type of one of the class template's class template partial
+ // specializations, we're entering into the definition of that
+ // class template partial specialization.
+ if (ClassTemplatePartialSpecializationDecl *PartialSpec
+ = ClassTemplate->findPartialSpecialization(ContextType))
+ return PartialSpec;
}
}
@@ -195,6 +204,7 @@
if (T == Context.getCanonicalType(InjectedClassName))
return Template->getTemplatedDecl();
}
+ // FIXME: check for class template partial specializations
}
return 0;
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 425b502..4264f32 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -815,6 +815,8 @@
= cast<ClassTemplateSpecializationDecl>(Record->getDecl());
// If the nested name specifier refers to an explicit specialization,
// we don't need a template<> header.
+ // FIXME: revisit this approach once we cope with specialization
+ // properly.
if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization)
continue;
}
@@ -836,7 +838,8 @@
unsigned Idx = 0;
for (unsigned NumTemplateIds = TemplateIdsInSpecifier.size();
Idx != NumTemplateIds; ++Idx) {
- bool DependentTemplateId = TemplateIdsInSpecifier[Idx]->isDependentType();
+ QualType TemplateId = QualType(TemplateIdsInSpecifier[Idx], 0);
+ bool DependentTemplateId = TemplateId->isDependentType();
if (Idx >= NumParamLists) {
// We have a template-id without a corresponding template parameter
// list.
@@ -844,7 +847,7 @@
// FIXME: the location information here isn't great.
Diag(SS.getRange().getBegin(),
diag::err_template_spec_needs_template_parameters)
- << QualType(TemplateIdsInSpecifier[Idx], 0)
+ << TemplateId
<< SS.getRange();
} else {
Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_header)
@@ -856,11 +859,32 @@
}
// Check the template parameter list against its corresponding template-id.
- TemplateDecl *Template
- = TemplateIdsInSpecifier[Idx]->getTemplateName().getAsTemplateDecl();
- TemplateParameterListsAreEqual(ParamLists[Idx],
- Template->getTemplateParameters(),
- true);
+ if (DependentTemplateId) {
+ TemplateDecl *Template
+ = TemplateIdsInSpecifier[Idx]->getTemplateName().getAsTemplateDecl();
+
+ if (ClassTemplateDecl *ClassTemplate
+ = dyn_cast<ClassTemplateDecl>(Template)) {
+ TemplateParameterList *ExpectedTemplateParams = 0;
+ // Is this template-id naming the primary template?
+ if (Context.hasSameType(TemplateId,
+ ClassTemplate->getInjectedClassNameType(Context)))
+ ExpectedTemplateParams = ClassTemplate->getTemplateParameters();
+ // ... or a partial specialization?
+ else if (ClassTemplatePartialSpecializationDecl *PartialSpec
+ = ClassTemplate->findPartialSpecialization(TemplateId))
+ ExpectedTemplateParams = PartialSpec->getTemplateParameters();
+
+ if (ExpectedTemplateParams)
+ TemplateParameterListsAreEqual(ParamLists[Idx],
+ ExpectedTemplateParams,
+ true);
+ }
+ } else if (ParamLists[Idx]->size() > 0)
+ Diag(ParamLists[Idx]->getTemplateLoc(),
+ diag::err_template_param_list_matches_nontemplate)
+ << TemplateId
+ << ParamLists[Idx]->getSourceRange();
}
// If there were at least as many template-ids as there were template
@@ -2493,6 +2517,8 @@
/*ExplicitInstantiation=*/false))
return true;
+ // The canonical type
+ QualType CanonType;
if (PrevDecl && PrevDecl->getSpecializationKind() == TSK_Undeclared) {
// Since the only prior class template specialization with these
// arguments was referenced but not declared, reuse that
@@ -2501,7 +2527,15 @@
Specialization = PrevDecl;
Specialization->setLocation(TemplateNameLoc);
PrevDecl = 0;
+ CanonType = Context.getTypeDeclType(Specialization);
} else if (isPartialSpecialization) {
+ // Build the canonical type that describes the converted template
+ // arguments of the class template partial specialization.
+ CanonType = Context.getTemplateSpecializationType(
+ TemplateName(ClassTemplate),
+ Converted.getFlatArguments(),
+ Converted.flatSize());
+
// Create a new class template partial specialization declaration node.
TemplateParameterList *TemplateParams
= static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
@@ -2554,7 +2588,6 @@
}
}
}
-
} else {
// Create a new class template specialization declaration node for
// this explicit specialization.
@@ -2573,6 +2606,8 @@
ClassTemplate->getSpecializations().InsertNode(Specialization,
InsertPos);
}
+
+ CanonType = Context.getTypeDeclType(Specialization);
}
// Note that this is an explicit specialization.
@@ -2603,7 +2638,7 @@
= Context.getTemplateSpecializationType(Name,
TemplateArgs.data(),
TemplateArgs.size(),
- Context.getTypeDeclType(Specialization));
+ CanonType);
Specialization->setTypeAsWritten(WrittenTy);
TemplateArgsIn.release();