From 57890d00f8107a4656bc393cd4f171dd1e0b8007 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 11 May 2018 01:26:11 +0000 Subject: [PATCH] Don't propagate dllimport to base class template static data members MSVC doesn't, so we shouldn't. Fixes PR37232. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@332074 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Attr.td | 10 ++++ lib/Sema/SemaDeclCXX.cpp | 17 +++++++ test/CodeGenCXX/dllimport-template-sdm.cpp | 53 ++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 test/CodeGenCXX/dllimport-template-sdm.cpp diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 9e6a5d6de5..be8d7190ef 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -2566,6 +2566,16 @@ def DLLImport : InheritableAttr, TargetSpecificAttr { let Spellings = [Declspec<"dllimport">, GCC<"dllimport">]; let Subjects = SubjectList<[Function, Var, CXXRecord, ObjCInterface]>; let Documentation = [DLLImportDocs]; + + + let AdditionalMembers = [{ +private: + bool PropagatedToBaseTemplate = false; + +public: + void setPropagatedToBaseTemplate() { PropagatedToBaseTemplate = true; } + bool wasPropagatedToBaseTemplate() { return PropagatedToBaseTemplate; } + }]; } def SelectAny : InheritableAttr { diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index fc2c147415..102e7a5058 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -5626,6 +5626,13 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { // The class is either imported or exported. const bool ClassExported = ClassAttr->getKind() == attr::DLLExport; + // Check if this was a dllimport attribute propagated from a derived class to + // a base class template specialization. We don't apply these attributes to + // static data members. + const bool PropagatedImport = + !ClassExported && + cast(ClassAttr)->wasPropagatedToBaseTemplate(); + TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind(); // Ignore explicit dllexport on explicit class template instantiation declarations. @@ -5677,6 +5684,11 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { } } + // Don't apply dllimport attributes to static data members of class template + // instantiations when the attribute is propagated from a derived class. + if (VD && PropagatedImport) + continue; + if (!cast(Member)->isExternallyVisible()) continue; @@ -5729,6 +5741,11 @@ void Sema::propagateDLLAttrToBaseClassTemplate( NewAttr->setInherited(true); BaseTemplateSpec->addAttr(NewAttr); + // If this was an import, mark that we propagated it from a derived class to + // a base class template specialization. + if (auto *ImportAttr = dyn_cast(NewAttr)) + ImportAttr->setPropagatedToBaseTemplate(); + // 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. diff --git a/test/CodeGenCXX/dllimport-template-sdm.cpp b/test/CodeGenCXX/dllimport-template-sdm.cpp new file mode 100644 index 0000000000..33cbdf6b7e --- /dev/null +++ b/test/CodeGenCXX/dllimport-template-sdm.cpp @@ -0,0 +1,53 @@ +// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -std=c++14 -fms-extensions -o - %s | FileCheck %s --check-prefix=IMPORT +// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -std=c++14 -fms-extensions -o - %s -DTEST_EXPORT | FileCheck %s --check-prefix=EXPORT + +#ifndef TEST_EXPORT +#define DLLATTR __declspec(dllimport) +#else +#define DLLATTR __declspec(dllexport) +#endif + +// PR37232: When a dllimport attribute is propagated from a derived class to a +// base class that happens to be a template specialization, it is only applied +// to template *methods*, and not static data members. If a dllexport attribute +// is propagated, it still applies to static data members. + +// IMPORT-DAG: @"?sdm@Exporter@@2HB" = available_externally dllimport constant i32 2, align 4 +// IMPORT-DAG: @"?csdm@?$A@H@@2HB" = linkonce_odr dso_local constant i32 2, comdat, align 4 +// IMPORT-DAG: @"?sdm@?$A@H@@2HA" = linkonce_odr dso_local global i32 1, comdat, align 4 +// IMPORT-DAG: @"?sdm@?$B@H@@2HB" = available_externally dllimport constant i32 2, align 4 +// IMPORT-DAG: @"?sdm@?$C@H@@2HB" = available_externally dllimport constant i32 2, align 4 + +// EXPORT-DAG: @"?sdm@Exporter@@2HB" = weak_odr dso_local dllexport constant i32 2, comdat, align 4 +// EXPORT-DAG: @"?csdm@?$A@H@@2HB" = weak_odr dso_local dllexport constant i32 2, comdat, align 4 +// EXPORT-DAG: @"?sdm@?$A@H@@2HA" = weak_odr dso_local dllexport global i32 1, comdat, align 4 +// EXPORT-DAG: @"?sdm@?$B@H@@2HB" = weak_odr dso_local dllexport constant i32 2, comdat, align 4 +// EXPORT-DAG: @"?sdm@?$C@H@@2HB" = weak_odr dso_local dllexport constant i32 2, comdat, align 4 + + +template struct A { + static constexpr int csdm = 2; + static int sdm; +}; +template int A::sdm = 1; + +struct DLLATTR Exporter : A { + static constexpr int sdm = 2; +}; + +template struct DLLATTR B { static constexpr int sdm = 2; }; + +template struct DLLATTR C; +template struct C { static constexpr int sdm = 2; }; + +void takeRef(const int &_Args) {} + +int main() { + takeRef(Exporter::sdm); + takeRef(A::csdm); + takeRef(A::sdm); + takeRef(B::sdm); + takeRef(C::sdm); + + return 1; +} -- 2.40.0