diff options
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 27 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/mingw-template-dllexport.cpp | 38 | ||||
-rw-r--r-- | clang/test/SemaCXX/dllexport.cpp | 29 |
5 files changed, 94 insertions, 9 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 059183dbaf1..24619218273 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2863,6 +2863,9 @@ def warn_attribute_dllimport_static_field_definition : Warning< def warn_attribute_dllexport_explicit_instantiation_decl : Warning< "explicit instantiation declaration should not be 'dllexport'">, 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< "invalid constructor form class in system header, should not be explicit">, InGroup<DiagGroup<"invalid-initializer-from-system-header">>; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 797bbbeca95..c03bcb5e3a5 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -5697,9 +5697,11 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { 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() && - TSK == TSK_ExplicitInstantiationDeclaration) { + TSK == TSK_ExplicitInstantiationDeclaration && + !Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) { Class->dropAttr<DLLExportAttr>(); return; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 973911eb840..939941a4c2d 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -8732,8 +8732,10 @@ DeclResult Sema::ActOnExplicitInstantiation( ? TSK_ExplicitInstantiationDefinition : TSK_ExplicitInstantiationDeclaration; - if (TSK == TSK_ExplicitInstantiationDeclaration) { - // Check for dllexport class template instantiation declarations. + if (TSK == TSK_ExplicitInstantiationDeclaration && + !Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) { + // Check for dllexport class template instantiation declarations, + // except for MinGW mode. for (const ParsedAttr &AL : Attr) { if (AL.getKind() == ParsedAttr::AT_DLLExport) { Diag(ExternLoc, @@ -8793,6 +8795,19 @@ DeclResult Sema::ActOnExplicitInstantiation( TemplateSpecializationKind PrevDecl_TSK = 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, SS.isSet(), TSK)) return true; @@ -8949,6 +8964,14 @@ DeclResult Sema::ActOnExplicitInstantiation( 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 // instantiating the members which will trigger ASTConsumer callbacks. Specialization->setTemplateSpecializationKind(TSK); diff --git a/clang/test/CodeGenCXX/mingw-template-dllexport.cpp b/clang/test/CodeGenCXX/mingw-template-dllexport.cpp new file mode 100644 index 00000000000..478c4dfb288 --- /dev/null +++ b/clang/test/CodeGenCXX/mingw-template-dllexport.cpp @@ -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 diff --git a/clang/test/SemaCXX/dllexport.cpp b/clang/test/SemaCXX/dllexport.cpp index 3482e9ec505..e4a312adaee 100644 --- a/clang/test/SemaCXX/dllexport.cpp +++ b/clang/test/SemaCXX/dllexport.cpp @@ -367,10 +367,16 @@ ImplicitlyInstantiatedExportedTemplate<IncompleteType> implicitlyInstantiatedExp // Don't instantiate class members of templates with explicit instantiation declarations, even if they are exported. 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 }; -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. 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. 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}} -extern template struct ExplicitInstantiationDeclExportedTemplate<int>; // expected-warning{{explicit instantiation declaration should not be 'dllexport'}} +template <typename T> struct __declspec(dllexport) ExplicitInstantiationDeclExportedTemplate {}; +#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 {}; } struct __declspec(dllexport) PR23308 { @@ -438,6 +451,12 @@ template <typename T> struct ExplicitlyInstantiatedTemplate { void func() {} }; template struct ExplicitlyInstantiatedTemplate<int>; template <typename T> struct ExplicitlyExportInstantiatedTemplate { void func() {} }; 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 struct __declspec(dllimport) ExplicitlyImportInstantiatedTemplate<int>; |