- Add more tests

http://reviews.llvm.org/D3551

Files:
  include/clang/AST/Decl.h
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/Specifiers.h
  include/clang/Sema/DeclSpec.h
  include/clang/Sema/Sema.h
  lib/AST/DeclPrinter.cpp
  lib/Sema/DeclSpec.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclAttr.cpp
  test/SemaCXX/declspec-thread.cpp
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -693,7 +693,7 @@
     friend class ASTDeclReader;
 
     unsigned SClass : 3;
-    unsigned TSCSpec : 2;
+    unsigned TSCSpec : 3;
     unsigned InitStyle : 2;
 
     /// \brief Whether this variable is the exception variable in a C++ catch
@@ -725,7 +725,7 @@
     /// the type of this declaration with its previous declaration.
     unsigned PreviousDeclInSameBlockScope : 1;
   };
-  enum { NumVarDeclBits = 14 };
+  enum { NumVarDeclBits = 15 };
 
   friend class ASTDeclReader;
   friend class StmtIteratorBase;
@@ -754,7 +754,7 @@
     /// Otherwise, the number of function parameter scopes enclosing
     /// the function parameter scope in which this parameter was
     /// declared.
-    unsigned ScopeDepthOrObjCQuals : 7;
+    unsigned ScopeDepthOrObjCQuals : 6;
 
     /// The number of parameters preceding this parameter in the
     /// function parameter scope in which it was declared.
@@ -818,6 +818,7 @@
       return TLS_None;
     case TSCS___thread: // Fall through.
     case TSCS__Thread_local:
+    case TSCS___declspec_thread:
       return TLS_Static;
     case TSCS_thread_local:
       return TLS_Dynamic;
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1665,6 +1665,13 @@
   let Documentation = [Undocumented];
 }
 
+def Thread : InheritableAttr {
+  let Spellings = [Declspec<"thread">];
+  let LangOpts = [MicrosoftExt];
+  let Documentation = [Undocumented];
+  let Subjects = SubjectList<[Var]>;
+}
+
 def Win64 : IgnoredAttr {
   let Spellings = [Keyword<"__w64">];
   let LangOpts = [MicrosoftExt];
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -50,6 +50,23 @@
   }];
 }
 
+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
+compatiblity.  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 = [{
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2081,6 +2081,9 @@
   "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 @@
   "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">;
 
Index: include/clang/Basic/Specifiers.h
===================================================================
--- include/clang/Basic/Specifiers.h
+++ include/clang/Basic/Specifiers.h
@@ -163,7 +163,9 @@
     TSCS_thread_local,
     /// C11 _Thread_local. Must be combined with either 'static' or 'extern'
     /// if used at block scope.
-    TSCS__Thread_local
+    TSCS__Thread_local,
+    /// __declspec(thread). Equivalent to GNU __thread.
+    TSCS___declspec_thread
   };
 
   /// \brief Storage classes.
Index: include/clang/Sema/DeclSpec.h
===================================================================
--- include/clang/Sema/DeclSpec.h
+++ include/clang/Sema/DeclSpec.h
@@ -232,6 +232,7 @@
   typedef ThreadStorageClassSpecifier TSCS;
   static const TSCS TSCS_unspecified = clang::TSCS_unspecified;
   static const TSCS TSCS___thread = clang::TSCS___thread;
+  static const TSCS TSCS___declspec_thread = clang::TSCS___declspec_thread;
   static const TSCS TSCS_thread_local = clang::TSCS_thread_local;
   static const TSCS TSCS__Thread_local = clang::TSCS__Thread_local;
 
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -1955,6 +1955,11 @@
   SectionAttr *mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name,
                                 unsigned AttrSpellingListIndex);
 
