Rollup merge of #72331 - oddg:forbid-cast-of-cenum-implementing-drop, r=matthewjasper,nikomatsakis

Report error when casting an C-like enum implementing Drop

Following approach described in https://github.com/rust-lang/rust/issues/35941
This commit is contained in:
Ralf Jung 2020-06-19 08:55:57 +02:00 committed by GitHub
commit 9c54c65c9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 72 additions and 3 deletions

View File

@ -534,6 +534,16 @@
@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 @@
ASM_SUB_REGISTER,
UNSAFE_OP_IN_UNSAFE_FN,
INCOMPLETE_INCLUDE,
CENUM_IMPL_DROP_CAST,
]
}

View File

@ -678,7 +678,10 @@ fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
(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 @@ fn check_ref_cast(
// 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 @@ fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<(), ty::error::Typ
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> {

View File

@ -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
}

View File

@ -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