@@ -3,6 +3,7 @@ mod cast_possible_truncation;
33mod cast_possible_wrap;
44mod cast_precision_loss;
55mod cast_ptr_alignment;
6+ mod cast_ref_to_mut;
67mod cast_sign_loss;
78mod fn_to_numeric_cast;
89mod fn_to_numeric_cast_with_truncation;
@@ -14,7 +15,7 @@ use std::borrow::Cow;
1415use if_chain:: if_chain;
1516use rustc_ast:: LitKind ;
1617use rustc_errors:: Applicability ;
17- use rustc_hir:: { Expr , ExprKind , MutTy , Mutability , TyKind , UnOp } ;
18+ use rustc_hir:: { Expr , ExprKind , Mutability , TyKind } ;
1819use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
1920use rustc_middle:: lint:: in_external_macro;
2021use rustc_middle:: ty:: { self , TypeAndMut , UintTy } ;
@@ -23,7 +24,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
2324
2425use crate :: utils:: sugg:: Sugg ;
2526use crate :: utils:: {
26- is_hir_ty_cfg_dependant, meets_msrv, snippet_with_applicability, span_lint , span_lint_and_sugg, span_lint_and_then,
27+ is_hir_ty_cfg_dependant, meets_msrv, snippet_with_applicability, span_lint_and_sugg, span_lint_and_then,
2728} ;
2829
2930declare_clippy_lint ! {
@@ -255,12 +256,47 @@ declare_clippy_lint! {
255256 "casting a function pointer to a numeric type not wide enough to store the address"
256257}
257258
259+ declare_clippy_lint ! {
260+ /// **What it does:** Checks for casts of `&T` to `&mut T` anywhere in the code.
261+ ///
262+ /// **Why is this bad?** It’s basically guaranteed to be undefined behaviour.
263+ /// `UnsafeCell` is the only way to obtain aliasable data that is considered
264+ /// mutable.
265+ ///
266+ /// **Known problems:** None.
267+ ///
268+ /// **Example:**
269+ /// ```rust,ignore
270+ /// fn x(r: &i32) {
271+ /// unsafe {
272+ /// *(r as *const _ as *mut _) += 1;
273+ /// }
274+ /// }
275+ /// ```
276+ ///
277+ /// Instead consider using interior mutability types.
278+ ///
279+ /// ```rust
280+ /// use std::cell::UnsafeCell;
281+ ///
282+ /// fn x(r: &UnsafeCell<i32>) {
283+ /// unsafe {
284+ /// *r.get() += 1;
285+ /// }
286+ /// }
287+ /// ```
288+ pub CAST_REF_TO_MUT ,
289+ correctness,
290+ "a cast of reference to a mutable pointer"
291+ }
292+
258293declare_lint_pass ! ( Casts => [
259294 CAST_PRECISION_LOSS ,
260295 CAST_SIGN_LOSS ,
261296 CAST_POSSIBLE_TRUNCATION ,
262297 CAST_POSSIBLE_WRAP ,
263298 CAST_LOSSLESS ,
299+ CAST_REF_TO_MUT ,
264300 UNNECESSARY_CAST ,
265301 CAST_PTR_ALIGNMENT ,
266302 FN_TO_NUMERIC_CAST ,
@@ -269,6 +305,8 @@ declare_lint_pass!(Casts => [
269305
270306impl < ' tcx > LateLintPass < ' tcx > for Casts {
271307 fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
308+ cast_ref_to_mut:: check ( cx, expr) ;
309+
272310 if expr. span . from_expansion ( ) {
273311 return ;
274312 }
@@ -300,63 +338,6 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
300338 }
301339}
302340
303- declare_clippy_lint ! {
304- /// **What it does:** Checks for casts of `&T` to `&mut T` anywhere in the code.
305- ///
306- /// **Why is this bad?** It’s basically guaranteed to be undefined behaviour.
307- /// `UnsafeCell` is the only way to obtain aliasable data that is considered
308- /// mutable.
309- ///
310- /// **Known problems:** None.
311- ///
312- /// **Example:**
313- /// ```rust,ignore
314- /// fn x(r: &i32) {
315- /// unsafe {
316- /// *(r as *const _ as *mut _) += 1;
317- /// }
318- /// }
319- /// ```
320- ///
321- /// Instead consider using interior mutability types.
322- ///
323- /// ```rust
324- /// use std::cell::UnsafeCell;
325- ///
326- /// fn x(r: &UnsafeCell<i32>) {
327- /// unsafe {
328- /// *r.get() += 1;
329- /// }
330- /// }
331- /// ```
332- pub CAST_REF_TO_MUT ,
333- correctness,
334- "a cast of reference to a mutable pointer"
335- }
336-
337- declare_lint_pass ! ( RefToMut => [ CAST_REF_TO_MUT ] ) ;
338-
339- impl < ' tcx > LateLintPass < ' tcx > for RefToMut {
340- fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' _ > ) {
341- if_chain ! {
342- if let ExprKind :: Unary ( UnOp :: Deref , e) = & expr. kind;
343- if let ExprKind :: Cast ( e, t) = & e. kind;
344- if let TyKind :: Ptr ( MutTy { mutbl: Mutability :: Mut , .. } ) = t. kind;
345- if let ExprKind :: Cast ( e, t) = & e. kind;
346- if let TyKind :: Ptr ( MutTy { mutbl: Mutability :: Not , .. } ) = t. kind;
347- if let ty:: Ref ( ..) = cx. typeck_results( ) . node_type( e. hir_id) . kind( ) ;
348- then {
349- span_lint(
350- cx,
351- CAST_REF_TO_MUT ,
352- expr. span,
353- "casting `&T` to `&mut T` may cause undefined behavior, consider instead using an `UnsafeCell`" ,
354- ) ;
355- }
356- }
357- }
358- }
359-
360341const PTR_AS_PTR_MSRV : RustcVersion = RustcVersion :: new ( 1 , 38 , 0 ) ;
361342
362343declare_clippy_lint ! {
0 commit comments