diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 11 | ||||
-rw-r--r-- | clang/lib/AST/Decl.cpp | 21 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 20 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 91 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 9 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 28 |
8 files changed, 135 insertions, 54 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 1fa492c874b..85b4fd6d6cc 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -232,9 +232,10 @@ void ASTContext::InitBuiltinTypes() { InitBuiltinType(NullPtrTy, BuiltinType::NullPtr); } -VarDecl *ASTContext::getInstantiatedFromStaticDataMember(VarDecl *Var) { +MemberSpecializationInfo * +ASTContext::getInstantiatedFromStaticDataMember(VarDecl *Var) { assert(Var->isStaticDataMember() && "Not a static data member"); - llvm::DenseMap<VarDecl *, VarDecl *>::iterator Pos + llvm::DenseMap<VarDecl *, MemberSpecializationInfo *>::iterator Pos = InstantiatedFromStaticDataMember.find(Var); if (Pos == InstantiatedFromStaticDataMember.end()) return 0; @@ -243,12 +244,14 @@ VarDecl *ASTContext::getInstantiatedFromStaticDataMember(VarDecl *Var) { } void -ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl) { +ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, + TemplateSpecializationKind TSK) { assert(Inst->isStaticDataMember() && "Not a static data member"); assert(Tmpl->isStaticDataMember() && "Not a static data member"); assert(!InstantiatedFromStaticDataMember[Inst] && "Already noted what static data member was instantiated from"); - InstantiatedFromStaticDataMember[Inst] = Tmpl; + InstantiatedFromStaticDataMember[Inst] + = new (*this) MemberSpecializationInfo(Tmpl, TSK); } UnresolvedUsingDecl * diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index a5c9fa4bac8..5584e4c3dad 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -371,7 +371,26 @@ SourceRange VarDecl::getSourceRange() const { } VarDecl *VarDecl::getInstantiatedFromStaticDataMember() { - return getASTContext().getInstantiatedFromStaticDataMember(this); + if (MemberSpecializationInfo *MSI + = getASTContext().getInstantiatedFromStaticDataMember(this)) + return cast<VarDecl>(MSI->getInstantiatedFrom()); + + return 0; +} + +TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() { + if (MemberSpecializationInfo *MSI + = getASTContext().getInstantiatedFromStaticDataMember(this)) + return MSI->getTemplateSpecializationKind(); + + return TSK_Undeclared; +} + +void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + MemberSpecializationInfo *MSI + = getASTContext().getInstantiatedFromStaticDataMember(this); + assert(MSI && "Not an instantiated static data member?"); + MSI->setTemplateSpecializationKind(TSK); } bool VarDecl::isTentativeDefinition(ASTContext &Context) const { diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 6142eacd57f..08cb06db561 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2519,8 +2519,7 @@ public: unsigned NumExplicitTemplateArgs, SourceLocation RAngleLoc, NamedDecl *&PrevDecl); - bool CheckMemberFunctionSpecialization(CXXMethodDecl *FD, - NamedDecl *&PrevDecl); + bool CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl); virtual DeclResult ActOnExplicitInstantiation(Scope *S, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index d612bb8351f..2070335a614 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2193,7 +2193,6 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. - // FIXME: Actually record when this is an explicit specialization! bool isExplicitSpecialization = false; if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( @@ -2259,7 +2258,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, !(NewVD->hasLinkage() && isOutOfScopePreviousDeclaration(PrevDecl, DC, Context))) PrevDecl = 0; - + // Merge the decl with the existing one if appropriate. if (PrevDecl) { if (isa<FieldDecl>(PrevDecl) && D.getCXXScopeSpec().isSet()) { @@ -2281,6 +2280,11 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, CheckVariableDeclaration(NewVD, PrevDecl, Redeclaration); + // This is an explicit specialization of a static data member. Check it. + if (isExplicitSpecialization && !NewVD->isInvalidDecl() && + CheckMemberSpecialization(NewVD, PrevDecl)) + NewVD->setInvalidDecl(); + // attributes declared post-definition are currently ignored if (PrevDecl) { const VarDecl *Def = 0, *PrevVD = dyn_cast<VarDecl>(PrevDecl); @@ -2837,8 +2841,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, PrevDecl)) NewFD->setInvalidDecl(); } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) && - CheckMemberFunctionSpecialization(cast<CXXMethodDecl>(NewFD), - PrevDecl)) + CheckMemberSpecialization(NewFD, PrevDecl)) NewFD->setInvalidDecl(); // Perform semantic checking on the function declaration. @@ -3400,6 +3403,15 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, return; } + // C++ [temp.expl.spec]p15: + // An explicit specialization of a static data member of a template is a + // definition if the declaration includes an initializer; otherwise, it + // is a declaration. + if (Var->isStaticDataMember() && + Var->getInstantiatedFromStaticDataMember() && + Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return; + // C++ [dcl.init]p9: // If no initializer is specified for an object, and the object // is of (possibly cv-qualified) non-POD class type (or array diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 3bd72d07d2e..c9525f39e55 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6209,11 +6209,9 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (VarDecl *Var = dyn_cast<VarDecl>(D)) { // Implicit instantiation of static data members of class templates. - // FIXME: distinguish between implicit instantiations (which we need to - // actually instantiate) and explicit specializations. - // FIXME: extern templates if (Var->isStaticDataMember() && - Var->getInstantiatedFromStaticDataMember()) + Var->getInstantiatedFromStaticDataMember() && + Var->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) PendingImplicitInstantiations.push_back(std::make_pair(Var, Loc)); // FIXME: keep track of references to static data? diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 9d3efa60b06..5c6ec0004af 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2365,8 +2365,9 @@ static TemplateSpecializationKind getTemplateSpecializationKind(NamedDecl *D) { return CTS->getSpecializationKind(); if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) return Function->getTemplateSpecializationKind(); - - // FIXME: static data members! + if (VarDecl *Var = dyn_cast<VarDecl>(D)) + return Var->getTemplateSpecializationKind(); + // FIXME: member classes of class templates! return TSK_Undeclared; } @@ -3118,7 +3119,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, return false; } -/// \brief Perform semantic analysis for the given member function +/// \brief Perform semantic analysis for the given non-template member /// specialization. /// /// This routine performs all of the semantic analysis required for an @@ -3126,27 +3127,45 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, /// the function declaration \p FD will become a member function /// specialization. /// -/// \param FD the function declaration, which will be updated to become a -/// function template specialization. +/// \param Member the member declaration, which will be updated to become a +/// specialization. /// /// \param PrevDecl the set of declarations, one of which may be specialized /// by this function specialization. bool -Sema::CheckMemberFunctionSpecialization(CXXMethodDecl *FD, - NamedDecl *&PrevDecl) { - // Try to find the member function we are instantiating. - CXXMethodDecl *Instantiation = 0; - for (OverloadIterator Ovl(PrevDecl), OvlEnd; Ovl != OvlEnd; ++Ovl) { - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Ovl)) { - if (Context.hasSameType(FD->getType(), Method->getType())) { - Instantiation = Method; - break; +Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) { + assert(!isa<TemplateDecl>(Member) && "Only for non-template members"); + + // Try to find the member we are instantiating. + NamedDecl *Instantiation = 0; + NamedDecl *InstantiatedFrom = 0; + if (!PrevDecl) { + // Nowhere to look anyway. + } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Member)) { + for (OverloadIterator Ovl(PrevDecl), OvlEnd; Ovl != OvlEnd; ++Ovl) { + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Ovl)) { + if (Context.hasSameType(Function->getType(), Method->getType())) { + Instantiation = Method; + InstantiatedFrom = Method->getInstantiatedFromMemberFunction(); + break; + } + } + } + } else if (isa<VarDecl>(Member)) { + if (VarDecl *PrevVar = dyn_cast<VarDecl>(PrevDecl)) + if (PrevVar->isStaticDataMember()) { + Instantiation = PrevDecl; + InstantiatedFrom = PrevVar->getInstantiatedFromStaticDataMember(); } + } else if (isa<RecordDecl>(Member)) { + if (CXXRecordDecl *PrevRecord = dyn_cast<CXXRecordDecl>(PrevDecl)) { + Instantiation = PrevDecl; + InstantiatedFrom = PrevRecord->getInstantiatedFromMemberClass(); } } if (!Instantiation) { - // There is no previous declaration that matches. Since member function + // There is no previous declaration that matches. Since member // specializations are always out-of-line, the caller will complain about // this mismatch later. return false; @@ -3155,30 +3174,43 @@ Sema::CheckMemberFunctionSpecialization(CXXMethodDecl *FD, // FIXME: Check if the prior declaration has a point of instantiation. // If so, we have run afoul of C++ [temp.expl.spec]p6. - // Make sure that this is a specialization of a member function. - FunctionDecl *FunctionInTemplate - = Instantiation->getInstantiatedFromMemberFunction(); - if (!FunctionInTemplate) { - Diag(FD->getLocation(), diag::err_function_spec_not_instantiated) - << FD; + // Make sure that this is a specialization of a member. + if (!InstantiatedFrom) { + Diag(Member->getLocation(), diag::err_spec_member_not_instantiated) + << Member; Diag(Instantiation->getLocation(), diag::note_specialized_decl); return true; } // Check the scope of this explicit specialization. if (CheckTemplateSpecializationScope(*this, - FunctionInTemplate, - Instantiation, FD->getLocation(), + InstantiatedFrom, + Instantiation, Member->getLocation(), false, TSK_ExplicitSpecialization)) return true; // FIXME: Check for specialization-after-instantiation errors and such. - // Note that this function is an explicit instantiation of a member function. - Instantiation->setTemplateSpecializationKind(TSK_ExplicitSpecialization); - FD->setInstantiationOfMemberFunction(FunctionInTemplate, - TSK_ExplicitSpecialization); - + // Note that this is an explicit instantiation of a member. + 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); + cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction( + cast<CXXMethodDecl>(InstantiatedFrom), + TSK_ExplicitSpecialization); + } else if (isa<VarDecl>(Member)) { + Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member), + cast<VarDecl>(InstantiatedFrom), + TSK_ExplicitSpecialization); + } else { + assert(isa<CXXRecordDecl>(Member) && "Only member classes remain"); + // FIXME: Record TSK_ExplicitSpecialization. + cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass( + cast<CXXRecordDecl>(InstantiatedFrom)); + } + // Save the caller the trouble of having to figure out which declaration // this specialization matches. PrevDecl = Instantiation; @@ -3547,7 +3579,8 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, } // Instantiate static data member. - // FIXME: Note that this is an explicit instantiation. + // FIXME: Check for prior specializations and such. + Prev->setTemplateSpecializationKind(TSK); if (TSK == TSK_ExplicitInstantiationDefinition) InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index ee6600adc6a..2f7af60e05d 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -982,9 +982,12 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, if (!Function->getBody() && TSK != TSK_ExplicitInstantiationDeclaration) InstantiateFunctionDefinition(PointOfInstantiation, Function); } else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) { - if (Var->isStaticDataMember() && - TSK != TSK_ExplicitInstantiationDeclaration) - InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var); + if (Var->isStaticDataMember()) { + Var->setTemplateSpecializationKind(TSK); + + if (TSK != TSK_ExplicitInstantiationDeclaration) + InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var); + } } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) { if (Record->isInjectedClassName()) continue; diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index fcacb4a3f00..bafcea054e1 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -155,6 +155,12 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Owner->addDecl(Var); } + // Link instantiations of static data members back to the template from + // which they were instantiated. + if (Var->isStaticDataMember()) + SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D, + TSK_ImplicitInstantiation); + if (D->getInit()) { OwningExprResult Init = SemaRef.SubstExpr(D->getInit(), TemplateArgs); @@ -191,11 +197,6 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { } else if (!Var->isStaticDataMember() || Var->isOutOfLine()) SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false); - // Link instantiations of static data members back to the template from - // which they were instantiated. - if (Var->isStaticDataMember()) - SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D); - return Var; } @@ -977,6 +978,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, assert(!Function->getBody() && "Already instantiated!"); + // Never instantiate an explicit specialization. + if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return; + // Find the function body that we'll be substituting. const FunctionDecl *PatternDecl = 0; if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate()) { @@ -1084,7 +1089,6 @@ void Sema::InstantiateStaticDataMemberDefinition( return; // Find the out-of-line definition of this static data member. - // FIXME: Do we have to look for specializations separately? VarDecl *Def = Var->getInstantiatedFromStaticDataMember(); bool FoundOutOfLineDef = false; assert(Def && "This data member was not instantiated from a template?"); @@ -1106,7 +1110,17 @@ void Sema::InstantiateStaticDataMemberDefinition( return; } - // FIXME: extern templates + // Never instantiate an explicit specialization. + if (Def->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return; + + // C++0x [temp.explicit]p9: + // Except for inline functions, other explicit instantiation declarations + // have the effect of suppressing the implicit instantiation of the entity + // to which they refer. + if (Def->getTemplateSpecializationKind() + == TSK_ExplicitInstantiationDeclaration) + return; InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); if (Inst) |