Skip to content

Commit e413dc3

Browse files
committed
Auto merge of #64987 - oli-obk:code_reuse_prevents_bugs, r=eddyb
Compute the layout of uninhabited structs fixes #64506 r? @eddyb
2 parents 446e5e5 + 373c362 commit e413dc3

File tree

5 files changed

+37
-18
lines changed

5 files changed

+37
-18
lines changed

src/librustc/mir/interpret/error.rs

-6
Original file line numberDiff line numberDiff line change
@@ -389,10 +389,6 @@ pub enum UnsupportedOpInfo<'tcx> {
389389
/// Free-form case. Only for errors that are never caught!
390390
Unsupported(String),
391391

392-
/// FIXME(#64506) Error used to work around accessing projections of
393-
/// uninhabited types.
394-
UninhabitedValue,
395-
396392
// -- Everything below is not categorized yet --
397393
FunctionAbiMismatch(Abi, Abi),
398394
FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
@@ -556,8 +552,6 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> {
556552
not a power of two"),
557553
Unsupported(ref msg) =>
558554
write!(f, "{}", msg),
559-
UninhabitedValue =>
560-
write!(f, "tried to use an uninhabited value"),
561555
}
562556
}
563557
}

src/librustc/ty/layout.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -824,10 +824,14 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
824824
});
825825
(present_variants.next(), present_variants.next())
826826
};
827-
if present_first.is_none() {
827+
let present_first = match present_first {
828+
present_first @ Some(_) => present_first,
828829
// Uninhabited because it has no variants, or only absent ones.
829-
return tcx.layout_raw(param_env.and(tcx.types.never));
830-
}
830+
None if def.is_enum() => return tcx.layout_raw(param_env.and(tcx.types.never)),
831+
// if it's a struct, still compute a layout so that we can still compute the
832+
// field offsets
833+
None => Some(VariantIdx::new(0)),
834+
};
831835

832836
let is_struct = !def.is_enum() ||
833837
// Only one variant is present.

src/librustc_mir/interpret/place.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc::mir;
99
use rustc::mir::interpret::truncate;
1010
use rustc::ty::{self, Ty};
1111
use rustc::ty::layout::{
12-
self, Size, Abi, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx, PrimitiveExt
12+
self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx, PrimitiveExt
1313
};
1414
use rustc::ty::TypeFoldable;
1515

@@ -377,20 +377,17 @@ where
377377
layout::FieldPlacement::Array { stride, .. } => {
378378
let len = base.len(self)?;
379379
if field >= len {
380-
// This can be violated because this runs during promotion on code where the
381-
// type system has not yet ensured that such things don't happen.
380+
// This can be violated because the index (field) can be a runtime value
381+
// provided by the user.
382382
debug!("tried to access element {} of array/slice with length {}", field, len);
383383
throw_panic!(BoundsCheck { len, index: field });
384384
}
385385
stride * field
386386
}
387387
layout::FieldPlacement::Union(count) => {
388-
// FIXME(#64506) `UninhabitedValue` can be removed when this issue is resolved
389-
if base.layout.abi == Abi::Uninhabited {
390-
throw_unsup!(UninhabitedValue);
391-
}
392388
assert!(field < count as u64,
393-
"Tried to access field {} of union with {} fields", field, count);
389+
"Tried to access field {} of union {:#?} with {} fields",
390+
field, base.layout, count);
394391
// Offset is always 0
395392
Size::from_bytes(0)
396393
}

src/librustc_target/abi/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,11 @@ impl FieldPlacement {
738738

739739
pub fn offset(&self, i: usize) -> Size {
740740
match *self {
741-
FieldPlacement::Union(_) => Size::ZERO,
741+
FieldPlacement::Union(count) => {
742+
assert!(i < count,
743+
"Tried to access field {} of union with {} fields", i, count);
744+
Size::ZERO
745+
},
742746
FieldPlacement::Array { stride, count } => {
743747
let i = i as u64;
744748
assert!(i < count);

src/test/ui/consts/issue-64506.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// check-pass
2+
3+
#[derive(Copy, Clone)]
4+
pub struct ChildStdin {
5+
inner: AnonPipe,
6+
}
7+
8+
#[derive(Copy, Clone)]
9+
enum AnonPipe {}
10+
11+
const FOO: () = {
12+
union Foo {
13+
a: ChildStdin,
14+
b: (),
15+
}
16+
let x = unsafe { Foo { b: () }.a };
17+
let x = &x.inner;
18+
};
19+
20+
fn main() {}

0 commit comments

Comments
 (0)