diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 47 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 14 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 41 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 23 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 9 |
6 files changed, 114 insertions, 22 deletions
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 7408f2fc607..2d35117a50b 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 2070335a614..267eea8a1bc 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/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/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 5c6ec0004af..219d73146ea 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/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/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 2f7af60e05d..ec00d9805c0 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/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/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index bafcea054e1..b354827e016 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/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/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 402bc9db088..da72197f0ca 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/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); } } } |