diff options
-rw-r--r-- | include/clang/AST/DeclCXX.h | 24 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 47 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 14 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 41 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 23 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 9 | ||||
-rw-r--r-- | test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp | 49 | ||||
-rw-r--r-- | test/Parser/cxx-template-decl.cpp | 9 |
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(); |