[cfe-commits] r77606 - in /cfe/trunk: include/clang/AST/DeclTemplate.h include/clang/Basic/DiagnosticSemaKinds.td lib/AST/ASTContext.cpp lib/AST/DeclTemplate.cpp lib/Sema/SemaCXXScopeSpec.cpp lib/Sema/SemaTemplate.cpp test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp
Douglas Gregor
dgregor at apple.com
Thu Jul 30 10:40:51 PDT 2009
Author: dgregor
Date: Thu Jul 30 12:40:51 2009
New Revision: 77606
URL: http://llvm.org/viewvc/llvm-project?rev=77606&view=rev
Log:
Support out-of-line definitions of the members of class template
partial specializations.
Added:
cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp (with props)
cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp (with props)
Modified:
cfe/trunk/include/clang/AST/DeclTemplate.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/AST/ASTContext.cpp
cfe/trunk/lib/AST/DeclTemplate.cpp
cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=77606&r1=77605&r2=77606&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Thu Jul 30 12:40:51 2009
@@ -1057,6 +1057,16 @@
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.
///
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=77606&r1=77605&r2=77606&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jul 30 12:40:51 2009
@@ -858,6 +858,9 @@
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">;
Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=77606&r1=77605&r2=77606&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Thu Jul 30 12:40:51 2009
@@ -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
Modified: cfe/trunk/lib/AST/DeclTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=77606&r1=77605&r2=77606&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Thu Jul 30 12:40:51 2009
@@ -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;
Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=77606&r1=77605&r2=77606&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Thu Jul 30 12:40:51 2009
@@ -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;
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=77606&r1=77605&r2=77606&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Jul 30 12:40:51 2009
@@ -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();
Added: cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp?rev=77606&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp Thu Jul 30 12:40:51 2009
@@ -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}}
Propchange: cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1-neg.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp?rev=77606&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp Thu Jul 30 12:40:51 2009
@@ -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;
Propchange: cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/temp.class.spec.mfunc/p1.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the cfe-commits
mailing list