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

E0621 when converting dyn reference to dyn pointer #81474

Open
obsgolem opened this issue Jan 28, 2021 · 5 comments
Open

E0621 when converting dyn reference to dyn pointer #81474

obsgolem opened this issue Jan 28, 2021 · 5 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-lifetimes Area: lifetime related A-raw-pointers Area: raw pointers, MaybeUninit, NonNull A-trait-objects Area: trait objects, vtable layout D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@obsgolem
Copy link
Contributor

I tried this code: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=fa659e7e2652bb05a7e407a9925b1344

I expected to see this happen: The reference should convert to a pointer, losing all lifetime information.

Instead, this happened: Rust askes that the reference be given a static lifetime. This doesn't occur with non-dyn references. In addition, if you make a small modification to the code then it works: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=1257118244ee5aef365f12906c3b52fc

Meta

rustc --version --verbose:

1.49.0
@obsgolem obsgolem added the C-bug Category: This is a bug. label Jan 28, 2021
@SkiFire13
Copy link
Contributor

I think the problem here is that trait object lifetimes elision rules are different for references and pointers.

  • &'a mut T requires T: 'a so &'a mut dyn Empty is the same as &'a mut (dyn Empty + 'a)
  • *mut T doesn't have a bound on T, so *mut dyn Empty is the same as *mut (dyn Empty + 'static).

The pointed types don't match, and so the compiler gives an error. However the hint it gives is wrong, you don't need to add 'static to the reference, just to the trait object.

@SNCPlay42
Copy link
Contributor

It's kind of surprising (to me, at least) that even a pointer cast can't launder the lifetime, given that you'd have to do an unsafe dereference to actually obtain a value with the laundered lifetime, but this appears to be the case in general, not just for dyn Trait.

Alternatively, you can make launder not infer 'static:

#![allow(unused)]

trait Empty {
    
}

fn launder<'a>(t:*mut (dyn Empty + 'a)) -> *mut (dyn Empty + 'a) {
    t
}

fn test(e: &mut dyn Empty) {
    launder(e as *mut dyn Empty);
}

@SkiFire13
Copy link
Contributor

I forgot the the modified version, I guess it works because T is inferred to be *mut (dyn Empty + 'a) where 'a is the lifetime of the mutable reference. For example, this also works https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f308580239dfc177694f0e0c68e34ca6

It's a bit confusing how you can omit the lifetime from the cast though.

@luksan
Copy link

luksan commented Feb 14, 2022

I don't know if it's the same issue, but I would like the following to work, without putting a lifetime on struct A.
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=038f1b78575df957dd948bdf3f714151

#![allow(unused)]

trait Empty {}

struct Dep<'a> (&'a mut u8);

impl Empty for Dep<'_>{}

struct A {
    deps: Vec<*const dyn Empty>,
}

impl A {
    pub fn inject(&mut self, dep: *const dyn Empty) {
        self.deps.push(dep);
    }
}

fn test(dep: &Dep<'_>) {
    let mut a = A{deps: vec![]};
    a.inject(dep);
}

@ChrisDenton ChrisDenton added the needs-triage-legacy Old issue that were never triaged. Remove this label once the issue has been sufficiently triaged. label Jul 16, 2023
@fmease fmease added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-diagnostics Area: Messages for errors, warnings, and lints D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. A-raw-pointers Area: raw pointers, MaybeUninit, NonNull A-trait-objects Area: trait objects, vtable layout A-lifetimes Area: lifetime related and removed C-bug Category: This is a bug. needs-triage-legacy Old issue that were never triaged. Remove this label once the issue has been sufficiently triaged. labels Jan 25, 2024
@fmease
Copy link
Member

fmease commented Jan 25, 2024

However the hint it gives is wrong, you don't need to add 'static to the reference, just to the trait object

The current output doesn't contain such a suggestion (anymore?):

error: lifetime may not live long enough
  --> src/lib.rs:12:13
   |
11 | fn test(e: &mut dyn Empty) {
   |            - let's call the lifetime of this reference `'1`
12 |     launder(e as *mut dyn Empty);
   |             ^ cast requires that `'1` must outlive `'static`

Classifying this as a diagnostic issue: We should (1) add a hint explaining that the lifetime requirement was introduced by a default object lifetime and (2, optionally) suggest relaxing the object lifetime (if the relevant trait object type comes from the local crate etc.).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-lifetimes Area: lifetime related A-raw-pointers Area: raw pointers, MaybeUninit, NonNull A-trait-objects Area: trait objects, vtable layout D-terse Diagnostics: An error or lint that doesn't give enough information about the problem at hand. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants