blob: 87f776cd92670a6f92af0b2b0224173d26786698 [file] [edit]
#![feature(sync_unsafe_cell)]
use std::cell::SyncUnsafeCell;
#[no_mangle]
static FOO: u8 = 42;
#[export_name = "BAR_EXPORTED"]
static BAR_LOCAL_NAME: u16 = 1000;
#[no_mangle]
static mut MUTABLE_STATIC: i32 = -1;
#[export_name = "MY_LINK_NAME"]
static RUST_SYMBOL: u32 = 7;
#[no_mangle]
static FOO_U32: u32 = 42;
#[no_mangle]
static INTERIOR_MUT: SyncUnsafeCell<i32> = SyncUnsafeCell::new(42);
#[no_mangle]
static ARRAY: [u32; 5] = [1, 2, 3, 4, 5];
fn increase_mutable_static_by_original_def(add_val: i32) {
unsafe {
let new_val = (&raw mut MUTABLE_STATIC).read() + add_val;
(&raw mut MUTABLE_STATIC).write(new_val);
}
}
fn main() {
// The loop ensures we hit both the uncached and cached case.
for _ in 0..3 {
extern "Rust" {
static FOO: u8;
}
assert_eq!(unsafe { (&raw const FOO).read() }, 42);
extern "C" {
static BAR_EXPORTED: u16;
}
assert_eq!(unsafe { (&raw const BAR_EXPORTED).read() }, 1000);
extern "C" {
#[link_name = "MY_LINK_NAME"]
static EXTERN_STATIC: u32;
}
assert_eq!(unsafe { (&raw const EXTERN_STATIC).read() }, 7);
// Ensure that SyncUnsafeCell and `static mut` are interchangable.
extern "C" {
#[link_name = "INTERIOR_MUT"]
static mut INTERIOR_MUT_AS_MUTABLE_STATIC: i32;
#[link_name = "MUTABLE_STATIC"]
static MUTABLE_STATIC_AS_INTERIOR_MUT: SyncUnsafeCell<i32>;
}
unsafe {
(&raw mut INTERIOR_MUT_AS_MUTABLE_STATIC).write(7);
MUTABLE_STATIC_AS_INTERIOR_MUT.get().write(3);
}
// It's okay for the actual static to be bigger or more aligned than the extern declaration.
extern "C" {
// Actual size is bigger (20 bytes).
#[link_name = "ARRAY"]
static ARRAY_UNKNOWN_SIZE: [u32; 0];
// Actual size and alignment is that of u32, not u16.
#[link_name = "FOO_U32"]
static U16_TO_FOO_U32: u16;
}
unsafe {
let ptr = (&raw const ARRAY_UNKNOWN_SIZE).cast::<i32>();
assert_eq!(ptr.read(), 1);
assert_eq!(ptr.offset(2).read(), 3);
// We see one half of FOO_U32, depending on endianess.
if cfg!(target_endian = "little") {
assert_eq!(U16_TO_FOO_U32, 42);
} else {
assert_eq!(U16_TO_FOO_U32, 0);
}
}
}
extern "Rust" {
static mut MUTABLE_STATIC: i32;
}
// Check what happens if we mix accesses via the two aliases: the original
// definition at the top of the file, and the extern declaration just above.
unsafe {
assert_eq!((&raw const MUTABLE_STATIC).read(), 3);
(&raw mut MUTABLE_STATIC).write(32);
increase_mutable_static_by_original_def(10);
assert_eq!((&raw const MUTABLE_STATIC).read(), 42);
}
extern "Rust" {
static FOO_U32: i32;
}
// This is like a transmute between raw pointers, so not UB.
assert_eq!(unsafe { (&raw const FOO_U32).read() }, 42i32);
}