Skip to content

Commit cc41030

Browse files
committed
Auto merge of #83605 - RalfJung:unaligned, r=petrochenkov
unaligned_references: align(N) fields in packed(N) structs are fine This removes some false positives from the unaligned_references lint: in a `repr(packed(2))` struct, fields of alignment 2 (and less) are guaranteed to be properly aligned, so we do not have to consider them "disaligned".
2 parents cb0e0db + 1ab05c1 commit cc41030

7 files changed

+87
-34
lines changed

compiler/rustc_mir/src/util/alignment.rs

+24-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use rustc_middle::mir::*;
22
use rustc_middle::ty::{self, TyCtxt};
3+
use rustc_target::abi::Align;
34

45
/// Returns `true` if this place is allowed to be less aligned
56
/// than its containing struct (because it is within a packed
@@ -14,17 +15,25 @@ where
1415
L: HasLocalDecls<'tcx>,
1516
{
1617
debug!("is_disaligned({:?})", place);
17-
if !is_within_packed(tcx, local_decls, place) {
18-
debug!("is_disaligned({:?}) - not within packed", place);
19-
return false;
20-
}
18+
let pack = match is_within_packed(tcx, local_decls, place) {
19+
None => {
20+
debug!("is_disaligned({:?}) - not within packed", place);
21+
return false;
22+
}
23+
Some(pack) => pack,
24+
};
2125

2226
let ty = place.ty(local_decls, tcx).ty;
2327
match tcx.layout_raw(param_env.and(ty)) {
24-
Ok(layout) if layout.align.abi.bytes() == 1 => {
25-
// if the alignment is 1, the type can't be further
26-
// disaligned.
27-
debug!("is_disaligned({:?}) - align = 1", place);
28+
Ok(layout) if layout.align.abi <= pack => {
29+
// If the packed alignment is greater or equal to the field alignment, the type won't be
30+
// further disaligned.
31+
debug!(
32+
"is_disaligned({:?}) - align = {}, packed = {}; not disaligned",
33+
place,
34+
layout.align.abi.bytes(),
35+
pack.bytes()
36+
);
2837
false
2938
}
3039
_ => {
@@ -34,7 +43,11 @@ where
3443
}
3544
}
3645

37-
fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: Place<'tcx>) -> bool
46+
fn is_within_packed<'tcx, L>(
47+
tcx: TyCtxt<'tcx>,
48+
local_decls: &L,
49+
place: Place<'tcx>,
50+
) -> Option<Align>
3851
where
3952
L: HasLocalDecls<'tcx>,
4053
{
@@ -45,13 +58,13 @@ where
4558
ProjectionElem::Field(..) => {
4659
let ty = place_base.ty(local_decls, tcx).ty;
4760
match ty.kind() {
48-
ty::Adt(def, _) if def.repr.packed() => return true,
61+
ty::Adt(def, _) => return def.repr.pack,
4962
_ => {}
5063
}
5164
}
5265
_ => {}
5366
}
5467
}
5568

56-
false
69+
None
5770
}

src/test/ui/lint/unaligned_references.rs

+15
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ pub struct Good {
88
aligned: [u8; 32],
99
}
1010

