From: David Majnemer Date: Sat, 4 Oct 2014 06:51:54 +0000 (+0000) Subject: MS ABI: Disallow dllimported/exported variables from having TLS X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=18fa1456dc3d536c2da0e040d54fab6b0bbe594f;p=clang MS ABI: Disallow dllimported/exported variables from having TLS Windows TLS relies on indexing through a tls_index in order to get at the DLL's thread local variables. However, this index is not exported along with the variable: it is assumed that all accesses to thread local variables are inside the same module which created the variable in the first place. While there are several implementation techniques we could adopt to fix this (notably, the Itanium ABI gets this for free), it is not worth the heroics. Instead, let's just ban this combination. We could revisit this in the future if we need to. This fixes PR21111. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@219049 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 5fb3af6190..7db98d5992 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2161,6 +2161,8 @@ def err_declspec_thread_on_thread_variable : Error< "thread-local storage specifier">; def err_attribute_dll_not_extern : Error< "%q0 must have external linkage when declared %q1">; +def err_attribute_dll_thread_local : Error< + "%q0 cannot be thread local when declared %q1">; def warn_attribute_invalid_on_definition : Warning< "'%0' attribute cannot be specified on a definition">, InGroup; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 03dd2a7093..c3c436d8e3 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -9534,8 +9534,11 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { } } + // Grab the dllimport or dllexport attribute off of the VarDecl. + const InheritableAttr *DLLAttr = getDLLAttr(VD); + // Imported static data members cannot be defined out-of-line. - if (const DLLImportAttr *IA = VD->getAttr()) { + if (const auto *IA = dyn_cast_or_null(DLLAttr)) { if (VD->isStaticDataMember() && VD->isOutOfLine() && VD->isThisDeclarationADefinition()) { // We allow definitions of dllimport class template static data members @@ -9556,6 +9559,14 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { } } + // dllimport/dllexport variables cannot be thread local, their TLS index + // isn't exported with the variable. + if (DLLAttr && VD->getTLSKind()) { + Diag(VD->getLocation(), diag::err_attribute_dll_thread_local) << VD + << DLLAttr; + VD->setInvalidDecl(); + } + if (UsedAttr *Attr = VD->getAttr()) { if (!Attr->isInherited() && !VD->isThisDeclarationADefinition()) { Diag(Attr->getLocation(), diag::warn_attribute_ignored) << Attr; diff --git a/test/Sema/dllexport.c b/test/Sema/dllexport.c index 6c71ad8298..76b6f6dc5a 100644 --- a/test/Sema/dllexport.c +++ b/test/Sema/dllexport.c @@ -49,6 +49,9 @@ __declspec(dllexport) extern int GlobalRedecl4; // expected-warning{{redeclarati // External linkage is required. __declspec(dllexport) static int StaticGlobal; // expected-error{{'StaticGlobal' must have external linkage when declared 'dllexport'}} +// Thread local variables are invalid. +__declspec(dllexport) __thread int ThreadLocalGlobal; // expected-error{{'ThreadLocalGlobal' cannot be thread local when declared 'dllexport'}} + // Export in local scope. void functionScope() { __declspec(dllexport) int LocalVarDecl; // expected-error{{'LocalVarDecl' must have external linkage when declared 'dllexport'}} diff --git a/test/Sema/dllimport.c b/test/Sema/dllimport.c index d64c85953d..1b111077b6 100644 --- a/test/Sema/dllimport.c +++ b/test/Sema/dllimport.c @@ -77,6 +77,9 @@ __declspec(dllimport) extern int GlobalRedecl5; // expected-warning{{redeclarati // External linkage is required. __declspec(dllimport) static int StaticGlobal; // expected-error{{'StaticGlobal' must have external linkage when declared 'dllimport'}} +// Thread local variables are invalid. +__declspec(dllimport) __thread int ThreadLocalGlobal; // expected-error{{'ThreadLocalGlobal' cannot be thread local when declared 'dllimport'}} + // Import in local scope. __declspec(dllimport) float LocalRedecl1; // expected-note{{previous definition is here}} __declspec(dllimport) float LocalRedecl2; // expected-note{{previous definition is here}} diff --git a/test/SemaCXX/dllexport.cpp b/test/SemaCXX/dllexport.cpp index df87c73786..5d68894409 100644 --- a/test/SemaCXX/dllexport.cpp +++ b/test/SemaCXX/dllexport.cpp @@ -64,6 +64,9 @@ namespace ns { __declspec(dllexport) int ExternalGlobal; } __declspec(dllexport) auto InternalAutoTypeGlobal = Internal(); // expected-error{{'InternalAutoTypeGlobal' must have external linkage when declared 'dllexport'}} __declspec(dllexport) auto ExternalAutoTypeGlobal = External(); +// Thread local variables are invalid. +__declspec(dllexport) __thread int ThreadLocalGlobal; // expected-error{{'ThreadLocalGlobal' cannot be thread local when declared 'dllexport'}} + // Export in local scope. void functionScope() { __declspec(dllexport) int LocalVarDecl; // expected-error{{'LocalVarDecl' must have external linkage when declared 'dllexport'}} diff --git a/test/SemaCXX/dllimport.cpp b/test/SemaCXX/dllimport.cpp index d0e88368fc..1ba25dbbc5 100644 --- a/test/SemaCXX/dllimport.cpp +++ b/test/SemaCXX/dllimport.cpp @@ -86,6 +86,9 @@ namespace ns { __declspec(dllimport) int ExternalGlobal; } __declspec(dllimport) auto InternalAutoTypeGlobal = Internal(); // expected-error{{'InternalAutoTypeGlobal' must have external linkage when declared 'dllimport'}} // expected-error@-1{{definition of dllimport data}} +// Thread local variables are invalid. +__declspec(dllimport) __thread int ThreadLocalGlobal; // expected-error{{'ThreadLocalGlobal' cannot be thread local when declared 'dllimport'}} + // Import in local scope. __declspec(dllimport) float LocalRedecl1; // expected-note{{previous definition is here}} __declspec(dllimport) float LocalRedecl2; // expected-note{{previous definition is here}}