forked from OSchip/llvm-project
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:
parent
d92a3633e1
commit
1d957a336f
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
Loading…
Reference in New Issue