diff options
Diffstat (limited to 'lib/Sema')
-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 |
4 files changed, 114 insertions, 27 deletions
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); + } } } } |