Warn about dllexported explicit class template instantiation declarations (PR22035)

Clang would previously become confused and crash here.

It does not make a lot of sense to export these, so warning seems appropriate.

MSVC will export some member functions for this kind of specializations, whereas
MinGW ignores the dllexport-edness. The latter behaviour seems better.

Differential Revision: http://reviews.llvm.org/D6984

llvm-svn: 226208
This commit is contained in:
Hans Wennborg 2015-01-15 21:18:30 +00:00
parent e2ab0f17cf
commit fd76d91366
5 changed files with 50 additions and 8 deletions

View File

@ -2201,6 +2201,9 @@ def err_attribute_dllimport_static_field_definition : Error<
def warn_attribute_dllimport_static_field_definition : Warning<
"definition of dllimport static field">,
InGroup<DiagGroup<"dllimport-static-field-def">>;
def warn_attribute_dllexport_explicit_instantiation_decl : Warning<
"explicit instantiation declaration should not be 'dllexport'">,
InGroup<DiagGroup<"dllexport-explicit-instantation-decl">>;
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">>;

View File

@ -4709,15 +4709,20 @@ static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) {
const bool ClassExported = ClassAttr->getKind() == attr::DLLExport;
const bool ClassImported = !ClassExported;
TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind();
// Don't dllexport explicit class template instantiation declarations.
if (ClassExported && TSK == TSK_ExplicitInstantiationDeclaration) {
Class->dropAttr<DLLExportAttr>();
return;
}
// Force declaration of implicit members so they can inherit the attribute.
S.ForceDeclarationOfImplicitMembers(Class);
// FIXME: MSVC's docs say all bases must be exportable, but this doesn't
// seem to be true in practice?
TemplateSpecializationKind TSK =
Class->getTemplateSpecializationKind();
for (Decl *Member : Class->decls()) {
VarDecl *VD = dyn_cast<VarDecl>(Member);
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member);

View File

@ -7165,9 +7165,27 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// There are two forms of explicit instantiation: an explicit instantiation
// definition and an explicit instantiation declaration. An explicit
// instantiation declaration begins with the extern keyword. [...]
TemplateSpecializationKind TSK
= ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
: TSK_ExplicitInstantiationDeclaration;
TemplateSpecializationKind TSK = ExternLoc.isInvalid()
? TSK_ExplicitInstantiationDefinition
: TSK_ExplicitInstantiationDeclaration;
if (TSK == TSK_ExplicitInstantiationDeclaration) {
// Check for dllexport class template instantiation declarations.
for (AttributeList *A = Attr; A; A = A->getNext()) {
if (A->getKind() == AttributeList::AT_DLLExport) {
Diag(ExternLoc,
diag::warn_attribute_dllexport_explicit_instantiation_decl);
Diag(A->getLoc(), diag::note_attribute);
break;
}
}
if (auto *A = ClassTemplate->getTemplatedDecl()->getAttr<DLLExportAttr>()) {
Diag(ExternLoc,
diag::warn_attribute_dllexport_explicit_instantiation_decl);
Diag(A->getLocation(), diag::note_attribute);
}
}
// Translate the parser's template argument list in our AST format.
TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);

View File

@ -631,6 +631,17 @@ template <typename T> struct ExplicitInstConstexprMembers {
};
template struct __declspec(dllexport) ExplicitInstConstexprMembers<void>;
template <typename T> struct ExplicitInstantiationDeclTemplate { void f() {} };
extern template struct __declspec(dllexport) ExplicitInstantiationDeclTemplate<int>;
USEMEMFUNC(ExplicitInstantiationDeclTemplate<int>, f);
// M32-DAG: {{declare|define available_externally}} x86_thiscallcc void @"\01?f@?$ExplicitInstantiationDeclTemplate@H@@QAEXXZ"
template <typename T> struct __declspec(dllexport) ExplicitInstantiationDeclExportedTemplate { void f() {} };
extern template struct ExplicitInstantiationDeclExportedTemplate<int>;
USEMEMFUNC(ExplicitInstantiationDeclExportedTemplate<int>, f);
// M32-DAG: {{declare|define available_externally}} x86_thiscallcc void @"\01?f@?$ExplicitInstantiationDeclExportedTemplate@H@@QAEXXZ"
//===----------------------------------------------------------------------===//
// Classes with template base classes
//===----------------------------------------------------------------------===//

View File

@ -353,10 +353,10 @@ 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 {
template <typename T> struct __declspec(dllexport) ExportedTemplateWithExplicitInstantiationDecl { // expected-note{{attribute is here}}
int f() { return sizeof(T); } // no-error
};
extern template struct ExportedTemplateWithExplicitInstantiationDecl<IncompleteType2>;
extern template struct ExportedTemplateWithExplicitInstantiationDecl<IncompleteType2>; // expected-warning{{explicit instantiation declaration should not be 'dllexport'}}
// Instantiate class members for explicitly instantiated exported templates.
struct IncompleteType3; // expected-note{{forward declaration of 'IncompleteType3'}}
@ -386,7 +386,12 @@ template <typename T> struct __declspec(dllexport) ExportedBaseClassTemplateOfEx
};
struct __declspec(dllexport) ExportedBaseClass2 : public ExportedBaseClassTemplateOfExportedClass<IncompleteType5> {};
// 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}}
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'}}
//===----------------------------------------------------------------------===//
// Classes with template base classes