-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Check #[thread_local] statics correctly in the compiler. #43746
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
cc @rust-lang/libs @rust-lang/compiler |
If |
@est31 I expect it be replaced by macros 2.0 hygiene. |
@@ -643,7 +643,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { | |||
Ok(self.cat_rvalue_node(id, span, expr_ty)) | |||
} | |||
|
|||
Def::Static(_, mutbl) => { | |||
Def::Static(def_id, mutbl) => { | |||
// `#[thread_local]` statics may not outlive the current function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like 2-space indent here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The entire file has broken (read: old-skool match
rules) indentation, I'm actually on a multiple of 4 and the Def::Static
line above is wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I just mentioned this b/c the line just after these modifications is 4-space indented, but yes it looks like the indentation is off in most of this file.
Is the intention to get thread-local statics "working" in the sense that it's harder to get them wrong in the compiler? Do you think we should get them on the path to stabilization? Other programs which work today and "shouldn't" work are: #![feature(thread_local)]
#[thread_local]
static A: u32 = 1;
static B: &'static u32 = &A;
fn main() {} but maybe this patch starts to reject that? |
@alexcrichton Interesting, I didn't consider that. Does that not ICE? Trigger an LLVM assertion or linker error? That is, I don't know what meaningful codegen LLVM could possibly have for As for the intention, I want people to stop pitching |
LMRTFY (let me rust that for you) It works, and I wouldn't expect it to work (I'd expect a rustc error) |
Out of minimal reduction, on Release mode, we have this LLVM IR: @A = thread_local constant i32 1, align 4
@B = local_unnamed_addr constant i32* @A, align 8 And these assembly entries: .type A,@object
.section .tdata.A,"awT",@progbits
.globl A
.p2align 2
A:
.long 1
.size A, 4 .type B,@object
.section .data.rel.ro.B,"aw",@progbits
.globl B
.p2align 3
B:
.quad A
.size B, 8 What I suspect is happening is EDIT: okay, so I was right about the addresses (see playpen) but... changes to the TLS are reflected in the original?! Or is EDIT2: oh it just looks like the loads from EDIT3: fixed up demo - however, because of the aggressive load folding behavior which changes uses of |
2c2be49
to
44dbbeb
Compare
@alexcrichton I've just pushed an updated version of the PR which also checks those cases. |
@bors: r+ 👍 |
📌 Commit 44dbbeb has been approved by |
⌛ Testing commit 44dbbeb3da7305b94241901f539034cbfd8150cb with merge 86293a2c4fe7cd45130286b270638779e2ae824f... |
💔 Test failed - status-travis |
Looks legit |
Ah, fallout from #43522, I'll rebase and try to fix it. |
44dbbeb
to
eba7592
Compare
@bors r=alexcrichton |
📌 Commit eba7592 has been approved by |
Check #[thread_local] statics correctly in the compiler. Fixes #43733 by introducing `#[allow_internal_unsafe]` analogous to `#[allow_internal_unstable]`, for letting a macro expand to `unsafe` blocks and functions even in `#![forbid(unsafe_code)]` crates. Fixes #17954 by not letting references to `#[thread_local]` statics escape the function they're taken in - we can't just use a magical lifetime because Rust has *lifetime parametrism*, so if we added the often-proposed `'thread` lifetime, we'd have no way to check it in generic code. To avoid potential edge cases in the compiler, the lifetime is actually that of a temporary at the same position, i.e. `&TLS_STATIC` has the same lifetime `&non_const_fn()` would. Referring to `#[thread_local]` `static`s at compile-time is banned now (as per PR discussion). Additionally, to remove `unsafe impl Sync` from `std::thread::local::fast::Key`, `#[thread_local]` statics are now not required to implement `Sync`, as they are not shared between threads.
💔 Test failed - status-appveyor |
looks legit |
So the borrow-checker is more clever than I gave it credit for. Maybe I don't need the |
eba7592
to
61ca14f
Compare
@bors r=alexcrichton |
📌 Commit 61ca14f has been approved by |
⌛ Testing commit 61ca14f10f55dac0fbee1525d570fd9e01780431 with merge ffbde4279123b29b6fc73c1e8023751bdbde44ad... |
💔 Test failed - status-travis |
[00:59:58] ---- [run-pass] run-pass/thread-local-extern-static.rs stdout ----
[00:59:58]
[00:59:58] error: auxiliary build of "/checkout/src/test/run-pass/auxiliary/thread-local-extern-static.rs" failed to compile:
[00:59:58] status: exit code: 101
[00:59:58] command: /checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc /checkout/src/test/run-pass/auxiliary/thread-local-extern-static.rs -L /checkout/obj/build/x86_64-unknown-linux-gnu/test/run-pass --target=arm-linux-androideabi --crate-type=dylib -L /checkout/obj/build/x86_64-unknown-linux-gnu/test/run-pass/thread-local-extern-static.stage2-arm-linux-androideabi.run-pass.libaux -C prefer-dynamic --out-dir /checkout/obj/build/x86_64-unknown-linux-gnu/test/run-pass/thread-local-extern-static.stage2-arm-linux-androideabi.run-pass.libaux -Clinker=/android/ndk/arm-9/bin/arm-linux-androideabi-gcc -Crpath -O -Lnative=/checkout/obj/build/arm-linux-androideabi/native/rust-test-helpers
[00:59:58] stdout:
[00:59:58] ------------------------------------------
[00:59:58]
[00:59:58] ------------------------------------------
[00:59:58] stderr:
[00:59:58] ------------------------------------------
[00:59:58] error[E0277]: the trait bound `std::cell::Cell<u32>: std::marker::Sync` is not satisfied
[00:59:58] --> /checkout/src/test/run-pass/auxiliary/thread-local-extern-static.rs:18:1
[00:59:58] |
[00:59:58] 18 | pub static FOO: Cell<u32> = Cell::new(3);
[00:59:58] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::Cell<u32>` cannot be shared between threads safely
[00:59:58] |
[00:59:58] = help: the trait `std::marker::Sync` is not implemented for `std::cell::Cell<u32>`
[00:59:58] = note: shared static variables must have a type that implements `Sync`
[00:59:58]
[00:59:58] error: aborting due to previous error
[00:59:58]
[00:59:58]
[00:59:58] ------------------------------------------
[00:59:58]
[00:59:58] thread '[run-pass] run-pass/thread-local-extern-static.rs' panicked at 'explicit panic', /checkout/src/tools/compiletest/src/runtest.rs:2511:8
[00:59:58] note: Run with `RUST_BACKTRACE=1` for a backtrace.
[00:59:58]
[00:59:58]
[00:59:58] failures:
[00:59:58] [run-pass] run-pass/thread-local-extern-static.rs
[00:59:58]
[00:59:58] test result: FAILED. 2707 passed; 1 failed; 20 ignored; 0 measured; 0 filtered out |
@kennytm No, I guess no architecture with OS TLS got to the tests before. |
61ca14f
to
92892d3
Compare
@bors r=alexcrichton |
📌 Commit 92892d3 has been approved by |
Check #[thread_local] statics correctly in the compiler. Fixes #43733 by introducing `#[allow_internal_unsafe]` analogous to `#[allow_internal_unstable]`, for letting a macro expand to `unsafe` blocks and functions even in `#![forbid(unsafe_code)]` crates. Fixes #17954 by not letting references to `#[thread_local]` statics escape the function they're taken in - we can't just use a magical lifetime because Rust has *lifetime parametrism*, so if we added the often-proposed `'thread` lifetime, we'd have no way to check it in generic code. To avoid potential edge cases in the compiler, the lifetime is actually that of a temporary at the same position, i.e. `&TLS_STATIC` has the same lifetime `&non_const_fn()` would. Referring to `#[thread_local]` `static`s at compile-time is banned now (as per PR discussion). Additionally, to remove `unsafe impl Sync` from `std::thread::local::fast::Key`, `#[thread_local]` statics are now not required to implement `Sync`, as they are not shared between threads.
☀️ Test successful - status-appveyor, status-travis |
- New allocator API - Remove the "allocator" feature, which should be unnecessary due to how the new allocator API works - NonZero no longer implements Deref (rust-lang/rust#41064) - NonZero::new() returns an Option; use NonZero::new_unchecked() - Thread locals are no longer 'static (rust-lang/rust#43746) - Changes to feature flags - Use unsafe to access extern static (rust-lang/rust#36247)
Fixes #43733 by introducing
#[allow_internal_unsafe]
analogous to#[allow_internal_unstable]
, for letting a macro expand tounsafe
blocks and functions even in#![forbid(unsafe_code)]
crates.Fixes #17954 by not letting references to
#[thread_local]
statics escape the function they're taken in - we can't just use a magical lifetime because Rust has lifetime parametrism, so if we added the often-proposed'thread
lifetime, we'd have no way to check it in generic code.To avoid potential edge cases in the compiler, the lifetime is actually that of a temporary at the same position, i.e.
&TLS_STATIC
has the same lifetime&non_const_fn()
would.Referring to
#[thread_local]
static
s at compile-time is banned now (as per PR discussion).Additionally, to remove
unsafe impl Sync
fromstd::thread::local::fast::Key
,#[thread_local]
statics are now not required to implementSync
, as they are not shared between threads.