Can lifetimes affect layouts?

Is it possible, given the following trait, for <T as Foo<'a>>::Output and <T as Foo<'b>>::Output to have different layouts in memory?

trait Foo<'a> {
    type Output;
}

I'm asking because std::mem::transmute gives me an error when transmuting between the two: Rust Playground

If it is possible for them to have different layouts, do you have an example?

With specialization they can, though that's also the case where specialization is unsound today.

Which is a long/indirect way of saying “they can't have different layouts”?

I'm pretty sure that this would be an example of a "dependently-sized type" that the error message mentions. As I understand it, transmute expects to know the exact size at the call site. Since the <T as Foo<'_>>::Output projections can't be normalized into a specific type, transmute does not attempt to do any further reasoning. See also rust-lang/rust#61956; a type with a const-generic size can't be transmuted.

Do you have an example of how this could happen? I see a few open issues for unsoundness with specialization, but I'm not sure how I would use one of them to get different layouts. They mostly seem to give you a way to turn &'a T into &'static T, but that's not what I'm worried about here.

I had a similar error, but in the context of GATs, recently:

Curiously, 'static specialization seems to override any lifetime-generic defaults. Consider this basic example (Rust Playground):

#![feature(specialization)]

pub trait Trait<'a> {
    type AssocType;
}

pub struct Struct;

impl<'a, T> Trait<'a> for T {
    default type AssocType = ();
}

impl Trait<'static> for Struct {
    type AssocType = i32;
}

pub fn test<'a>() -> <Struct as Trait<'a>>::AssocType {
    unimplemented!()
}

The compiler complains that Struct only implements Trait<'static>. But if the second impl block is commented out, the code compiles with only the incomplete_features lint.

Reading through the issue that @LegionMammal978 linked as well as related issues, it looks like std::mem::transmute just doesn't work on type parameters in general. For example, std::mem::transmute::<T, T>(...) returns the same error even though T and T are clearly the same type.

In current stable Rust they can't. I suspect the error message is too conservative and just sees X::Output vs Y::Output.

For all of you that are interested, I just posted about a crate that I'm working on that is based on the assumption that lifetime can't affect layouts: `borrowed_with_owner`, an alternative to `owning_ref`

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.