binrw icon indicating copy to clipboard operation
binrw copied to clipboard

Confusing rustc error message on generic struct with misleading suggestion

Open molenzwiebel opened this issue 1 year ago • 1 comments

I have the following:

#[derive(Debug, BinRead)]
pub struct Array<T>
where
    T: for<'a> BinRead<Args<'a> = ()>,
{
    _count: u32,
    #[br(count = _count)]
    pub data: Vec<T>,
}

For this, rustc complains about a missing lifetime bound on T, but does so in an interesting manner (see expando at the end for the full message):

image

The correct solution here is to either add a 'static bound to T (if we're fine with disallowing a borrowed T), or to add a lifetime bound to the struct (and a PhantomData). Perhaps that could be made clearer.

Full message

error[E0310]: the parameter type `T` may not live long enough
   --> src\base_binrw.rs:159:17
    |
159 | #[derive(Debug, BinRead)]
    |                 ^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
    |
    = note: this error originates in the derive macro `BinRead` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider adding an explicit lifetime bound...
    |
162 |     T: for<'a> BinRead<Args<'a> = ()> + 'static,
    |                                       +++++++++

error[E0311]: the parameter type `T` may not live long enough
   --> src\base_binrw.rs:159:17
    |
159 | #[derive(Debug, BinRead)]
    |                 ^^^^^^^
    |
note: the parameter type `T` must be valid for the anonymous lifetime defined here...
   --> src\base_binrw.rs:159:17
    |
159 | #[derive(Debug, BinRead)]
    |                 ^^^^^^^
note: ...so that the type `T` will meet its required lifetime bounds
   --> src\base_binrw.rs:159:17
    |
159 | #[derive(Debug, BinRead)]
    |                 ^^^^^^^
    = note: this error originates in the derive macro `BinRead` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider adding an explicit lifetime bound...
    |
159 ~ #[derive(Debug, 'a, BinRead)]
160 | pub struct Array<T>
161 | where
162 ~     T: for<'a> BinRead<Args<'a> = ()> + 'a,
    |

molenzwiebel avatar May 02 '23 18:05 molenzwiebel

I can modify the diagnostic to not give an obviously wrong suggestion about where to place a lifetime, but E0311 is giving a bogus suggestion in this situation because impl<T> BinRead for Vec<T> is constrained to T: 'static (due to fake specialisation). As a result, the only correct actions are either to add T: 'static or to use a different parse_with function that does not constrain T. It seems to me that rustc should not be emitting these suggestions at all since they will never work—applying the suggestion just causes it to emit the same suggestion again with a different lifetime name.

I can’t think of a way to reliably communicate this information in a useful way. proc-macros don’t have the ability to retrieve type information so it’s not possible to know for sure what Vec is to see how it is being used and emit a custom error, nor am I aware of a way to suppress the bad E0311 diagnostic.

csnover avatar Jul 07 '23 18:07 csnover