rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.03k stars 12.68k forks source link

mut struct member var(ref) bind to new obj still hint: does not live long enough #128225

Open sohide opened 3 months ago

sohide commented 3 months ago
#[derive(Debug)]
struct ImportantExcerpt<'a> {
    part: &'a str,
}

fn main() {
    let mut root = ImportantExcerpt {part: "abc"};
    {
        let novel = String::from("Call me Ishmael. Some years ago...");
        let first_sentence = novel.split('.').next().expect("Could not find a '.'");
        root = ImportantExcerpt {part: first_sentence};
        root.part = "1234";  // bind to new static str
    }
    println!("{:?}", root);  // error does not live long enough
}
tgross35 commented 3 months ago

Could you add some more context about what is going wrong vs. what you expect to happen?

theemathas commented 3 months ago

Here's my understanding of what issue is being reported.

This code doesn't compile:

struct Wrap<'a>(&'a i32);

static TWO: i32 = 2;

fn main() {
    let mut x;
    {
        let y = 1;
        x = Wrap(&y);
        x.0 = &TWO;
    }
    let _z = x;
}
Error message ```rust error[E0597]: `y` does not live long enough --> src/main.rs:9:18 | 8 | let y = 1; | - binding `y` declared here 9 | x = Wrap(&y); | ^^ borrowed value does not live long enough 10 | x.0 = &TWO; 11 | } | - `y` dropped here while still borrowed 12 | let _z = x; | - borrow later used here For more information about this error, try `rustc --explain E0597`. ```

But this code compiles fine:

struct Wrap<'a>(&'a i32);

static TWO: i32 = 2;

fn main() {
    let mut x;
    {
        let y = 1;
        x = Wrap(&y);
        x = Wrap(&TWO);
    }
    let _z = x;
}

Weird. I would expect either both to compile or neither to compile.

sohide commented 3 months ago

Here's my understanding of what issue is being reported.

This code doesn't compile:

struct Wrap<'a>(&'a i32);

static TWO: i32 = 2;

fn main() {
    let mut x;
    {
        let y = 1;
        x = Wrap(&y);
        x.0 = &TWO;
    }
    let _z = x;
}

Error message But this code compiles fine:

struct Wrap<'a>(&'a i32);

static TWO: i32 = 2;

fn main() {
    let mut x;
    {
        let y = 1;
        x = Wrap(&y);
        x = Wrap(&TWO);
    }
    let _z = x;
}

Weird. I would expect either both to compile or neither to compile.

Yes, that's exactly what I want to say. In the first code snippet, x.0 was rebind, and won't become dangling. I expect the first can be compile without error.

RalfJung commented 1 month ago

I expect the first can be compile without error.

That would be UB, as it would assign a value that does not satisfy its validity invariant. So the first must be rejected.

theemathas commented 1 month ago

What value and what validity invariant are you talking about? Miri doesn't complain about this code:

struct Wrap<'a>(&'a i32);

static TWO: i32 = 2;

fn main() {
    let mut x;
    {
        let y = 1;
        x = Wrap(unsafe { std::mem::transmute(&y) });
        x = Wrap(&TWO);
    }
    let _z = x;
}
RalfJung commented 1 month ago

Ah sorry I misread the code, I thought it was

struct Wrap<'a>(&'a i32);

static TWO: i32 = 2;

fn main() {
    let mut x;
    {
        let y = 1;
        x = Wrap(&y);
    }
    let _z = x;
}

That must be rejected for sure. I should not post before I am properly awake. ;)

The actual issue may just be explained by strong (type-changing) assignments. That would also explain why it does not work when changing just the field of a type.