aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/SemaDecl.cpp24
-rw-r--r--lib/Sema/SemaExpr.cpp38
-rw-r--r--lib/Sema/SemaTemplate.cpp72
-rw-r--r--lib/Sema/SemaType.cpp7
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);
+ }
}
}
}