Skip to content

Commit 9ed667f

Browse files
authored
Rollup merge of #130371 - saethlin:transmutability-enum-ice, r=compiler-errors
Correctly account for niche-optimized tags in rustc_transmute This is a bit hacky, but it fixes the ICE and makes it possible to run the safe transmute check on every `mem::transmute` check we instantiate. I want to write a lint that needs to do that, but this stands well on its own. cc `@jswrenn` here's the fix I alluded to yesterday :) Fixes#123693
2 parents 3225bd5 + 2ac554b commit 9ed667f

3 files changed

Lines changed: 34 additions & 32 deletions

File tree

‎compiler/rustc_transmute/src/layout/tree.rs‎

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ pub(crate) mod rustc {
175175
use rustc_middle::ty::{self,AdtDef,AdtKind,List,ScalarInt,Ty,TyCtxt,TypeVisitableExt};
176176
use rustc_span::ErrorGuaranteed;
177177
use rustc_target::abi::{
178-
FieldIdx,FieldsShape,Layout,Size,TyAndLayout,VariantIdx,Variants,
178+
FieldIdx,FieldsShape,Layout,Size,TagEncoding,TyAndLayout,VariantIdx,Variants,
179179
};
180180

181181
usesuper::Tree;
@@ -319,11 +319,17 @@ pub(crate) mod rustc {
319319
assert!(def.is_enum());
320320

321321
// Computes the variant of a given index.
322-
let layout_of_variant = |index| {
322+
let layout_of_variant = |index,encoding:Option<TagEncoding<VariantIdx>>| {
323323
let tag = cx.tcx.tag_for_variant((cx.tcx.erase_regions(ty), index));
324324
let variant_def = Def::Variant(def.variant(index));
325325
let variant_layout = ty_variant(cx,(ty, layout), index);
326-
Self::from_variant(variant_def, tag,(ty, variant_layout), layout.size, cx)
326+
Self::from_variant(
327+
variant_def,
328+
tag.map(|tag| (tag, index, encoding.unwrap())),
329+
(ty, variant_layout),
330+
layout.size,
331+
cx,
332+
)
327333
};
328334

329335
// We consider three kinds of enums, each demanding a different
@@ -345,9 +351,9 @@ pub(crate) mod rustc {
345351
Variants::Single{ index } => {
346352
// `Variants::Single` on enums with variants denotes that
347353
// the enum delegates its layout to the variant at `index`.
348-
layout_of_variant(*index)
354+
layout_of_variant(*index,None)
349355
}
350-
Variants::Multiple{ tag_field, .. } => {
356+
Variants::Multiple{tag, tag_encoding,tag_field, .. } => {
351357
// `Variants::Multiple` denotes an enum with multiple
352358
// variants. The layout of such an enum is the disjunction
353359
// of the layouts of its tagged variants.
@@ -359,7 +365,7 @@ pub(crate) mod rustc {
359365
let variants = def.discriminants(cx.tcx()).try_fold(
360366
Self::uninhabited(),
361367
|variants,(idx,ref discriminant)| {
362-
let variant = layout_of_variant(idx)?;
368+
let variant = layout_of_variant(idx,Some(tag_encoding.clone()))?;
363369
Result::<Self,Err>::Ok(variants.or(variant))
364370
},
365371
)?;
@@ -380,7 +386,7 @@ pub(crate) mod rustc {
380386
/// `0`.
381387
fnfrom_variant(
382388
def:Def<'tcx>,
383-
tag:Option<ScalarInt>,
389+
tag:Option<(ScalarInt,VariantIdx,TagEncoding<VariantIdx>)>,
384390
(ty, layout):(Ty<'tcx>,Layout<'tcx>),
385391
total_size:Size,
386392
cx:LayoutCx<'tcx,TyCtxt<'tcx>>,
@@ -400,9 +406,18 @@ pub(crate) mod rustc {
400406
letmut struct_tree = Self::def(def);
401407

402408
// If a `tag` is provided, place it at the start of the layout.
403-
ifletSome(tag) = tag {
404-
size += tag.size();
405-
struct_tree = struct_tree.then(Self::from_tag(tag, cx.tcx));
409+
ifletSome((tag, index, encoding)) = &tag {
410+
match encoding {
411+
TagEncoding::Direct => {
412+
size += tag.size();
413+
}
414+
TagEncoding::Niche{ niche_variants, .. } => {
415+
if !niche_variants.contains(index){
416+
size += tag.size();
417+
}
418+
}
419+
}
420+
struct_tree = struct_tree.then(Self::from_tag(*tag, cx.tcx));
406421
}
407422

408423
// Append the fields, in memory order, to the layout.

‎tests/crashes/123693.rs‎

Lines changed: 0 additions & 22 deletions
This file was deleted.

‎tests/ui/transmutability/enums/niche_optimization.rs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,12 @@ fn no_niche() {
154154
assert::is_transmutable::<Pair<V1,MaybeUninit<u8>>,OptionLike>();
155155
assert::is_transmutable::<Pair<V2,MaybeUninit<u8>>,OptionLike>();
156156
}
157+
158+
fnniche_fields(){
159+
enumKind{
160+
A(bool,bool),
161+
B(bool),
162+
}
163+
164+
assert::is_maybe_transmutable::<u16,Kind>();
165+
}

0 commit comments

Comments
 (0)