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