r207734 - Add support for __declspec(thread) under -fms-extensions
Reid Kleckner
reid at kleckner.net
Wed Apr 30 20:16:48 PDT 2014
Author: rnk
Date: Wed Apr 30 22:16:47 2014
New Revision: 207734
URL: http://llvm.org/viewvc/llvm-project?rev=207734&view=rev
Log:
Add support for __declspec(thread) under -fms-extensions
Reviewers: rsmith
Differential Revision: http://reviews.llvm.org/D3551
Added:
cfe/trunk/test/SemaCXX/declspec-thread.cpp
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/include/clang/Basic/Attr.td
cfe/trunk/include/clang/Basic/AttrDocs.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=207734&r1=207733&r2=207734&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed Apr 30 22:16:47 2014
@@ -808,22 +808,12 @@ public:
void setTSCSpec(ThreadStorageClassSpecifier TSC) {
VarDeclBits.TSCSpec = TSC;
+ assert(VarDeclBits.TSCSpec == TSC && "truncation");
}
ThreadStorageClassSpecifier getTSCSpec() const {
return static_cast<ThreadStorageClassSpecifier>(VarDeclBits.TSCSpec);
}
- TLSKind getTLSKind() const {
- switch (VarDeclBits.TSCSpec) {
- case TSCS_unspecified:
- return TLS_None;
- case TSCS___thread: // Fall through.
- case TSCS__Thread_local:
- return TLS_Static;
- case TSCS_thread_local:
- return TLS_Dynamic;
- }
- llvm_unreachable("Unknown thread storage class specifier!");
- }
+ TLSKind getTLSKind() const;
/// hasLocalStorage - Returns true if a variable with function scope
/// is a non-static local variable.
Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=207734&r1=207733&r2=207734&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Wed Apr 30 22:16:47 2014
@@ -1665,6 +1665,13 @@ def SelectAny : InheritableAttr {
let Documentation = [Undocumented];
}
+def Thread : Attr {
+ let Spellings = [Declspec<"thread">];
+ let LangOpts = [MicrosoftExt];
+ let Documentation = [ThreadDocs];
+ let Subjects = SubjectList<[Var]>;
+}
+
def Win64 : IgnoredAttr {
let Spellings = [Keyword<"__w64">];
let LangOpts = [MicrosoftExt];
Modified: cfe/trunk/include/clang/Basic/AttrDocs.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=207734&r1=207733&r2=207734&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/AttrDocs.td (original)
+++ cfe/trunk/include/clang/Basic/AttrDocs.td Wed Apr 30 22:16:47 2014
@@ -50,6 +50,23 @@ TLS models are mutually exclusive.
}];
}
+def ThreadDocs : Documentation {
+ let Category = DocCatVariable;
+ let Content = [{
+The ``__declspec(thread)`` attribute declares a variable with thread local
+storage. It is available under the ``-fms-extensions`` flag for MSVC
+compatibility. Documentation for the Visual C++ attribute is available on MSDN_.
+
+.. _MSDN: http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx
+
+In Clang, ``__declspec(thread)`` is generally equivalent in functionality to the
+GNU ``__thread`` keyword. The variable must not have a destructor and must have
+a constant initializer, if any. The attribute only applies to variables
+declared with static storage duration, such as globals, class static data
+members, and static locals.
+ }];
+}
+
def CarriesDependencyDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=207734&r1=207733&r2=207734&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Apr 30 22:16:47 2014
@@ -2081,6 +2081,9 @@ def err_attribute_weak_static : Error<
"weak declaration cannot have internal linkage">;
def err_attribute_selectany_non_extern_data : Error<
"'selectany' can only be applied to data items with external linkage">;
+def err_declspec_thread_on_thread_variable : Error<
+ "'__declspec(thread)' applied to variable that already has a "
+ "thread-local storage specifier">;
def err_attribute_dll_not_extern : Error<
"%q0 must have external linkage when declared %q1">;
def warn_attribute_invalid_on_definition : Warning<
@@ -5996,6 +5999,8 @@ def err_thread_dynamic_init : Error<
"initializer for thread-local variable must be a constant expression">;
def err_thread_nontrivial_dtor : Error<
"type of thread-local variable has non-trivial destruction">;
+def err_thread_nontrivial_ctor : Error<
+ "type of thread-local variable has non-trivial construction">;
def note_use_thread_local : Note<
"use 'thread_local' to allow this">;
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=207734&r1=207733&r2=207734&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Wed Apr 30 22:16:47 2014
@@ -1646,6 +1646,21 @@ void VarDecl::setStorageClass(StorageCla
VarDeclBits.SClass = SC;
}
+VarDecl::TLSKind VarDecl::getTLSKind() const {
+ switch (VarDeclBits.TSCSpec) {
+ case TSCS_unspecified:
+ if (hasAttr<ThreadAttr>())
+ return TLS_Static;
+ return TLS_None;
+ case TSCS___thread: // Fall through.
+ case TSCS__Thread_local:
+ return TLS_Static;
+ case TSCS_thread_local:
+ return TLS_Dynamic;
+ }
+ llvm_unreachable("Unknown thread storage class specifier!");
+}
+
SourceRange VarDecl::getSourceRange() const {
if (const Expr *Init = getInit()) {
SourceLocation InitEnd = Init->getLocEnd();
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=207734&r1=207733&r2=207734&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Wed Apr 30 22:16:47 2014
@@ -3697,6 +3697,25 @@ static void handleMSInheritanceAttr(Sema
D->addAttr(IA);
}
+static void handleDeclspecThreadAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ VarDecl *VD = cast<VarDecl>(D);
+ if (!S.Context.getTargetInfo().isTLSSupported()) {
+ S.Diag(Attr.getLoc(), diag::err_thread_unsupported);
+ return;
+ }
+ if (VD->getTSCSpec() != TSCS_unspecified) {
+ S.Diag(Attr.getLoc(), diag::err_declspec_thread_on_thread_variable);
+ return;
+ }
+ if (VD->hasLocalStorage()) {
+ S.Diag(Attr.getLoc(), diag::err_thread_non_global) << "__declspec(thread)";
+ return;
+ }
+ VD->addAttr(::new (S.Context) ThreadAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
+}
+
static void handleARMInterruptAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
// Check the attribute arguments.
@@ -4394,6 +4413,9 @@ static void ProcessDeclAttribute(Sema &S
case AttributeList::AT_SelectAny:
handleSimpleAttribute<SelectAnyAttr>(S, D, Attr);
break;
+ case AttributeList::AT_Thread:
+ handleDeclspecThreadAttr(S, D, Attr);
+ break;
// Thread safety attributes:
case AttributeList::AT_AssertExclusiveLock:
Added: cfe/trunk/test/SemaCXX/declspec-thread.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/declspec-thread.cpp?rev=207734&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/declspec-thread.cpp (added)
+++ cfe/trunk/test/SemaCXX/declspec-thread.cpp Wed Apr 30 22:16:47 2014
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -std=c++11 -fms-extensions -verify %s
+
+__thread __declspec(thread) int a; // expected-error {{already has a thread-local storage specifier}}
+__declspec(thread) __thread int b; // expected-error {{already has a thread-local storage specifier}}
+__declspec(thread) int c(); // expected-warning {{only applies to variables}}
+__declspec(thread) int d;
+int foo();
+__declspec(thread) int e = foo(); // expected-error {{must be a constant expression}} expected-note {{thread_local}}
+
+struct HasCtor { HasCtor(); int x; };
+__declspec(thread) HasCtor f; // expected-error {{must be a constant expression}} expected-note {{thread_local}}
+
+struct HasDtor { ~HasDtor(); int x; };
+__declspec(thread) HasDtor g; // expected-error {{non-trivial destruction}} expected-note {{thread_local}}
+
+struct HasDefaultedDefaultCtor {
+ HasDefaultedDefaultCtor() = default;
+ int x;
+};
+__declspec(thread) HasDefaultedDefaultCtor h;
+
+struct HasConstexprCtor {
+ constexpr HasConstexprCtor(int x) : x(x) {}
+ int x;
+};
+__declspec(thread) HasConstexprCtor i(42);
+
+int foo() {
+ __declspec(thread) int a; // expected-error {{must have global storage}}
+ static __declspec(thread) int b;
+}
+
+extern __declspec(thread) int fwd_thread_var;
+__declspec(thread) int fwd_thread_var = 5;
+
+extern int fwd_thread_var_mismatch; // expected-note {{previous declaration}}
+__declspec(thread) int fwd_thread_var_mismatch = 5; // expected-error-re {{thread-local {{.*}} follows non-thread-local}}
+
+extern __declspec(thread) int thread_mismatch_2; // expected-note {{previous declaration}}
+int thread_mismatch_2 = 5; // expected-error-re {{non-thread-local {{.*}} follows thread-local}}
+
+typedef __declspec(thread) int tls_int_t; // expected-warning {{only applies to variables}}
More information about the cfe-commits
mailing list