An explicit instantiation definition only instantiations those class

members that have a definition. Also, use
CheckSpecializationInstantiationRedecl as part of this instantiation
to make sure that we diagnose the various kinds of problems that can
occur with explicit instantiations.

llvm-svn: 85270
This commit is contained in:
Douglas Gregor 2009-10-27 18:42:08 +00:00
parent d92a3633e1
commit 1d957a336f
7 changed files with 187 additions and 81 deletions

View File

@ -605,6 +605,9 @@ public:
/// \brief Determine whether this is or was instantiated from an out-of-line
/// definition of a static data member.
bool isOutOfLine() const;
/// \brief If this is a static data member, find its out-of-line definition.
VarDecl *getOutOfLineDefinition();
/// \brief If this variable is an instantiated static data member of a
/// class template specialization, returns the templated static data member

View File

@ -383,6 +383,19 @@ bool VarDecl::isOutOfLine() const {
return false;
}
VarDecl *VarDecl::getOutOfLineDefinition() {
if (!isStaticDataMember())
return 0;
for (VarDecl::redecl_iterator RD = redecls_begin(), RDEnd = redecls_end();
RD != RDEnd; ++RD) {
if (RD->getLexicalDeclContext()->isFileContext())
return *RD;
}
return 0;
}
VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return cast<VarDecl>(MSI->getInstantiatedFrom());

View File

@ -2577,6 +2577,14 @@ public:
MultiTemplateParamsArg TemplateParameterLists,
Declarator &D);
bool
CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
TemplateSpecializationKind NewTSK,
NamedDecl *PrevDecl,
TemplateSpecializationKind PrevTSK,
SourceLocation PrevPointOfInstantiation,
bool &SuppressNew);
bool CheckFunctionTemplateSpecialization(FunctionDecl *FD,
bool HasExplicitTemplateArgs,
SourceLocation LAngleLoc,

View File

@ -3073,8 +3073,6 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
/// for those cases where they are required and determining whether the
/// new specialization/instantiation will have any effect.
///
/// \param S the semantic analysis object.
///
/// \param NewLoc the location of the new explicit specialization or
/// instantiation.
///
@ -3092,14 +3090,13 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
///
/// \returns true if there was an error that should prevent the introduction of
/// the new declaration into the AST, false otherwise.
static bool
CheckSpecializationInstantiationRedecl(Sema &S,
SourceLocation NewLoc,
TemplateSpecializationKind NewTSK,
NamedDecl *PrevDecl,
TemplateSpecializationKind PrevTSK,
SourceLocation PrevPointOfInstantiation,
bool &SuppressNew) {
bool
Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
TemplateSpecializationKind NewTSK,
NamedDecl *PrevDecl,
TemplateSpecializationKind PrevTSK,
SourceLocation PrevPointOfInstantiation,
bool &SuppressNew) {
SuppressNew = false;
switch (NewTSK) {
@ -3137,9 +3134,9 @@ CheckSpecializationInstantiationRedecl(Sema &S,
// 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.
S.Diag(NewLoc, diag::err_specialization_after_instantiation)
Diag(NewLoc, diag::err_specialization_after_instantiation)
<< PrevDecl;
S.Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here)
Diag(PrevPointOfInstantiation, diag::note_instantiation_required_here)
<< (PrevTSK != TSK_ImplicitInstantiation);
return true;
@ -3172,10 +3169,10 @@ CheckSpecializationInstantiationRedecl(Sema &S,
// If an entity is the subject of both an explicit instantiation
// declaration and an explicit instantiation definition in the same
// translation unit, the definition shall follow the declaration.
S.Diag(NewLoc,
diag::err_explicit_instantiation_declaration_after_definition);
S.Diag(PrevPointOfInstantiation,
diag::note_explicit_instantiation_definition_here);
Diag(NewLoc,
diag::err_explicit_instantiation_declaration_after_definition);
Diag(PrevPointOfInstantiation,
diag::note_explicit_instantiation_definition_here);
assert(PrevPointOfInstantiation.isValid() &&
"Explicit instantiation without point of instantiation?");
SuppressNew = true;
@ -3201,10 +3198,10 @@ CheckSpecializationInstantiationRedecl(Sema &S,
// In C++98/03 mode, we only give an extension warning here, because it
// is not not harmful to try to explicitly instantiate something that
// has been explicitly specialized.
if (!S.getLangOptions().CPlusPlus0x) {
S.Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization)
if (!getLangOptions().CPlusPlus0x) {
Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization)
<< PrevDecl;
S.Diag(PrevDecl->getLocation(),
Diag(PrevDecl->getLocation(),
diag::note_previous_template_specialization);
}
SuppressNew = true;
@ -3220,10 +3217,10 @@ CheckSpecializationInstantiationRedecl(Sema &S,
// For a given template and a given set of template-arguments,
// - an explicit instantiation definition shall appear at most once
// in a program,
S.Diag(NewLoc, diag::err_explicit_instantiation_duplicate)
Diag(NewLoc, diag::err_explicit_instantiation_duplicate)
<< PrevDecl;
S.Diag(PrevPointOfInstantiation,
diag::note_previous_explicit_instantiation);
Diag(PrevPointOfInstantiation,
diag::note_previous_explicit_instantiation);
SuppressNew = true;
return false;
}
@ -3336,7 +3333,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
// 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
// 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.
@ -3662,7 +3659,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
if (PrevDecl) {
bool SuppressNew = false;
if (CheckSpecializationInstantiationRedecl(*this, TemplateNameLoc, TSK,
if (CheckSpecializationInstantiationRedecl(TemplateNameLoc, TSK,
PrevDecl,
PrevDecl->getSpecializationKind(),
PrevDecl->getPointOfInstantiation(),
@ -3738,7 +3735,11 @@ Sema::ActOnExplicitInstantiation(Scope *S,
Specialization->getDefinition(Context));
if (!Def)
InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK);
else // Instantiate the members of this class template specialization.
// Instantiate the members of this class template specialization.
Def = cast_or_null<ClassTemplateSpecializationDecl>(
Specialization->getDefinition(Context));
if (Def)
InstantiateClassTemplateSpecializationMembers(TemplateNameLoc, Def, TSK);
return DeclPtrTy::make(Specialization);
@ -3820,7 +3821,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
MemberSpecializationInfo *MSInfo = PrevDecl->getMemberSpecializationInfo();
bool SuppressNew = false;
assert(MSInfo && "No member specialization information?");
if (CheckSpecializationInstantiationRedecl(*this, TemplateLoc, TSK,
if (CheckSpecializationInstantiationRedecl(TemplateLoc, TSK,
PrevDecl,
MSInfo->getTemplateSpecializationKind(),
MSInfo->getPointOfInstantiation(),
@ -3844,13 +3845,21 @@ Sema::ActOnExplicitInstantiation(Scope *S,
Diag(Pattern->getLocation(), diag::note_forward_declaration)
<< Pattern;
return true;
} else if (InstantiateClass(NameLoc, Record, Def,
getTemplateInstantiationArgs(Record),
TSK))
return true;
} else // Instantiate all of the members of the class.
InstantiateClassMembers(NameLoc, RecordDef,
getTemplateInstantiationArgs(Record), TSK);
} else {
if (InstantiateClass(NameLoc, Record, Def,
getTemplateInstantiationArgs(Record),
TSK))
return true;
RecordDef = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context));
if (!RecordDef)
return true;
}
}
// Instantiate all of the members of the class.
InstantiateClassMembers(NameLoc, RecordDef,
getTemplateInstantiationArgs(Record), TSK);
// FIXME: We don't have any representation for explicit instantiations of
// member classes. Such a representation is not needed for compilation, but it
@ -3969,8 +3978,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo();
assert(MSInfo && "Missing static data member specialization info?");
bool SuppressNew = false;
if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK,
Prev,
if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, Prev,
MSInfo->getTemplateSpecializationKind(),
MSInfo->getPointOfInstantiation(),
SuppressNew))
@ -4069,7 +4077,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
if (PrevDecl) {
bool SuppressNew = false;
if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK,
if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK,
PrevDecl,
PrevDecl->getTemplateSpecializationKind(),
PrevDecl->getPointOfInstantiation(),

View File

@ -914,13 +914,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
if (!Invalid)
Consumer.HandleTagDeclDefinition(Instantiation);
// If this is an explicit instantiation, instantiate our members, too.
if (!Invalid && TSK != TSK_ImplicitInstantiation) {
Inst.Clear();
InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs,
TSK);
}
return Invalid;
}
@ -944,9 +937,6 @@ Sema::InstantiateClassTemplateSpecialization(
// declaration (C++0x [temp.explicit]p10); go ahead and perform the
// explicit instantiation.
ClassTemplateSpec->setSpecializationKind(TSK);
InstantiateClassTemplateSpecializationMembers(PointOfInstantiation,
ClassTemplateSpec,
TSK);
return false;
}
@ -1089,48 +1079,112 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
for (DeclContext::decl_iterator D = Instantiation->decls_begin(),
DEnd = Instantiation->decls_end();
D != DEnd; ++D) {
bool SuppressNew = false;
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(*D)) {
if (Function->getInstantiatedFromMemberFunction()) {
// If this member was explicitly specialized, do nothing.
if (Function->getTemplateSpecializationKind() ==
TSK_ExplicitSpecialization)
if (FunctionDecl *Pattern
= Function->getInstantiatedFromMemberFunction()) {
MemberSpecializationInfo *MSInfo
= Function->getMemberSpecializationInfo();
assert(MSInfo && "No member specialization information?");
if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK,
Function,
MSInfo->getTemplateSpecializationKind(),
MSInfo->getPointOfInstantiation(),
SuppressNew) ||
SuppressNew)
continue;
Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
if (Function->getBody())
continue;
if (TSK == TSK_ExplicitInstantiationDefinition) {
// C++0x [temp.explicit]p8:
// An explicit instantiation definition that names a class template
// specialization explicitly instantiates the class template
// specialization and is only an explicit instantiation definition
// of members whose definition is visible at the point of
// instantiation.
if (!Pattern->getBody())
continue;
Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
InstantiateFunctionDefinition(PointOfInstantiation, Function);
} else {
Function->setTemplateSpecializationKind(TSK, PointOfInstantiation);
}
}
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)
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
assert(MSInfo && "No member specialization information?");
if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK,
Var,
MSInfo->getTemplateSpecializationKind(),
MSInfo->getPointOfInstantiation(),
SuppressNew) ||
SuppressNew)
continue;
Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
if (TSK == TSK_ExplicitInstantiationDefinition)
if (TSK == TSK_ExplicitInstantiationDefinition) {
// C++0x [temp.explicit]p8:
// An explicit instantiation definition that names a class template
// specialization explicitly instantiates the class template
// specialization and is only an explicit instantiation definition
// of members whose definition is visible at the point of
// instantiation.
if (!Var->getInstantiatedFromStaticDataMember()
->getOutOfLineDefinition())
continue;
Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var);
}
} else {
Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
}
}
} else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
if (Record->isInjectedClassName())
continue;
assert(Record->getInstantiatedFromMemberClass() &&
"Missing instantiated-from-template information");
// If this member was explicitly specialized, do nothing.
if (Record->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
MemberSpecializationInfo *MSInfo = Record->getMemberSpecializationInfo();
assert(MSInfo && "No member specialization information?");
if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK,
Record,
MSInfo->getTemplateSpecializationKind(),
MSInfo->getPointOfInstantiation(),
SuppressNew) ||
SuppressNew)
continue;
if (!Record->getDefinition(Context))
InstantiateClass(PointOfInstantiation, Record,
Record->getInstantiatedFromMemberClass(),
CXXRecordDecl *Pattern = Record->getInstantiatedFromMemberClass();
assert(Pattern && "Missing instantiated-from-template information");
if (!Record->getDefinition(Context)) {
if (!Pattern->getDefinition(Context)) {
// C++0x [temp.explicit]p8:
// An explicit instantiation definition that names a class template
// specialization explicitly instantiates the class template
// specialization and is only an explicit instantiation definition
// of members whose definition is visible at the point of
// instantiation.
if (TSK == TSK_ExplicitInstantiationDeclaration) {
MSInfo->setTemplateSpecializationKind(TSK);
MSInfo->setPointOfInstantiation(PointOfInstantiation);
}
continue;
}
InstantiateClass(PointOfInstantiation, Record, Pattern,
TemplateArgs,
TSK);
}
InstantiateClassMembers(PointOfInstantiation, Record, TemplateArgs,
TSK);
Pattern = cast_or_null<CXXRecordDecl>(Record->getDefinition(Context));
if (Pattern)
InstantiateClassMembers(PointOfInstantiation, Pattern, TemplateArgs,
TSK);
}
}
}

View File

@ -1231,24 +1231,17 @@ void Sema::InstantiateStaticDataMemberDefinition(
// Find the out-of-line definition of this static data member.
VarDecl *Def = Var->getInstantiatedFromStaticDataMember();
bool FoundOutOfLineDef = false;
assert(Def && "This data member was not instantiated from a template?");
assert(Def->isStaticDataMember() && "Not a static data member?");
for (VarDecl::redecl_iterator RD = Def->redecls_begin(),
RDEnd = Def->redecls_end();
RD != RDEnd; ++RD) {
if (RD->getLexicalDeclContext()->isFileContext()) {
Def = *RD;
FoundOutOfLineDef = true;
}
}
assert(Def->isStaticDataMember() && "Not a static data member?");
Def = Def->getOutOfLineDefinition();
if (!FoundOutOfLineDef) {
if (!Def) {
// We did not find an out-of-line definition of this static data member,
// so we won't perform any instantiation. Rather, we rely on the user to
// instantiate this definition (or provide a specialization for it) in
// another translation unit.
if (DefinitionRequired) {
Def = Var->getInstantiatedFromStaticDataMember();
Diag(PointOfInstantiation,
diag::err_explicit_instantiation_undefined_member)
<< 2 << Var->getDeclName() << Var->getDeclContext();

View File

@ -0,0 +1,27 @@
// RUN: clang-cc -fsyntax-only -verify %s
template<typename T>
struct X0 {
struct MemberClass;
T* f0(T* ptr);
static T* static_member;
};
template class X0<int>; // okay
template class X0<int(int)>; // okay; nothing gets instantiated.
template<typename T>
struct X0<T>::MemberClass {
T member;
};
template<typename T>
T* X0<T>::f0(T* ptr) {
return ptr + 1;
}
template<typename T>
T* X0<T>::static_member = 0;