aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-07-30 17:40:51 +0000
committerDouglas Gregor <dgregor@apple.com>2009-07-30 17:40:51 +0000
commitb88e888404ad0a2bdd9bfae457e8530bb38a87c5 (patch)
tree0ddb6d55fd383dfb6a5cb6ce7cb3afda20729a07
parent17edea8b0befb10066f7c6f5b01469d2fb679c9b (diff)
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
-rw-r--r--include/clang/AST/DeclTemplate.h10
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--lib/AST/ASTContext.cpp15
-rw-r--r--lib/AST/DeclTemplate.cpp15
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp14
-rw-r--r--lib/Sema/SemaTemplate.cpp53
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp25
-rw-r--r--test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp15
8 files changed, 132 insertions, 18 deletions
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 7cf8bfdecf..501f82d6ba 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -1057,6 +1057,16 @@ public:
return CommonPtr->PartialSpecializations;
}
+ /// \brief Find a class template partial specialization with the given
+ /// type T.
+ ///
+ /// \brief A dependent type that names a specialization of this class
+ /// template.
+ ///
+ /// \returns the class template partial specialization that exactly matches
+ /// the type \p T, or NULL if no such partial specialization exists.
+ ClassTemplatePartialSpecializationDecl *findPartialSpecialization(QualType T);
+
/// \brief Retrieve the type of the injected-class-name for this
/// class template.
///
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index ab454d0e47..25e331721a 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -858,6 +858,9 @@ def err_template_spec_needs_header : Error<
def err_template_spec_needs_template_parameters : Error<
"template specialization or definition requires a template parameter list"
"corresponding to the nested type %0">;
+def err_template_param_list_matches_nontemplate : Error<
+ "template parameter list matching the non-templated nested type %0 should "
+ "be empty ('template<>')">;
def err_template_spec_extra_headers : Error<
"extraneous template parameter list in template specialization or "
"out-of-line template definition">;
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 66aa363c28..e9bcc04c28 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1669,9 +1669,10 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
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 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
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 4677d17dc9..6b3ea437ab 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -161,6 +161,21 @@ void ClassTemplateDecl::Destroy(ASTContext& C) {
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 a5a20307ac..1580e721d3 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -55,14 +55,23 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
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 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
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 425b50263f..4264f32e9d 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -815,6 +815,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
= 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 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
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 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
// 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 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
}
// 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 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
/*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 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
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 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
}
}
}
-
} else {
// Create a new class template specialization declaration node for
// this explicit specialization.
@@ -2573,6 +2606,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
ClassTemplate->getSpecializations().InsertNode(Specialization,
InsertPos);
}
+
+ CanonType = Context.getTypeDeclType(Specialization);
}
// Note that this is an explicit specialization.
@@ -2603,7 +2638,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
= Context.getTemplateSpecializationType(Name,
TemplateArgs.data(),
TemplateArgs.size(),
- Context.getTypeDeclType(Specialization));
+ CanonType);
Specialization->setTypeAsWritten(WrittenTy);
TemplateArgsIn.release();
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp
new file mode 100644
index 0000000000..47cf8379c3
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, int N>
+struct A;
+
+template<typename T> // expected-note{{previous template declaration}}
+struct A<T*, 2> {
+ void f0();
+ void f1();
+ void f2();
+};
+
+template<>
+struct A<int, 1> {
+ void g0();
+};
+
+// FIXME: We should probably give more precise diagnostics here, but the
+// diagnostics we give aren't terrible.
+// FIXME: why not point to the first parameter that's "too many"?
+template<typename T, int N> // expected-error{{too many template parameters}}
+void A<T*, 2>::f0() { }
+
+template<typename T, int N>
+void A<T, N>::f1() { } // expected-error{{out-of-line definition}}
diff --git a/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp
new file mode 100644
index 0000000000..0321a7cfa3
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, int N>
+struct A;
+
+template<typename T>
+struct A<T*, 2> {
+ void f(T*);
+
+ static T value;
+};
+
+template<class X> void A<X*, 2>::f(X*) { }
+
+template<class X> X A<X*, 2>::value;