From cec425462356bd7c51c1178408265add592b7d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Fri, 5 Feb 2021 15:47:46 +0300 Subject: [PATCH 1/2] Implement new lint for detecting buggy pointer-to-int casts New lint `invalid_ptr_to_int_cast` detects pointer (or function) to integer casts when the integer is not usize (or u64), and suggests going through usize, e.g. `x as usize as u32`. See #81686 for motivation. Closes #81686 --- compiler/rustc_lint_defs/src/builtin.rs | 41 +++++ compiler/rustc_middle/src/ty/sty.rs | 5 + compiler/rustc_typeck/src/check/cast.rs | 121 +++++++++---- compiler/rustc_typeck/src/check/expr.rs | 2 +- .../lint/lint-invalid-ptr-to-int-cast.fixed | 42 +++++ .../ui/lint/lint-invalid-ptr-to-int-cast.rs | 42 +++++ .../lint/lint-invalid-ptr-to-int-cast.stderr | 163 ++++++++++++++++++ .../clippy_lints/src/transmute/utils.rs | 7 +- 8 files changed, 382 insertions(+), 41 deletions(-) create mode 100644 src/test/ui/lint/lint-invalid-ptr-to-int-cast.fixed create mode 100644 src/test/ui/lint/lint-invalid-ptr-to-int-cast.rs create mode 100644 src/test/ui/lint/lint-invalid-ptr-to-int-cast.stderr diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index b602490905c29..5a369a0f45cd2 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2876,6 +2876,46 @@ declare_lint! { }; } +declare_lint! { + /// The `invalid_ptr_to_int_cast` lint triggers if a pointer is cast to any integer type other + /// than `usize` or `u64`, since doing so is often a bug. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(invalid_ptr_to_int_cast)] + /// + /// fn main() { + /// let x = 100_000_000; + /// let y = u16::max as u32; // the user meant the constant `u16::MAX`, rather than the + /// // function `u16::max`, but this cast is technically permitted, + /// // so will not produce an error + /// println!("{}", x > y); // prints `false` (unexpectedly) + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The example above shows how a user might accidentally cast a function pointer (rather than + /// an integer constant) to an integer type other than `usize` or `u64`. Though this is + /// currently permitted by Rust, there is very little reason to cast a pointer to any integer + /// other than a `usize` or `u64`. Therefore, any instances of such casts are likely to be + /// bugs. + /// + /// This lint warns against those cases. + /// + /// In the future, we may want to make this a hard error. + /// + /// To cast a pointer to an integer type other than `usize` or `u64` without triggering the + /// lint, you can first cast to a `usize` and then to the integer type, e.g. `ptr as usize as + /// u32`. + pub INVALID_PTR_TO_INT_CAST, + Allow, + "detects pointers casts to integer types other than `usize` or `u64`", +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -2960,6 +3000,7 @@ declare_lint_pass! { LEGACY_DERIVE_HELPERS, PROC_MACRO_BACK_COMPAT, OR_PATTERNS_BACK_COMPAT, + INVALID_PTR_TO_INT_CAST, ] } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e352d0bc75697..0519f678150a3 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1946,6 +1946,11 @@ impl<'tcx> TyS<'tcx> { matches!(self.kind(), FnPtr(_)) } + #[inline] + pub fn is_raw_ptr(&self) -> bool { + matches!(self.kind(), RawPtr(_)) + } + #[inline] pub fn is_impl_trait(&self) -> bool { matches!(self.kind(), Opaque(..)) diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 16c344e8e2b9e..32ec3e2d8ba83 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -50,11 +50,16 @@ use rustc_trait_selection::traits::error_reporting::report_object_safety_error; /// Reifies a cast check to be checked once we have full type information for /// a function context. pub struct CastCheck<'tcx> { + /// The full expr: ` as ` + full_expr: &'tcx hir::Expr<'tcx>, + /// Expr being cast: `` in ` as `. expr: &'tcx hir::Expr<'tcx>, + /// Type of the expr being cast (`expr` field) expr_ty: Ty<'tcx>, + /// Target of the cast: `` in ` as ` cast_ty: Ty<'tcx>, + /// Span of `` in ` as ` cast_span: Span, - span: Span, } /// The kind of pointer and associated metadata (thin, length or vtable) - we @@ -191,13 +196,13 @@ fn make_invalid_casting_error<'a, 'tcx>( impl<'a, 'tcx> CastCheck<'tcx> { pub fn new( fcx: &FnCtxt<'a, 'tcx>, + full_expr: &'tcx hir::Expr<'tcx>, expr: &'tcx hir::Expr<'tcx>, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, cast_span: Span, - span: Span, ) -> Result, ErrorReported> { - let check = CastCheck { expr, expr_ty, cast_ty, cast_span, span }; + let check = CastCheck { full_expr, expr, expr_ty, cast_ty, cast_span }; // For better error messages, check for some obviously unsized // cases now. We do a more thorough check at the end, once @@ -217,10 +222,10 @@ impl<'a, 'tcx> CastCheck<'tcx> { // an error has already been reported } CastError::NeedDeref => { - let error_span = self.span; + let error_span = self.full_expr.span; let mut err = make_invalid_casting_error( fcx.tcx.sess, - self.span, + error_span, self.expr_ty, self.cast_ty, fcx, @@ -245,7 +250,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { CastError::NeedViaThinPtr | CastError::NeedViaPtr => { let mut err = make_invalid_casting_error( fcx.tcx.sess, - self.span, + self.full_expr.span, self.expr_ty, self.cast_ty, fcx, @@ -265,7 +270,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { CastError::NeedViaInt => { make_invalid_casting_error( fcx.tcx.sess, - self.span, + self.full_expr.span, self.expr_ty, self.cast_ty, fcx, @@ -282,7 +287,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { CastError::IllegalCast => { make_invalid_casting_error( fcx.tcx.sess, - self.span, + self.full_expr.span, self.expr_ty, self.cast_ty, fcx, @@ -292,7 +297,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { CastError::DifferingKinds => { make_invalid_casting_error( fcx.tcx.sess, - self.span, + self.full_expr.span, self.expr_ty, self.cast_ty, fcx, @@ -301,25 +306,29 @@ impl<'a, 'tcx> CastCheck<'tcx> { .emit(); } CastError::CastToBool => { - let mut err = - struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`"); + let mut err = struct_span_err!( + fcx.tcx.sess, + self.full_expr.span, + E0054, + "cannot cast as `bool`" + ); if self.expr_ty.is_numeric() { match fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { Ok(snippet) => { err.span_suggestion( - self.span, + self.full_expr.span, "compare with zero instead", format!("{} != 0", snippet), Applicability::MachineApplicable, ); } Err(_) => { - err.span_help(self.span, "compare with zero instead"); + err.span_help(self.full_expr.span, "compare with zero instead"); } } } else { - err.span_label(self.span, "unsupported cast"); + err.span_label(self.full_expr.span, "unsupported cast"); } err.emit(); @@ -327,19 +336,19 @@ impl<'a, 'tcx> CastCheck<'tcx> { CastError::CastToChar => { type_error_struct!( fcx.tcx.sess, - self.span, + self.full_expr.span, self.expr_ty, E0604, "only `u8` can be cast as `char`, not `{}`", self.expr_ty ) - .span_label(self.span, "invalid cast") + .span_label(self.full_expr.span, "invalid cast") .emit(); } CastError::NonScalar => { let mut err = type_error_struct!( fcx.tcx.sess, - self.span, + self.full_expr.span, self.expr_ty, E0605, "non-primitive cast: `{}` as `{}`", @@ -361,7 +370,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } } if let Some(sugg) = sugg { - err.span_label(self.span, "invalid cast"); + err.span_label(self.full_expr.span, "invalid cast"); err.span_suggestion_verbose( self.expr.span.shrink_to_lo(), "borrow the value for the cast to be valid", @@ -396,7 +405,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { { label = false; err.span_suggestion( - self.span, + self.full_expr.span, "consider using the `From` trait instead", format!("{}::from({})", self.cast_ty, snippet), Applicability::MaybeIncorrect, @@ -407,12 +416,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { let msg = "an `as` expression can only be used to convert between primitive \ types or to coerce to a specific trait object"; if label { - err.span_label(self.span, msg); + err.span_label(self.full_expr.span, msg); } else { err.note(msg); } } else { - err.span_label(self.span, "invalid cast"); + err.span_label(self.full_expr.span, "invalid cast"); } err.emit(); } @@ -421,7 +430,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { SizedUnsizedCast { sess: &fcx.tcx.sess, - span: self.span, + span: self.full_expr.span, expr_ty: self.expr_ty, cast_ty: fcx.ty_to_string(self.cast_ty), } @@ -436,7 +445,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { }; let mut err = struct_span_err!( fcx.tcx.sess, - if unknown_cast_to { self.cast_span } else { self.span }, + if unknown_cast_to { self.cast_span } else { self.full_expr.span }, E0641, "cannot cast {} a pointer of an unknown kind", if unknown_cast_to { "to" } else { "from" } @@ -449,7 +458,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { ); } else { err.span_label( - self.span, + self.full_expr.span, "the type information given here is insufficient to check whether \ the pointer cast is valid", ); @@ -467,7 +476,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { let tstr = fcx.ty_to_string(self.cast_ty); let mut err = type_error_struct!( fcx.tcx.sess, - self.span, + self.full_expr.span, self.expr_ty, E0620, "cast to unsized type: `{}` as `{}`", @@ -497,7 +506,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { "consider using an implicit coercion to `&{}{}` instead", mtstr, tstr ); - err.span_help(self.span, msg); + err.span_help(self.full_expr.span, msg); } } ty::Adt(def, ..) if def.is_box() => { @@ -535,7 +544,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } else { ("", lint::builtin::TRIVIAL_CASTS) }; - fcx.tcx.struct_span_lint_hir(lint, self.expr.hir_id, self.span, |err| { + fcx.tcx.struct_span_lint_hir(lint, self.expr.hir_id, self.full_expr.span, |err| { err.build(&format!( "trivial {}cast: `{}` as `{}`", adjective, @@ -551,13 +560,49 @@ impl<'a, 'tcx> CastCheck<'tcx> { }); } + /// invald-ptr-to-int-cast lint: when casting a pointer to a numeric type it only makes sense + /// to cast to `usize` or `u64`. Other cases are often bugs. See #81686 as an example. + fn invalid_ptr_to_int_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { + if self.expr_ty.is_fn() || self.expr_ty.is_raw_ptr() { + let cast_ty_kind = self.cast_ty.kind(); + let is_integral_cast = matches!(cast_ty_kind, ty::Int(_) | ty::Uint(_)); + if is_integral_cast + && !matches!(cast_ty_kind, ty::Uint(ty::UintTy::Usize | ty::UintTy::U64)) + { + fcx.tcx.struct_span_lint_hir( + lint::builtin::INVALID_PTR_TO_INT_CAST, + self.full_expr.hir_id, + self.full_expr.span, + |lint| { + let msg = format!("casting pointer to `{}`", self.cast_ty); + let mut lint = lint.build(&msg); + lint.help("pointers should only be cast to `usize` or `u64`"); + + if let Ok(e_snippet) = + fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) + { + lint.span_suggestion( + self.full_expr.span, + &format!("to cast to `{}`, cast to `usize` first", self.cast_ty), + format!("{} as usize as {}", e_snippet, self.cast_ty), + Applicability::MaybeIncorrect, + ); + } + + lint.emit(); + }, + ); + } + } + } + pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) { - self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); - self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); + self.expr_ty = fcx.structurally_resolved_type(self.full_expr.span, self.expr_ty); + self.cast_ty = fcx.structurally_resolved_type(self.full_expr.span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty); - if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span) { + if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.full_expr.span) { self.report_cast_to_unsized_type(fcx); } else if self.expr_ty.references_error() || self.cast_ty.references_error() { // No sense in giving duplicate error messages @@ -565,6 +610,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { match self.try_coercion_cast(fcx) { Ok(()) => { self.trivial_cast_lint(fcx); + self.invalid_ptr_to_int_cast_lint(fcx); debug!(" -> CoercionCast"); fcx.typeck_results.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id); } @@ -574,6 +620,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { Err(_) => { match self.do_check(fcx) { Ok(k) => { + self.invalid_ptr_to_int_cast_lint(fcx); debug!(" -> {:?}", k); } Err(e) => self.report_cast_error(fcx, e), @@ -698,8 +745,8 @@ impl<'a, 'tcx> CastCheck<'tcx> { debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast); // ptr-ptr cast. vtables must match. - let expr_kind = fcx.pointer_kind(m_expr.ty, self.span)?; - let cast_kind = fcx.pointer_kind(m_cast.ty, self.span)?; + let expr_kind = fcx.pointer_kind(m_expr.ty, self.full_expr.span)?; + let cast_kind = fcx.pointer_kind(m_cast.ty, self.full_expr.span)?; let cast_kind = match cast_kind { // We can't cast if target pointer kind is unknown @@ -738,7 +785,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { ) -> Result { // fptr-ptr cast. must be to thin ptr - match fcx.pointer_kind(m_cast.ty, self.span)? { + match fcx.pointer_kind(m_cast.ty, self.full_expr.span)? { None => Err(CastError::UnknownCastPtrKind), Some(PointerKind::Thin) => Ok(CastKind::FnPtrPtrCast), _ => Err(CastError::IllegalCast), @@ -752,7 +799,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { ) -> Result { // ptr-addr cast. must be from thin ptr - match fcx.pointer_kind(m_expr.ty, self.span)? { + match fcx.pointer_kind(m_expr.ty, self.full_expr.span)? { None => Err(CastError::UnknownExprPtrKind), Some(PointerKind::Thin) => Ok(CastKind::PtrAddrCast), _ => Err(CastError::NeedViaThinPtr), @@ -787,7 +834,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { }); // this will report a type mismatch if needed - fcx.demand_eqtype(self.span, ety, m_cast.ty); + fcx.demand_eqtype(self.full_expr.span, ety, m_cast.ty); return Ok(CastKind::ArrayPtrCast); } } @@ -801,7 +848,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { m_cast: TypeAndMut<'tcx>, ) -> Result { // ptr-addr cast. pointer must be thin. - match fcx.pointer_kind(m_cast.ty, self.span)? { + match fcx.pointer_kind(m_cast.ty, self.full_expr.span)? { None => Err(CastError::UnknownCastPtrKind), Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast), _ => Err(CastError::IllegalCast), @@ -821,7 +868,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { fcx.tcx.struct_span_lint_hir( lint::builtin::CENUM_IMPL_DROP_CAST, self.expr.hir_id, - self.span, + self.full_expr.span, |err| { err.build(&format!( "cannot cast enum `{}` into integer `{}` because it implements `Drop`", diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 30d60514063d9..c7842e53a2c38 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -995,7 +995,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Defer other checks until we're done type checking. let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { + match cast::CastCheck::new(self, expr, e, t_expr, t_cast, t.span) { Ok(cast_check) => { deferred_cast_checks.push(cast_check); t_cast diff --git a/src/test/ui/lint/lint-invalid-ptr-to-int-cast.fixed b/src/test/ui/lint/lint-invalid-ptr-to-int-cast.fixed new file mode 100644 index 0000000000000..06d84fdd94906 --- /dev/null +++ b/src/test/ui/lint/lint-invalid-ptr-to-int-cast.fixed @@ -0,0 +1,42 @@ +// check-pass +// run-rustfix +// compile-flags: -W invalid-ptr-to-int-cast + +fn main() { + // Motivation for this lint: user meant u16::MAX + let _ = u16::max as usize as u32; //~ casting pointer to `u32` [invalid_ptr_to_int_cast] + + // Pointer to int + let a: usize = 123; + let ptr: *const usize = &a as *const usize; + + let _ = ptr as usize as u8; //~ casting pointer to `u8` [invalid_ptr_to_int_cast] + let _ = ptr as usize as u16; //~ casting pointer to `u16` [invalid_ptr_to_int_cast] + let _ = ptr as usize as u32; //~ casting pointer to `u32` [invalid_ptr_to_int_cast] + let _ = ptr as u64; + let _ = ptr as usize as u128; //~ casting pointer to `u128` [invalid_ptr_to_int_cast] + let _ = ptr as usize as i8; //~ casting pointer to `i8` [invalid_ptr_to_int_cast] + let _ = ptr as usize as i16; //~ casting pointer to `i16` [invalid_ptr_to_int_cast] + let _ = ptr as usize as i32; //~ casting pointer to `i32` [invalid_ptr_to_int_cast] + let _ = ptr as usize as i64; //~ casting pointer to `i64` [invalid_ptr_to_int_cast] + let _ = ptr as usize as i128; //~ casting pointer to `i128` [invalid_ptr_to_int_cast] + let _ = ptr as usize; + + // Function to int + fn test() {} + + let _ = test as usize as u8; //~ casting pointer to `u8` [invalid_ptr_to_int_cast] + let _ = test as usize as u16; //~ casting pointer to `u16` [invalid_ptr_to_int_cast] + let _ = test as usize as u32; //~ casting pointer to `u32` [invalid_ptr_to_int_cast] + let _ = test as u64; + let _ = test as usize as u128; //~ casting pointer to `u128` [invalid_ptr_to_int_cast] + let _ = test as usize as i8; //~ casting pointer to `i8` [invalid_ptr_to_int_cast] + let _ = test as usize as i16; //~ casting pointer to `i16` [invalid_ptr_to_int_cast] + let _ = test as usize as i32; //~ casting pointer to `i32` [invalid_ptr_to_int_cast] + let _ = test as usize as i64; //~ casting pointer to `i64` [invalid_ptr_to_int_cast] + let _ = test as usize as i128; //~ casting pointer to `i128` [invalid_ptr_to_int_cast] + let _ = test as usize; + + // Make sure we handle delayed coercion cast checking + let _ = {({ test }) as usize as u16}; //~ casting pointer to `u16` [invalid_ptr_to_int_cast] +} diff --git a/src/test/ui/lint/lint-invalid-ptr-to-int-cast.rs b/src/test/ui/lint/lint-invalid-ptr-to-int-cast.rs new file mode 100644 index 0000000000000..0600c114bb777 --- /dev/null +++ b/src/test/ui/lint/lint-invalid-ptr-to-int-cast.rs @@ -0,0 +1,42 @@ +// check-pass +// run-rustfix +// compile-flags: -W invalid-ptr-to-int-cast + +fn main() { + // Motivation for this lint: user meant u16::MAX + let _ = u16::max as u32; //~ casting pointer to `u32` [invalid_ptr_to_int_cast] + + // Pointer to int + let a: usize = 123; + let ptr: *const usize = &a as *const usize; + + let _ = ptr as u8; //~ casting pointer to `u8` [invalid_ptr_to_int_cast] + let _ = ptr as u16; //~ casting pointer to `u16` [invalid_ptr_to_int_cast] + let _ = ptr as u32; //~ casting pointer to `u32` [invalid_ptr_to_int_cast] + let _ = ptr as u64; + let _ = ptr as u128; //~ casting pointer to `u128` [invalid_ptr_to_int_cast] + let _ = ptr as i8; //~ casting pointer to `i8` [invalid_ptr_to_int_cast] + let _ = ptr as i16; //~ casting pointer to `i16` [invalid_ptr_to_int_cast] + let _ = ptr as i32; //~ casting pointer to `i32` [invalid_ptr_to_int_cast] + let _ = ptr as i64; //~ casting pointer to `i64` [invalid_ptr_to_int_cast] + let _ = ptr as i128; //~ casting pointer to `i128` [invalid_ptr_to_int_cast] + let _ = ptr as usize; + + // Function to int + fn test() {} + + let _ = test as u8; //~ casting pointer to `u8` [invalid_ptr_to_int_cast] + let _ = test as u16; //~ casting pointer to `u16` [invalid_ptr_to_int_cast] + let _ = test as u32; //~ casting pointer to `u32` [invalid_ptr_to_int_cast] + let _ = test as u64; + let _ = test as u128; //~ casting pointer to `u128` [invalid_ptr_to_int_cast] + let _ = test as i8; //~ casting pointer to `i8` [invalid_ptr_to_int_cast] + let _ = test as i16; //~ casting pointer to `i16` [invalid_ptr_to_int_cast] + let _ = test as i32; //~ casting pointer to `i32` [invalid_ptr_to_int_cast] + let _ = test as i64; //~ casting pointer to `i64` [invalid_ptr_to_int_cast] + let _ = test as i128; //~ casting pointer to `i128` [invalid_ptr_to_int_cast] + let _ = test as usize; + + // Make sure we handle delayed coercion cast checking + let _ = {({ test }) as u16}; //~ casting pointer to `u16` [invalid_ptr_to_int_cast] +} diff --git a/src/test/ui/lint/lint-invalid-ptr-to-int-cast.stderr b/src/test/ui/lint/lint-invalid-ptr-to-int-cast.stderr new file mode 100644 index 0000000000000..84f0e5419c0c6 --- /dev/null +++ b/src/test/ui/lint/lint-invalid-ptr-to-int-cast.stderr @@ -0,0 +1,163 @@ +warning: casting pointer to `u32` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:7:13 + | +LL | let _ = u16::max as u32; + | ^^^^^^^^^^^^^^^ help: to cast to `u32`, cast to `usize` first: `u16::max as usize as u32` + | + = note: requested on the command line with `-W invalid-ptr-to-int-cast` + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `u8` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:13:13 + | +LL | let _ = ptr as u8; + | ^^^^^^^^^ help: to cast to `u8`, cast to `usize` first: `ptr as usize as u8` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `u16` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:14:13 + | +LL | let _ = ptr as u16; + | ^^^^^^^^^^ help: to cast to `u16`, cast to `usize` first: `ptr as usize as u16` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `u32` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:15:13 + | +LL | let _ = ptr as u32; + | ^^^^^^^^^^ help: to cast to `u32`, cast to `usize` first: `ptr as usize as u32` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `u128` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:17:13 + | +LL | let _ = ptr as u128; + | ^^^^^^^^^^^ help: to cast to `u128`, cast to `usize` first: `ptr as usize as u128` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `i8` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:18:13 + | +LL | let _ = ptr as i8; + | ^^^^^^^^^ help: to cast to `i8`, cast to `usize` first: `ptr as usize as i8` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `i16` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:19:13 + | +LL | let _ = ptr as i16; + | ^^^^^^^^^^ help: to cast to `i16`, cast to `usize` first: `ptr as usize as i16` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `i32` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:20:13 + | +LL | let _ = ptr as i32; + | ^^^^^^^^^^ help: to cast to `i32`, cast to `usize` first: `ptr as usize as i32` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `i64` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:21:13 + | +LL | let _ = ptr as i64; + | ^^^^^^^^^^ help: to cast to `i64`, cast to `usize` first: `ptr as usize as i64` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `i128` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:22:13 + | +LL | let _ = ptr as i128; + | ^^^^^^^^^^^ help: to cast to `i128`, cast to `usize` first: `ptr as usize as i128` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `u8` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:28:13 + | +LL | let _ = test as u8; + | ^^^^^^^^^^ help: to cast to `u8`, cast to `usize` first: `test as usize as u8` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `u16` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:29:13 + | +LL | let _ = test as u16; + | ^^^^^^^^^^^ help: to cast to `u16`, cast to `usize` first: `test as usize as u16` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `u32` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:30:13 + | +LL | let _ = test as u32; + | ^^^^^^^^^^^ help: to cast to `u32`, cast to `usize` first: `test as usize as u32` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `u128` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:32:13 + | +LL | let _ = test as u128; + | ^^^^^^^^^^^^ help: to cast to `u128`, cast to `usize` first: `test as usize as u128` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `i8` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:33:13 + | +LL | let _ = test as i8; + | ^^^^^^^^^^ help: to cast to `i8`, cast to `usize` first: `test as usize as i8` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `i16` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:34:13 + | +LL | let _ = test as i16; + | ^^^^^^^^^^^ help: to cast to `i16`, cast to `usize` first: `test as usize as i16` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `i32` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:35:13 + | +LL | let _ = test as i32; + | ^^^^^^^^^^^ help: to cast to `i32`, cast to `usize` first: `test as usize as i32` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `i64` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:36:13 + | +LL | let _ = test as i64; + | ^^^^^^^^^^^ help: to cast to `i64`, cast to `usize` first: `test as usize as i64` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `i128` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:37:13 + | +LL | let _ = test as i128; + | ^^^^^^^^^^^^ help: to cast to `i128`, cast to `usize` first: `test as usize as i128` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: casting pointer to `u16` + --> $DIR/lint-invalid-ptr-to-int-cast.rs:41:14 + | +LL | let _ = {({ test }) as u16}; + | ^^^^^^^^^^^^^^^^^ help: to cast to `u16`, cast to `usize` first: `({ test }) as usize as u16` + | + = help: pointers should only be cast to `usize` or `u64` + +warning: 20 warnings emitted + diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs index c6d0d63b0b542..b9a80719339bb 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs @@ -84,9 +84,10 @@ fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx> ); if let Ok(check) = CastCheck::new( - &fn_ctxt, e, from_ty, to_ty, - // We won't show any error to the user, so we don't care what the span is here. - DUMMY_SP, DUMMY_SP, + // We won't show any error to the user, so we don't care about the span and expressions + // here + &fn_ctxt, e, e, from_ty, to_ty, + DUMMY_SP, ) { let res = check.do_check(&fn_ctxt); From 81df07d7d882b54a9ef2743709261889f64ca911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Sat, 3 Apr 2021 12:06:30 +0300 Subject: [PATCH 2/2] Make it deny by default, for testing --- compiler/rustc_lint_defs/src/builtin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 5a369a0f45cd2..355b7f5ac314b 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2912,7 +2912,7 @@ declare_lint! { /// lint, you can first cast to a `usize` and then to the integer type, e.g. `ptr as usize as /// u32`. pub INVALID_PTR_TO_INT_CAST, - Allow, + Deny, "detects pointers casts to integer types other than `usize` or `u64`", }