/// \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
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());
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,
/// 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.
///
///
/// \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) {
// 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;
// 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;
// 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;
// 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;
}
// 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.
if (PrevDecl) {
bool SuppressNew = false;
- if (CheckSpecializationInstantiationRedecl(*this, TemplateNameLoc, TSK,
+ if (CheckSpecializationInstantiationRedecl(TemplateNameLoc, TSK,
PrevDecl,
PrevDecl->getSpecializationKind(),
PrevDecl->getPointOfInstantiation(),
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);
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(),
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
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))
if (PrevDecl) {
bool SuppressNew = false;
- if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK,
+ if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK,
PrevDecl,
PrevDecl->getTemplateSpecializationKind(),
PrevDecl->getPointOfInstantiation(),
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;
}
// declaration (C++0x [temp.explicit]p10); go ahead and perform the
// explicit instantiation.
ClassTemplateSpec->setSpecializationKind(TSK);
- InstantiateClassTemplateSpecializationMembers(PointOfInstantiation,
- ClassTemplateSpec,
- TSK);
return false;
}
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);
}
}
}
// 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();
--- /dev/null
+// 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;
+