makepad/libs/relax/compiler/tests/const_by_value_copy.rs
Admin b22a714840 makepad run: the Rust JIT (libs/relax) and makepad-remote
The JIT that runs makepad apps from source: lexer, front end, type checker,
lazy borrow checker (Gandalf; `--check-first` opts in), codegen, session and
warm/cold caches keyed by compiler stamp, provided crates bound late,
startup images, live patching. User-facing name is `makepad run` (binary
`makepad`, MAKEPAD_RUN_* env, ~/.makepad-run); libs/relax stays the internal
library name. `makepad check` reports rustc-style diagnostics with rustc
error codes and checks a whole workspace (`--workspace`). Runs on macOS,
Linux, Windows and Android. makepad-remote: one tool schema for apps and the
WM (app/1): grabs, captures, traces, frame profiles and tweaks.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 12:26:21 +02:00

129 lines
3.4 KiB
Rust

// A `const` used by value is a fresh copy at each use (Reference: constant items are inlined
// wherever they are used); only `&CONST` may share promoted storage, and that cannot be written.
// A local initialised from a const and then mutated must never write through to the const:
// sha256 copies its IV into its state and mutates it, and every hash after the first in a
// process came out wrong. rustc prints the same lines.
use std::hint::black_box;
const IV: [u32; 8] = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
];
#[derive(Clone, Copy, Debug, PartialEq)]
struct State {
a: u64,
b: [u16; 4],
c: u8,
}
const START: State = State { a: 7, b: [1, 2, 3, 4], c: 9 };
struct Hasher;
impl Hasher {
const INIT: [u64; 4] = [11, 22, 33, 44];
}
// the sha256 pattern: copy the const into the state, mutate it in a loop, return it
fn rounds(n: u32) -> [u32; 8] {
let mut s = IV;
for i in 0..n {
let t = s[7].wrapping_add(i).rotate_left(5) ^ s[0];
for j in (1..8).rev() {
s[j] = s[j - 1].wrapping_add(t);
}
s[0] = t;
}
s
}
fn struct_copy() -> State {
let mut s = START;
s.a += 1;
s.b[2] = 100;
s.c = s.c.wrapping_mul(3);
s
}
fn assoc_copy() -> [u64; 4] {
let mut h = Hasher::INIT;
h[0] = h[0].wrapping_add(1);
h[3] *= 2;
h
}
fn bump(h: &mut [u32; 8]) {
for x in h.iter_mut() {
*x = x.wrapping_add(1);
}
}
mod inner {
// a const reached through a module path, written through `&mut` in a callee
pub fn through_mut() -> [u32; 8] {
let mut h = super::IV;
super::bump(&mut h);
h
}
}
fn borrowed() -> &'static [u32; 8] {
&IV
}
#[test]
fn const_by_value_copy() {
// (a) array const copied into a mut local and mutated, then the const read again
let mut h = IV;
h[0] = h[0].wrapping_add(1);
black_box(&mut h);
assert_eq!(h[0], 0x6a09e668);
assert_eq!(IV[0], 0x6a09e667);
let again = IV;
assert_eq!(again[0], 0x6a09e667);
// (b) a struct const the same way
let s1 = struct_copy();
let s2 = struct_copy();
assert_eq!(s1, s2);
assert_eq!(s1, State { a: 8, b: [1, 2, 100, 4], c: 27 });
assert_eq!(START, State { a: 7, b: [1, 2, 3, 4], c: 9 });
// (c) a mutated copy in a loop, called twice: the same result both times
let r1 = rounds(black_box(64));
let r2 = rounds(black_box(64));
assert_eq!(r1, r2);
assert_eq!(IV[7], 0x5be0cd19);
// (d) an associated const
let a1 = assoc_copy();
let a2 = assoc_copy();
assert_eq!(a1, a2);
assert_eq!(a1, [12, 22, 33, 88]);
assert_eq!(Hasher::INIT, [11, 22, 33, 44]);
// (c') the IV written through `&mut` in a callee, reached through a module path
let m1 = inner::through_mut();
let m2 = inner::through_mut();
assert_eq!(m1, m2);
assert_eq!(m1[0], 0x6a09e668);
assert_eq!(IV[0], 0x6a09e667);
// `&mut CONST` borrows a fresh temporary
#[allow(const_item_mutation)]
{
let t = &mut IV;
t[0] = 5;
bump(&mut IV);
assert_eq!(t[0], 5);
}
assert_eq!(IV[0], 0x6a09e667);
// (e) `&CONST` borrows still work (and may share storage: they cannot be written)
let b = borrowed();
assert_eq!(b, &IV);
assert_eq!(b[0], 0x6a09e667);
let r = &IV;
assert_eq!(r[3], 0xa54ff53a);
println!("{:08x} {:08x} {:?} {:?} {:?}", r1[0], r1[7], s1, a1, b[0]);
}