Skip to content

Code broke with crossbeam-utils 0.8.10. Worked in 0.8.9. Not a ZST. #854

@rickwebiii

Description

@rickwebiii

I discovered that my code was failing to build after running cargo update. The root cause is due to MR 834 and I think there's a teaching moment for me to understand why this change broke my code. Here is a minimal repro of code that compiles (don't run it, it will panic due to bounds checks) using AtomicCell:

use crossbeam_utils::atomic::AtomicCell;
use std::borrow::Cow;

#[derive(Clone)]
struct Data {
    // Don't be a ZST
    val: u8
}

fn fn_2<F>(f: F)
where 
    F: Fn(i64) -> Result<(), ()> + Sync + Send {
}

fn get_data<'a>(data: &'a [AtomicCell<Cow<Data>>], i: usize) -> &'a Data {
    unsafe { data[i].as_ptr().as_ref().unwrap() }
}

fn main() {
    let data: Vec<AtomicCell<Cow<Data>>> = vec![];

    fn_2(|i| {
        data[0].store(Cow::Owned(Data { val: 0 }));

        let a = get_data(&data, 0);

        data[1].store(Cow::Borrowed(a));

        Ok(())
    });

    let _ = &data[0];
}

If you use crossbeam-utils = "=0.8.9" in your Cargo.toml, this code compiles (with warnings). If you update the version to =0.8.10, you get this error:

error[E0597]: `data` does not live long enough
  --> src/main.rs:24:9
   |
23 |     fn_2(|i| {
   |          --- value captured here
24 |         data[0].store(Cow::Owned(Data { val: 0 }));
   |         ^^^^ borrowed value does not live long enough
...
34 | }
   | -
   | |
   | `data` dropped here while still borrowed
   | borrow might be used here, when `data` is dropped and runs the `Drop` code for type `Vec`

The code is kinda sketchy, but the idea is some entries in the Vec are values while other entries are references to other values in the same Vec. While this approach is likely a bad idea (you can get dangling references when data is dropping) and I've since switched from Cow to Arc, I do want to know why compilation broke.

Reading the MR, there was discussion on whether to do a minor or major semver bump and that people using ZSTs would be broken. But the above repro doesn't use a ZST. I'm curious why this code breaks without using a zero sized type and whether this is actually a bug in the Rust compiler.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions