Skip to content

Commit 3d18841

Browse files
committed
feat(cast_ptr_alignment): also lint to-types with unknown alignment
1 parent 505a44a commit 3d18841

File tree

4 files changed

+82
-20
lines changed

4 files changed

+82
-20
lines changed

clippy_lints/src/casts/cast_ptr_alignment.rs

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
use clippy_utils::diagnostics::span_lint;
1+
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
22
use clippy_utils::ty::is_c_void;
33
use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, sym};
4+
use rustc_abi::Align;
45
use rustc_hir::{Expr, ExprKind, GenericArg};
56
use rustc_lint::LateContext;
6-
use rustc_middle::ty::layout::LayoutOf;
7+
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
78
use rustc_middle::ty::{self, Ty};
89

910
use 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

clippy_lints/src/casts/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ declare_clippy_lint! {
222222
declare_clippy_lint! {
223223
/// ### What it does
224224
/// Checks for casts, using `as` or `pointer::cast`, from a
225-
/// less strictly aligned pointer to a more strictly aligned pointer.
225+
/// less strictly aligned pointer to a (possibly) more strictly aligned pointer.
226226
///
227227
/// ### Why is this bad?
228228
/// Dereferencing the resulting pointer may be undefined behavior.

tests/ui/cast_ptr_alignment.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
//@require-annotations-for-level: ERROR
12
#![feature(core_intrinsics)]
23
#![warn(clippy::cast_ptr_alignment)]
34
#![expect(clippy::no_effect, clippy::cast_lossless, clippy::borrow_as_ptr)]
@@ -52,3 +53,21 @@ fn issue_2881() {
5253
core::intrinsics::unaligned_volatile_store(ptr as *mut u16, 0);
5354
}
5455
}
56+
57+
fn issue_3440() {
58+
#[rustfmt::skip] // the error message comment gets split in 2 lines...
59+
trait Trait {
60+
unsafe fn frob(bytes: *const u8) -> *const Self
61+
where
62+
Self: Sized,
63+
{
64+
let _ = bytes as *const [Self; 2];
65+
//~^ ERROR: casting from `*const u8` to a possibly more-strictly-aligned pointer (`*const [Self; 2]`)
66+
//~| NOTE: the alignment of the target pointer isn't known because the alignment of `Self` can vary
67+
68+
bytes as *const Self
69+
//~^ ERROR: casting from `*const u8` to a possibly more-strictly-aligned pointer (`*const Self`)
70+
//~| NOTE: the alignment of `Self` can vary
71+
}
72+
}
73+
}

tests/ui/cast_ptr_alignment.stderr

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: casting from `*const u8` to a more-strictly-aligned pointer (`*const u16`) (1 < 2 bytes)
2-
--> tests/ui/cast_ptr_alignment.rs:9:5
2+
--> tests/ui/cast_ptr_alignment.rs:10:5
33
|
44
LL | (&1u8 as *const u8) as *const u16;
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,22 +8,38 @@ LL | (&1u8 as *const u8) as *const u16;
88
= help: to override `-D warnings` add `#[allow(clippy::cast_ptr_alignment)]`
99

1010
error: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`) (1 < 2 bytes)
11-
--> tests/ui/cast_ptr_alignment.rs:12:5
11+
--> tests/ui/cast_ptr_alignment.rs:13:5
1212
|
1313
LL | (&mut 1u8 as *mut u8) as *mut u16;
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1515

1616
error: casting from `*const u8` to a more-strictly-aligned pointer (`*const u16`) (1 < 2 bytes)
17-
--> tests/ui/cast_ptr_alignment.rs:16:5
17+
--> tests/ui/cast_ptr_alignment.rs:17:5
1818
|
1919
LL | (&1u8 as *const u8).cast::<u16>();
2020
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2121

2222
error: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`) (1 < 2 bytes)
23-
--> tests/ui/cast_ptr_alignment.rs:19:5
23+
--> tests/ui/cast_ptr_alignment.rs:20:5
2424
|
2525
LL | (&mut 1u8 as *mut u8).cast::<u16>();
2626
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2727

28-
error: aborting due to 4 previous errors
28+
error: casting from `*const u8` to a possibly more-strictly-aligned pointer (`*const [Self; 2]`)
29+
--> tests/ui/cast_ptr_alignment.rs:64:21
30+
|
31+
LL | let _ = bytes as *const [Self; 2];
32+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
33+
|
34+
= note: the alignment of the target pointer isn't known because the alignment of `Self` can vary
35+
36+
error: casting from `*const u8` to a possibly more-strictly-aligned pointer (`*const Self`)
37+
--> tests/ui/cast_ptr_alignment.rs:68:13
38+
|
39+
LL | bytes as *const Self
40+
| ^^^^^^^^^^^^^^^^^^^^
41+
|
42+
= note: the alignment of `Self` can vary
43+
44+
error: aborting due to 6 previous errors
2945

0 commit comments

Comments
 (0)