diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 1a789009f0611..e24950f9fe130 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -291,10 +291,10 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> { self.consume_operand(location, operand) } - Rvalue::Len(place) | Rvalue::Discriminant(place) => { + Rvalue::Len(place) | Rvalue::Discriminant { place, .. } => { let af = match *rvalue { Rvalue::Len(..) => Some(ArtificialField::ArrayLength), - Rvalue::Discriminant(..) => None, + Rvalue::Discriminant { .. } => None, _ => unreachable!(), }; self.access_place( diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 0007d8026e66b..f8194713e6bb5 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1280,10 +1280,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.consume_operand(location, (operand, span), flow_state) } - Rvalue::Len(place) | Rvalue::Discriminant(place) => { + Rvalue::Len(place) | Rvalue::Discriminant { place, .. } => { let af = match *rvalue { Rvalue::Len(..) => Some(ArtificialField::ArrayLength), - Rvalue::Discriminant(..) => None, + Rvalue::Discriminant { .. } => None, _ => unreachable!(), }; self.access_place( diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index e9fa33f656f31..2a915d5a7a73f 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2260,7 +2260,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Rvalue::AddressOf(..) | Rvalue::ThreadLocalRef(..) | Rvalue::Len(..) - | Rvalue::Discriminant(..) => {} + | Rvalue::Discriminant { .. } => {} } } @@ -2281,7 +2281,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | Rvalue::CheckedBinaryOp(..) | Rvalue::NullaryOp(..) | Rvalue::UnaryOp(..) - | Rvalue::Discriminant(..) => None, + | Rvalue::Discriminant { .. } => None, Rvalue::Aggregate(aggregate, _) => match **aggregate { AggregateKind::Adt(_, _, _, user_ty, _) => user_ty, diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index a9ff710c91ed6..e5ab4cca13a96 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -634,6 +634,7 @@ fn codegen_stmt<'tcx>( fx, operand, fx.layout_of(operand.layout().ty.discriminant_ty(fx.tcx)), + false, ) .load_scalar(fx); @@ -684,11 +685,15 @@ fn codegen_stmt<'tcx>( let operand = codegen_operand(fx, operand); operand.unsize_value(fx, lval); } - Rvalue::Discriminant(place) => { + Rvalue::Discriminant { place, relative } => { let place = codegen_place(fx, place); let value = place.to_cvalue(fx); - let discr = - crate::discriminant::codegen_get_discriminant(fx, value, dest_layout); + let discr = crate::discriminant::codegen_get_discriminant( + fx, + value, + dest_layout, + relative, + ); lval.write_cvalue(fx, discr); } Rvalue::Repeat(ref operand, times) => { diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs index 6b2893fdaeb29..8961e2447a177 100644 --- a/compiler/rustc_codegen_cranelift/src/discriminant.rs +++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs @@ -60,10 +60,13 @@ pub(crate) fn codegen_set_discriminant<'tcx>( } } +/// If `relative` is true, we instead calculate the *relative* discriminant (see +/// `RValue::Discriminant`). pub(crate) fn codegen_get_discriminant<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, value: CValue<'tcx>, dest_layout: TyAndLayout<'tcx>, + relative: bool, ) -> CValue<'tcx> { let layout = value.layout(); @@ -131,38 +134,46 @@ pub(crate) fn codegen_get_discriminant<'tcx>( // FIXME handle niche_start > i64::MAX fx.bcx.ins().iadd_imm(tag, -i64::try_from(niche_start).unwrap()) }; - let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); - let is_niche = { - codegen_icmp_imm( - fx, - IntCC::UnsignedLessThanOrEqual, - relative_discr, - i128::from(relative_max), - ) - }; - // NOTE(eddyb) this addition needs to be performed on the final - // type, in case the niche itself can't represent all variant - // indices (e.g. `u8` niche with more than `256` variants, - // but enough uninhabited variants so that the remaining variants - // fit in the niche). - // In other words, `niche_variants.end - niche_variants.start` - // is representable in the niche, but `niche_variants.end` - // might not be, in extreme cases. - let niche_discr = { - let relative_discr = if relative_max == 0 { - // HACK(eddyb) since we have only one niche, we know which - // one it is, and we can avoid having a dynamic value here. - fx.bcx.ins().iconst(cast_to, 0) - } else { - clif_intcast(fx, relative_discr, cast_to, false) + if relative { + CValue::by_val(clif_intcast(fx, relative_discr, cast_to, false), dest_layout) + } else { + let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); + let is_niche = { + codegen_icmp_imm( + fx, + IntCC::UnsignedLessThanOrEqual, + relative_discr, + i128::from(relative_max), + ) }; - fx.bcx.ins().iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32())) - }; - let dataful_variant = fx.bcx.ins().iconst(cast_to, i64::from(dataful_variant.as_u32())); - let discr = fx.bcx.ins().select(is_niche, niche_discr, dataful_variant); - CValue::by_val(discr, dest_layout) + // NOTE(eddyb) this addition needs to be performed on the final + // type, in case the niche itself can't represent all variant + // indices (e.g. `u8` niche with more than `256` variants, + // but enough uninhabited variants so that the remaining variants + // fit in the niche). + // In other words, `niche_variants.end - niche_variants.start` + // is representable in the niche, but `niche_variants.end` + // might not be, in extreme cases. + let niche_discr = { + let relative_discr = if relative_max == 0 { + // HACK(eddyb) since we have only one niche, we know which + // one it is, and we can avoid having a dynamic value here. + fx.bcx.ins().iconst(cast_to, 0) + } else { + clif_intcast(fx, relative_discr, cast_to, false) + }; + fx.bcx + .ins() + .iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32())) + }; + + let dataful_variant = + fx.bcx.ins().iconst(cast_to, i64::from(dataful_variant.as_u32())); + let discr = fx.bcx.ins().select(is_niche, niche_discr, dataful_variant); + CValue::by_val(discr, dest_layout) + } } } } diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index f15c469ae5741..e20a0c2430631 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -359,7 +359,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { sym::discriminant_value => { if ret_ty.is_integral() { - args[0].deref(bx.cx()).codegen_get_discr(bx, ret_ty) + args[0].deref(bx.cx()).codegen_get_discr(bx, ret_ty, false) } else { span_bug!(span, "Invalid discriminant type for `{:?}`", arg_tys[0]) } diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 17cfb6c5dfb54..9f9a1e0823984 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -204,10 +204,14 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { } /// Obtain the actual discriminant of a value. + /// + /// If `relative` is true, instead calculate the *relative* discriminant (see + /// `RValue::Discriminant`). pub fn codegen_get_discr>( self, bx: &mut Bx, cast_to: Ty<'tcx>, + relative: bool, ) -> V { let cast_to = bx.cx().immediate_backend_type(bx.cx().layout_of(cast_to)); if self.layout.abi.is_uninhabited() { @@ -266,44 +270,49 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { } else { bx.sub(tag, bx.cx().const_uint_big(niche_llty, niche_start)) }; - let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); - let is_niche = if relative_max == 0 { - // Avoid calling `const_uint`, which wouldn't work for pointers. - // Also use canonical == 0 instead of non-canonical u<= 0. - // FIXME(eddyb) check the actual primitive type here. - bx.icmp(IntPredicate::IntEQ, relative_discr, bx.cx().const_null(niche_llty)) + let relative_max = niche_variants.size_hint().1.unwrap() - 1; + + if relative { + bx.intcast(relative_discr, cast_to, false) } else { - let relative_max = bx.cx().const_uint(niche_llty, relative_max as u64); - bx.icmp(IntPredicate::IntULE, relative_discr, relative_max) - }; + // NOTE(eddyb) this addition needs to be performed on the final + // type, in case the niche itself can't represent all variant + // indices (e.g. `u8` niche with more than `256` variants, + // but enough uninhabited variants so that the remaining variants + // fit in the niche). + // In other words, `niche_variants.end - niche_variants.start` + // is representable in the niche, but `niche_variants.end` + // might not be, in extreme cases. + let niche_discr = { + let relative_discr = if relative_max == 0 { + // HACK(eddyb) since we have only one niche, we know which + // one it is, and we can avoid having a dynamic value here. + bx.cx().const_uint(cast_to, 0) + } else { + bx.intcast(relative_discr, cast_to, false) + }; + bx.add( + relative_discr, + bx.cx().const_uint(cast_to, niche_variants.start().as_u32() as u64), + ) + }; - // NOTE(eddyb) this addition needs to be performed on the final - // type, in case the niche itself can't represent all variant - // indices (e.g. `u8` niche with more than `256` variants, - // but enough uninhabited variants so that the remaining variants - // fit in the niche). - // In other words, `niche_variants.end - niche_variants.start` - // is representable in the niche, but `niche_variants.end` - // might not be, in extreme cases. - let niche_discr = { - let relative_discr = if relative_max == 0 { - // HACK(eddyb) since we have only one niche, we know which - // one it is, and we can avoid having a dynamic value here. - bx.cx().const_uint(cast_to, 0) + let is_niche = if relative_max == 0 { + // Avoid calling `const_uint`, which wouldn't work for pointers. + // Also use canonical == 0 instead of non-canonical u<= 0. + // FIXME(eddyb) check the actual primitive type here. + bx.icmp(IntPredicate::IntEQ, relative_discr, bx.cx().const_null(niche_llty)) } else { - bx.intcast(relative_discr, cast_to, false) + let relative_max = bx.cx().const_uint(niche_llty, relative_max as u64); + bx.icmp(IntPredicate::IntULE, relative_discr, relative_max) }; - bx.add( - relative_discr, - bx.cx().const_uint(cast_to, niche_variants.start().as_u32() as u64), - ) - }; - bx.select( - is_niche, - niche_discr, - bx.cx().const_uint(cast_to, dataful_variant.as_u32() as u64), - ) + bx.select( + is_niche, + niche_discr, + bx.cx().const_uint(cast_to, dataful_variant.as_u32() as u64), + ) + } } } } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 68decce82ab52..e65207d58d553 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -469,12 +469,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (bx, OperandRef { val: OperandValue::Immediate(llval), layout: operand.layout }) } - mir::Rvalue::Discriminant(ref place) => { + mir::Rvalue::Discriminant { ref place, relative } => { let discr_ty = rvalue.ty(self.mir, bx.tcx()); let discr_ty = self.monomorphize(discr_ty); let discr = self .codegen_place(&mut bx, place.as_ref()) - .codegen_get_discr(&mut bx, discr_ty); + .codegen_get_discr(&mut bx, discr_ty, relative); ( bx, OperandRef { @@ -751,7 +751,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::BinaryOp(..) | mir::Rvalue::CheckedBinaryOp(..) | mir::Rvalue::UnaryOp(..) | - mir::Rvalue::Discriminant(..) | + mir::Rvalue::Discriminant { .. } | mir::Rvalue::NullaryOp(..) | mir::Rvalue::ThreadLocalRef(_) | mir::Rvalue::Use(..) => // (*) diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 6fd7f707e7e5d..1b5977c46d9e8 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -109,7 +109,7 @@ fn const_to_valtree_inner<'tcx>( bug!("uninhabited types should have errored and never gotten converted to valtree") } - let variant = ecx.read_discriminant(&place.into()).unwrap().1; + let variant = ecx.read_discriminant(&place.into(), false).unwrap().1; branches(def.variant(variant).fields.len(), def.is_enum().then_some(variant)) } @@ -152,7 +152,7 @@ pub(crate) fn try_destructure_const<'tcx>( // index). ty::Adt(def, _) if def.variants().is_empty() => throw_ub!(Unreachable), ty::Adt(def, _) => { - let variant = ecx.read_discriminant(&op)?.1; + let variant = ecx.read_discriminant(&op, false)?.1; let down = ecx.operand_downcast(&op, variant)?; (def.variant(variant).fields.len(), Some(variant), down) } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index c80d7d7178742..a0486c026a36a 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -230,7 +230,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } sym::discriminant_value => { let place = self.deref_operand(&args[0])?; - let discr_val = self.read_discriminant(&place.into())?.0; + let discr_val = self.read_discriminant(&place.into(), false)?.0; self.write_scalar(discr_val, dest)?; } sym::unchecked_shl diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 9000567558b84..1eb9bacbb96ae 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -631,9 +631,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Read discriminant, return the runtime value as well as the variant index. /// Can also legally be called on non-enums (e.g. through the discriminant_value intrinsic)! + /// If `relative` is true, we instead calculate the *relative* discriminant + /// (See the doc comment on `RValue::Discriminant`). pub fn read_discriminant( &self, op: &OpTy<'tcx, M::PointerTag>, + relative: bool, ) -> InterpResult<'tcx, (Scalar, VariantIdx)> { trace!("read_discriminant_value {:#?}", op.layout); // Get type and layout of the discriminant. @@ -722,7 +725,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // discriminant (encoded in niche/tag) and variant index are the same. let variants_start = niche_variants.start().as_u32(); let variants_end = niche_variants.end().as_u32(); - let variant = match tag_val.try_to_int() { + match tag_val.try_to_int() { Err(dbg_val) => { // So this is a pointer then, and casting to an int failed. // Can only happen during CTFE. @@ -734,7 +737,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if !ptr_valid { throw_ub!(InvalidTag(dbg_val)) } - dataful_variant + ( + Scalar::from_uint(dataful_variant.as_u32(), discr_layout.size), + dataful_variant, + ) } Ok(tag_bits) => { let tag_bits = tag_bits.assert_bits(tag_layout.size); @@ -748,7 +754,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .to_scalar()? .assert_bits(tag_val.layout.size); // Check if this is in the range that indicates an actual discriminant. - if variant_index_relative <= u128::from(variants_end - variants_start) { + let variant = if variant_index_relative + <= u128::from(variants_end - variants_start) + { let variant_index_relative = u32::try_from(variant_index_relative) .expect("we checked that this fits into a u32"); // Then computing the absolute variant idx should not overflow any more. @@ -766,13 +774,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { VariantIdx::from_u32(variant_index) } else { dataful_variant + }; + + // No need to cast, because the variant index directly serves as + // discriminant and is encoded in the tag. + if relative { + (Scalar::from_uint(variant_index_relative, discr_layout.size), variant) + } else { + (Scalar::from_uint(variant.as_u32(), discr_layout.size), variant) } } - }; - // Compute the size of the scalar we need to return. - // No need to cast, because the variant index directly serves as discriminant and is - // encoded in the tag. - (Scalar::from_uint(variant.as_u32(), discr_layout.size), variant) + } } }) } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 4272bfd5d6c6f..7782b0810a5dd 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -297,9 +297,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.cast(&src, cast_kind, cast_ty, &dest)?; } - Discriminant(place) => { + Discriminant { place, relative } => { let op = self.eval_place_to_op(place, None)?; - let discr_val = self.read_discriminant(&op)?.0; + let discr_val = self.read_discriminant(&op, relative)?.0; self.write_scalar(discr_val, &dest)?; } } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 9da7f5e30cb9e..f8340e83fcf27 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -704,7 +704,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> ) -> InterpResult<'tcx, VariantIdx> { self.with_elem(PathElem::EnumTag, move |this| { Ok(try_validation!( - this.ecx.read_discriminant(op), + this.ecx.read_discriminant(op, /*relative*/false), this.path, err_ub!(InvalidTag(val)) => { "{:x}", val } expected { "a valid enum tag" }, diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index 679d30227f136..65709cdda204d 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -135,7 +135,7 @@ macro_rules! make_value_visitor { &mut self, op: &OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, VariantIdx> { - Ok(self.ecx().read_discriminant(op)?.1) + Ok(self.ecx().read_discriminant(op, /*relative*/ false)?.1) } // Recursive actions, ready to be overloaded. diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index e203c79030d20..1eee05cc2de17 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -463,7 +463,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Use(_) | Rvalue::Repeat(..) - | Rvalue::Discriminant(..) + | Rvalue::Discriminant { .. } | Rvalue::Len(_) | Rvalue::Aggregate(..) => {} diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 9fd94dc334ff2..f1d2b972625f8 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -256,7 +256,7 @@ where Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) } - Rvalue::Discriminant(place) | Rvalue::Len(place) => { + Rvalue::Discriminant { place, .. } | Rvalue::Len(place) => { in_place::(cx, in_local, place.as_ref()) } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs index fd7febc17a3a7..2e50703c73f4f 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs @@ -206,7 +206,7 @@ where | mir::Rvalue::CheckedBinaryOp(..) | mir::Rvalue::NullaryOp(..) | mir::Rvalue::UnaryOp(..) - | mir::Rvalue::Discriminant(..) + | mir::Rvalue::Discriminant { .. } | mir::Rvalue::Aggregate(..) => {} } } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index faea2111d9210..b7524010969a8 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -486,7 +486,7 @@ impl<'tcx> Validator<'_, 'tcx> { self.validate_operand(operand)?; } - Rvalue::Discriminant(place) | Rvalue::Len(place) => { + Rvalue::Discriminant { place, .. } | Rvalue::Len(place) => { self.validate_place(place.as_ref())? } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 0a4f84558fee4..e1d80a45a541f 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2308,7 +2308,16 @@ pub enum Rvalue<'tcx> { /// /// Undefined (i.e., no effort is made to make it defined, but there’s no reason why it cannot /// be defined to return, say, a 0) if ADT is not an enum. - Discriminant(Place<'tcx>), + /// + /// If `relative` is true, and the ADT has the niche-filling optimization, yields + /// the *relative* discriminant. The relative discriminant is essentially the value of the tag + /// minus `niche_variants.start()`; that is, it's relative to the niche variants. + /// The ability to calculate the relative discriminant exists only for the `AddNicheCases` + /// optimization. + Discriminant { + place: Place<'tcx>, + relative: bool, + }, /// Creates an aggregate value, like a tuple or struct. This is /// only needed because we want to distinguish `dest = Foo { x: @@ -2444,7 +2453,10 @@ impl<'tcx> Debug for Rvalue<'tcx> { write!(fmt, "Checked{:?}({:?}, {:?})", op, a, b) } UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a), - Discriminant(ref place) => write!(fmt, "discriminant({:?})", place), + Discriminant { ref place, relative: false } => write!(fmt, "discriminant({:?})", place), + Discriminant { ref place, relative: true } => { + write!(fmt, "relative_discriminant({:?})", place) + } NullaryOp(ref op, ref t) => write!(fmt, "{:?}({:?})", op, t), ThreadLocalRef(did) => ty::tls::with(|tcx| { let muta = tcx.static_mutability(did).unwrap().prefix_str(); diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 51d8113840a93..568fc614c8d2a 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -194,7 +194,9 @@ impl<'tcx> Rvalue<'tcx> { tcx.intern_tup(&[ty, tcx.types.bool]) } Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx), - Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), + Rvalue::Discriminant { ref place, .. } => { + place.ty(local_decls, tcx).ty.discriminant_ty(tcx) + } Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => tcx.types.usize, Rvalue::Aggregate(ref ak, ref ops) => match **ak { AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64), diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index 901f3bf4f7d41..038a122906c44 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -214,7 +214,9 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { Box::new((rhs.try_fold_with(folder)?, lhs.try_fold_with(folder)?)), ), UnaryOp(op, val) => UnaryOp(op, val.try_fold_with(folder)?), - Discriminant(place) => Discriminant(place.try_fold_with(folder)?), + Discriminant { place, relative } => { + Discriminant { place: place.try_fold_with(folder)?, relative } + } NullaryOp(op, ty) => NullaryOp(op, ty.try_fold_with(folder)?), Aggregate(kind, fields) => { let kind = kind.try_map_id(|kind| { @@ -265,7 +267,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { lhs.visit_with(visitor) } UnaryOp(_, ref val) => val.visit_with(visitor), - Discriminant(ref place) => place.visit_with(visitor), + Discriminant { ref place, .. } => place.visit_with(visitor), NullaryOp(_, ty) => ty.visit_with(visitor), Aggregate(ref kind, ref fields) => { match **kind { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index aeb0f956eb4f7..5ead8833113cf 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -698,7 +698,7 @@ macro_rules! make_mir_visitor { self.visit_operand(op, location); } - Rvalue::Discriminant(place) => { + Rvalue::Discriminant { place, .. } => { self.visit_place( place, PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 96069f05b40f3..01d382c44f35e 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -192,7 +192,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug_assert_eq!( target_blocks[idx.index()], otherwise_block, - "found canididates for untested discriminant: {:?}", + "found candidates for untested discriminant: {:?}", discr, ); None @@ -207,7 +207,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, self.source_info(scrutinee_span), discr, - Rvalue::Discriminant(place), + Rvalue::Discriminant { place, relative: false }, ); self.cfg.terminate( block, diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index f568121b2192c..295d1d12fcb9e 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -579,7 +579,7 @@ where // way lies only trouble. let discr_ty = adt.repr().discr_type().to_ty(self.tcx()); let discr = Place::from(self.new_temp(discr_ty)); - let discr_rv = Rvalue::Discriminant(self.place); + let discr_rv = Rvalue::Discriminant { place: self.place, relative: false }; let switch_block = BasicBlockData { statements: vec![self.assign(discr, discr_rv)], terminator: Some(Terminator { diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 4981ab5152cd7..fab2e2c177866 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -107,7 +107,7 @@ where | mir::Rvalue::CheckedBinaryOp(..) | mir::Rvalue::NullaryOp(..) | mir::Rvalue::UnaryOp(..) - | mir::Rvalue::Discriminant(..) + | mir::Rvalue::Discriminant { .. } | mir::Rvalue::Aggregate(..) => {} } } diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs index d90ead3228c2d..92bea063d02e2 100644 --- a/compiler/rustc_mir_dataflow/src/impls/mod.rs +++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs @@ -708,9 +708,10 @@ fn switch_on_enum_discriminant<'mir, 'tcx>( ) -> Option<(mir::Place<'tcx>, ty::AdtDef<'tcx>)> { for statement in block.statements.iter().rev() { match &statement.kind { - mir::StatementKind::Assign(box (lhs, mir::Rvalue::Discriminant(discriminated))) - if *lhs == switch_on => - { + mir::StatementKind::Assign(box ( + lhs, + mir::Rvalue::Discriminant { place: discriminated, relative: false }, + )) if *lhs == switch_on => { match discriminated.ty(body, tcx).ty.kind() { ty::Adt(def, _) => return Some((*discriminated, *def)), diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 26bbc34e780bb..264fd0f835cae 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -330,7 +330,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { } Rvalue::Ref(..) | Rvalue::AddressOf(..) - | Rvalue::Discriminant(..) + | Rvalue::Discriminant { .. } | Rvalue::Len(..) | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} } diff --git a/compiler/rustc_mir_transform/src/add_niche_cases.rs b/compiler/rustc_mir_transform/src/add_niche_cases.rs new file mode 100644 index 0000000000000..b7876278a3b39 --- /dev/null +++ b/compiler/rustc_mir_transform/src/add_niche_cases.rs @@ -0,0 +1,178 @@ +//! Turn a SwitchInt over a discriminant into a SwitchInt over a +//! relative discriminant, adding extra cases for the potential values +//! representing the dataful variant as needed. +//! +//! This lets us avoid some arithmetic and a select that would occur +//! in the usual discriminant calculation. + +use crate::MirPass; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_target::abi::{TagEncoding, Variants}; + +use std::iter; + +// This is arbitrary but seems to work well enough. +const ALLOWED_EXTRA_BRANCHES: u128 = 20; + +pub struct AddNicheCases; + +impl<'tcx> MirPass<'tcx> for AddNicheCases { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() >= 1 + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if body.generator.is_some() { + return; + } + + let def_id = body.source.def_id(); + let param_env = tcx.param_env(def_id); + + let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut(); + + for bb_idx in bbs.indices() { + let extract_from_switch_int = || { + if let TerminatorKind::SwitchInt { + discr: Operand::Copy(ref d) | Operand::Move(ref d), + ref targets, + .. + } = bbs[bb_idx].terminator().kind + { + if targets.iter().len() <= 1 { + return None; + } + + let otherwise_is_unreachable = { + match bbs[targets.otherwise()].terminator().kind { + TerminatorKind::Unreachable => true, + _ => false, + } + }; + + if targets.iter().len() == 2 && otherwise_is_unreachable { + // This will be well optimized anyway. + return None; + } + + if bbs[bb_idx].statements.is_empty() { + return None; + } + + // If the last statement is assigning a discriminant, + // this is what we're looking for. + if let &StatementKind::Assign(box (ref place, ref rvalue)) = + &bbs[bb_idx].statements.last().unwrap().kind + { + if *place == *d { + if let Rvalue::Discriminant { place, relative: false } = rvalue { + return Some((*d, *place, targets)); + } + } + } + } + None + }; + + let (d, enum_place, targets) = match extract_from_switch_int() { + Some(vals) => vals, + None => continue, + }; + + let enum_ty = enum_place.ty(local_decls, tcx).ty; + let d_ty = d.ty(local_decls, tcx).ty; + let enum_ty_and_layout = match tcx.layout_of(param_env.and(enum_ty)) { + Ok(ty_and_layout) => ty_and_layout, + _ => continue, + }; + + let (tag, tag_encoding) = match enum_ty_and_layout.layout.variants() { + Variants::Multiple { tag, ref tag_encoding, .. } => (tag, tag_encoding), + + _ => continue, + }; + + let (dataful_variant, niche_start, niche_variants) = match tag_encoding { + TagEncoding::Niche { dataful_variant, niche_start, niche_variants, .. } => { + (*dataful_variant, *niche_start, niche_variants) + } + + _ => continue, + }; + + let niche_variants_count_m1 = + niche_variants.end().as_u32() - niche_variants.start().as_u32(); + + let niche_variants_count = niche_variants_count_m1 as u128 + 1; + + let dataful_bb = { + let found = targets.iter().find(|(v, _)| *v == dataful_variant.as_u32() as u128); + if let Some((_, b)) = found { + b + } else { + // The dataful variant doesn't appear in the target blocks anyway. + continue; + } + }; + + let valid_range = tag.valid_range; + let max_value = tag.value.size(&tcx).unsigned_int_max(); + let valid_values_count_m1 = valid_range.end.wrapping_sub(valid_range.start); + + let needed_extra_branches_m1 = valid_values_count_m1 + .checked_sub(niche_variants_count) + .expect("Can't have fewer variants than valid values in a niche"); + if needed_extra_branches_m1 > ALLOWED_EXTRA_BRANCHES - 1 { + continue; + } + + let first = if niche_start == valid_range.start { + // valid and non-variant values come at the end + niche_variants.end().as_u32() as u128 + 1 + } else { + // valid and non-variant values come at the beginning + let last = (niche_variants.start().as_u32() as u128).wrapping_sub(1); + last.wrapping_sub(needed_extra_branches_m1) + }; + + let needed_extra_branches = needed_extra_branches_m1 as usize + 1; + let new_values = iter::successors(Some(first), |v| Some(v.wrapping_add(1))) + .map(|v| v & max_value) + .take(needed_extra_branches); + let new_targets = iter::repeat(dataful_bb); + let new_values_targets = new_values.zip(new_targets); + + let old_iter = targets.iter().filter(|(v, _)| *v != dataful_variant.as_u32() as u128); + let all_values_targets = new_values_targets.chain(old_iter).map(|(v, t)| { + (v.wrapping_sub(niche_variants.start().as_u32() as u128) & max_value, t) + }); + let otherwise = targets.otherwise(); + + let new_targets = SwitchTargets::new(all_values_targets, otherwise); + let source_info = bbs[bb_idx].terminator().source_info; + + let span = local_decls[d.local].source_info.span; + let fake_d: Place<'_> = local_decls.push(LocalDecl::new(d_ty, span)).into(); + let assignment = Statement { + source_info: bbs[bb_idx].statements.last().unwrap().source_info, + kind: StatementKind::Assign(Box::new(( + fake_d, + Rvalue::Discriminant { place: enum_place, relative: true }, + ))), + }; + + let new_terminator = Terminator { + source_info, + kind: TerminatorKind::SwitchInt { + discr: Operand::Copy(fake_d), + switch_ty: d_ty, + targets: new_targets, + }, + }; + + *bbs[bb_idx].statements.last_mut().unwrap() = assignment; + bbs[bb_idx].terminator = Some(new_terminator); + } + } +} diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index e1dbf90b5b9e7..a103d249b60c5 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -618,7 +618,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { | Rvalue::Len(..) | Rvalue::Cast(..) | Rvalue::ShallowInitBox(..) - | Rvalue::Discriminant(..) + | Rvalue::Discriminant { .. } | Rvalue::NullaryOp(..) => {} } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 5be745bc1de38..6e11e78ef282f 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -684,7 +684,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { | Rvalue::Len(..) | Rvalue::Cast(..) | Rvalue::ShallowInitBox(..) - | Rvalue::Discriminant(..) + | Rvalue::Discriminant { .. } | Rvalue::NullaryOp(..) => {} } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 5d0b58e9c5360..6ad6fa578a4bb 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -916,7 +916,7 @@ impl<'tcx> Visitor<'tcx> for BorrowCollector { | Rvalue::CheckedBinaryOp(..) | Rvalue::NullaryOp(..) | Rvalue::UnaryOp(..) - | Rvalue::Discriminant(..) + | Rvalue::Discriminant { .. } | Rvalue::Aggregate(..) | Rvalue::ThreadLocalRef(..) => {} } diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index 5bde0c01412ac..4d284c736ce8b 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -147,7 +147,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { patch.add_assign( parent_end, Place::from(second_discriminant_temp), - Rvalue::Discriminant(opt_data.child_place), + Rvalue::Discriminant { place: opt_data.child_place, relative: false }, ); // create temp to store inequality comparison between the two discriminants, `_t` in @@ -354,7 +354,7 @@ fn evaluate_candidate<'tcx>( = &bbs[child].statements.first().map(|x| &x.kind) else { return None; }; - let (_, Rvalue::Discriminant(child_place)) = &**boxed else { + let (_, Rvalue::Discriminant { place: child_place, relative: false }) = &**boxed else { return None; }; let destination = parent_dest.unwrap_or(child_targets.otherwise()); @@ -394,7 +394,7 @@ fn verify_candidate_branch<'tcx>( let StatementKind::Assign(boxed) = &branch.statements[0].kind else { return false }; - let (discr_place, Rvalue::Discriminant(from_place)) = &**boxed else { + let (discr_place, Rvalue::Discriminant { place: from_place, relative: false }) = &**boxed else { return false }; if *from_place != place { diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 04b5c4e091958..b539fec7cd57d 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -289,7 +289,10 @@ impl<'tcx> TransformVisitor<'tcx> { let self_place = Place::from(SELF_ARG); let assign = Statement { source_info: SourceInfo::outermost(body.span), - kind: StatementKind::Assign(Box::new((temp, Rvalue::Discriminant(self_place)))), + kind: StatementKind::Assign(Box::new(( + temp, + Rvalue::Discriminant { place: self_place, relative: false }, + ))), }; (assign, temp) } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 2fca498a12502..e511aa022153f 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -40,6 +40,7 @@ use pass_manager::{self as pm, Lint, MirLint, WithMinOptLevel}; mod abort_unwinding_calls; mod add_call_guards; mod add_moves_for_packed_drops; +mod add_niche_cases; mod add_retag; mod check_const_item_mutation; mod check_packed_ref; @@ -483,6 +484,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // Const-prop runs unconditionally, but doesn't mutate the MIR at mir-opt-level=0. &o1(simplify_branches::SimplifyConstCondition::new("after-const-prop")), &early_otherwise_branch::EarlyOtherwiseBranch, + &add_niche_cases::AddNicheCases, &simplify_comparison_integral::SimplifyComparisonIntegral, &simplify_try::SimplifyArmIdentity, &simplify_try::SimplifyBranchSame, diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 684d988ee9ed2..ecc767dc7655f 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -118,7 +118,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { source_info: terminator.source_info, kind: StatementKind::Assign(Box::new(( destination, - Rvalue::Discriminant(arg), + Rvalue::Discriminant { place: arg, relative: false }, ))), }); terminator.kind = TerminatorKind::Goto { target }; diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index 03b9ecc959695..fd02ae788dd7c 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -39,7 +39,10 @@ impl RemoveNoopLandingPads { // These are all noops in a landing pad } - StatementKind::Assign(box (place, Rvalue::Use(_) | Rvalue::Discriminant(_))) => { + StatementKind::Assign(box ( + place, + Rvalue::Use(_) | Rvalue::Discriminant { .. }, + )) => { if place.as_local().is_some() { // Writing to a local (e.g., a drop flag) does not // turn a landing pad to a non-nop diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index d265720e18296..bfac9d3a08455 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -219,7 +219,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData< Rvalue::Cast(_, Operand::Copy(place) | Operand::Move(place), _) | Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::UnaryOp(_, Operand::Copy(place) | Operand::Move(place)) - | Rvalue::Discriminant(place) => tracked_place = place, + | Rvalue::Discriminant { place, .. } => tracked_place = place, } } } @@ -280,7 +280,7 @@ fn find_determining_place<'tcx>( | Rvalue::UnaryOp(_, Operand::Copy(new) | Operand::Move(new)) | Rvalue::Cast(_, Operand::Move(new) | Operand::Copy(new), _) | Rvalue::Repeat(Operand::Move(new) | Operand::Copy(new), _) - | Rvalue::Discriminant(new) + | Rvalue::Discriminant { place: new, .. } => switch_place = new, // The following rvalues might still make the block diff --git a/compiler/rustc_mir_transform/src/simplify_try.rs b/compiler/rustc_mir_transform/src/simplify_try.rs index ce4b45062e8de..f1164ed43d50c 100644 --- a/compiler/rustc_mir_transform/src/simplify_try.rs +++ b/compiler/rustc_mir_transform/src/simplify_try.rs @@ -612,7 +612,7 @@ impl<'tcx> SimplifyBranchSameOptimizationFinder<'_, 'tcx> { if Some(*place) == discr_switched_on.place() => { match rhs { - Rvalue::Discriminant(adt_place) if adt_place.ty(self.body, self.tcx).ty.is_enum() => adt_place, + Rvalue::Discriminant { place, .. } if place.ty(self.body, self.tcx).ty.is_enum() => place, _ => { trace!("NO: expected a discriminant read of an enum instead of: {:?}", rhs); return None; diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs index bd196f1187966..470c00da0fe8c 100644 --- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs @@ -34,7 +34,8 @@ fn get_switched_on_type<'tcx>( let stmt_before_term = (!block_data.statements.is_empty()) .then(|| &block_data.statements[block_data.statements.len() - 1].kind); - if let Some(StatementKind::Assign(box (l, Rvalue::Discriminant(place)))) = stmt_before_term + if let Some(StatementKind::Assign(box (l, Rvalue::Discriminant { place, .. }))) = + stmt_before_term { if l.as_local() == Some(local) { let ty = place.ty(body, tcx).ty; diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 891531951c1a0..bd5aece59508c 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -123,9 +123,10 @@ fn check_rvalue<'tcx>( match rvalue { Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())), Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => check_operand(tcx, operand, span, body), - Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { - check_place(tcx, *place, span, body) - }, + Rvalue::Len(place) + | Rvalue::Discriminant { place, .. } + | Rvalue::Ref(_, _, place) + | Rvalue::AddressOf(_, place) => check_place(tcx, *place, span, body), Rvalue::Cast(CastKind::Misc, operand, cast_ty) => { use rustc_middle::ty::cast::CastTy; let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast");