Change:
<!-- Thank you for filing a regression report! A regression is something that changed between versions of Rust but was not supposed to. Please provide a short summary of the regression, along with any information you feel is relevant to replicate it. --is now not transmutable when is (dependent on) a generic parameter and , when it was previously (I don't necessarily think this is a significant enough problem to be worth "fixing", but I guess it is technically a regression). I tried this code: I expected to see this happen: compilation success Instead, this happened: compilation error <!-- Provide the most recent version this worked on, for example: It most recently worked on: Rust 1.47 --It most recently worked on: Rust 1.63.0 <!-- Provide the version you are using that has the regression. --: <!-- Did the compiler crash? If so, please provide a backtrace. --(no backtrace, compiler didn't crash) changed the definition of from to (The following is (AFAICT) why this change caused this regression; It is not itself a regression, and it applies to all (recent) versions of rustc (i.e. since at least 1.41.0)) AFICT, rustc currently only supports transmuting a subset of types that it conservatively can guarantee are the same size. For generic struct types with parameters, i think rustc can only guarantee the size if the whole struct's size does not depend on the parameters, or if the struct's only non-zst field is a (transitive transparent wrapper of a) pointer type depending on a generic parameter ( only has and variants, so can only express completely known and only-a-pointer sizes), e.g. (See also: ) <details<summaryMoved to </summary<p(See also: ) Unrelated note: I think this size-calculation ignoring all ZSTs (not just 1-ZSTs) when there is a pointer field can cause to (incorrectly?) allow transmuting between differently-sized types, e.g. this compiles and runs normally, but ICEs under miri: </p</details modify labels: +regression-from-stable-to-beta -regression-untriaged
This is not a regression, but not for the reason you say. Quoting the reference: does not have a attribute, so you're not allowed to rely on its layout.
Nominating to get sign-off on acceptable breakage from libs-api; I expect this is an obvious case. I think this is another case where we should consider making the compiler lint on transmutes of types that aren't marked with a repr, and maybe even hard error for std types.
While I would be personally in favor of this, such a change will cause breakage in the ecosystem, which I suspect others would conclude is too much.
Yeah, I think it's a difficult tradeoff. We obviously can't catch everything (e.g., pointer casting is probably too far), but I think a warning is going to do 90% of the work for us and is hopefully relatively obviously OK.
One thought I had was having transmute Kinda do the job of randomizelayout, in the sense that it goes "Okay, you're transmuting from to . Now, the stdlib controls the layout of that tuple, and could legally insert padding there. So let's pretend it did, and then emit a warning (and later, ideally, a hard error)". Since we can just pretend that we laid out the type like that, and as long as we halt compilation because of it, I don't think anyone can notice to prove us wrong (there's no feature) You need to not forbid things like -, but that shouldn't be too difficult? I do think we've had enough issues where people are transmuting stdlib types (see: trying to change the layout of the std::net socket type) to justify being harsh here. Should I open a separate issue to try and hash out the details of how we do it there?
this is like forbidding transmuting -though. The only thing differing here is the lifetime and I think it's a pretty reasonable assumption that types are never going to be able to change layout based on lifetime information. (The possibility of this happening is why has basically been dead and considered unsound)
(This is mostly unrelated to this "regression", and is more just questions about /'s guarantees in general). I agree that relying on a specific layout is not allowed, so I guess it makes sense that it's okay for to not work when is unknown (since it could affect the layout), but does this also mean that it is unsound to to when is a concrete type? because I was under the impression that lifetimes could not affect codegen (including type layout), so and would be guaranteed to have the same (unspecified) layout (in one compilation), regardless of any explicit ? (especially since types whose lifetime parameter is not invariant can be coerced to a different lifetime). (Although, the type layout page you linked does not mention lifetimes at all, so maybe I was misinterpreting something from somewhere else.) Although also, the docs for  explicitly state that one of the uses of transmute is for "Extending a lifetime, or shortening an invariant lifetime", with an example using a struct. (Maybe it is only intended to apply for types defined in the current crate? Or maybe only for types that (are known to) only contain references?) Even if "transmuting away lifetimes" is not allowed, presumably it should always be valid to transmute a type to itself regardless of layout? (or using , where can't guarantee the size). This would probably be good, but I think it would [need to be/benefit from being] somewhat recursive (since e.g. would presumably be unsound to transmute if is unsound to transmute? (except maybe to another struct with that same -typed field in the same place?)). Also, it should probably not lint/error on transmutes between a type and a wrapper of that same type.
Yes, indeed you are not supposed to transmute . You should never assume you can transmute any type from another crate unless the type explicitly says so. This is true even if they have a annotation, as not all annotations are stable guarantees. See e.g.
Whether transmuting between types that only differ in lifetimes should work or not is not really a library issue, but more a question for the language team. One could argue it's a bug if doesn't compile, which is not new to 1.63.
So to clarify, the question for the language team: Should always be accepted (even if isn't repr(anything))? It's not uncommon to use to unsafely change a lifetime, but today that sometimes results in an error, depending on some details of : see .
Per discussion in rust-lang/lang meeting today, we are re-nominating this for consideration.
searched nightlies: from nightly-2022-06-01 to nightly-2022-09-06 regressed nightly: nightly-2022-06-26 searched commit range: regressed commit: <details<summarybisected with <a href=''cargo-bisect-rustc</av0.6.3</summaryHost triple: x86_64-unknown-linux-gnu Reproduce with: </details

Discussion:
pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) { let tcx = self.tcx; let span = tcx.hir().span(hir_id); <del> let convert = |ty: Ty<'tcx>| { </del> <ins> let normalize = |ty| { </ins> let ty = self.resolve_vars_if_possible(ty); <del> let ty = tcx.normalize_erasing_regions(self.param_env, ty); (SizeSkeleton::compute(ty, tcx, self.param_env), ty) </del> <ins> self.tcx.normalize_erasing_regions(self.param_env, ty) </ins> }; <del> let (sk_from, from) = convert(from); let (sk_to, to) = convert(to); </del> <ins> let from = normalize(from); let to = normalize(to); trace!(?from, ?to); // Transmutes that are only changing lifetimes are always ok. if from == to { return; } let skel = |ty| SizeSkeleton::compute(ty, tcx, self.param_env); let sk_from = skel(from); let sk_to = skel(to); trace!(?sk_from, ?sk_to); </ins> // Check for same size using the skeletons. if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {

<ins> // check-pass </ins> trait Foo { type Bar; } unsafe fn noop<F: Foo>(foo: F::Bar) -> F::Bar { <del> ::std::mem::transmute(foo) //~ ERROR cannot transmute between types of different sizes </del> <ins> ::std::mem::transmute(foo) </ins> } fn main() {}

<del> error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute-equal-assoc-types.rs:6:5 | LL |     ::std::mem::transmute(foo) |     ^^^^^^^^^^^^^^^^^^^^^ | = note: `<F as Foo>::Bar` does not have a fixed size error: aborting due to previous error For more information about this error, try `rustc --explain E0512`. </del>

<ins> // check-pass use std::ptr::NonNull; struct Foo<'a, T: ?Sized>(&'a (), NonNull<T>); fn foo<'a, 'b, T: ?Sized>(x: Foo<'a, T>) -> Foo<'b, T> { unsafe { std::mem::transmute(x) } } struct Bar<'a, T: ?Sized>(&'a T); fn bar<'a, 'b, T: ?Sized>(x: Bar<'a, T>) -> Bar<'b, T> { unsafe { std::mem::transmute(x) } } struct Boo<'a, T: ?Sized>(&'a T, u32); fn boo<'a, 'b, T: ?Sized>(x: Boo<'a, T>) -> Boo<'b, T> { unsafe { std::mem::transmute(x) } } fn main() {} </ins>

unsafe fn transmute_lifetime<'a, 'b, C>(x: <C as TypeConstructor<'a>>::T) -> <C as TypeConstructor<'b>>::T where for<'z> C: TypeConstructor<'z> { <del> transmute(x) //~ ERROR cannot transmute between types of different sizes </del> <ins> transmute(x) </ins> } unsafe fn sizes() {

error[E0512]: cannot transmute between types of different sizes, or dependently-sized types <del> --> $DIR/main.rs:13:5 | LL |     transmute(x) |     ^^^^^^^^^ | = note: `<C as TypeConstructor<'_>>::T` does not have a fixed size error[E0512]: cannot transmute between types of different sizes, or dependently-sized types </del> --> $DIR/main.rs:17:17 | LL |     let x: u8 = transmute(10u16);

= note: source type: `i32` (32 bits) = note: target type: `Foo` (0 bits) <del> error: aborting due to 4 previous errors </del> <ins> error: aborting due to 3 previous errors </ins> For more information about this error, try `rustc --explain E0512`.