aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Ballman <aaron@aaronballman.com>2023-10-25 07:51:28 -0400
committerGitHub <noreply@github.com>2023-10-25 07:51:28 -0400
commit66f4a1399d7de3d38312a5b251d4f8acd75237ca (patch)
tree6ca8e1317e3a82dbcdfe308e7d3dd1070ec902a3
parent6d66440c50e3047b5ce152830d4ccae381c7c2bf (diff)
downloadllvm-66f4a1399d7de3d38312a5b251d4f8acd75237ca.zip
llvm-66f4a1399d7de3d38312a5b251d4f8acd75237ca.tar.gz
llvm-66f4a1399d7de3d38312a5b251d4f8acd75237ca.tar.bz2
[C23] Use thread_local semantics (#70107)
When implementing thread_local as a keyword in C23, we accidentally started using C++11 thread_local semantics when using that keyword instead of using C11 _Thread_local semantics. This oversight is fixed by pretending the user wrote _Thread_local instead. This doesn't have the best behavior in terms of diagnostics, but it does correct the semantic behavior. Fixes https://github.com/llvm/llvm-project/issues/70068 Fixes https://github.com/llvm/llvm-project/issues/69167
-rw-r--r--clang/docs/ReleaseNotes.rst4
-rw-r--r--clang/lib/Parse/ParseDecl.cpp11
-rw-r--r--clang/test/CodeGen/thread_local.c27
-rw-r--r--clang/test/Sema/thread_local.c19
4 files changed, 59 insertions, 2 deletions
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4cc1489..c0514e5 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -496,6 +496,10 @@ Bug Fixes in This Version
Fixes (`#65143 <https://github.com/llvm/llvm-project/issues/65143>`_)
- Fix crash in formatting the real/imaginary part of a complex lvalue.
Fixes (`#69218 <https://github.com/llvm/llvm-project/issues/69218>`_)
+- No longer use C++ ``thread_local`` semantics in C23 when using
+ ``thread_local`` instead of ``_Thread_local``.
+ Fixes (`#70068 <https://github.com/llvm/llvm-project/issues/70068>`_) and
+ (`#69167 <https://github.com/llvm/llvm-project/issues/69167>`_)
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 14a28e5..78c3ab7 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4076,8 +4076,15 @@ void Parser::ParseDeclarationSpecifiers(
case tok::kw_thread_local:
if (getLangOpts().C23)
Diag(Tok, diag::warn_c23_compat_keyword) << Tok.getName();
- isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS_thread_local, Loc,
- PrevSpec, DiagID);
+ // We map thread_local to _Thread_local in C23 mode so it retains the C
+ // semantics rather than getting the C++ semantics.
+ // FIXME: diagnostics will show _Thread_local when the user wrote
+ // thread_local in source in C23 mode; we need some general way to
+ // identify which way the user spelled the keyword in source.
+ isInvalid = DS.SetStorageClassSpecThread(
+ getLangOpts().C23 ? DeclSpec::TSCS__Thread_local
+ : DeclSpec::TSCS_thread_local,
+ Loc, PrevSpec, DiagID);
isStorageClass = true;
break;
case tok::kw__Thread_local:
diff --git a/clang/test/CodeGen/thread_local.c b/clang/test/CodeGen/thread_local.c
new file mode 100644
index 0000000..b97f31c
--- /dev/null
+++ b/clang/test/CodeGen/thread_local.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple i686-pc-linux-gnu -std=c23 -emit-llvm -o - %s | FileCheck %s
+
+// Ensure that thread_local and _Thread_local emit the same codegen. See
+// https://github.com/llvm/llvm-project/issues/70068 for details.
+
+void func(void) {
+ static thread_local int i = 12;
+ static _Thread_local int j = 13;
+
+ extern thread_local int k;
+ extern thread_local int l;
+
+ (void)k;
+ (void)l;
+}
+
+// CHECK: @func.i = internal thread_local global i32 12, align 4
+// CHECK-NEXT: @func.j = internal thread_local global i32 13, align 4
+// CHECK-NEXT: @k = external thread_local global i32, align 4
+// CHECK-NEXT: @l = external thread_local global i32, align 4
+
+// CHECK: define dso_local void @func()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: %[[K:.+]] = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @k)
+// CHECK-NEXT: load i32, ptr %[[K]], align 4
+// CHECK-NEXT: %[[L:.+]] = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @l)
+// CHECK-NEXT: load i32, ptr %[[L]], align 4
diff --git a/clang/test/Sema/thread_local.c b/clang/test/Sema/thread_local.c
new file mode 100644
index 0000000..a0de0aa
--- /dev/null
+++ b/clang/test/Sema/thread_local.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c23 %s -verify
+
+// Ensure that thread_local and _Thread_local are synonyms in C23 and both
+// restrict local variables to be explicitly static or extern.
+void func(void) {
+ // FIXME: it would be nice if the diagnostic said 'thread_local' in this case.
+ thread_local int i = 12; // expected-error {{'_Thread_local' variables must have global storage}}
+ _Thread_local int j = 13; // expected-error {{'_Thread_local' variables must have global storage}}
+
+ static thread_local int k = 14;
+ static _Thread_local int l = 15;
+
+ extern thread_local int m;
+ extern thread_local int n;
+}
+
+// This would previously fail because the tls models were different.
+extern thread_local unsigned a;
+_Thread_local unsigned a = 0;