diff options
| author | Yuki Okushi <huyuumi.dev@gmail.com> | 2020-03-20 17:02:03 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-03-20 17:02:03 +0900 |
| commit | 3554f2d9411b0924fea8c78dfa82060b9500f261 (patch) | |
| tree | 2369d939a5f0d77432c3b87add3007e59c6e1c21 | |
| parent | 5d395176809c8f8a8399a8bec31bb2f6cdbf975a (diff) | |
| parent | 74608c7f206171cb72c020a03800b2d9035a35fa (diff) | |
| download | rust-3554f2d9411b0924fea8c78dfa82060b9500f261.tar.gz rust-3554f2d9411b0924fea8c78dfa82060b9500f261.zip | |
Rollup merge of #69768 - oli-obk:union_field_ice, r=eddyb,RalfJung
Compute the correct layout for variants of uninhabited enums r? @eddyb cc @RalfJung fixes #69191 cc #69763
| -rw-r--r-- | src/librustc/ty/layout.rs | 14 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/operand.rs | 2 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/place.rs | 8 | ||||
| -rw-r--r-- | src/librustc_target/abi/mod.rs | 5 |
4 files changed, 16 insertions, 13 deletions
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 041dfc7d169..6d28796b348 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -780,8 +780,8 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { present_first @ Some(_) => present_first, // Uninhabited because it has no variants, or only absent ones. None if def.is_enum() => return tcx.layout_raw(param_env.and(tcx.types.never)), - // if it's a struct, still compute a layout so that we can still compute the - // field offsets + // If it's a struct, still compute a layout so that we can still compute the + // field offsets. None => Some(VariantIdx::new(0)), }; @@ -1987,7 +1987,15 @@ where { fn for_variant(this: TyLayout<'tcx>, cx: &C, variant_index: VariantIdx) -> TyLayout<'tcx> { let details = match this.variants { - Variants::Single { index } if index == variant_index => this.details, + Variants::Single { index } + // If all variants but one are uninhabited, the variant layout is the enum layout. + if index == variant_index && + // Don't confuse variants of uninhabited enums with the enum itself. + // For more details see https://github.com/rust-lang/rust/issues/69763. + this.fields != FieldPlacement::Union(0) => + { + this.details + } Variants::Single { index } => { // Deny calling for_variant more than once for non-Single enums. diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 316cf2ee419..da55d710ba7 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -355,7 +355,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let base = match op.try_as_mplace(self) { Ok(mplace) => { - // The easy case + // We can reuse the mplace field computation logic for indirect operands. let field = self.mplace_field(mplace, field)?; return Ok(field.into()); } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 107cfee5ace..22ac0ac65a8 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -410,14 +410,6 @@ where stride * field } layout::FieldPlacement::Union(count) => { - // This is a narrow bug-fix for rust-lang/rust#69191: if we are - // trying to access absent field of uninhabited variant, then - // signal UB (but don't ICE the compiler). - // FIXME temporary hack to work around incoherence between - // layout computation and MIR building - if field >= count as u64 && base.layout.abi == layout::Abi::Uninhabited { - throw_ub!(Unreachable); - } assert!( field < count as u64, "Tried to access field {} of union {:#?} with {} fields", diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 2f8bbd66c32..afa30e7e632 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -660,7 +660,10 @@ impl FieldPlacement { pub fn offset(&self, i: usize) -> Size { match *self { - FieldPlacement::Union(_) => Size::ZERO, + FieldPlacement::Union(count) => { + assert!(i < count, "tried to access field {} of union with {} fields", i, count); + Size::ZERO + } FieldPlacement::Array { stride, count } => { let i = i as u64; assert!(i < count); |
