It would remove any optimization that treats &_
as meaning immutable for the value wrapped in UnsafeCell<_>
.
for example,
pub fn foo(x: &UnsafeCell<u32>) {
unsafe {
let a = *x.get();
std::thread::yield_now();
let b = *x.get();
assert_eq!(a, b);
}
}
generates
long assembly with panic handling
&T as core::fmt::Debug>::fmt:
pushq %r14
pushq %rbx
pushq %rax
movq %rsi, %rbx
movq (%rdi), %r14
movq %rsi, %rdi
callq *core::fmt::Formatter::debug_lower_hex@GOTPCREL(%rip)
testb %al, %al
je .LBB0_1
movq %r14, %rdi
movq %rbx, %rsi
addq $8, %rsp
popq %rbx
popq %r14
jmpq *core::fmt::num::<impl core::fmt::LowerHex for u32>::fmt@GOTPCREL(%rip)
.LBB0_1:
movq %rbx, %rdi
callq *core::fmt::Formatter::debug_upper_hex@GOTPCREL(%rip)
movq %r14, %rdi
movq %rbx, %rsi
addq $8, %rsp
testb %al, %al
je .LBB0_2
popq %rbx
popq %r14
jmpq *core::fmt::num::<impl core::fmt::UpperHex for u32>::fmt@GOTPCREL(%rip)
.LBB0_2:
popq %rbx
popq %r14
jmpq *core::fmt::num::imp::<impl core::fmt::Display for u32>::fmt@GOTPCREL(%rip)
playground::foo:
pushq %rbp
pushq %rbx
subq $104, %rsp
movq %rdi, %rbx
movl (%rdi), %ebp
movl %ebp, (%rsp)
callq *std::thread::yield_now@GOTPCREL(%rip)
movl (%rbx), %eax
movl %eax, 4(%rsp)
cmpl %eax, %ebp
jne .LBB1_1
addq $104, %rsp
popq %rbx
popq %rbp
retq
.LBB1_1:
movq %rsp, %rax
movq %rax, 8(%rsp)
leaq 4(%rsp), %rax
movq %rax, 16(%rsp)
leaq 8(%rsp), %rax
movq %rax, 24(%rsp)
leaq <&T as core::fmt::Debug>::fmt(%rip), %rax
movq %rax, 32(%rsp)
leaq 16(%rsp), %rcx
movq %rcx, 40(%rsp)
movq %rax, 48(%rsp)
leaq .Lanon.ec0bd99b1b4051f7d320bc576b3d0a71.3(%rip), %rax
movq %rax, 56(%rsp)
movq $3, 64(%rsp)
movq $0, 72(%rsp)
leaq 24(%rsp), %rax
movq %rax, 88(%rsp)
movq $2, 96(%rsp)
leaq .Lanon.ec0bd99b1b4051f7d320bc576b3d0a71.5(%rip), %rsi
leaq 56(%rsp), %rdi
callq *std::panicking::begin_panic_fmt@GOTPCREL(%rip)
ud2
.Lanon.ec0bd99b1b4051f7d320bc576b3d0a71.0:
.ascii "assertion failed: `(left == right)`\n left: `"
.Lanon.ec0bd99b1b4051f7d320bc576b3d0a71.1:
.ascii "`,\n right: `"
.Lanon.ec0bd99b1b4051f7d320bc576b3d0a71.2:
.byte 96
.Lanon.ec0bd99b1b4051f7d320bc576b3d0a71.3:
.quad .Lanon.ec0bd99b1b4051f7d320bc576b3d0a71.0
.asciz "-\000\000\000\000\000\000"
.quad .Lanon.ec0bd99b1b4051f7d320bc576b3d0a71.1
.asciz "\f\000\000\000\000\000\000"
.quad .Lanon.ec0bd99b1b4051f7d320bc576b3d0a71.2
.asciz "\001\000\000\000\000\000\000"
.Lanon.ec0bd99b1b4051f7d320bc576b3d0a71.4:
.ascii "src/lib.rs"
.Lanon.ec0bd99b1b4051f7d320bc576b3d0a71.5:
.quad .Lanon.ec0bd99b1b4051f7d320bc576b3d0a71.4
.asciz "\n\000\000\000\000\000\000\000\b\000\000\000\t\000\000"
while
pub fn bar(x: &u32) {
let a = *x;
std::thread::yield_now();
let b = *x;
assert_eq!(a, b);
}
generates almost nothing (completely optimized away the assert)
playground::bar:
jmpq *std::thread::yield_now@GOTPCREL(%rip)
On playground
Note, that the only thing between the two get
s is a thread yield!
This behavior is correct and wanted. You don't want these optimizations when you have shared mutability, as they will lead to subtle and infuriating bugs.