+  /// Check if the thread storage specifier is valid, and set it if so.  Return
+  /// if the thread storage specifier was set.
+  bool handleThreadStorageSpec(ThreadStorageClassSpecifier TSCS, VarDecl *VD,
+                               SourceLocation SpecifierLoc);
+
   /// \brief Describes the kind of merge to perform for availability
   /// attributes (including "deprecated", "unavailable", and "availability").
   enum AvailabilityMergeKind {
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -655,6 +655,8 @@
     switch (D->getTSCSpec()) {
     case TSCS_unspecified:
       break;
+    case TSCS___declspec_thread:
+      break; // Nothing, the attribute printer will do it for us.
     case TSCS___thread:
       Out << "__thread ";
       break;
Index: lib/Sema/DeclSpec.cpp
===================================================================
--- lib/Sema/DeclSpec.cpp
+++ lib/Sema/DeclSpec.cpp
@@ -383,6 +383,7 @@
   switch (S) {
   case DeclSpec::TSCS_unspecified:   return "unspecified";
   case DeclSpec::TSCS___thread:      return "__thread";
+  case DeclSpec::TSCS___declspec_thread: return "__declspec(thread)";
   case DeclSpec::TSCS_thread_local:  return "thread_local";
   case DeclSpec::TSCS__Thread_local: return "_Thread_local";
   }
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -5041,6 +5041,35 @@
   return true;
 }
 
+bool Sema::handleThreadStorageSpec(ThreadStorageClassSpecifier TSCS,
+                                   VarDecl *VD, SourceLocation SpecifierLoc) {
+  if (!Context.getTargetInfo().isTLSSupported()) {
+    Diag(SpecifierLoc, diag::err_thread_unsupported);
+    return false;
+  }
+
+  if (!VD->hasLocalStorage()) {
+    VD->setTSCSpec(TSCS);
+    return true;
+  }
+
+  // C++11 [dcl.stc]p4:
+  //   When thread_local is applied to a variable of block scope the
+  //   storage-class-specifier static is implied if it does not appear
+  //   explicitly.
+  // Core issue: 'static' is not implied if the variable is declared
+  //   'extern'.
+  if (VD->getStorageClass() == SC_None && TSCS == TSCS_thread_local &&
+      VD->getDeclContext()->isFunctionOrMethod()) {
+    VD->setTSCSpec(TSCS);
+    return true;
+  }
+
+  Diag(SpecifierLoc, diag::err_thread_non_global)
+      << DeclSpec::getSpecifierName(TSCS);
+  return false;
+}
+
 NamedDecl *
 Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
                               TypeSourceInfo *TInfo, LookupResult &Previous,
@@ -5333,28 +5362,9 @@
   if (IsLocalExternDecl)
     NewVD->setLocalExternDecl();
 
-  if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) {
-    if (NewVD->hasLocalStorage()) {
-      // C++11 [dcl.stc]p4:
-      //   When thread_local is applied to a variable of block scope the
-      //   storage-class-specifier static is implied if it does not appear
-      //   explicitly.
-      // Core issue: 'static' is not implied if the variable is declared
-      //   'extern'.
-      if (SCSpec == DeclSpec::SCS_unspecified &&
-          TSCS == DeclSpec::TSCS_thread_local &&
-          DC->isFunctionOrMethod())
-        NewVD->setTSCSpec(TSCS);
-      else
-        Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
-             diag::err_thread_non_global)
-          << DeclSpec::getSpecifierName(TSCS);
-    } else if (!Context.getTargetInfo().isTLSSupported())
-      Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
-           diag::err_thread_unsupported);
-    else
-      NewVD->setTSCSpec(TSCS);
-  }
+  if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec())
+    handleThreadStorageSpec(TSCS, NewVD,
+                            D.getDeclSpec().getThreadStorageClassSpecLoc());
 
   // C99 6.7.4p3
   //   An inline definition of a function with external linkage shall
@@ -8913,6 +8923,17 @@
       Diag(var->getLocation(), diag::warn_missing_variable_declarations) << var;
   }
 
+  if (var->getTSCSpec() == TSCS___declspec_thread) {
+    const CXXRecordDecl *RD = var->getType()->getAsCXXRecordDecl();
+    if (RD && RD->hasNonTrivialDefaultConstructor()) {
+      // MSVC doesn't allow thread local variables with any constructors, but we
+      // only look for the default constructor.
+      Diag(var->getLocation(), diag::err_thread_nontrivial_ctor);
+      if (getLangOpts().CPlusPlus11)
+        Diag(var->getLocation(), diag::note_use_thread_local);
+    }
+  }
+
   if (var->getTLSKind() == VarDecl::TLS_Static &&
       var->getType().isDestructedType()) {
     // GNU C++98 edits for __thread, [basic.start.term]p3:
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -3697,6 +3697,18 @@
     D->addAttr(IA);
 }
 
+static void handleDeclspecThreadAttr(Sema &S, Decl *D,
+                                     const AttributeList &Attr) {
+  VarDecl *VD = cast<VarDecl>(D);
+  if (VD->getTSCSpec() != TSCS_unspecified) {
+    S.Diag(Attr.getLoc(), diag::err_declspec_thread_on_thread_variable);
+    return;
+  }
+  if (S.handleThreadStorageSpec(TSCS___declspec_thread, VD, Attr.getLoc()))
+    D->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 +4406,9 @@
   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:
Index: test/SemaCXX/declspec-thread.cpp
===================================================================
--- /dev/null
+++ 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 {{non-trivial construction}} 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}}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to