forked from OSchip/llvm-project
[MinGW] Fix dllexport of explicit template instantiation
Contrary to MSVC, GCC/MinGW needs to have the dllexport attribute on the template instantiation declaration, not on the definition. Previously clang never marked explicit template instantiations as dllexport in MinGW mode, if the instantiation had a previous declaration, regardless of where the attribute was placed. This makes Clang behave like GCC in this regard, and allows using the same attribute form for both MinGW compilers. This fixes PR40256. Differential Revision: https://reviews.llvm.org/D61118 llvm-svn: 359285
This commit is contained in:
parent
c316b22496
commit
5be69bc68a
|
@ -2863,6 +2863,9 @@ def warn_attribute_dllimport_static_field_definition : Warning<
|
||||||
def warn_attribute_dllexport_explicit_instantiation_decl : Warning<
|
def warn_attribute_dllexport_explicit_instantiation_decl : Warning<
|
||||||
"explicit instantiation declaration should not be 'dllexport'">,
|
"explicit instantiation declaration should not be 'dllexport'">,
|
||||||
InGroup<DiagGroup<"dllexport-explicit-instantiation-decl">>;
|
InGroup<DiagGroup<"dllexport-explicit-instantiation-decl">>;
|
||||||
|
def warn_attribute_dllexport_explicit_instantiation_def : Warning<
|
||||||
|
"'dllexport' attribute ignored on explicit instantiation definition">,
|
||||||
|
InGroup<IgnoredAttributes>;
|
||||||
def warn_invalid_initializer_from_system_header : Warning<
|
def warn_invalid_initializer_from_system_header : Warning<
|
||||||
"invalid constructor form class in system header, should not be explicit">,
|
"invalid constructor form class in system header, should not be explicit">,
|
||||||
InGroup<DiagGroup<"invalid-initializer-from-system-header">>;
|
InGroup<DiagGroup<"invalid-initializer-from-system-header">>;
|
||||||
|
|
|
@ -5697,9 +5697,11 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
|
||||||
|
|
||||||
TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind();
|
TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind();
|
||||||
|
|
||||||
// Ignore explicit dllexport on explicit class template instantiation declarations.
|
// Ignore explicit dllexport on explicit class template instantiation
|
||||||
|
// declarations, except in MinGW mode.
|
||||||
if (ClassExported && !ClassAttr->isInherited() &&
|
if (ClassExported && !ClassAttr->isInherited() &&
|
||||||
TSK == TSK_ExplicitInstantiationDeclaration) {
|
TSK == TSK_ExplicitInstantiationDeclaration &&
|
||||||
|
!Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) {
|
||||||
Class->dropAttr<DLLExportAttr>();
|
Class->dropAttr<DLLExportAttr>();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8732,8 +8732,10 @@ DeclResult Sema::ActOnExplicitInstantiation(
|
||||||
? TSK_ExplicitInstantiationDefinition
|
? TSK_ExplicitInstantiationDefinition
|
||||||
: TSK_ExplicitInstantiationDeclaration;
|
: TSK_ExplicitInstantiationDeclaration;
|
||||||
|
|
||||||
if (TSK == TSK_ExplicitInstantiationDeclaration) {
|
if (TSK == TSK_ExplicitInstantiationDeclaration &&
|
||||||
// Check for dllexport class template instantiation declarations.
|
!Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) {
|
||||||
|
// Check for dllexport class template instantiation declarations,
|
||||||
|
// except for MinGW mode.
|
||||||
for (const ParsedAttr &AL : Attr) {
|
for (const ParsedAttr &AL : Attr) {
|
||||||
if (AL.getKind() == ParsedAttr::AT_DLLExport) {
|
if (AL.getKind() == ParsedAttr::AT_DLLExport) {
|
||||||
Diag(ExternLoc,
|
Diag(ExternLoc,
|
||||||
|
@ -8793,6 +8795,19 @@ DeclResult Sema::ActOnExplicitInstantiation(
|
||||||
TemplateSpecializationKind PrevDecl_TSK
|
TemplateSpecializationKind PrevDecl_TSK
|
||||||
= PrevDecl ? PrevDecl->getTemplateSpecializationKind() : TSK_Undeclared;
|
= PrevDecl ? PrevDecl->getTemplateSpecializationKind() : TSK_Undeclared;
|
||||||
|
|
||||||
|
if (TSK == TSK_ExplicitInstantiationDefinition && PrevDecl != nullptr &&
|
||||||
|
Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) {
|
||||||
|
// Check for dllexport class template instantiation definitions in MinGW
|
||||||
|
// mode, if a previous declaration of the instantiation was seen.
|
||||||
|
for (const ParsedAttr &AL : Attr) {
|
||||||
|
if (AL.getKind() == ParsedAttr::AT_DLLExport) {
|
||||||
|
Diag(AL.getLoc(),
|
||||||
|
diag::warn_attribute_dllexport_explicit_instantiation_def);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (CheckExplicitInstantiation(*this, ClassTemplate, TemplateNameLoc,
|
if (CheckExplicitInstantiation(*this, ClassTemplate, TemplateNameLoc,
|
||||||
SS.isSet(), TSK))
|
SS.isSet(), TSK))
|
||||||
return true;
|
return true;
|
||||||
|
@ -8949,6 +8964,14 @@ DeclResult Sema::ActOnExplicitInstantiation(
|
||||||
dllExportImportClassTemplateSpecialization(*this, Def);
|
dllExportImportClassTemplateSpecialization(*this, Def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In MinGW mode, export the template instantiation if the declaration
|
||||||
|
// was marked dllexport.
|
||||||
|
if (PrevDecl_TSK == TSK_ExplicitInstantiationDeclaration &&
|
||||||
|
Context.getTargetInfo().getTriple().isWindowsGNUEnvironment() &&
|
||||||
|
PrevDecl->hasAttr<DLLExportAttr>()) {
|
||||||
|
dllExportImportClassTemplateSpecialization(*this, Def);
|
||||||
|
}
|
||||||
|
|
||||||
// Set the template specialization kind. Make sure it is set before
|
// Set the template specialization kind. Make sure it is set before
|
||||||
// instantiating the members which will trigger ASTConsumer callbacks.
|
// instantiating the members which will trigger ASTConsumer callbacks.
|
||||||
Specialization->setTemplateSpecializationKind(TSK);
|
Specialization->setTemplateSpecializationKind(TSK);
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
// RUN: %clang_cc1 -emit-llvm -triple i686-mingw32 %s -o - | FileCheck %s
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class c {
|
||||||
|
void f();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> void c<T>::f() {}
|
||||||
|
|
||||||
|
template class __declspec(dllexport) c<int>;
|
||||||
|
|
||||||
|
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIiE1fEv
|
||||||
|
|
||||||
|
extern template class __declspec(dllexport) c<char>;
|
||||||
|
template class c<char>;
|
||||||
|
|
||||||
|
// CHECK: define {{.*}} dllexport {{.*}} @_ZN1cIcE1fEv
|
||||||
|
|
||||||
|
extern template class c<double>;
|
||||||
|
template class __declspec(dllexport) c<double>;
|
||||||
|
|
||||||
|
// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN1cIdE1fEv
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct outer {
|
||||||
|
void f();
|
||||||
|
struct inner {
|
||||||
|
void f();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> void outer<T>::f() {}
|
||||||
|
template <class T> void outer<T>::inner::f() {}
|
||||||
|
|
||||||
|
template class __declspec(dllexport) outer<int>;
|
||||||
|
|
||||||
|
// CHECK: define {{.*}} dllexport {{.*}} @_ZN5outerIiE1fEv
|
||||||
|
// CHECK-NOT: define {{.*}} dllexport {{.*}} @_ZN5outerIiE5inner1fEv
|
|
@ -367,10 +367,16 @@ ImplicitlyInstantiatedExportedTemplate<IncompleteType> implicitlyInstantiatedExp
|
||||||
|
|
||||||
// Don't instantiate class members of templates with explicit instantiation declarations, even if they are exported.
|
// Don't instantiate class members of templates with explicit instantiation declarations, even if they are exported.
|
||||||
struct IncompleteType2;
|
struct IncompleteType2;
|
||||||
template <typename T> struct __declspec(dllexport) ExportedTemplateWithExplicitInstantiationDecl { // expected-note{{attribute is here}}
|
#ifdef MS
|
||||||
|
// expected-note@+2{{attribute is here}}
|
||||||
|
#endif
|
||||||
|
template <typename T> struct __declspec(dllexport) ExportedTemplateWithExplicitInstantiationDecl {
|
||||||
int f() { return sizeof(T); } // no-error
|
int f() { return sizeof(T); } // no-error
|
||||||
};
|
};
|
||||||
extern template struct ExportedTemplateWithExplicitInstantiationDecl<IncompleteType2>; // expected-warning{{explicit instantiation declaration should not be 'dllexport'}}
|
#ifdef MS
|
||||||
|
// expected-warning@+2{{explicit instantiation declaration should not be 'dllexport'}}
|
||||||
|
#endif
|
||||||
|
extern template struct ExportedTemplateWithExplicitInstantiationDecl<IncompleteType2>;
|
||||||
|
|
||||||
// Instantiate class members for explicitly instantiated exported templates.
|
// Instantiate class members for explicitly instantiated exported templates.
|
||||||
struct IncompleteType3; // expected-note{{forward declaration of 'IncompleteType3'}}
|
struct IncompleteType3; // expected-note{{forward declaration of 'IncompleteType3'}}
|
||||||
|
@ -402,10 +408,17 @@ struct __declspec(dllexport) ExportedBaseClass2 : public ExportedBaseClassTempla
|
||||||
|
|
||||||
// Warn about explicit instantiation declarations of dllexport classes.
|
// Warn about explicit instantiation declarations of dllexport classes.
|
||||||
template <typename T> struct ExplicitInstantiationDeclTemplate {};
|
template <typename T> struct ExplicitInstantiationDeclTemplate {};
|
||||||
extern template struct __declspec(dllexport) ExplicitInstantiationDeclTemplate<int>; // expected-warning{{explicit instantiation declaration should not be 'dllexport'}} expected-note{{attribute is here}}
|
#ifdef MS
|
||||||
|
// expected-warning@+2{{explicit instantiation declaration should not be 'dllexport'}} expected-note@+2{{attribute is here}}
|
||||||
|
#endif
|
||||||
|
extern template struct __declspec(dllexport) ExplicitInstantiationDeclTemplate<int>;
|
||||||
|
|
||||||
template <typename T> struct __declspec(dllexport) ExplicitInstantiationDeclExportedTemplate {}; // expected-note{{attribute is here}}
|
template <typename T> struct __declspec(dllexport) ExplicitInstantiationDeclExportedTemplate {};
|
||||||
extern template struct ExplicitInstantiationDeclExportedTemplate<int>; // expected-warning{{explicit instantiation declaration should not be 'dllexport'}}
|
#ifdef MS
|
||||||
|
// expected-note@-2{{attribute is here}}
|
||||||
|
// expected-warning@+2{{explicit instantiation declaration should not be 'dllexport'}}
|
||||||
|
#endif
|
||||||
|
extern template struct ExplicitInstantiationDeclExportedTemplate<int>;
|
||||||
|
|
||||||
namespace { struct InternalLinkageType {}; }
|
namespace { struct InternalLinkageType {}; }
|
||||||
struct __declspec(dllexport) PR23308 {
|
struct __declspec(dllexport) PR23308 {
|
||||||
|
@ -438,6 +451,12 @@ template <typename T> struct ExplicitlyInstantiatedTemplate { void func() {} };
|
||||||
template struct ExplicitlyInstantiatedTemplate<int>;
|
template struct ExplicitlyInstantiatedTemplate<int>;
|
||||||
template <typename T> struct ExplicitlyExportInstantiatedTemplate { void func() {} };
|
template <typename T> struct ExplicitlyExportInstantiatedTemplate { void func() {} };
|
||||||
template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate<int>;
|
template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate<int>;
|
||||||
|
template <typename T> struct ExplicitlyExportDeclaredInstantiatedTemplate { void func() {} };
|
||||||
|
extern template struct ExplicitlyExportDeclaredInstantiatedTemplate<int>;
|
||||||
|
#ifndef MS
|
||||||
|
// expected-warning@+2{{'dllexport' attribute ignored on explicit instantiation definition}}
|
||||||
|
#endif
|
||||||
|
template struct __declspec(dllexport) ExplicitlyExportDeclaredInstantiatedTemplate<int>;
|
||||||
template <typename T> struct ExplicitlyImportInstantiatedTemplate { void func() {} };
|
template <typename T> struct ExplicitlyImportInstantiatedTemplate { void func() {} };
|
||||||
template struct __declspec(dllimport) ExplicitlyImportInstantiatedTemplate<int>;
|
template struct __declspec(dllimport) ExplicitlyImportInstantiatedTemplate<int>;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue