Skip to content

Commit

Permalink
[C23] Use thread_local semantics (#70107)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
AaronBallman authored and tru committed Oct 27, 2023
1 parent afbe354 commit 2a41d97
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 3 deletions.
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,10 @@ Bug Fixes in This Version
points (i.e., uses function descriptor objects instead).
- Fixes a ``clang-17`` regression where ``LLVM_UNREACHABLE_OPTIMIZE=OFF``
cannot be used with ``Release`` mode builds. (`#68237 <https://github.com/llvm/llvm-project/issues/68237>`_).
- 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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
13 changes: 10 additions & 3 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3997,9 +3997,16 @@ void Parser::ParseDeclarationSpecifiers(
break;
case tok::kw_thread_local:
if (getLangOpts().C2x)
Diag(Tok, diag::warn_c2x_compat_keyword) << Tok.getName();
isInvalid = DS.SetStorageClassSpecThread(DeclSpec::TSCS_thread_local, Loc,
PrevSpec, DiagID);
Diag(Tok, diag::warn_c23_compat_keyword) << Tok.getName();
// 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().C2x ? DeclSpec::TSCS__Thread_local
: DeclSpec::TSCS_thread_local,
Loc, PrevSpec, DiagID);
isStorageClass = true;
break;
case tok::kw__Thread_local:
Expand Down
27 changes: 27 additions & 0 deletions clang/test/CodeGen/thread_local.c
Original file line number Diff line number Diff line change
@@ -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
19 changes: 19 additions & 0 deletions clang/test/Sema/thread_local.c
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit 2a41d97

Please sign in to comment.