Change:
<!-- [31mICE[0m: Rustc '' 'thread 'rustc' panicked at 'Size::sub: 0 - 1 would result in negative size'', 'thread 'rustc' panicked at 'Size::sub: 0 - 1 would result in negative size'' File: --auto-reduced (treereduce-rust): &lt;details&lt;summary&lt;strongoriginal code&lt;/strong&lt;/summary&lt;poriginal: </p</detailsVersion information ` Command: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongProgram output</strong</summary<p</p</details<!-- query stack: [evaluateobligation] evaluating trait selection obligation [typeck] type-checking [analysis] running analysis passes on this crate --<!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
cc
On it! Thanks for the report.
Further minimized:
The cause here is neat. here is niche optimizable, with its second variant being subject to niche optimization. Typically, a niche-optimized enum has one tagless variant, and zero or more tagged variants laid out in the usual manner: the tag is placed, and then the rest of the fields follow. But reveals that's not what happens here. Because is a ZST, is placed at offset , rather than (following the tag). In other words: the tag is co-located with the field. This produces an ICE, because our assumption that fields follow tag is violated (a checked sub panics).
claim

Discussion:
use rustc_middle::ty::{self, AdtDef, AdtKind, List, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::ErrorGuaranteed; use rustc_target::abi::{ <del> FieldIdx, FieldsShape, Layout, Size, TyAndLayout, VariantIdx, Variants, </del> <ins> FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants, </ins> }; use super::Tree;

assert!(def.is_enum()); // Computes the variant of a given index. <del> let layout_of_variant = |index| { </del> <ins> let layout_of_variant = |index, encoding: Option<TagEncoding<VariantIdx>>| { </ins> let tag = cx.tcx.tag_for_variant((cx.tcx.erase_regions(ty), index)); let variant_def = Def::Variant(def.variant(index)); let variant_layout = ty_variant(cx, (ty, layout), index); <del> Self::from_variant(variant_def, tag, (ty, variant_layout), layout.size, cx) </del> <ins> Self::from_variant( variant_def, tag.map(|tag| (tag, index, encoding.unwrap())), (ty, variant_layout), layout.size, cx, ) </ins> }; // We consider three kinds of enums, each demanding a different

Variants::Single { index } => { // `Variants::Single` on enums with variants denotes that // the enum delegates its layout to the variant at `index`. <del> layout_of_variant(*index) </del> <ins> layout_of_variant(*index, None) </ins> } <del> Variants::Multiple { tag_field, .. } => { </del> <ins> Variants::Multiple { tag, tag_encoding, tag_field, .. } => { </ins> // `Variants::Multiple` denotes an enum with multiple // variants. The layout of such an enum is the disjunction // of the layouts of its tagged variants.

let variants = def.discriminants(cx.tcx()).try_fold( Self::uninhabited(), |variants, (idx, ref discriminant)| { <del> let variant = layout_of_variant(idx)?; </del> <ins> let variant = layout_of_variant(idx, Some(tag_encoding.clone()))?; </ins> Result::<Self, Err>::Ok(variants.or(variant)) }, )?;

/// `0`. fn from_variant( def: Def<'tcx>, <del> tag: Option<ScalarInt>, </del> <ins> tag: Option<(ScalarInt, VariantIdx, TagEncoding<VariantIdx>)>, </ins> (ty, layout): (Ty<'tcx>, Layout<'tcx>), total_size: Size, cx: LayoutCx<'tcx, TyCtxt<'tcx>>,

let mut struct_tree = Self::def(def); // If a `tag` is provided, place it at the start of the layout. <del> if let Some(tag) = tag { size += tag.size(); struct_tree = struct_tree.then(Self::from_tag(tag, cx.tcx)); </del> <ins> if let Some((tag, index, encoding)) = &tag { match encoding { TagEncoding::Direct => { size += tag.size(); } TagEncoding::Niche { niche_variants, .. } => { if !niche_variants.contains(index) { size += tag.size(); } } } struct_tree = struct_tree.then(Self::from_tag(*tag, cx.tcx)); </ins> } // Append the fields, in memory order, to the layout.

<del> //@ known-bug: #123693 #![feature(transmutability)] mod assert { use std::mem::{Assume, TransmuteFrom}; pub fn is_transmutable<Src, Dst>() where Dst: TransmuteFrom<Src, { Assume::NOTHING }>, { } } enum Lopsided { Smol(()), Lorg(bool), } fn should_pad_variants() { assert::is_transmutable::<Lopsided, ()>(); } </del>

assert::is_transmutable::<Pair<V1, MaybeUninit<u8>>, OptionLike>(); assert::is_transmutable::<Pair<V2, MaybeUninit<u8>>, OptionLike>(); } <ins> fn niche_fields() { enum Kind { A(bool, bool), B(bool), } assert::is_maybe_transmutable::<u16, Kind>(); } </ins>