about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc_session/lint/builtin.rs11
-rw-r--r--src/librustc_typeck/check/cast.rs30
-rw-r--r--src/test/ui/cenum_impl_drop_cast.rs18
-rw-r--r--src/test/ui/cenum_impl_drop_cast.stderr16
4 files changed, 72 insertions, 3 deletions
diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs
index 58388bafbed..5a8f5c1b9fb 100644
--- a/src/librustc_session/lint/builtin.rs
+++ b/src/librustc_session/lint/builtin.rs
@@ -534,6 +534,16 @@ declare_lint! {
     @feature_gate = sym::unsafe_block_in_unsafe_fn;
 }
 
+declare_lint! {
+    pub CENUM_IMPL_DROP_CAST,
+    Warn,
+    "a C-like enum implementing Drop is cast",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #73333 <https://github.com/rust-lang/rust/issues/73333>",
+        edition: None,
+    };
+}
+
 declare_lint_pass! {
     /// Does nothing as a lint pass, but registers some `Lint`s
     /// that are used by other parts of the compiler.
@@ -607,6 +617,7 @@ declare_lint_pass! {
         ASM_SUB_REGISTER,
         UNSAFE_OP_IN_UNSAFE_FN,
         INCOMPLETE_INCLUDE,
+        CENUM_IMPL_DROP_CAST,
     ]
 }
 
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 78474dac76f..1ea7bf25ef2 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -678,7 +678,10 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
 
             // prim -> prim
-            (Int(CEnum), Int(_)) => Ok(CastKind::EnumCast),
+            (Int(CEnum), Int(_)) => {
+                self.cenum_impl_drop_lint(fcx);
+                Ok(CastKind::EnumCast)
+            }
             (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
 
             (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast),
@@ -775,11 +778,13 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 // Coerce to a raw pointer so that we generate AddressOf in MIR.
                 let array_ptr_type = fcx.tcx.mk_ptr(m_expr);
                 fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No)
-                    .unwrap_or_else(|_| bug!(
+                    .unwrap_or_else(|_| {
+                        bug!(
                         "could not cast from reference to array to pointer to array ({:?} to {:?})",
                         self.expr_ty,
                         array_ptr_type,
-                    ));
+                    )
+                    });
 
                 // this will report a type mismatch if needed
                 fcx.demand_eqtype(self.span, ety, m_cast.ty);
@@ -809,6 +814,25 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             Err(err) => Err(err),
         }
     }
+
+    fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
+        if let ty::Adt(d, _) = self.expr_ty.kind {
+            if d.has_dtor(fcx.tcx) {
+                fcx.tcx.struct_span_lint_hir(
+                    lint::builtin::CENUM_IMPL_DROP_CAST,
+                    self.expr.hir_id,
+                    self.span,
+                    |err| {
+                        err.build(&format!(
+                            "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
+                            self.expr_ty, self.cast_ty
+                        ))
+                        .emit();
+                    },
+                );
+            }
+        }
+    }
 }
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
diff --git a/src/test/ui/cenum_impl_drop_cast.rs b/src/test/ui/cenum_impl_drop_cast.rs
new file mode 100644
index 00000000000..96e3d967e2c
--- /dev/null
+++ b/src/test/ui/cenum_impl_drop_cast.rs
@@ -0,0 +1,18 @@
+#![deny(cenum_impl_drop_cast)]
+
+enum E {
+    A = 0,
+}
+
+impl Drop for E {
+    fn drop(&mut self) {
+        println!("Drop");
+    }
+}
+
+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/src/test/ui/cenum_impl_drop_cast.stderr b/src/test/ui/cenum_impl_drop_cast.stderr
new file mode 100644
index 00000000000..8d847a0c80b
--- /dev/null
+++ b/src/test/ui/cenum_impl_drop_cast.stderr
@@ -0,0 +1,16 @@
+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;
+   |             ^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/cenum_impl_drop_cast.rs:1:9
+   |
+LL | #![deny(cenum_impl_drop_cast)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+   = 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 <https://github.com/rust-lang/rust/issues/73333>
+
+error: aborting due to previous error
+