1- use clippy_utils:: diagnostics:: span_lint;
1+ use clippy_utils:: diagnostics:: { span_lint, span_lint_and_then } ;
22use clippy_utils:: ty:: is_c_void;
33use clippy_utils:: { get_parent_expr, is_hir_ty_cfg_dependant, sym} ;
4+ use rustc_abi:: Align ;
45use rustc_hir:: { Expr , ExprKind , GenericArg } ;
56use rustc_lint:: LateContext ;
6- use rustc_middle:: ty:: layout:: LayoutOf ;
7+ use rustc_middle:: ty:: layout:: { LayoutError , LayoutOf } ;
78use rustc_middle:: ty:: { self , Ty } ;
89
910use super :: CAST_PTR_ALIGNMENT ;
@@ -29,24 +30,50 @@ fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_f
2930 if let ty:: RawPtr ( from_ptr_ty, _) = * cast_from. kind ( )
3031 && let ty:: RawPtr ( to_ptr_ty, _) = * cast_to. kind ( )
3132 && let Ok ( from_layout) = cx. layout_of ( from_ptr_ty)
32- && let Ok ( to_layout) = cx. layout_of ( to_ptr_ty)
33- && from_layout. align . abi < to_layout. align . abi
3433 // with c_void, we inherently need to trust the user
3534 && !is_c_void ( cx, from_ptr_ty)
3635 // when casting from a ZST, we don't know enough to properly lint
3736 && !from_layout. is_zst ( )
3837 && !is_used_as_unaligned ( cx, expr)
3938 {
40- span_lint (
41- cx,
42- CAST_PTR_ALIGNMENT ,
43- expr. span ,
44- format ! (
45- "casting from `{cast_from}` to a more-strictly-aligned pointer (`{cast_to}`) ({} < {} bytes)" ,
46- from_layout. align. bytes( ) ,
47- to_layout. align. bytes( ) ,
48- ) ,
49- ) ;
39+ // When the to-type has a lower alignment, it's always properly aligned when cast. Only when the
40+ // to-type has a higher alignment can it not be properly aligned (16 -> 32, 48 is not a multiple of
41+ // 32!)
42+ match cx. layout_of ( to_ptr_ty) {
43+ Ok ( to_layout) => {
44+ if from_layout. align . abi < to_layout. align . abi {
45+ span_lint (
46+ cx,
47+ CAST_PTR_ALIGNMENT ,
48+ expr. span ,
49+ format ! (
50+ "casting from `{cast_from}` to a more-strictly-aligned pointer (`{cast_to}`) ({} < {} bytes)" ,
51+ from_layout. align. bytes( ) ,
52+ to_layout. align. bytes( ) ,
53+ ) ,
54+ ) ;
55+ }
56+ } ,
57+ Err ( LayoutError :: TooGeneric ( too_generic_ty) ) => {
58+ // With the maximum possible alignment, there is no "higher alignment" case.
59+ if from_layout. align . abi != Align :: MAX {
60+ span_lint_and_then (
61+ cx,
62+ CAST_PTR_ALIGNMENT ,
63+ expr. span ,
64+ format ! ( "casting from `{cast_from}` to a possibly more-strictly-aligned pointer (`{cast_to}`)" ) ,
65+ |diag| {
66+ if too_generic_ty == to_ptr_ty {
67+ diag. note ( format ! ( "the alignment of `{too_generic_ty}` can vary" ) ) ;
68+ } else {
69+ diag. note ( format ! ( "the alignment of the target pointer isn't known because the alignment of `{too_generic_ty}` can vary" ) ) ;
70+ }
71+ } ,
72+ ) ;
73+ }
74+ } ,
75+ _ => { } ,
76+ }
5077 }
5178}
5279
0 commit comments