mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-28 17:53:56 +00:00
Rollup merge of #132255 - workingjubilee:layout-is-🏚️, r=compiler-errors
Add `LayoutS::is_uninhabited` and use it Use accessors for the things that accessors are good at: reducing everyone's need to be nosy and peek at the internals of every data structure.
This commit is contained in:
commit
259ddf9b50
@ -4100,6 +4100,7 @@ version = "0.0.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"rustc_abi",
|
||||||
"rustc_arena",
|
"rustc_arena",
|
||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
"rustc_attr",
|
"rustc_attr",
|
||||||
|
@ -28,7 +28,7 @@ where
|
|||||||
VariantIdx: Idx,
|
VariantIdx: Idx,
|
||||||
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
|
F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
|
||||||
{
|
{
|
||||||
let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited());
|
let uninhabited = fields.iter().any(|f| f.is_uninhabited());
|
||||||
// We cannot ignore alignment; that might lead us to entirely discard a variant and
|
// We cannot ignore alignment; that might lead us to entirely discard a variant and
|
||||||
// produce an enum that is less aligned than it should be!
|
// produce an enum that is less aligned than it should be!
|
||||||
let is_1zst = fields.iter().all(|f| f.is_1zst());
|
let is_1zst = fields.iter().all(|f| f.is_1zst());
|
||||||
@ -681,7 +681,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||||||
let discr_type = repr.discr_type();
|
let discr_type = repr.discr_type();
|
||||||
let bits = Integer::from_attr(dl, discr_type).size().bits();
|
let bits = Integer::from_attr(dl, discr_type).size().bits();
|
||||||
for (i, mut val) in discriminants {
|
for (i, mut val) in discriminants {
|
||||||
if !repr.c() && variants[i].iter().any(|f| f.abi.is_uninhabited()) {
|
if !repr.c() && variants[i].iter().any(|f| f.is_uninhabited()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if discr_type.is_signed() {
|
if discr_type.is_signed() {
|
||||||
|
@ -1652,6 +1652,11 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if this is an uninhabited type
|
||||||
|
pub fn is_uninhabited(&self) -> bool {
|
||||||
|
self.abi.is_uninhabited()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
|
pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
|
||||||
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
|
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
|
||||||
let size = scalar.size(cx);
|
let size = scalar.size(cx);
|
||||||
|
@ -415,7 +415,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||||||
instance: Option<ty::Instance<'tcx>>,
|
instance: Option<ty::Instance<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let mut func_attrs = SmallVec::<[_; 3]>::new();
|
let mut func_attrs = SmallVec::<[_; 3]>::new();
|
||||||
if self.ret.layout.abi.is_uninhabited() {
|
if self.ret.layout.is_uninhabited() {
|
||||||
func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(cx.llcx));
|
func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(cx.llcx));
|
||||||
}
|
}
|
||||||
if !self.can_unwind {
|
if !self.can_unwind {
|
||||||
@ -532,7 +532,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||||||
|
|
||||||
fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value) {
|
fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value) {
|
||||||
let mut func_attrs = SmallVec::<[_; 2]>::new();
|
let mut func_attrs = SmallVec::<[_; 2]>::new();
|
||||||
if self.ret.layout.abi.is_uninhabited() {
|
if self.ret.layout.is_uninhabited() {
|
||||||
func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(bx.cx.llcx));
|
func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(bx.cx.llcx));
|
||||||
}
|
}
|
||||||
if !self.can_unwind {
|
if !self.can_unwind {
|
||||||
|
@ -364,7 +364,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||||||
|
|
||||||
let mut flags = DIFlags::FlagPrototyped;
|
let mut flags = DIFlags::FlagPrototyped;
|
||||||
|
|
||||||
if fn_abi.ret.layout.abi.is_uninhabited() {
|
if fn_abi.ret.layout.is_uninhabited() {
|
||||||
flags |= DIFlags::FlagNoReturn;
|
flags |= DIFlags::FlagNoReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,7 +438,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
_ => bug!("C-variadic function must have a `VaList` place"),
|
_ => bug!("C-variadic function must have a `VaList` place"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.fn_abi.ret.layout.abi.is_uninhabited() {
|
if self.fn_abi.ret.layout.is_uninhabited() {
|
||||||
// Functions with uninhabited return values are marked `noreturn`,
|
// Functions with uninhabited return values are marked `noreturn`,
|
||||||
// so we should make sure that we never actually do.
|
// so we should make sure that we never actually do.
|
||||||
// We play it safe by using a well-defined `abort`, but we could go for immediate UB
|
// We play it safe by using a well-defined `abort`, but we could go for immediate UB
|
||||||
@ -774,7 +774,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
Some(if do_panic {
|
Some(if do_panic {
|
||||||
let msg_str = with_no_visible_paths!({
|
let msg_str = with_no_visible_paths!({
|
||||||
with_no_trimmed_paths!({
|
with_no_trimmed_paths!({
|
||||||
if layout.abi.is_uninhabited() {
|
if layout.is_uninhabited() {
|
||||||
// Use this error even for the other intrinsics as it is more precise.
|
// Use this error even for the other intrinsics as it is more precise.
|
||||||
format!("attempted to instantiate uninhabited type `{ty}`")
|
format!("attempted to instantiate uninhabited type `{ty}`")
|
||||||
} else if requirement == ValidityRequirement::Zero {
|
} else if requirement == ValidityRequirement::Zero {
|
||||||
|
@ -55,7 +55,7 @@ impl<V: CodegenObject> PlaceValue<V> {
|
|||||||
/// Creates a `PlaceRef` to this location with the given type.
|
/// Creates a `PlaceRef` to this location with the given type.
|
||||||
pub fn with_type<'tcx>(self, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> {
|
pub fn with_type<'tcx>(self, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> {
|
||||||
assert!(
|
assert!(
|
||||||
layout.is_unsized() || layout.abi.is_uninhabited() || self.llextra.is_none(),
|
layout.is_unsized() || layout.is_uninhabited() || self.llextra.is_none(),
|
||||||
"Had pointer metadata {:?} for sized type {layout:?}",
|
"Had pointer metadata {:?} for sized type {layout:?}",
|
||||||
self.llextra,
|
self.llextra,
|
||||||
);
|
);
|
||||||
@ -239,7 +239,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||||||
let dl = &bx.tcx().data_layout;
|
let dl = &bx.tcx().data_layout;
|
||||||
let cast_to_layout = bx.cx().layout_of(cast_to);
|
let cast_to_layout = bx.cx().layout_of(cast_to);
|
||||||
let cast_to = bx.cx().immediate_backend_type(cast_to_layout);
|
let cast_to = bx.cx().immediate_backend_type(cast_to_layout);
|
||||||
if self.layout.abi.is_uninhabited() {
|
if self.layout.is_uninhabited() {
|
||||||
return bx.cx().const_poison(cast_to);
|
return bx.cx().const_poison(cast_to);
|
||||||
}
|
}
|
||||||
let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants {
|
let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants {
|
||||||
@ -358,7 +358,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||||||
bx: &mut Bx,
|
bx: &mut Bx,
|
||||||
variant_index: VariantIdx,
|
variant_index: VariantIdx,
|
||||||
) {
|
) {
|
||||||
if self.layout.for_variant(bx.cx(), variant_index).abi.is_uninhabited() {
|
if self.layout.for_variant(bx.cx(), variant_index).is_uninhabited() {
|
||||||
// We play it safe by using a well-defined `abort`, but we could go for immediate UB
|
// We play it safe by using a well-defined `abort`, but we could go for immediate UB
|
||||||
// if that turns out to be helpful.
|
// if that turns out to be helpful.
|
||||||
bx.abort();
|
bx.abort();
|
||||||
|
@ -203,10 +203,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
) -> Option<OperandValue<Bx::Value>> {
|
) -> Option<OperandValue<Bx::Value>> {
|
||||||
// Check for transmutes that are always UB.
|
// Check for transmutes that are always UB.
|
||||||
if operand.layout.size != cast.size
|
if operand.layout.size != cast.size
|
||||||
|| operand.layout.abi.is_uninhabited()
|
|| operand.layout.is_uninhabited()
|
||||||
|| cast.abi.is_uninhabited()
|
|| cast.is_uninhabited()
|
||||||
{
|
{
|
||||||
if !operand.layout.abi.is_uninhabited() {
|
if !operand.layout.is_uninhabited() {
|
||||||
// Since this is known statically and the input could have existed
|
// Since this is known statically and the input could have existed
|
||||||
// without already having hit UB, might as well trap for it.
|
// without already having hit UB, might as well trap for it.
|
||||||
bx.abort();
|
bx.abort();
|
||||||
@ -555,7 +555,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
|
|
||||||
assert!(bx.cx().is_backend_immediate(cast));
|
assert!(bx.cx().is_backend_immediate(cast));
|
||||||
let to_backend_ty = bx.cx().immediate_backend_type(cast);
|
let to_backend_ty = bx.cx().immediate_backend_type(cast);
|
||||||
if operand.layout.abi.is_uninhabited() {
|
if operand.layout.is_uninhabited() {
|
||||||
let val = OperandValue::Immediate(bx.cx().const_poison(to_backend_ty));
|
let val = OperandValue::Immediate(bx.cx().const_poison(to_backend_ty));
|
||||||
return OperandRef { val, layout: cast };
|
return OperandRef { val, layout: cast };
|
||||||
}
|
}
|
||||||
|
@ -395,7 +395,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn enforce_validity(ecx: &InterpCx<'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool {
|
fn enforce_validity(ecx: &InterpCx<'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool {
|
||||||
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.abi.is_uninhabited()
|
ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.is_uninhabited()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_mir(
|
fn load_mir(
|
||||||
|
@ -27,7 +27,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
// discriminant, so we cannot do anything here.
|
// discriminant, so we cannot do anything here.
|
||||||
// When evaluating we will always error before even getting here, but ConstProp 'executes'
|
// When evaluating we will always error before even getting here, but ConstProp 'executes'
|
||||||
// dead code, so we cannot ICE here.
|
// dead code, so we cannot ICE here.
|
||||||
if dest.layout().for_variant(self, variant_index).abi.is_uninhabited() {
|
if dest.layout().for_variant(self, variant_index).is_uninhabited() {
|
||||||
throw_ub!(UninhabitedEnumVariantWritten(variant_index))
|
throw_ub!(UninhabitedEnumVariantWritten(variant_index))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
// For consistency with `write_discriminant`, and to make sure that
|
// For consistency with `write_discriminant`, and to make sure that
|
||||||
// `project_downcast` cannot fail due to strange layouts, we declare immediate UB
|
// `project_downcast` cannot fail due to strange layouts, we declare immediate UB
|
||||||
// for uninhabited variants.
|
// for uninhabited variants.
|
||||||
if op.layout().for_variant(self, index).abi.is_uninhabited() {
|
if op.layout().for_variant(self, index).is_uninhabited() {
|
||||||
throw_ub!(UninhabitedEnumVariantRead(index))
|
throw_ub!(UninhabitedEnumVariantRead(index))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -203,7 +203,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
// Reading the discriminant of an uninhabited variant is UB. This is the basis for the
|
// Reading the discriminant of an uninhabited variant is UB. This is the basis for the
|
||||||
// `uninhabited_enum_branching` MIR pass. It also ensures consistency with
|
// `uninhabited_enum_branching` MIR pass. It also ensures consistency with
|
||||||
// `write_discriminant`.
|
// `write_discriminant`.
|
||||||
if op.layout().for_variant(self, index).abi.is_uninhabited() {
|
if op.layout().for_variant(self, index).is_uninhabited() {
|
||||||
throw_ub!(UninhabitedEnumVariantRead(index))
|
throw_ub!(UninhabitedEnumVariantRead(index))
|
||||||
}
|
}
|
||||||
interp_ok(index)
|
interp_ok(index)
|
||||||
|
@ -364,7 +364,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
let msg = match requirement {
|
let msg = match requirement {
|
||||||
// For *all* intrinsics we first check `is_uninhabited` to give a more specific
|
// For *all* intrinsics we first check `is_uninhabited` to give a more specific
|
||||||
// error message.
|
// error message.
|
||||||
_ if layout.abi.is_uninhabited() => format!(
|
_ if layout.is_uninhabited() => format!(
|
||||||
"aborted execution: attempted to instantiate uninhabited type `{ty}`"
|
"aborted execution: attempted to instantiate uninhabited type `{ty}`"
|
||||||
),
|
),
|
||||||
ValidityRequirement::Inhabited => bug!("handled earlier"),
|
ValidityRequirement::Inhabited => bug!("handled earlier"),
|
||||||
|
@ -315,7 +315,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
let ptr = left.to_scalar().to_pointer(self)?;
|
let ptr = left.to_scalar().to_pointer(self)?;
|
||||||
let pointee_ty = left.layout.ty.builtin_deref(true).unwrap();
|
let pointee_ty = left.layout.ty.builtin_deref(true).unwrap();
|
||||||
let pointee_layout = self.layout_of(pointee_ty)?;
|
let pointee_layout = self.layout_of(pointee_ty)?;
|
||||||
assert!(pointee_layout.abi.is_sized());
|
assert!(pointee_layout.is_sized());
|
||||||
|
|
||||||
// The size always fits in `i64` as it can be at most `isize::MAX`.
|
// The size always fits in `i64` as it can be at most `isize::MAX`.
|
||||||
let pointee_size = i64::try_from(pointee_layout.size.bytes()).unwrap();
|
let pointee_size = i64::try_from(pointee_layout.size.bytes()).unwrap();
|
||||||
@ -518,14 +518,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||||||
|
|
||||||
interp_ok(match null_op {
|
interp_ok(match null_op {
|
||||||
SizeOf => {
|
SizeOf => {
|
||||||
if !layout.abi.is_sized() {
|
if !layout.is_sized() {
|
||||||
span_bug!(self.cur_span(), "unsized type for `NullaryOp::SizeOf`");
|
span_bug!(self.cur_span(), "unsized type for `NullaryOp::SizeOf`");
|
||||||
}
|
}
|
||||||
let val = layout.size.bytes();
|
let val = layout.size.bytes();
|
||||||
ImmTy::from_uint(val, usize_layout())
|
ImmTy::from_uint(val, usize_layout())
|
||||||
}
|
}
|
||||||
AlignOf => {
|
AlignOf => {
|
||||||
if !layout.abi.is_sized() {
|
if !layout.is_sized() {
|
||||||
span_bug!(self.cur_span(), "unsized type for `NullaryOp::AlignOf`");
|
span_bug!(self.cur_span(), "unsized type for `NullaryOp::AlignOf`");
|
||||||
}
|
}
|
||||||
let val = layout.align.abi.bytes();
|
let val = layout.align.abi.bytes();
|
||||||
|
@ -542,7 +542,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
|
|||||||
throw_validation_failure!(self.path, NullPtr { ptr_kind })
|
throw_validation_failure!(self.path, NullPtr { ptr_kind })
|
||||||
}
|
}
|
||||||
// Do not allow references to uninhabited types.
|
// Do not allow references to uninhabited types.
|
||||||
if place.layout.abi.is_uninhabited() {
|
if place.layout.is_uninhabited() {
|
||||||
let ty = place.layout.ty;
|
let ty = place.layout.ty;
|
||||||
throw_validation_failure!(self.path, PtrToUninhabited { ptr_kind, ty })
|
throw_validation_failure!(self.path, PtrToUninhabited { ptr_kind, ty })
|
||||||
}
|
}
|
||||||
@ -867,7 +867,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
|
|||||||
/// Add the entire given place to the "data" range of this visit.
|
/// Add the entire given place to the "data" range of this visit.
|
||||||
fn add_data_range_place(&mut self, place: &PlaceTy<'tcx, M::Provenance>) {
|
fn add_data_range_place(&mut self, place: &PlaceTy<'tcx, M::Provenance>) {
|
||||||
// Only sized places can be added this way.
|
// Only sized places can be added this way.
|
||||||
debug_assert!(place.layout.abi.is_sized());
|
debug_assert!(place.layout.is_sized());
|
||||||
if let Some(data_bytes) = self.data_bytes.as_mut() {
|
if let Some(data_bytes) = self.data_bytes.as_mut() {
|
||||||
let offset = Self::data_range_offset(self.ecx, place);
|
let offset = Self::data_range_offset(self.ecx, place);
|
||||||
data_bytes.add_range(offset, place.layout.size);
|
data_bytes.add_range(offset, place.layout.size);
|
||||||
@ -945,7 +945,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
|
|||||||
layout: TyAndLayout<'tcx>,
|
layout: TyAndLayout<'tcx>,
|
||||||
) -> Cow<'e, RangeSet> {
|
) -> Cow<'e, RangeSet> {
|
||||||
assert!(layout.ty.is_union());
|
assert!(layout.ty.is_union());
|
||||||
assert!(layout.abi.is_sized(), "there are no unsized unions");
|
assert!(layout.is_sized(), "there are no unsized unions");
|
||||||
let layout_cx = LayoutCx::new(*ecx.tcx, ecx.param_env);
|
let layout_cx = LayoutCx::new(*ecx.tcx, ecx.param_env);
|
||||||
return M::cached_union_data_range(ecx, layout.ty, || {
|
return M::cached_union_data_range(ecx, layout.ty, || {
|
||||||
let mut out = RangeSet(Vec::new());
|
let mut out = RangeSet(Vec::new());
|
||||||
|
@ -29,7 +29,7 @@ pub fn check_validity_requirement<'tcx>(
|
|||||||
|
|
||||||
// There is nothing strict or lax about inhabitedness.
|
// There is nothing strict or lax about inhabitedness.
|
||||||
if kind == ValidityRequirement::Inhabited {
|
if kind == ValidityRequirement::Inhabited {
|
||||||
return Ok(!layout.abi.is_uninhabited());
|
return Ok(!layout.is_uninhabited());
|
||||||
}
|
}
|
||||||
|
|
||||||
let layout_cx = LayoutCx::new(tcx, param_env_and_ty.param_env);
|
let layout_cx = LayoutCx::new(tcx, param_env_and_ty.param_env);
|
||||||
|
@ -172,7 +172,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if layout.abi.is_uninhabited() {
|
if layout.is_uninhabited() {
|
||||||
tcx.node_span_lint(
|
tcx.node_span_lint(
|
||||||
UNINHABITED_STATIC,
|
UNINHABITED_STATIC,
|
||||||
tcx.local_def_id_to_hir_id(def_id),
|
tcx.local_def_id_to_hir_id(def_id),
|
||||||
|
@ -346,7 +346,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
|
|||||||
// First try computing a static layout.
|
// First try computing a static layout.
|
||||||
let err = match tcx.layout_of(param_env.and(ty)) {
|
let err = match tcx.layout_of(param_env.and(ty)) {
|
||||||
Ok(layout) => {
|
Ok(layout) => {
|
||||||
if layout.abi.is_sized() {
|
if layout.is_sized() {
|
||||||
return Ok(SizeSkeleton::Known(layout.size, Some(layout.align.abi)));
|
return Ok(SizeSkeleton::Known(layout.size, Some(layout.align.abi)));
|
||||||
} else {
|
} else {
|
||||||
// Just to be safe, don't claim a known layout for unsized types.
|
// Just to be safe, don't claim a known layout for unsized types.
|
||||||
|
@ -7,6 +7,7 @@ edition = "2021"
|
|||||||
# tidy-alphabetical-start
|
# tidy-alphabetical-start
|
||||||
either = "1"
|
either = "1"
|
||||||
itertools = "0.12"
|
itertools = "0.12"
|
||||||
|
rustc_abi = { path = "../rustc_abi" }
|
||||||
rustc_arena = { path = "../rustc_arena" }
|
rustc_arena = { path = "../rustc_arena" }
|
||||||
rustc_ast = { path = "../rustc_ast" }
|
rustc_ast = { path = "../rustc_ast" }
|
||||||
rustc_attr = { path = "../rustc_attr" }
|
rustc_attr = { path = "../rustc_attr" }
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
//! A pass that eliminates branches on uninhabited or unreachable enum variants.
|
//! A pass that eliminates branches on uninhabited or unreachable enum variants.
|
||||||
|
|
||||||
|
use rustc_abi::Variants;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_middle::mir::patch::MirPatch;
|
use rustc_middle::mir::patch::MirPatch;
|
||||||
@ -9,7 +10,6 @@ use rustc_middle::mir::{
|
|||||||
};
|
};
|
||||||
use rustc_middle::ty::layout::TyAndLayout;
|
use rustc_middle::ty::layout::TyAndLayout;
|
||||||
use rustc_middle::ty::{Ty, TyCtxt};
|
use rustc_middle::ty::{Ty, TyCtxt};
|
||||||
use rustc_target::abi::{Abi, Variants};
|
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
pub(super) struct UnreachableEnumBranching;
|
pub(super) struct UnreachableEnumBranching;
|
||||||
@ -65,7 +65,7 @@ fn variant_discriminants<'tcx>(
|
|||||||
Variants::Multiple { variants, .. } => variants
|
Variants::Multiple { variants, .. } => variants
|
||||||
.iter_enumerated()
|
.iter_enumerated()
|
||||||
.filter_map(|(idx, layout)| {
|
.filter_map(|(idx, layout)| {
|
||||||
(layout.abi != Abi::Uninhabited)
|
(!layout.is_uninhabited())
|
||||||
.then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val)
|
.then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val)
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -339,9 +339,7 @@ pub(crate) mod rustc {
|
|||||||
// 2. enums that delegate their layout to a variant
|
// 2. enums that delegate their layout to a variant
|
||||||
// 3. enums with multiple variants
|
// 3. enums with multiple variants
|
||||||
match layout.variants() {
|
match layout.variants() {
|
||||||
Variants::Single { .. }
|
Variants::Single { .. } if layout.is_uninhabited() && layout.size == Size::ZERO => {
|
||||||
if layout.abi.is_uninhabited() && layout.size == Size::ZERO =>
|
|
||||||
{
|
|
||||||
// The layout representation of uninhabited, ZST enums is
|
// The layout representation of uninhabited, ZST enums is
|
||||||
// defined to be like that of the `!` type, as opposed of a
|
// defined to be like that of the `!` type, as opposed of a
|
||||||
// typical enum. Consequently, they cannot be descended into
|
// typical enum. Consequently, they cannot be descended into
|
||||||
|
@ -10,7 +10,7 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa
|
|||||||
|
|
||||||
// Type-level uninhabitedness should always imply ABI uninhabitedness.
|
// Type-level uninhabitedness should always imply ABI uninhabitedness.
|
||||||
if layout.ty.is_privately_uninhabited(tcx, cx.param_env) {
|
if layout.ty.is_privately_uninhabited(tcx, cx.param_env) {
|
||||||
assert!(layout.abi.is_uninhabited());
|
assert!(layout.is_uninhabited());
|
||||||
}
|
}
|
||||||
|
|
||||||
if layout.size.bytes() % layout.align.abi.bytes() != 0 {
|
if layout.size.bytes() % layout.align.abi.bytes() != 0 {
|
||||||
@ -262,9 +262,7 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Skip empty variants.
|
// Skip empty variants.
|
||||||
if variant.size == Size::ZERO
|
if variant.size == Size::ZERO || variant.fields.count() == 0 || variant.is_uninhabited()
|
||||||
|| variant.fields.count() == 0
|
|
||||||
|| variant.abi.is_uninhabited()
|
|
||||||
{
|
{
|
||||||
// These are never actually accessed anyway, so we can skip the coherence check
|
// These are never actually accessed anyway, so we can skip the coherence check
|
||||||
// for them. They also fail that check, since they have
|
// for them. They also fail that check, since they have
|
||||||
|
@ -60,8 +60,8 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>(
|
|||||||
span_bug!(tcx.def_span(ty_def_id), "not an adt")
|
span_bug!(tcx.def_span(ty_def_id), "not an adt")
|
||||||
};
|
};
|
||||||
let name = adt.variant(variant_idx).name;
|
let name = adt.variant(variant_idx).name;
|
||||||
let is_unsized = variant_layout.abi.is_unsized();
|
let is_unsized = variant_layout.is_unsized();
|
||||||
let is_uninhabited = variant_layout.abi.is_uninhabited();
|
let is_uninhabited = variant_layout.is_uninhabited();
|
||||||
let size = variant_layout.size.bytes() - tag_size;
|
let size = variant_layout.size.bytes() - tag_size;
|
||||||
let type_layout_size = TypeLayoutSize { is_unsized, is_uninhabited, size };
|
let type_layout_size = TypeLayoutSize { is_unsized, is_uninhabited, size };
|
||||||
(name, type_layout_size)
|
(name, type_layout_size)
|
||||||
@ -72,8 +72,8 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let type_layout_size = tcx.layout_of(param_env.and(ty)).map(|layout| {
|
let type_layout_size = tcx.layout_of(param_env.and(ty)).map(|layout| {
|
||||||
let is_unsized = layout.abi.is_unsized();
|
let is_unsized = layout.is_unsized();
|
||||||
let is_uninhabited = layout.abi.is_uninhabited();
|
let is_uninhabited = layout.is_uninhabited();
|
||||||
let size = layout.size.bytes();
|
let size = layout.size.bytes();
|
||||||
TypeLayoutSize { is_unsized, is_uninhabited, size }
|
TypeLayoutSize { is_unsized, is_uninhabited, size }
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user