1
1
use clippy_utils:: diagnostics:: span_lint;
2
- use clippy_utils:: is_hir_ty_cfg_dependant;
3
2
use 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 } ;
5
4
use rustc_hir:: { Expr , ExprKind , GenericArg } ;
6
5
use rustc_lint:: LateContext ;
7
6
use rustc_middle:: ty:: layout:: LayoutOf ;
@@ -20,45 +19,78 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
20
19
) ;
21
20
lint_cast_ptr_alignment ( cx, expr, cast_from, cast_to) ;
22
21
} 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
27
25
// 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) ;
34
31
}
35
32
}
36
33
}
37
34
38
35
fn 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
45
41
// 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 )
47
43
// 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 ,
63
95
}
64
96
}
0 commit comments