Skip to content

Commit 66f4a13

Browse files
authored
[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 #70068 Fixes #69167
1 parent 6d66440 commit 66f4a13

File tree

4 files changed

+59
-2
lines changed

4 files changed

+59
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,10 @@ Bug Fixes in This Version
496496
Fixes (`#65143 <https://github.com/llvm/llvm-project/issues/65143>`_)
497497
- Fix crash in formatting the real/imaginary part of a complex lvalue.
498498
Fixes (`#69218 <https://github.com/llvm/llvm-project/issues/69218>`_)
499+
- No longer use C++ ``thread_local`` semantics in C23 when using
500+
``thread_local`` instead of ``_Thread_local``.
501+
Fixes (`#70068 <https://github.com/llvm/llvm-project/issues/70068>`_) and
502+
(`#69167 <https://github.com/llvm/llvm-project/issues/69167>`_)
499503

500504
Bug Fixes to Compiler Builtins
501505
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Parse/ParseDecl.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4076,8 +4076,15 @@ void Parser::ParseDeclarationSpecifiers(
40764076
case tok::kw_thread_local:
40774077
if (getLangOpts().C23)
40784078
Diag(Tok, diag::warn_c23_compat_keyword) << Tok.getName();
4079-
isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS_thread_local, Loc,
4080-
PrevSpec, DiagID);
4079+
// We map thread_local to _Thread_local in C23 mode so it retains the C
4080+
// semantics rather than getting the C++ semantics.
4081+
// FIXME: diagnostics will show _Thread_local when the user wrote
4082+
// thread_local in source in C23 mode; we need some general way to
4083+
// identify which way the user spelled the keyword in source.
4084+
isInvalid = DS.SetStorageClassSpecThread(
4085+
getLangOpts().C23 ? DeclSpec::TSCS__Thread_local
4086+
: DeclSpec::TSCS_thread_local,
4087+
Loc, PrevSpec, DiagID);
40814088
isStorageClass = true;
40824089
break;
40834090
case tok::kw__Thread_local:

clang/test/CodeGen/thread_local.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clang_cc1 -triple i686-pc-linux-gnu -std=c23 -emit-llvm -o - %s | FileCheck %s
2+
3+
// Ensure that thread_local and _Thread_local emit the same codegen. See
4+
// https://github.com/llvm/llvm-project/issues/70068 for details.
5+
6+
void func(void) {
7+
static thread_local int i = 12;
8+
static _Thread_local int j = 13;
9+
10+
extern thread_local int k;
11+
extern thread_local int l;
12+
13+
(void)k;
14+
(void)l;
15+
}
16+
17+
// CHECK: @func.i = internal thread_local global i32 12, align 4
18+
// CHECK-NEXT: @func.j = internal thread_local global i32 13, align 4
19+
// CHECK-NEXT: @k = external thread_local global i32, align 4
20+
// CHECK-NEXT: @l = external thread_local global i32, align 4
21+
22+
// CHECK: define dso_local void @func()
23+
// CHECK-NEXT: entry:
24+
// CHECK-NEXT: %[[K:.+]] = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @k)
25+
// CHECK-NEXT: load i32, ptr %[[K]], align 4
26+
// CHECK-NEXT: %[[L:.+]] = call align 4 ptr @llvm.threadlocal.address.p0(ptr align 4 @l)
27+
// CHECK-NEXT: load i32, ptr %[[L]], align 4

clang/test/Sema/thread_local.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %clang_cc1 -fsyntax-only -std=c23 %s -verify
2+
3+
// Ensure that thread_local and _Thread_local are synonyms in C23 and both
4+
// restrict local variables to be explicitly static or extern.
5+
void func(void) {
6+
// FIXME: it would be nice if the diagnostic said 'thread_local' in this case.
7+
thread_local int i = 12; // expected-error {{'_Thread_local' variables must have global storage}}
8+
_Thread_local int j = 13; // expected-error {{'_Thread_local' variables must have global storage}}
9+
10+
static thread_local int k = 14;
11+
static _Thread_local int l = 15;
12+
13+
extern thread_local int m;
14+
extern thread_local int n;
15+
}
16+
17+
// This would previously fail because the tls models were different.
18+
extern thread_local unsigned a;
19+
_Thread_local unsigned a = 0;

0 commit comments

Comments
 (0)