diff options
-rw-r--r-- | include/clang/AST/Decl.h | 18 | ||||
-rw-r--r-- | include/clang/AST/DeclCXX.h | 5 | ||||
-rw-r--r-- | include/clang/AST/DeclTemplate.h | 36 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 4 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 17 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 24 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 38 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 72 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 7 | ||||
-rw-r--r-- | test/SemaTemplate/class-template-spec.cpp | 6 |
11 files changed, 198 insertions, 42 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 0e91511dbd..7c326dee33 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -593,6 +593,11 @@ public: /// template specialization or instantiation this is. TemplateSpecializationKind getTemplateSpecializationKind(); + /// \brief If this variable is an instantiation of a static data member of a + /// class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo(); + /// \brief For a static data member that was instantiated from a static /// data member of a class template, set the template specialiation kind. void setTemplateSpecializationKind(TemplateSpecializationKind TSK); @@ -1075,6 +1080,11 @@ public: /// declaration returned by getInstantiatedFromMemberFunction(). FunctionDecl *getInstantiatedFromMemberFunction() const; + /// \brief If this function is an instantiation of a member function of a + /// class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo() const; + /// \brief Specify that this record is an instantiation of the /// member function FD. void setInstantiationOfMemberFunction(FunctionDecl *FD, @@ -1105,6 +1115,14 @@ public: bool isFunctionTemplateSpecialization() const { return getPrimaryTemplate() != 0; } + + /// \brief If this function is actually a function template specialization, + /// retrieve information about this function template specialization. + /// Otherwise, returns NULL. + FunctionTemplateSpecializationInfo *getTemplateSpecializationInfo() const { + return TemplateOrSpecialization. + dyn_cast<FunctionTemplateSpecializationInfo*>(); + } /// \brief Retrieve the primary template that this function template /// specialization either specializes or was instantiated from. diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 7c651b2cc0..c858c5c0df 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -706,6 +706,11 @@ public: /// declaration returned by getInstantiatedFromMemberClass(). CXXRecordDecl *getInstantiatedFromMemberClass() const; + /// \brief If this class is an instantiation of a member class of a + /// class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo() const; + /// \brief Specify that this record is an instantiation of the /// member class RD. void setInstantiationOfMemberClass(CXXRecordDecl *RD, diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index f49aeccb46..e21849c453 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -518,6 +518,10 @@ public: /// specialization from the function template. const TemplateArgumentList *TemplateArguments; + /// \brief The point at which this function template specialization was + /// first instantiated. + SourceLocation PointOfInstantiation; + /// \brief Retrieve the template from which this function was specialized. FunctionTemplateDecl *getTemplate() const { return Template.getPointer(); } @@ -533,6 +537,21 @@ public: Template.setInt(TSK - 1); } + /// \brief Retrieve the first point of instantiation of this function + /// template specialization. + /// + /// The point of instantiation may be an invalid source location if this + /// function has yet to be instantiated. + SourceLocation getPointOfInstantiation() const { + return PointOfInstantiation; + } + + /// \brief Set the (first) point of instantiation of this function template + /// specialization. + void setPointOfInstantiation(SourceLocation POI) { + PointOfInstantiation = POI; + } + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, TemplateArguments->getFlatArgumentList(), TemplateArguments->flat_size(), @@ -556,10 +575,13 @@ class MemberSpecializationInfo { // manner in which the instantiation occurred (in the lower two bits). llvm::PointerIntPair<NamedDecl *, 2> MemberAndTSK; + // The point at which this member was first instantiated. + SourceLocation PointOfInstantiation; + public: explicit MemberSpecializationInfo(NamedDecl *IF, TemplateSpecializationKind TSK) - : MemberAndTSK(IF, TSK - 1) { + : MemberAndTSK(IF, TSK - 1), PointOfInstantiation() { assert(TSK != TSK_Undeclared && "Cannot encode undeclared template specializations for members"); } @@ -579,6 +601,18 @@ public: "Cannot encode undeclared template specializations for members"); MemberAndTSK.setInt(TSK - 1); } + + /// \brief Retrieve the first point of instantiation of this member. + /// If the point of instantiation is an invalid location, then this member + /// has not yet been instantiated. + SourceLocation getPointOfInstantiation() const { + return PointOfInstantiation; + } + + /// \brief Set the first point of instantiation. + void setPointOfInstantiation(SourceLocation POI) { + PointOfInstantiation = POI; + } }; /// Declaration of a template function. diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 252cfd2718..cdc121f342 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -967,6 +967,10 @@ def err_template_spec_redecl_global_scope : Error< def err_spec_member_not_instantiated : Error< "specialization of member %q0 does not specialize an instantiated member">; def note_specialized_decl : Note<"attempt to specialize declaration here">; +def err_specialization_after_instantiation : Error< + "explicit specialization of %0 after instantiation">; +def note_instantiation_required_here : Note< + "%select{implicit|explicit}0 instantiation first required here">; // C++ class template specializations and out-of-line definitions def err_template_spec_needs_header : Error< diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 86c5719bb2..638d1cfd46 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -374,8 +374,7 @@ SourceRange VarDecl::getSourceRange() const { } VarDecl *VarDecl::getInstantiatedFromStaticDataMember() { - if (MemberSpecializationInfo *MSI - = getASTContext().getInstantiatedFromStaticDataMember(this)) + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return cast<VarDecl>(MSI->getInstantiatedFrom()); return 0; @@ -389,9 +388,12 @@ TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() { return TSK_Undeclared; } +MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() { + return getASTContext().getInstantiatedFromStaticDataMember(this); +} + void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { - MemberSpecializationInfo *MSI - = getASTContext().getInstantiatedFromStaticDataMember(this); + MemberSpecializationInfo *MSI = getMemberSpecializationInfo(); assert(MSI && "Not an instantiated static data member?"); MSI->setTemplateSpecializationKind(TSK); } @@ -703,13 +705,16 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { } FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const { - if (MemberSpecializationInfo *Info - = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>()) + if (MemberSpecializationInfo *Info = getMemberSpecializationInfo()) return cast<FunctionDecl>(Info->getInstantiatedFrom()); return 0; } +MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const { + return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>(); +} + void FunctionDecl::setInstantiationOfMemberFunction(FunctionDecl *FD, TemplateSpecializationKind TSK) { diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 64e800094e..b9a87aedd7 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -434,13 +434,16 @@ void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) { } CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const { - if (MemberSpecializationInfo *MSInfo - = TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>()) + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) return cast<CXXRecordDecl>(MSInfo->getInstantiatedFrom()); return 0; } +MemberSpecializationInfo *CXXRecordDecl::getMemberSpecializationInfo() const { + return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>(); +} + void CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD, TemplateSpecializationKind TSK) { @@ -456,8 +459,7 @@ TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() { = dyn_cast<ClassTemplateSpecializationDecl>(this)) return Spec->getSpecializationKind(); - if (MemberSpecializationInfo *MSInfo - = TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>()) + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) return MSInfo->getTemplateSpecializationKind(); return TSK_Undeclared; @@ -471,8 +473,7 @@ CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { return; } - if (MemberSpecializationInfo *MSInfo - = TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>()) { + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) { MSInfo->setTemplateSpecializationKind(TSK); return; } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index f12f2b9985..d29b84b308 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4279,14 +4279,22 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // Diagnose attempts to redefine a tag. if (TUK == TUK_Definition) { if (TagDecl *Def = PrevTagDecl->getDefinition(Context)) { - Diag(NameLoc, diag::err_redefinition) << Name; - Diag(Def->getLocation(), diag::note_previous_definition); - // If this is a redefinition, recover by making this - // struct be anonymous, which will make any later - // references get the previous definition. - Name = 0; - PrevDecl = 0; - Invalid = true; + // If we're defining a specialization and the previous definition + // is from an implicit instantiation, don't emit an error + // here; we'll catch this in the general case below. + if (!isExplicitSpecialization || + !isa<CXXRecordDecl>(Def) || + cast<CXXRecordDecl>(Def)->getTemplateSpecializationKind() + == TSK_ExplicitSpecialization) { + Diag(NameLoc, diag::err_redefinition) << Name; + Diag(Def->getLocation(), diag::note_previous_definition); + // If this is a redefinition, recover by making this + // struct be anonymous, which will make any later + // references get the previous definition. + Name = 0; + PrevDecl = 0; + Invalid = true; + } } else { // If the type is currently being defined, complain // about a nested redefinition. diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 9831fba319..3dc7d8f4ef 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -6199,10 +6199,28 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { // Implicit instantiation of function templates and member functions of // class templates. - if (!Function->getBody() && - Function->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) - PendingImplicitInstantiations.push_back(std::make_pair(Function, Loc)); - + if (!Function->getBody() && + Function->getTemplateSpecializationKind() + == TSK_ImplicitInstantiation) { + bool AlreadyInstantiated = false; + if (FunctionTemplateSpecializationInfo *SpecInfo + = Function->getTemplateSpecializationInfo()) { + if (SpecInfo->getPointOfInstantiation().isInvalid()) + SpecInfo->setPointOfInstantiation(Loc); + else + AlreadyInstantiated = true; + } else if (MemberSpecializationInfo *MSInfo + = Function->getMemberSpecializationInfo()) { + if (MSInfo->getPointOfInstantiation().isInvalid()) + MSInfo->setPointOfInstantiation(Loc); + else + AlreadyInstantiated = true; + } + + if (!AlreadyInstantiated) + PendingImplicitInstantiations.push_back(std::make_pair(Function, Loc)); + } + // FIXME: keep track of references to static functions Function->setUsed(true); return; @@ -6211,9 +6229,15 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (VarDecl *Var = dyn_cast<VarDecl>(D)) { // Implicit instantiation of static data members of class templates. if (Var->isStaticDataMember() && - Var->getInstantiatedFromStaticDataMember() && - Var->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) - PendingImplicitInstantiations.push_back(std::make_pair(Var, Loc)); + Var->getInstantiatedFromStaticDataMember()) { + MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo(); + assert(MSInfo && "Missing member specialization information?"); + if (MSInfo->getPointOfInstantiation().isInvalid() && + MSInfo->getTemplateSpecializationKind()== TSK_ImplicitInstantiation) { + MSInfo->setPointOfInstantiation(Loc); + PendingImplicitInstantiations.push_back(std::make_pair(Var, Loc)); + } + } // FIXME: keep track of references to static data? diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 8a12ac1168..8ca9089c5e 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2820,7 +2820,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TemplateNameLoc, isPartialSpecialization, TSK_ExplicitSpecialization)) return true; - + // The canonical type QualType CanonType; if (PrevDecl && @@ -2918,6 +2918,24 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, CanonType = Context.getTypeDeclType(Specialization); } + // C++ [temp.expl.spec]p6: + // If a template, a member template or the member of a class template is + // explicitly specialized then that specialization shall be declared + // before the first use of that specialization that would cause an implicit + // instantiation to take place, in every translation unit in which such a + // use occurs; no diagnostic is required. + if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) { + SourceRange Range(TemplateNameLoc, RAngleLoc); + Diag(TemplateNameLoc, diag::err_specialization_after_instantiation) + << Context.getTypeDeclType(Specialization) << Range; + + Diag(PrevDecl->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << (PrevDecl->getTemplateSpecializationKind() + != TSK_ImplicitInstantiation); + return true; + } + // If this is not a friend, note that this is an explicit specialization. if (TUK != TUK_Friend) Specialization->setSpecializationKind(TSK_ExplicitSpecialization); @@ -2925,8 +2943,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Check that this isn't a redefinition of this specialization. if (TUK == TUK_Definition) { if (RecordDecl *Def = Specialization->getDefinition(Context)) { - // FIXME: Should also handle explicit specialization after implicit - // instantiation with a special diagnostic. SourceRange Range(TemplateNameLoc, RAngleLoc); Diag(TemplateNameLoc, diag::err_redefinition) << Context.getTypeDeclType(Specialization) << Range; @@ -3106,7 +3122,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, return true; // FIXME: Check if the prior specialization has a point of instantiation. - // If so, we have run afoul of C++ [temp.expl.spec]p6. + // If so, we have run afoul of . // Check the scope of this explicit specialization. if (CheckTemplateSpecializationScope(*this, @@ -3114,11 +3130,29 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, Specialization, FD->getLocation(), false, TSK_ExplicitSpecialization)) return true; + + // C++ [temp.expl.spec]p6: + // If a template, a member template or the member of a class template is + // explicitly specialized then that spe- cialization shall be declared + // before the first use of that specialization that would cause an implicit + // instantiation to take place, in every translation unit in which such a + // use occurs; no diagnostic is required. + FunctionTemplateSpecializationInfo *SpecInfo + = Specialization->getTemplateSpecializationInfo(); + assert(SpecInfo && "Function template specialization info missing?"); + if (SpecInfo->getPointOfInstantiation().isValid()) { + Diag(FD->getLocation(), diag::err_specialization_after_instantiation) + << FD; + Diag(SpecInfo->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << (Specialization->getTemplateSpecializationKind() + != TSK_ImplicitInstantiation); + return true; + } // Mark the prior declaration as an explicit specialization, so that later // clients know that this is an explicit specialization. - // FIXME: Check for prior explicit instantiations? - Specialization->setTemplateSpecializationKind(TSK_ExplicitSpecialization); + SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization); // Turn the given function declaration into a function template // specialization, with the template arguments from the previous @@ -3156,6 +3190,8 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) { // Try to find the member we are instantiating. NamedDecl *Instantiation = 0; NamedDecl *InstantiatedFrom = 0; + MemberSpecializationInfo *MSInfo = 0; + if (!PrevDecl) { // Nowhere to look anyway. } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Member)) { @@ -3164,6 +3200,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) { if (Context.hasSameType(Function->getType(), Method->getType())) { Instantiation = Method; InstantiatedFrom = Method->getInstantiatedFromMemberFunction(); + MSInfo = Method->getMemberSpecializationInfo(); break; } } @@ -3173,11 +3210,13 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) { if (PrevVar->isStaticDataMember()) { Instantiation = PrevDecl; InstantiatedFrom = PrevVar->getInstantiatedFromStaticDataMember(); + MSInfo = PrevVar->getMemberSpecializationInfo(); } } else if (isa<RecordDecl>(Member)) { if (CXXRecordDecl *PrevRecord = dyn_cast<CXXRecordDecl>(PrevDecl)) { Instantiation = PrevDecl; InstantiatedFrom = PrevRecord->getInstantiatedFromMemberClass(); + MSInfo = PrevRecord->getMemberSpecializationInfo(); } } @@ -3188,9 +3227,6 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) { return false; } - // 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. if (!InstantiatedFrom) { Diag(Member->getLocation(), diag::err_spec_member_not_instantiated) @@ -3199,6 +3235,22 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) { return true; } + // C++ [temp.expl.spec]p6: + // If a template, a member template or the member of a class template is + // explicitly specialized then that spe- cialization shall be declared + // before the first use of that specialization that would cause an implicit + // instantiation to take place, in every translation unit in which such a + // use occurs; no diagnostic is required. + assert(MSInfo && "Member specialization info missing?"); + if (MSInfo->getPointOfInstantiation().isValid()) { + Diag(Member->getLocation(), diag::err_specialization_after_instantiation) + << Member; + Diag(MSInfo->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << (MSInfo->getTemplateSpecializationKind() != TSK_ImplicitInstantiation); + return true; + } + // Check the scope of this explicit specialization. if (CheckTemplateSpecializationScope(*this, InstantiatedFrom, @@ -3206,8 +3258,6 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, NamedDecl *&PrevDecl) { false, TSK_ExplicitSpecialization)) return true; - // 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 diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index b82e5ec9b1..3cdf615423 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1677,12 +1677,17 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, } else if (CXXRecordDecl *Rec = dyn_cast<CXXRecordDecl>(Record->getDecl())) { if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) { + MemberSpecializationInfo *MSInfo = Rec->getMemberSpecializationInfo(); + assert(MSInfo && "Missing member specialization information?"); // This record was instantiated from a class within a template. - if (Rec->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) + if (MSInfo->getTemplateSpecializationKind() + != TSK_ExplicitSpecialization) { + MSInfo->setPointOfInstantiation(Loc); return InstantiateClass(Loc, Rec, Pattern, getTemplateInstantiationArgs(Rec), TSK_ImplicitInstantiation, /*Complain=*/diag != 0); + } } } } diff --git a/test/SemaTemplate/class-template-spec.cpp b/test/SemaTemplate/class-template-spec.cpp index 05ddb05325..e44115c748 100644 --- a/test/SemaTemplate/class-template-spec.cpp +++ b/test/SemaTemplate/class-template-spec.cpp @@ -20,7 +20,8 @@ int test_incomplete_specs(A<double, double> *a1, A<double> *a2) { (void)a1->x; // expected-error{{incomplete definition of type 'A<double, double>'}} - (void)a2->x; // expected-error{{implicit instantiation of undefined template 'struct A<double, int>'}} + (void)a2->x; // expected-error{{implicit instantiation of undefined template 'struct A<double, int>'}} \ + // expected-note{{first required here}} } typedef float FLOAT; @@ -70,7 +71,8 @@ namespace N { } // Diagnose specialization errors -struct A<double> { }; // expected-error{{template specialization requires 'template<>'}} +struct A<double> { }; // expected-error{{template specialization requires 'template<>'}} \ + // expected-error{{after instantiation}} template<> struct ::A<double>; |