Skip to content

Commit ad7045e

Browse files
committed
still accept references to u8 slices and str in packed fields
1 parent 8b3435c commit ad7045e

File tree

3 files changed

+49
-13
lines changed

3 files changed

+49
-13
lines changed

compiler/rustc_const_eval/src/util/alignment.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,18 @@ where
2121
};
2222

2323
let ty = place.ty(local_decls, tcx).ty;
24+
let unsized_tail = || tcx.struct_tail_with_normalize(ty, |ty| ty, || {});
2425
match tcx.layout_of(param_env.and(ty)) {
25-
Ok(layout) if layout.align.abi <= pack && layout.is_sized() => {
26+
Ok(layout)
27+
if layout.align.abi <= pack
28+
&& (layout.is_sized()
29+
|| matches!(unsized_tail().kind(), ty::Slice(..) | ty::Str)) =>
30+
{
2631
// If the packed alignment is greater or equal to the field alignment, the type won't be
2732
// further disaligned.
2833
// However we need to ensure the field is sized; for unsized fields, `layout.align` is
29-
// just an approximation.
34+
// just an approximation -- except when the unsized tail is a slice, where the alignment
35+
// is fully determined by the type.
3036
debug!(
3137
"is_disaligned({:?}) - align = {}, packed = {}; not disaligned",
3238
place,

tests/ui/lint/unaligned_references.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,21 @@ impl Foo for Packed2 {
3333
// Test for #115396
3434
fn packed_dyn() {
3535
#[repr(packed)]
36-
struct Unaligned<T: ? Sized>(ManuallyDrop<T>);
36+
struct Unaligned<T: ?Sized>(ManuallyDrop<T>);
3737

3838
let ref local = Unaligned(ManuallyDrop::new([3, 5, 8u64]));
3939
let foo: &Unaligned<dyn Debug> = &*local;
4040
println!("{:?}", &*foo.0); //~ ERROR reference to packed field
41+
let foo: &Unaligned<[u64]> = &*local;
42+
println!("{:?}", &*foo.0); //~ ERROR reference to packed field
43+
44+
// Even if the actual alignment is 1, we cannot know that when looking at `dyn Debug.`
45+
let ref local = Unaligned(ManuallyDrop::new([3, 5, 8u8]));
46+
let foo: &Unaligned<dyn Debug> = &*local;
47+
println!("{:?}", &*foo.0); //~ ERROR reference to packed field
48+
// However, we *can* know the alignment when looking at a slice.
49+
let foo: &Unaligned<[u8]> = &*local;
50+
println!("{:?}", &*foo.0); // no error!
4151
}
4252

4353
fn main() {

tests/ui/lint/unaligned_references.stderr

+30-10
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,27 @@ LL | println!("{:?}", &*foo.0);
1919
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
2020

2121
error[E0793]: reference to packed field is unaligned
22-
--> $DIR/unaligned_references.rs:47:17
22+
--> $DIR/unaligned_references.rs:42:24
23+
|
24+
LL | println!("{:?}", &*foo.0);
25+
| ^^^^^
26+
|
27+
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
28+
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
29+
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
30+
31+
error[E0793]: reference to packed field is unaligned
32+
--> $DIR/unaligned_references.rs:47:24
33+
|
34+
LL | println!("{:?}", &*foo.0);
35+
| ^^^^^
36+
|
37+
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
38+
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
39+
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
40+
41+
error[E0793]: reference to packed field is unaligned
42+
--> $DIR/unaligned_references.rs:57:17
2343
|
2444
LL | let _ = &good.ptr;
2545
| ^^^^^^^^^
@@ -29,7 +49,7 @@ LL | let _ = &good.ptr;
2949
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
3050

3151
error[E0793]: reference to packed field is unaligned
32-
--> $DIR/unaligned_references.rs:48:17
52+
--> $DIR/unaligned_references.rs:58:17
3353
|
3454
LL | let _ = &good.data;
3555
| ^^^^^^^^^^
@@ -39,7 +59,7 @@ LL | let _ = &good.data;
3959
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
4060

4161
error[E0793]: reference to packed field is unaligned
42-
--> $DIR/unaligned_references.rs:50:17
62+
--> $DIR/unaligned_references.rs:60:17
4363
|
4464
LL | let _ = &good.data as *const _;
4565
| ^^^^^^^^^^
@@ -49,7 +69,7 @@ LL | let _ = &good.data as *const _;
4969
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
5070

5171
error[E0793]: reference to packed field is unaligned
52-
--> $DIR/unaligned_references.rs:51:27
72+
--> $DIR/unaligned_references.rs:61:27
5373
|
5474
LL | let _: *const _ = &good.data;
5575
| ^^^^^^^^^^
@@ -59,7 +79,7 @@ LL | let _: *const _ = &good.data;
5979
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
6080

6181
error[E0793]: reference to packed field is unaligned
62-
--> $DIR/unaligned_references.rs:53:17
82+
--> $DIR/unaligned_references.rs:63:17
6383
|
6484
LL | let _ = good.data.clone();
6585
| ^^^^^^^^^
@@ -69,7 +89,7 @@ LL | let _ = good.data.clone();
6989
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
7090

7191
error[E0793]: reference to packed field is unaligned
72-
--> $DIR/unaligned_references.rs:55:17
92+
--> $DIR/unaligned_references.rs:65:17
7393
|
7494
LL | let _ = &good.data2[0];
7595
| ^^^^^^^^^^^^^^
@@ -79,7 +99,7 @@ LL | let _ = &good.data2[0];
7999
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
80100

81101
error[E0793]: reference to packed field is unaligned
82-
--> $DIR/unaligned_references.rs:64:17
102+
--> $DIR/unaligned_references.rs:74:17
83103
|
84104
LL | let _ = &packed2.x;
85105
| ^^^^^^^^^^
@@ -89,7 +109,7 @@ LL | let _ = &packed2.x;
89109
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
90110

91111
error[E0793]: reference to packed field is unaligned
92-
--> $DIR/unaligned_references.rs:103:20
112+
--> $DIR/unaligned_references.rs:113:20
93113
|
94114
LL | let _ref = &m1.1.a;
95115
| ^^^^^^^
@@ -99,7 +119,7 @@ LL | let _ref = &m1.1.a;
99119
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
100120

101121
error[E0793]: reference to packed field is unaligned
102-
--> $DIR/unaligned_references.rs:106:20
122+
--> $DIR/unaligned_references.rs:116:20
103123
|
104124
LL | let _ref = &m2.1.a;
105125
| ^^^^^^^
@@ -108,6 +128,6 @@ LL | let _ref = &m2.1.a;
108128
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
109129
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
110130

111-
error: aborting due to 11 previous errors
131+
error: aborting due to 13 previous errors
112132

113133
For more information about this error, try `rustc --explain E0793`.

0 commit comments

Comments
 (0)