forked from OSchip/llvm-project
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:
parent
e2ab0f17cf
commit
fd76d91366
|
@ -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">>;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue