forked from OSchip/llvm-project
Enable DLL attribute propagation on explicit instantiation definitions (PR23770)
This is a follow-up to r225570 which enabled adding DLL attributes when a class template goes from explicit instantiation declaration to explicit instantiation definition. llvm-svn: 239375
This commit is contained in:
parent
c0875507be
commit
fce87cae44
|
@ -5110,6 +5110,10 @@ public:
|
|||
bool AnyErrors);
|
||||
|
||||
void checkClassLevelDLLAttribute(CXXRecordDecl *Class);
|
||||
void propagateDLLAttrToBaseClassTemplate(
|
||||
CXXRecordDecl *Class, Attr *ClassAttr,
|
||||
ClassTemplateSpecializationDecl *BaseTemplateSpec,
|
||||
SourceLocation BaseLoc);
|
||||
void CheckCompletedCXXClass(CXXRecordDecl *Record);
|
||||
void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
|
||||
Decl *TagDecl,
|
||||
|
|
|
@ -1345,61 +1345,6 @@ static bool findCircularInheritance(const CXXRecordDecl *Class,
|
|||
return false;
|
||||
}
|
||||
|
||||
/// \brief Perform propagation of DLL attributes from a derived class to a
|
||||
/// templated base class for MS compatibility.
|
||||
static void propagateDLLAttrToBaseClassTemplate(
|
||||
Sema &S, CXXRecordDecl *Class, Attr *ClassAttr,
|
||||
ClassTemplateSpecializationDecl *BaseTemplateSpec, SourceLocation BaseLoc) {
|
||||
if (getDLLAttr(
|
||||
BaseTemplateSpec->getSpecializedTemplate()->getTemplatedDecl())) {
|
||||
// If the base class template has a DLL attribute, don't try to change it.
|
||||
return;
|
||||
}
|
||||
|
||||
auto TSK = BaseTemplateSpec->getSpecializationKind();
|
||||
if (!getDLLAttr(BaseTemplateSpec) &&
|
||||
(TSK == TSK_Undeclared || TSK == TSK_ExplicitInstantiationDeclaration ||
|
||||
TSK == TSK_ImplicitInstantiation)) {
|
||||
// The template hasn't been instantiated yet (or it has, but only as an
|
||||
// explicit instantiation declaration or implicit instantiation, which means
|
||||
// we haven't codegenned any members yet), so propagate the attribute.
|
||||
auto *NewAttr = cast<InheritableAttr>(ClassAttr->clone(S.getASTContext()));
|
||||
NewAttr->setInherited(true);
|
||||
BaseTemplateSpec->addAttr(NewAttr);
|
||||
|
||||
// If the template is already instantiated, checkDLLAttributeRedeclaration()
|
||||
// needs to be run again to work see the new attribute. Otherwise this will
|
||||
// get run whenever the template is instantiated.
|
||||
if (TSK != TSK_Undeclared)
|
||||
S.checkClassLevelDLLAttribute(BaseTemplateSpec);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (getDLLAttr(BaseTemplateSpec)) {
|
||||
// The template has already been specialized or instantiated with an
|
||||
// attribute, explicitly or through propagation. We should not try to change
|
||||
// it.
|
||||
return;
|
||||
}
|
||||
|
||||
// The template was previously instantiated or explicitly specialized without
|
||||
// a dll attribute, It's too late for us to add an attribute, so warn that
|
||||
// this is unsupported.
|
||||
S.Diag(BaseLoc, diag::warn_attribute_dll_instantiated_base_class)
|
||||
<< BaseTemplateSpec->isExplicitSpecialization();
|
||||
S.Diag(ClassAttr->getLocation(), diag::note_attribute);
|
||||
if (BaseTemplateSpec->isExplicitSpecialization()) {
|
||||
S.Diag(BaseTemplateSpec->getLocation(),
|
||||
diag::note_template_class_explicit_specialization_was_here)
|
||||
<< BaseTemplateSpec;
|
||||
} else {
|
||||
S.Diag(BaseTemplateSpec->getPointOfInstantiation(),
|
||||
diag::note_template_class_instantiation_was_here)
|
||||
<< BaseTemplateSpec;
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Check the validity of a C++ base class specifier.
|
||||
///
|
||||
/// \returns a new CXXBaseSpecifier if well-formed, emits diagnostics
|
||||
|
@ -1471,8 +1416,8 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
|
|||
if (Attr *ClassAttr = getDLLAttr(Class)) {
|
||||
if (auto *BaseTemplate = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
|
||||
BaseType->getAsCXXRecordDecl())) {
|
||||
propagateDLLAttrToBaseClassTemplate(*this, Class, ClassAttr,
|
||||
BaseTemplate, BaseLoc);
|
||||
propagateDLLAttrToBaseClassTemplate(Class, ClassAttr, BaseTemplate,
|
||||
BaseLoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4884,6 +4829,61 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
|
|||
}
|
||||
}
|
||||
|
||||
/// \brief Perform propagation of DLL attributes from a derived class to a
|
||||
/// templated base class for MS compatibility.
|
||||
void Sema::propagateDLLAttrToBaseClassTemplate(
|
||||
CXXRecordDecl *Class, Attr *ClassAttr,
|
||||
ClassTemplateSpecializationDecl *BaseTemplateSpec, SourceLocation BaseLoc) {
|
||||
if (getDLLAttr(
|
||||
BaseTemplateSpec->getSpecializedTemplate()->getTemplatedDecl())) {
|
||||
// If the base class template has a DLL attribute, don't try to change it.
|
||||
return;
|
||||
}
|
||||
|
||||
auto TSK = BaseTemplateSpec->getSpecializationKind();
|
||||
if (!getDLLAttr(BaseTemplateSpec) &&
|
||||
(TSK == TSK_Undeclared || TSK == TSK_ExplicitInstantiationDeclaration ||
|
||||
TSK == TSK_ImplicitInstantiation)) {
|
||||
// The template hasn't been instantiated yet (or it has, but only as an
|
||||
// explicit instantiation declaration or implicit instantiation, which means
|
||||
// we haven't codegenned any members yet), so propagate the attribute.
|
||||
auto *NewAttr = cast<InheritableAttr>(ClassAttr->clone(getASTContext()));
|
||||
NewAttr->setInherited(true);
|
||||
BaseTemplateSpec->addAttr(NewAttr);
|
||||
|
||||
// If the template is already instantiated, checkDLLAttributeRedeclaration()
|
||||
// needs to be run again to work see the new attribute. Otherwise this will
|
||||
// get run whenever the template is instantiated.
|
||||
if (TSK != TSK_Undeclared)
|
||||
checkClassLevelDLLAttribute(BaseTemplateSpec);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (getDLLAttr(BaseTemplateSpec)) {
|
||||
// The template has already been specialized or instantiated with an
|
||||
// attribute, explicitly or through propagation. We should not try to change
|
||||
// it.
|
||||
return;
|
||||
}
|
||||
|
||||
// The template was previously instantiated or explicitly specialized without
|
||||
// a dll attribute, It's too late for us to add an attribute, so warn that
|
||||
// this is unsupported.
|
||||
Diag(BaseLoc, diag::warn_attribute_dll_instantiated_base_class)
|
||||
<< BaseTemplateSpec->isExplicitSpecialization();
|
||||
Diag(ClassAttr->getLocation(), diag::note_attribute);
|
||||
if (BaseTemplateSpec->isExplicitSpecialization()) {
|
||||
Diag(BaseTemplateSpec->getLocation(),
|
||||
diag::note_template_class_explicit_specialization_was_here)
|
||||
<< BaseTemplateSpec;
|
||||
} else {
|
||||
Diag(BaseTemplateSpec->getPointOfInstantiation(),
|
||||
diag::note_template_class_instantiation_was_here)
|
||||
<< BaseTemplateSpec;
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Perform semantic checks on a class definition that has been
|
||||
/// completing, introducing implicitly-declared members, checking for
|
||||
/// abstract types, etc.
|
||||
|
|
|
@ -7379,6 +7379,13 @@ Sema::ActOnExplicitInstantiation(Scope *S,
|
|||
A->setInherited(true);
|
||||
Def->addAttr(A);
|
||||
checkClassLevelDLLAttribute(Def);
|
||||
|
||||
// Propagate attribute to base class templates.
|
||||
for (auto &B : Def->bases()) {
|
||||
if (auto *BT = dyn_cast_or_null<ClassTemplateSpecializationDecl>(
|
||||
B.getType()->getAsCXXRecordDecl()))
|
||||
propagateDLLAttrToBaseClassTemplate(Def, A, BT, B.getLocStart());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -707,6 +707,11 @@ void PR23308::f(InternalLinkageType*) {}
|
|||
long use(PR23308* p) { p->f(nullptr); }
|
||||
// M32-DAG: define internal x86_thiscallcc void @"\01?f@PR23308@@QAEXPAUInternalLinkageType@?A@@@Z"
|
||||
|
||||
template <typename T> struct PR23770BaseTemplate { void f() {} };
|
||||
template <typename T> struct PR23770DerivedTemplate : PR23770BaseTemplate<int> {};
|
||||
extern template struct PR23770DerivedTemplate<int>;
|
||||
template struct __declspec(dllexport) PR23770DerivedTemplate<int>;
|
||||
// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?f@?$PR23770BaseTemplate@H@@QAEXXZ"
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -741,6 +741,12 @@ USEMEMFUNC(ExplicitInstantiationDeclExportedDefImportedTemplate<int>, f);
|
|||
// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?f@?$ExplicitInstantiationDeclExportedDefImportedTemplate@H@@QAEXXZ"
|
||||
// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc %struct.ExplicitInstantiationDeclExportedDefImportedTemplate* @"\01??0?$ExplicitInstantiationDeclExportedDefImportedTemplate@H@@QAE@XZ"
|
||||
|
||||
template <typename T> struct PR23770BaseTemplate { void f() {} };
|
||||
template <typename T> struct PR23770DerivedTemplate : PR23770BaseTemplate<int> {};
|
||||
extern template struct PR23770DerivedTemplate<int>;
|
||||
template struct __declspec(dllimport) PR23770DerivedTemplate<int>;
|
||||
USEMEMFUNC(PR23770BaseTemplate<int>, f);
|
||||
// M32-DAG: declare dllimport x86_thiscallcc void @"\01?f@?$PR23770BaseTemplate@H@@QAEXXZ"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Classes with template base classes
|
||||
|
|
Loading…
Reference in New Issue