From e0bbeb7a005bbf593ccae60f4b0ba86f17d3df63 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 23 Jan 2025 16:45:19 -0800 Subject: [PATCH] Make cenum_impl_drop_cast a hard error This changes the `cenum_impl_drop_cast` lint to be a hard error. This lint has been deny-by-default and warning in dependencies since https://github.com/rust-lang/rust/pull/97652 about 2.5 years ago. Closes https://github.com/rust-lang/rust/issues/73333 --- compiler/rustc_hir_typeck/src/cast.rs | 11 +-- compiler/rustc_hir_typeck/src/errors.rs | 4 +- compiler/rustc_lint/src/lib.rs | 5 ++ compiler/rustc_lint_defs/src/builtin.rs | 53 -------------- .../building/enum_cast.droppy.built.after.mir | 71 ------------------- tests/mir-opt/building/enum_cast.rs | 21 ------ tests/ui/cenum_impl_drop_cast.rs | 3 - tests/ui/cenum_impl_drop_cast.stderr | 25 +------ 8 files changed, 12 insertions(+), 181 deletions(-) delete mode 100644 tests/mir-opt/building/enum_cast.droppy.built.after.mir diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 5d00ecbe91874..65021a0cd1106 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -831,7 +831,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // prim -> prim (Int(CEnum), Int(_)) => { - self.cenum_impl_drop_lint(fcx); + self.err_if_cenum_impl_drop(fcx); Ok(CastKind::EnumCast) } (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast), @@ -1091,19 +1091,14 @@ impl<'a, 'tcx> CastCheck<'tcx> { } } - fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { + fn err_if_cenum_impl_drop(&self, fcx: &FnCtxt<'a, 'tcx>) { if let ty::Adt(d, _) = self.expr_ty.kind() && d.has_dtor(fcx.tcx) { let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); - fcx.tcx.emit_node_span_lint( - lint::builtin::CENUM_IMPL_DROP_CAST, - self.expr.hir_id, - self.span, - errors::CastEnumDrop { expr_ty, cast_ty }, - ); + fcx.dcx().emit_err(errors::CastEnumDrop { span: self.span, expr_ty, cast_ty }); } } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 052adaa69b2b9..143736072aa55 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -677,9 +677,11 @@ pub(crate) struct CannotCastToBool<'tcx> { pub help: CannotCastToBoolHelp, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag(hir_typeck_cast_enum_drop)] pub(crate) struct CastEnumDrop<'tcx> { + #[primary_span] + pub span: Span, pub expr_ty: Ty<'tcx>, pub cast_ty: Ty<'tcx>, } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 1465c2cff7bc1..39716785fbfe7 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -594,6 +594,11 @@ fn register_builtins(store: &mut LintStore) { for more information", ); store.register_removed("unsupported_calling_conventions", "converted into hard error"); + store.register_removed( + "cenum_impl_drop_cast", + "converted into hard error, \ + see for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 9fc527a6a3ab3..7fbd23bfdc4b6 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -27,7 +27,6 @@ declare_lint_pass! { BARE_TRAIT_OBJECTS, BINDINGS_WITH_VARIANT_NAME, BREAK_WITH_LABEL_AND_LOOP, - CENUM_IMPL_DROP_CAST, COHERENCE_LEAK_CHECK, CONFLICTING_REPR_HINTS, CONST_EVALUATABLE_UNCHECKED, @@ -2612,58 +2611,6 @@ declare_lint! { @edition Edition2024 => Warn; } -declare_lint! { - /// The `cenum_impl_drop_cast` lint detects an `as` cast of a field-less - /// `enum` that implements [`Drop`]. - /// - /// [`Drop`]: https://doc.rust-lang.org/std/ops/trait.Drop.html - /// - /// ### Example - /// - /// ```rust,compile_fail - /// # #![allow(unused)] - /// enum E { - /// A, - /// } - /// - /// impl Drop for E { - /// fn drop(&mut self) { - /// println!("Drop"); - /// } - /// } - /// - /// fn main() { - /// let e = E::A; - /// let i = e as u32; - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Casting a field-less `enum` that does not implement [`Copy`] to an - /// integer moves the value without calling `drop`. This can result in - /// surprising behavior if it was expected that `drop` should be called. - /// Calling `drop` automatically would be inconsistent with other move - /// operations. Since neither behavior is clear or consistent, it was - /// decided that a cast of this nature will no longer be allowed. - /// - /// This is a [future-incompatible] lint to transition this to a hard error - /// in the future. See [issue #73333] for more details. - /// - /// [future-incompatible]: ../index.md#future-incompatible-lints - /// [issue #73333]: https://github.com/rust-lang/rust/issues/73333 - /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html - pub CENUM_IMPL_DROP_CAST, - Deny, - "a C-like enum implementing Drop is cast", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #73333 ", - }; -} - declare_lint! { /// The `fuzzy_provenance_casts` lint detects an `as` cast between an integer /// and a pointer. diff --git a/tests/mir-opt/building/enum_cast.droppy.built.after.mir b/tests/mir-opt/building/enum_cast.droppy.built.after.mir deleted file mode 100644 index f53c9199a4949..0000000000000 --- a/tests/mir-opt/building/enum_cast.droppy.built.after.mir +++ /dev/null @@ -1,71 +0,0 @@ -// MIR for `droppy` after built - -fn droppy() -> () { - let mut _0: (); - let _1: (); - let _2: Droppy; - let _4: Droppy; - let mut _5: isize; - let mut _6: u8; - let mut _7: bool; - let _8: Droppy; - scope 1 { - debug x => _2; - scope 2 { - debug y => _3; - } - scope 3 { - let _3: usize; - } - } - scope 4 { - debug z => _8; - } - - bb0: { - StorageLive(_1); - StorageLive(_2); - _2 = Droppy::C; - FakeRead(ForLet(None), _2); - StorageLive(_3); - StorageLive(_4); - _4 = move _2; - _5 = discriminant(_4); - _6 = copy _5 as u8 (IntToInt); - _7 = Le(copy _6, const 2_u8); - assume(move _7); - _3 = move _5 as usize (IntToInt); - drop(_4) -> [return: bb1, unwind: bb4]; - } - - bb1: { - StorageDead(_4); - FakeRead(ForLet(None), _3); - _1 = const (); - StorageDead(_3); - drop(_2) -> [return: bb2, unwind: bb5]; - } - - bb2: { - StorageDead(_2); - StorageDead(_1); - StorageLive(_8); - _8 = Droppy::B; - FakeRead(ForLet(None), _8); - _0 = const (); - drop(_8) -> [return: bb3, unwind: bb5]; - } - - bb3: { - StorageDead(_8); - return; - } - - bb4 (cleanup): { - drop(_2) -> [return: bb5, unwind terminate(cleanup)]; - } - - bb5 (cleanup): { - resume; - } -} diff --git a/tests/mir-opt/building/enum_cast.rs b/tests/mir-opt/building/enum_cast.rs index 7ff0cdbfe8df0..4fb9a27e3093b 100644 --- a/tests/mir-opt/building/enum_cast.rs +++ b/tests/mir-opt/building/enum_cast.rs @@ -41,27 +41,6 @@ fn far(far: Far) -> isize { far as isize } -// EMIT_MIR enum_cast.droppy.built.after.mir -enum Droppy { - A, - B, - C, -} - -impl Drop for Droppy { - fn drop(&mut self) {} -} - -fn droppy() { - { - let x = Droppy::C; - // remove this entire test once `cenum_impl_drop_cast` becomes a hard error - #[allow(cenum_impl_drop_cast)] - let y = x as usize; - } - let z = Droppy::B; -} - #[repr(i16)] enum SignedAroundZero { A = -2, diff --git a/tests/ui/cenum_impl_drop_cast.rs b/tests/ui/cenum_impl_drop_cast.rs index 96e3d967e2c61..f681434dd86ac 100644 --- a/tests/ui/cenum_impl_drop_cast.rs +++ b/tests/ui/cenum_impl_drop_cast.rs @@ -1,5 +1,3 @@ -#![deny(cenum_impl_drop_cast)] - enum E { A = 0, } @@ -14,5 +12,4 @@ fn main() { let e = E::A; let i = e as u32; //~^ ERROR cannot cast enum `E` into integer `u32` because it implements `Drop` - //~| WARN this was previously accepted } diff --git a/tests/ui/cenum_impl_drop_cast.stderr b/tests/ui/cenum_impl_drop_cast.stderr index 541d15d021d3f..35c69f4b4b785 100644 --- a/tests/ui/cenum_impl_drop_cast.stderr +++ b/tests/ui/cenum_impl_drop_cast.stderr @@ -1,31 +1,8 @@ error: cannot cast enum `E` into integer `u32` because it implements `Drop` - --> $DIR/cenum_impl_drop_cast.rs:15:13 + --> $DIR/cenum_impl_drop_cast.rs:13:13 | LL | let i = e as u32; | ^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #73333 -note: the lint level is defined here - --> $DIR/cenum_impl_drop_cast.rs:1:9 - | -LL | #![deny(cenum_impl_drop_cast)] - | ^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error -Future incompatibility report: Future breakage diagnostic: -error: cannot cast enum `E` into integer `u32` because it implements `Drop` - --> $DIR/cenum_impl_drop_cast.rs:15:13 - | -LL | let i = e as u32; - | ^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #73333 -note: the lint level is defined here - --> $DIR/cenum_impl_drop_cast.rs:1:9 - | -LL | #![deny(cenum_impl_drop_cast)] - | ^^^^^^^^^^^^^^^^^^^^ -