0

Can someone help me explaining the following code? In scope 1 and 2, the local variable created get dropped when their scope ends which is as expected. However in scope 3 and 4, it seems that the local variable declared behind a reference did not get dropped, the local variable declared in scope 4 is right next to that in scope 3 instead of replacing it. Then again, in scope 5 a local variable is declared behind a reference but with the same value as that of scope 3, but instead of going 1 byte up in address of local variable declared in scope 4, it was given the address of the local variable declared in scope 3. After many thoughts on why rust is behaving this way, my best guess is that this is the work of rust compiler and it does this to optimize the code.

pub fn scope_1() -> *const u8 {
    let ui: u8 = 1;
    return &ui as *const u8;
}

pub fn scope_2() -> *const u8 {
    let ui: u8 = 2;
    return &ui as *const u8;
}

pub fn scope_3() -> *const u8 {
    let uip: &u8 = &3;
    return uip as *const u8;
}

pub fn scope_4() -> *const u8 {
    let uip: &u8 = &4;
    return uip as *const u8;
}

pub fn scope_5() -> *const u8 {
    let uip: &u8 = &3;
    return uip as *const u8;
}

fn main() {
    unsafe {
        let s1 = scope_1();
        print!("scope 1 ptr: {:?}\n", s1); // 0x56da2ff3f7
        print!("scope 1 val: {}\n", *s1);  // 0

        let s2 = scope_2();
        print!("scope 2 ptr: {:?}\n", s2); // 0x56da2ff3f7
        print!("scope 2 val: {}\n", *s2);  // 0

        let s3 = scope_3();
        print!("scope 3 ptr: {:?}\n", s3); // 0x7ff64676e458
        print!("scope 3 val: {}\n", *s3);  // 3

        let s4 = scope_4();
        print!("scope 4 ptr: {:?}\n", s4); // 0x7ff64676e459
        print!("scope 4 val: {}\n", *s4);  // 4

        let s5 = scope_5();
        print!("scope 5 ptr: {:?}\n", s5); // 0x7ff64676e458
        print!("scope 5 val: {}\n", *s5);  // 3
    }    
}
Tr3nchHvlk
  • 137
  • 1
  • 6

1 Answers1

1

First of all, *s1 and *s2 are UB so any observation made from this is categorical nonsense, none of it is reliable because as far as the compiler is concerned it doesn't happen.

Second, what you're observing with scope 3 to 5 (not sure why you needed 3 of them) is constant promotion.

That is, because you're referencing trivial literals which

could be written in a constant and borrowed

rather than allocate a stack slot and borrow that the compiler promotes the constant to a static, stores that in the binary, and then creates an &'static borrow.

Masklinn
  • 34,759
  • 3
  • 38
  • 57
  • That's what I thought when I noticed the &str is just a static borrow to a str stored in binary, so &u8 in that case could be similar. Thanks for clearing that up. – Tr3nchHvlk Nov 26 '22 at 18:49
  • 1
    The case of string literals is a bit different, they are not promoted, a string literal is always `&'static str`. – Masklinn Nov 26 '22 at 18:52