diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/AST/Decl.h | 14 | ||||
-rw-r--r-- | clang/include/clang/Basic/Attr.td | 7 | ||||
-rw-r--r-- | clang/include/clang/Basic/AttrDocs.td | 17 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 5 | ||||
-rw-r--r-- | clang/lib/AST/Decl.cpp | 15 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 22 | ||||
-rw-r--r-- | clang/test/SemaCXX/declspec-thread.cpp | 42 |
7 files changed, 110 insertions, 12 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 1ad8a90c4f3..443ac2782af 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -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. diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 6c08e49dac0..bc16819ac20 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -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]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 7f057d0bf5e..a5eb25c1d9f 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -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 = [{ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index a81154596b7..c8467688f35 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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">; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index e33e26b5165..b264be15edf 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1646,6 +1646,21 @@ void VarDecl::setStorageClass(StorageClass SC) { 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(); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 1920182ce20..c33408f193a 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3697,6 +3697,25 @@ static void handleMSInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) 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, Scope *scope, Decl *D, 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: diff --git a/clang/test/SemaCXX/declspec-thread.cpp b/clang/test/SemaCXX/declspec-thread.cpp new file mode 100644 index 00000000000..954f943d973 --- /dev/null +++ b/clang/test/SemaCXX/declspec-thread.cpp @@ -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}} |