11use clippy_utils:: diagnostics:: span_lint;
2- use clippy_utils:: is_hir_ty_cfg_dependant;
32use clippy_utils:: ty:: is_c_void;
4- use if_chain :: if_chain ;
3+ use clippy_utils :: { get_parent_expr , is_hir_ty_cfg_dependant , match_any_def_paths , paths } ;
54use rustc_hir:: { Expr , ExprKind , GenericArg } ;
65use rustc_lint:: LateContext ;
76use rustc_middle:: ty:: layout:: LayoutOf ;
@@ -20,45 +19,78 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
2019 ) ;
2120 lint_cast_ptr_alignment ( cx, expr, cast_from, cast_to) ;
2221 } else if let ExprKind :: MethodCall ( method_path, [ self_arg, ..] , _) = & expr. kind {
23- if_chain ! {
24- if method_path. ident. name == sym!( cast) ;
25- if let Some ( generic_args) = method_path. args;
26- if let [ GenericArg :: Type ( cast_to) ] = generic_args. args;
22+ if method_path. ident . name == sym ! ( cast)
23+ && let Some ( generic_args) = method_path. args
24+ && let [ GenericArg :: Type ( cast_to) ] = generic_args. args
2725 // There probably is no obvious reason to do this, just to be consistent with `as` cases.
28- if !is_hir_ty_cfg_dependant( cx, cast_to) ;
29- then {
30- let ( cast_from, cast_to) =
31- ( cx. typeck_results( ) . expr_ty( self_arg) , cx. typeck_results( ) . expr_ty( expr) ) ;
32- lint_cast_ptr_alignment( cx, expr, cast_from, cast_to) ;
33- }
26+ && !is_hir_ty_cfg_dependant ( cx, cast_to)
27+ {
28+ let ( cast_from, cast_to) =
29+ ( cx. typeck_results ( ) . expr_ty ( self_arg) , cx. typeck_results ( ) . expr_ty ( expr) ) ;
30+ lint_cast_ptr_alignment ( cx, expr, cast_from, cast_to) ;
3431 }
3532 }
3633}
3734
3835fn lint_cast_ptr_alignment < ' tcx > ( cx : & LateContext < ' tcx > , expr : & Expr < ' _ > , cast_from : Ty < ' tcx > , cast_to : Ty < ' tcx > ) {
39- if_chain ! {
40- if let ty:: RawPtr ( from_ptr_ty) = & cast_from. kind( ) ;
41- if let ty:: RawPtr ( to_ptr_ty) = & cast_to. kind( ) ;
42- if let Ok ( from_layout) = cx. layout_of( from_ptr_ty. ty) ;
43- if let Ok ( to_layout) = cx. layout_of( to_ptr_ty. ty) ;
44- if from_layout. align. abi < to_layout. align. abi;
36+ if let ty:: RawPtr ( from_ptr_ty) = & cast_from. kind ( )
37+ && let ty:: RawPtr ( to_ptr_ty) = & cast_to. kind ( )
38+ && let Ok ( from_layout) = cx. layout_of ( from_ptr_ty. ty )
39+ && let Ok ( to_layout) = cx. layout_of ( to_ptr_ty. ty )
40+ && from_layout. align . abi < to_layout. align . abi
4541 // with c_void, we inherently need to trust the user
46- if !is_c_void( cx, from_ptr_ty. ty) ;
42+ && !is_c_void ( cx, from_ptr_ty. ty )
4743 // when casting from a ZST, we don't know enough to properly lint
48- if !from_layout. is_zst( ) ;
49- then {
50- span_lint(
51- cx,
52- CAST_PTR_ALIGNMENT ,
53- expr. span,
54- & format!(
55- "casting from `{}` to a more-strictly-aligned pointer (`{}`) ({} < {} bytes)" ,
56- cast_from,
57- cast_to,
58- from_layout. align. abi. bytes( ) ,
59- to_layout. align. abi. bytes( ) ,
60- ) ,
61- ) ;
62- }
44+ && !from_layout. is_zst ( )
45+ && !is_used_as_unaligned ( cx, expr)
46+ {
47+ span_lint (
48+ cx,
49+ CAST_PTR_ALIGNMENT ,
50+ expr. span ,
51+ & format ! (
52+ "casting from `{}` to a more-strictly-aligned pointer (`{}`) ({} < {} bytes)" ,
53+ cast_from,
54+ cast_to,
55+ from_layout. align. abi. bytes( ) ,
56+ to_layout. align. abi. bytes( ) ,
57+ ) ,
58+ ) ;
59+ }
60+ }
61+
62+ fn is_used_as_unaligned ( cx : & LateContext < ' _ > , e : & Expr < ' _ > ) -> bool {
63+ let Some ( parent) = get_parent_expr ( cx, e) else {
64+ return false ;
65+ } ;
66+ match parent. kind {
67+ ExprKind :: MethodCall ( name, [ self_arg, ..] , _) if self_arg. hir_id == e. hir_id => {
68+ if matches ! ( name. ident. as_str( ) , "read_unaligned" | "write_unaligned" )
69+ && let Some ( def_id) = cx. typeck_results ( ) . type_dependent_def_id ( parent. hir_id )
70+ && let Some ( def_id) = cx. tcx . impl_of_method ( def_id)
71+ && cx. tcx . type_of ( def_id) . is_unsafe_ptr ( )
72+ {
73+ true
74+ } else {
75+ false
76+ }
77+ } ,
78+ ExprKind :: Call ( func, [ arg, ..] ) if arg. hir_id == e. hir_id => {
79+ static PATHS : & [ & [ & str ] ] = & [
80+ paths:: PTR_READ_UNALIGNED . as_slice ( ) ,
81+ paths:: PTR_WRITE_UNALIGNED . as_slice ( ) ,
82+ paths:: PTR_UNALIGNED_VOLATILE_LOAD . as_slice ( ) ,
83+ paths:: PTR_UNALIGNED_VOLATILE_STORE . as_slice ( ) ,
84+ ] ;
85+ if let ExprKind :: Path ( path) = & func. kind
86+ && let Some ( def_id) = cx. qpath_res ( path, func. hir_id ) . opt_def_id ( )
87+ && match_any_def_paths ( cx, def_id, PATHS ) . is_some ( )
88+ {
89+ true
90+ } else {
91+ false
92+ }
93+ } ,
94+ _ => false ,
6395 }
6496}
0 commit comments