Want to be clear, an UnsafeCell will disable optimizations on the whole composite tree?e

Document says:

If you have a reference &T , then normally in Rust the compiler performs optimizations based on the knowledge that &T points to immutable data. Mutating that data, for example through an alias or by transmuting an &T into an &mut T , is considered undefined behavior. UnsafeCell<T> opts-out of the immutability guarantee for &T : a shared reference &UnsafeCell<T> may point to data that is being mutated. This is called “interior mutability”.

It is OK indeed. What comes to my mind is: If

struct a {
    f: UnsafeCell<String>
}

struct b {
    af: &a
}

struct c {
    bf: &b
}

struct d {
    cf: &c
}

...

struct y {
    xf: &x
}

struct z {
    yf: &y
}

fn xxx(r: &z) {
    ....
}

Will the compiler knowns it should not assume r immutable and prevents some optimization because yf.xf. ...cf.bf.af.f is an UnsafeCell?

The compiler can assume that only the nested field will mutate.

AFAIK, it doesn't do so at the moment, but completely disable noalias optimization in presence of UnsafeCell. However, this can change in the future.

No. In the example you provided, only the innermost z.yf.xf…cf.bf.af.f field is an UnsafeCell, so that's the only thing that you are allowed to treat as such. All the other fields of all the other structs must still uphold the no-aliased-mutability rule, otherwise the code will have UB. It's not like you use one single UnsafeCell in your code and then every relevant optimization is turned off across the entire code.

let it more clear, define xxx as

fn xxx(r: &z) {
    let v = r.yf;
    for i in 0 .. 10 {
        if r.yf != v {
            break;
        }
        println!("{}", i);
    }
}

will be optimized to

fn xxx(r: &z) {
    for i in 0 .. 10 {
        println!("{}", i)
    }
}

?

Since r.yf.xf…cf.bf.af.f is an UnsafeCell<T>, it might be modified (e.g., on another thread) even while it is borrowed, so that optimization would be incorrect in the general case.

A sufficiently smart compiler might still be able to do it in specific cases, if whole-program analysis could prove that such a modification never happens in practice.

I suppose since the code doesn't use any memory barriers, the compiler could rule out access from other threads (which would be UB), in which case it can optimize out the comparisons as long as there are no calls within the loop to other functions that might modify the f field.

1 Like

without memory barriers will delay seeing UnsafeCell's modification, without checking in the loop, the delay is infinite, It will surprise me if

fn xxx(r: &z) {
    let v = r.yf;
    loop {
        if r.yf != v {
            break;
        }
        println!("{}", i);
    }
}

becomes

fn xxx(r: &z) {
    loop {
        println!("{}", i);
    }
}

It is another question, though.
The main question here is does

struct z {
    yf: &y
}

fn xxx(r: &z) {
    let v = r.yf;
    loop {
        if atomic_load(r.yf) != v {
            break;
        }
        println!("{}", i);
    }
}

can make compiler assuming yf will not be modified during xxx because of &y

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.