summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/AST/Decl.h14
-rw-r--r--clang/include/clang/Basic/Attr.td7
-rw-r--r--clang/include/clang/Basic/AttrDocs.td17
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--clang/lib/AST/Decl.cpp15
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp22
-rw-r--r--clang/test/SemaCXX/declspec-thread.cpp42
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}}
OpenPOWER on IntegriCloud