aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DeclCXX.h24
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--lib/AST/DeclCXX.cpp47
-rw-r--r--lib/Sema/SemaDecl.cpp14
-rw-r--r--lib/Sema/SemaTemplate.cpp41
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp23
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp2
-rw-r--r--lib/Sema/SemaType.cpp9
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp49
-rw-r--r--test/Parser/cxx-template-decl.cpp9
10 files changed, 181 insertions, 39 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index ee6314cc36..85c678acd2 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -391,8 +391,9 @@ class CXXRecordDecl : public RecordDecl {
/// declarations that describe a class template, this will be a
/// pointer to a ClassTemplateDecl. For member
/// classes of class template specializations, this will be the
- /// RecordDecl from which the member class was instantiated.
- llvm::PointerUnion<ClassTemplateDecl*, CXXRecordDecl*>
+ /// MemberSpecializationInfo referring to the member class that was
+ /// instantiated or specialized.
+ llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*>
TemplateOrInstantiation;
void getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
@@ -703,15 +704,12 @@ public:
/// the CXXRecordDecl X<T>::A. When a complete definition of
/// X<int>::A is required, it will be instantiated from the
/// declaration returned by getInstantiatedFromMemberClass().
- CXXRecordDecl *getInstantiatedFromMemberClass() const {
- return TemplateOrInstantiation.dyn_cast<CXXRecordDecl*>();
- }
-
+ CXXRecordDecl *getInstantiatedFromMemberClass() const;
+
/// \brief Specify that this record is an instantiation of the
/// member class RD.
- void setInstantiationOfMemberClass(CXXRecordDecl *RD) {
- TemplateOrInstantiation = RD;
- }
+ void setInstantiationOfMemberClass(CXXRecordDecl *RD,
+ TemplateSpecializationKind TSK);
/// \brief Retrieves the class template that is described by this
/// class declaration.
@@ -732,6 +730,14 @@ public:
TemplateOrInstantiation = Template;
}
+ /// \brief Determine whether this particular class is a specialization or
+ /// instantiation of a class template or member class of a class template,
+ /// and how it was instantiated or specialized.
+ TemplateSpecializationKind getTemplateSpecializationKind();
+
+ /// \brief Set the kind of specialization or template instantiation this is.
+ void setTemplateSpecializationKind(TemplateSpecializationKind TSK);
+
/// getDefaultConstructor - Returns the default constructor for this class
CXXConstructorDecl *getDefaultConstructor(ASTContext &Context);
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 09f39513b4..0a267091f5 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -846,6 +846,8 @@ def err_template_param_default_arg_missing : Error<
def err_template_variable : Error<"variable %0 declared as a template">;
def err_template_variable_noparams : Error<
"extraneous 'template<>' in declaration of variable %0">;
+def err_template_tag_noparams : Error<
+ "extraneous 'template<>' in declaration of %0 %1">;
// C++ Template Argument Lists
def err_template_arg_list_different_arity : Error<
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 7408f2fc60..2d35117a50 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -437,6 +437,53 @@ void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) {
Conversions.addOverload(ConvDecl);
}
+CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const {
+ if (MemberSpecializationInfo *MSInfo
+ = TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>())
+ return cast<CXXRecordDecl>(MSInfo->getInstantiatedFrom());
+
+ return 0;
+}
+
+void
+CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
+ TemplateSpecializationKind TSK) {
+ assert(TemplateOrInstantiation.isNull() &&
+ "Previous template or instantiation?");
+ assert(!isa<ClassTemplateSpecializationDecl>(this));
+ TemplateOrInstantiation
+ = new (getASTContext()) MemberSpecializationInfo(RD, TSK);
+}
+
+TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() {
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(this))
+ return Spec->getSpecializationKind();
+
+ if (MemberSpecializationInfo *MSInfo
+ = TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>())
+ return MSInfo->getTemplateSpecializationKind();
+
+ return TSK_Undeclared;
+}
+
+void
+CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(this)) {
+ Spec->setSpecializationKind(TSK);
+ return;
+ }
+
+ if (MemberSpecializationInfo *MSInfo
+ = TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>()) {
+ MSInfo->setTemplateSpecializationKind(TSK);
+ return;
+ }
+
+ assert(false && "Not a class template or member class specialization");
+}
+
CXXConstructorDecl *
CXXRecordDecl::getDefaultConstructor(ASTContext &Context) {
QualType ClassType = Context.getTypeDeclType(this);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 2070335a61..267eea8a1b 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -4161,11 +4161,14 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
TemplateParameterLists.release();
return Result.get();
} else {
- // FIXME: diagnose the extraneous 'template<>', once we recover
- // slightly better in ParseTemplate.cpp from bogus template
- // parameters.
+ // The "template<>" header is extraneous.
+ Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams)
+ << ElaboratedType::getNameForTagKind(Kind) << Name;
+ isExplicitSpecialization = true;
}
}
+
+ TemplateParameterLists.release();
}
DeclContext *SearchDC = CurContext;
@@ -4493,6 +4496,11 @@ CreateNewDecl:
}
}
+ // If this is a specialization of a member class (of a class template),
+ // check the specialization.
+ if (isExplicitSpecialization && CheckMemberSpecialization(New, PrevDecl))
+ Invalid = true;
+
if (Invalid)
New->setInvalidDecl();
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 5c6ec0004a..219d73146e 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2360,15 +2360,13 @@ static TemplateSpecializationKind getTemplateSpecializationKind(NamedDecl *D) {
if (!D)
return TSK_Undeclared;
- if (ClassTemplateSpecializationDecl *CTS
- = dyn_cast<ClassTemplateSpecializationDecl>(D))
- return CTS->getSpecializationKind();
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D))
+ return Record->getTemplateSpecializationKind();
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
return Function->getTemplateSpecializationKind();
if (VarDecl *Var = dyn_cast<VarDecl>(D))
return Var->getTemplateSpecializationKind();
- // FIXME: member classes of class templates!
return TSK_Undeclared;
}
@@ -3192,23 +3190,46 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) {
// FIXME: Check for specialization-after-instantiation errors and such.
// Note that this is an explicit instantiation of a member.
+ // the original declaration to note that it is an explicit specialization
+ // (if it was previously an implicit instantiation). This latter step
+ // makes bookkeeping easier.
if (isa<FunctionDecl>(Member)) {
- // FIXME: We're also setting the original instantiation we found to be
- // an explicit specialization, although I'd rather not have to do this.
- cast<FunctionDecl>(Instantiation)->setTemplateSpecializationKind(
- TSK_ExplicitSpecialization);
+ FunctionDecl *InstantiationFunction = cast<FunctionDecl>(Instantiation);
+ if (InstantiationFunction->getTemplateSpecializationKind() ==
+ TSK_ImplicitInstantiation) {
+ InstantiationFunction->setTemplateSpecializationKind(
+ TSK_ExplicitSpecialization);
+ InstantiationFunction->setLocation(Member->getLocation());
+ }
+
cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction(
cast<CXXMethodDecl>(InstantiatedFrom),
TSK_ExplicitSpecialization);
} else if (isa<VarDecl>(Member)) {
+ VarDecl *InstantiationVar = cast<VarDecl>(Instantiation);
+ if (InstantiationVar->getTemplateSpecializationKind() ==
+ TSK_ImplicitInstantiation) {
+ InstantiationVar->setTemplateSpecializationKind(
+ TSK_ExplicitSpecialization);
+ InstantiationVar->setLocation(Member->getLocation());
+ }
+
Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member),
cast<VarDecl>(InstantiatedFrom),
TSK_ExplicitSpecialization);
} else {
assert(isa<CXXRecordDecl>(Member) && "Only member classes remain");
- // FIXME: Record TSK_ExplicitSpecialization.
+ CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation);
+ if (InstantiationClass->getTemplateSpecializationKind() ==
+ TSK_ImplicitInstantiation) {
+ InstantiationClass->setTemplateSpecializationKind(
+ TSK_ExplicitSpecialization);
+ InstantiationClass->setLocation(Member->getLocation());
+ }
+
cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
- cast<CXXRecordDecl>(InstantiatedFrom));
+ cast<CXXRecordDecl>(InstantiatedFrom),
+ TSK_ExplicitSpecialization);
}
// Save the caller the trouble of having to figure out which declaration
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 2f7af60e05..ec00d9805c 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -972,20 +972,30 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation,
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateSpecializationKind TSK) {
- // FIXME: extern templates
for (DeclContext::decl_iterator D = Instantiation->decls_begin(),
DEnd = Instantiation->decls_end();
D != DEnd; ++D) {
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) {
- if (Function->getInstantiatedFromMemberFunction())
+ if (Function->getInstantiatedFromMemberFunction()) {
+ // If this member was explicitly specialized, do nothing.
+ if (Function->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization)
+ continue;
+
Function->setTemplateSpecializationKind(TSK);
- if (!Function->getBody() && TSK != TSK_ExplicitInstantiationDeclaration)
+ }
+
+ if (!Function->getBody() && TSK == TSK_ExplicitInstantiationDefinition)
InstantiateFunctionDefinition(PointOfInstantiation, Function);
} else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
if (Var->isStaticDataMember()) {
+ // If this member was explicitly specialized, do nothing.
+ if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ continue;
+
Var->setTemplateSpecializationKind(TSK);
- if (TSK != TSK_ExplicitInstantiationDeclaration)
+ if (TSK == TSK_ExplicitInstantiationDefinition)
InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var);
}
} else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
@@ -994,6 +1004,11 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
assert(Record->getInstantiatedFromMemberClass() &&
"Missing instantiated-from-template information");
+
+ // If this member was explicitly specialized, do nothing.
+ if (Record->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ continue;
+
if (!Record->getDefinition(Context))
InstantiateClass(PointOfInstantiation, Record,
Record->getInstantiatedFromMemberClass(),
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index bafcea054e..b354827e01 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -454,7 +454,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
if (D->getAccess() != AS_none)
Record->setAccess(D->getAccess());
if (!D->isInjectedClassName())
- Record->setInstantiationOfMemberClass(D);
+ Record->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation);
// If the original function was part of a friend declaration,
// inherit its namespace state.
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 402bc9db08..da72197f0c 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1849,10 +1849,11 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
= dyn_cast<CXXRecordDecl>(Record->getDecl())) {
if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) {
// This record was instantiated from a class within a template.
- return InstantiateClass(Loc, Rec, Pattern,
- getTemplateInstantiationArgs(Rec),
- TSK_ImplicitInstantiation,
- /*Complain=*/diag != 0);
+ if (Rec->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
+ return InstantiateClass(Loc, Rec, Pattern,
+ getTemplateInstantiationArgs(Rec),
+ TSK_ImplicitInstantiation,
+ /*Complain=*/diag != 0);
}
}
}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
index 438c41159a..0ba95d875a 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
@@ -55,7 +55,7 @@ struct X0 { // expected-note 2{{here}}
t = 17;
}
- struct Inner : public T { };
+ struct Inner : public T { }; // expected-note 3{{here}}
template<typename U>
struct InnerTemplate : public T { };
@@ -115,6 +115,8 @@ namespace N0 {
template<> long X0<long>::member = 17;
template<> float X0<float>::member;
+
+ template<> double X0<double>::member;
}
NonDefaultConstructible &get_static_member() {
@@ -125,14 +127,51 @@ template<> int N0::X0<int>::member; // expected-error{{originally}}
template<> float N0::X0<float>::member = 3.14f;
-#if 0
-// FIXME: update the remainder of this test to check for scopes properly.
+namespace N1 {
+ template<> double N0::X0<double>::member = 3.14; // expected-error{{not in a namespace enclosing}}
+}
+
// -- member class of a class template
+namespace N0 {
+
+ template<>
+ struct X0<void*>::Inner { };
+
+ template<>
+ struct X0<int>::Inner { };
+
+ template<>
+ struct X0<unsigned>::Inner;
+
+ template<>
+ struct X0<float>::Inner;
+
+ template<>
+ struct X0<double>::Inner; // expected-note{{forward declaration}}
+}
+
template<>
-struct X0<void*>::Inner { };
+struct N0::X0<long>::Inner { }; // expected-error{{originally}}
-X0<void*>::Inner inner0;
+template<>
+struct N0::X0<float>::Inner { };
+
+namespace N1 {
+ template<>
+ struct N0::X0<unsigned>::Inner { }; // expected-error{{member class specialization}}
+ template<>
+ struct N0::X0<unsigned long>::Inner { }; // expected-error{{member class specialization}}
+};
+
+N0::X0<void*>::Inner inner0;
+N0::X0<int>::Inner inner1;
+N0::X0<long>::Inner inner2;
+N0::X0<float>::Inner inner3;
+N0::X0<double>::Inner inner4; // expected-error{{incomplete}}
+
+#if 0
+// FIXME: update the remainder of this test to check for scopes properly.
// -- member class template of a class template
template<>
template<>
diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp
index 7f1ff3dc31..9309b72a55 100644
--- a/test/Parser/cxx-template-decl.cpp
+++ b/test/Parser/cxx-template-decl.cpp
@@ -7,9 +7,12 @@ template x; // expected-error {{C++ requires a type specifier for al
export template x; // expected-error {{expected '<' after 'template'}}
export template<class T> class x0; // expected-note {{exported templates are unsupported}}
template < ; // expected-error {{parse error}} expected-error {{declaration does not declare anything}}
-template <template X> struct Err1; // expected-error {{expected '<' after 'template'}}
-template <template <typename> > struct Err2; // expected-error {{expected 'class' before '>'}}
-template <template <typename> Foo> struct Err3; // expected-error {{expected 'class' before 'Foo'}}
+template <template X> struct Err1; // expected-error {{expected '<' after 'template'}} \
+// expected-error{{extraneous}}
+template <template <typename> > struct Err2; // expected-error {{expected 'class' before '>'}} \
+// expected-error{{extraneous}}
+template <template <typename> Foo> struct Err3; // expected-error {{expected 'class' before 'Foo'}} \
+// expected-error{{extraneous}}
// Template function declarations
template <typename T> void foo();