11+
#[repr(packed(2))]
12+
pub struct Packed2 {
13+
x: u32,
14+
y: u16,
15+
z: u8,
16+
}
17+
1118
fn main() {
1219
unsafe {
1320
let good = Good { data: 0, ptr: &0, data2: [0, 0], aligned: [0; 32] };
@@ -32,4 +39,12 @@ fn main() {
3239
let _ = &good.aligned; // ok, has align 1
3340
let _ = &good.aligned[2]; // ok, has align 1
3441
}
42+
43+
unsafe {
44+
let packed2 = Packed2 { x: 0, y: 0, z: 0 };
45+
let _ = &packed2.x; //~ ERROR reference to packed field
46+
//~^ previously accepted
47+
let _ = &packed2.y; // ok, has align 2 in packed(2) struct
48+
let _ = &packed2.z; // ok, has align 1
49+
}
3550
}

src/test/ui/lint/unaligned_references.stderr

+17-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: reference to packed field is unaligned
2-
--> $DIR/unaligned_references.rs:15:17
2+
--> $DIR/unaligned_references.rs:22:17
33
|
44
LL | let _ = &good.ptr;
55
| ^^^^^^^^^
@@ -14,7 +14,7 @@ LL | #![deny(unaligned_references)]
1414
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
1515

1616
error: reference to packed field is unaligned
17-
--> $DIR/unaligned_references.rs:17:17
17+
--> $DIR/unaligned_references.rs:24:17
1818
|
1919
LL | let _ = &good.data;
2020
| ^^^^^^^^^^
@@ -24,7 +24,7 @@ LL | let _ = &good.data;
2424
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
2525

2626
error: reference to packed field is unaligned
27-
--> $DIR/unaligned_references.rs:20:17
27+
--> $DIR/unaligned_references.rs:27:17
2828
|
2929
LL | let _ = &good.data as *const _;
3030
| ^^^^^^^^^^
@@ -34,7 +34,7 @@ LL | let _ = &good.data as *const _;
3434
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
3535

3636
error: reference to packed field is unaligned
37-
--> $DIR/unaligned_references.rs:22:27
37+
--> $DIR/unaligned_references.rs:29:27
3838
|
3939
LL | let _: *const _ = &good.data;
4040
| ^^^^^^^^^^
@@ -44,7 +44,7 @@ LL | let _: *const _ = &good.data;
4444
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
4545

4646
error: reference to packed field is unaligned
47-
--> $DIR/unaligned_references.rs:25:17
47+
--> $DIR/unaligned_references.rs:32:17
4848
|
4949
LL | let _ = good.data.clone();
5050
| ^^^^^^^^^
@@ -54,7 +54,7 @@ LL | let _ = good.data.clone();
5454
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
5555

5656
error: reference to packed field is unaligned
57-
--> $DIR/unaligned_references.rs:28:17
57+
--> $DIR/unaligned_references.rs:35:17
5858
|
5959
LL | let _ = &good.data2[0];
6060
| ^^^^^^^^^^^^^^
@@ -63,5 +63,15 @@ LL | let _ = &good.data2[0];
6363
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
6464
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
6565

66-
error: aborting due to 6 previous errors
66+
error: reference to packed field is unaligned
67+
--> $DIR/unaligned_references.rs:45:17
68+
|
69+
LL | let _ = &packed2.x;
70+
| ^^^^^^^^^^
71+
|
72+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
73+
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
74+
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
75+
76+
error: aborting due to 7 previous errors
6777

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// run-pass (note: this is spec-UB, but it works for now)
2+
// ignore-32bit (needs `usize` to be 8-aligned to reproduce all the errors below)
3+
#![allow(dead_code)]
4+
// ignore-emscripten weird assertion?
5+
6+
#[repr(C, packed(4))]
7+
struct Foo4C {
8+
bar: u8,
9+
baz: usize
10+
}
11+
12+
pub fn main() {
13+
let foo = Foo4C { bar: 1, baz: 2 };
14+
let brw = &foo.baz; //~WARN reference to packed field is unaligned
15+
//~^ previously accepted
16+
assert_eq!(*brw, 2);
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
warning: reference to packed field is unaligned
2+
--> $DIR/packed-struct-borrow-element-64bit.rs:14:15
3+
|
4+
LL | let brw = &foo.baz;
5+
| ^^^^^^^^
6+
|
7+
= note: `#[warn(unaligned_references)]` on by default
8+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
9+
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
10+
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
11+
12+
warning: 1 warning emitted
13+

src/test/ui/packed/packed-struct-borrow-element.rs

-5
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,4 @@ pub fn main() {
3030
let brw = &foo.baz; //~WARN reference to packed field is unaligned
3131
//~^ previously accepted
3232
assert_eq!(*brw, 2);
33-
34-
let foo = Foo4C { bar: 1, baz: 2 };
35-
let brw = &foo.baz; //~WARN reference to packed field is unaligned
36-
//~^ previously accepted
37-
assert_eq!(*brw, 2);
3833
}

src/test/ui/packed/packed-struct-borrow-element.stderr

+1-11
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,5 @@ LL | let brw = &foo.baz;
1919
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
2020
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
2121

22-
warning: reference to packed field is unaligned
23-
--> $DIR/packed-struct-borrow-element.rs:35:15
24-
|
25-
LL | let brw = &foo.baz;
26-
| ^^^^^^^^
27-
|
28-
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
29-
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
30-
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
31-
32-
warning: 3 warnings emitted
22+
warning: 2 warnings emitted
3323

0 commit comments

Comments
 (0)