Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compilation error when trying to drop with cyclic lifetimes #50

Open
uselessgoddess opened this issue Jul 27, 2022 · 5 comments
Open

Compilation error when trying to drop with cyclic lifetimes #50

uselessgoddess opened this issue Jul 27, 2022 · 5 comments

Comments

@uselessgoddess
Copy link

//use beef::lean::Cow; -- compile error
use std::borrow::Cow;

struct Data<'a> {
    data: String,
    follower: Option<Cow<'a, str>>,
}

fn main() {
    let mut data = Data {
        data: "hello".into(),
        follower: None,
    };
    data.follower = Cow::from(&data.data).into();
}

In this code, follower has lifetime 'data and data has lifetime 'data
If i use beef::Cow – compiler tells me:

error[E0597]: `data.data` does not live long enough
  --> src\main.rs:14:31
   |
14 |     data.follower = Cow::from(data.data.as_str()).into();
   |                               ^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
15 | }
   | -
   | |
   | `data.data` dropped here while still borrowed
   | borrow might be used here, when `data` is dropped and runs the destructor for type `Data<'_>`
@CAD97
Copy link

CAD97 commented Jul 27, 2022

This is likely that Cow needs #[may_dangle]. I'm not 100% that this is sound, though; at a minimum it adds the requirement for the reconstructed owner to respect the #[may_dangle] rules.

@uselessgoddess
Copy link
Author

Maybe rules are not so strict, since std::Cow with default Drop solves this

@uselessgoddess
Copy link
Author

uselessgoddess commented Jul 27, 2022

However, if I understand correctly, we will have to add #[may_dangle] for all params. Badly

unsafe impl<#[may_dangle] 'a, #[may_dangle] T, U> Drop for Cow<'a, T, U> {
    fn drop(&mut self) {
        // impl . . . 
        touch data with T and 'a
    }
}

@CAD97
Copy link

CAD97 commented Jul 27, 2022

The reason std's Cow works is that it doesn't have a manual Drop implementation. This is for-dropck equivalent to each of its generic parameters being marked #[may_dangle] iff all fields mark the parameter as #[may_dangle]. The base case is that the primitive generic types &'a T and *const T are #[may_dangle] on their generics, and holding a type by-value is obviously not.

@uselessgoddess
Copy link
Author

That is, it works in std because Drop of T is either implemented automatically or marked with #[may_dangle]
For example Vec
Or example with std::Cow:

use std::borrow::Cow;
use std::marker::PhantomData;

#[derive(Clone)]
struct StrongDropck<'a>(PhantomData<&'a ()>);

impl Drop for StrongDropck<'_> {
    fn drop(&mut self) {}
}

struct Data<'a> {
    data: StrongDropck<'a>,
    follower: Option<Cow<'a, StrongDropck<'a>>>,
}

fn main() {
    let mut data = Data {
        data: StrongDropck(PhantomData),
        follower: None,
    };
    data.follower = Cow::Borrowed(&data.data).into();
}

Then if we impl Drop with dropck eyepath, then it will be wrong, since StrongDropck will not check dropck.
But now Beef is impl only for str and [T]. Maybe it will be safe

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants