Skip to content

Commit ca65bc9

Browse files
committed
Show packed field alignment in mir_transform_unaligned_packed_ref
1 parent 3f2a592 commit ca65bc9

File tree

13 files changed

+81
-61
lines changed

13 files changed

+81
-61
lines changed

compiler/rustc_const_eval/src/util/alignment.rs

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,57 @@ use rustc_middle::mir::*;
33
use rustc_middle::ty::{self, TyCtxt};
44
use tracing::debug;
55

6-
/// Returns `true` if this place is allowed to be less aligned
7-
/// than its containing struct (because it is within a packed
8-
/// struct).
6+
/// The actual and expected alignment for a place.
7+
pub struct Disalignment {
8+
pub actual: Align,
9+
// Unsized types may not have an expected alignment
10+
pub expected: Option<Align>,
11+
}
12+
13+
/// Returns a [`Disalignment`] if this place is allowed to be less aligned
14+
/// than its type normally requires (because it is within a packed struct).
915
pub fn is_disaligned<'tcx, L>(
1016
tcx: TyCtxt<'tcx>,
1117
local_decls: &L,
1218
typing_env: ty::TypingEnv<'tcx>,
1319
place: Place<'tcx>,
14-
) -> bool
20+
) -> Option<Disalignment>
1521
where
1622
L: HasLocalDecls<'tcx>,
1723
{
1824
debug!("is_disaligned({:?})", place);
1925
let Some(pack) = is_within_packed(tcx, local_decls, place) else {
2026
debug!("is_disaligned({:?}) - not within packed", place);
21-
return false;
27+
return None;
2228
};
2329

2430
let ty = place.ty(local_decls, tcx).ty;
2531
let unsized_tail = || tcx.struct_tail_for_codegen(ty, typing_env);
2632
match tcx.layout_of(typing_env.as_query_input(ty)) {
2733
Ok(layout)
28-
if layout.align.abi <= pack
29-
&& (layout.is_sized()
30-
|| matches!(unsized_tail().kind(), ty::Slice(..) | ty::Str)) =>
34+
if (layout.is_sized() || matches!(unsized_tail().kind(), ty::Slice(..) | ty::Str)) =>
3135
{
3236
// If the packed alignment is greater or equal to the field alignment, the type won't be
3337
// further disaligned.
3438
// However we need to ensure the field is sized; for unsized fields, `layout.align` is
3539
// just an approximation -- except when the unsized tail is a slice, where the alignment
3640
// is fully determined by the type.
37-
debug!(
38-
"is_disaligned({:?}) - align = {}, packed = {}; not disaligned",
39-
place,
40-
layout.align.bytes(),
41-
pack.bytes()
42-
);
43-
false
41+
if layout.align.abi <= pack {
42+
debug!(
43+
"is_disaligned({:?}) - align = {}, packed = {}; not disaligned",
44+
place,
45+
layout.align.bytes(),
46+
pack.bytes()
47+
);
48+
None
49+
} else {
50+
Some(Disalignment { actual: pack, expected: Some(layout.align.abi) })
51+
}
4452
}
4553
_ => {
4654
// We cannot figure out the layout. Conservatively assume that this is disaligned.
4755
debug!("is_disaligned({:?}) - true", place);
48-
true
56+
Some(Disalignment { actual: pack, expected: None })
4957
}
5058
}
5159
}

compiler/rustc_mir_transform/messages.ftl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ mir_transform_tail_expr_local = {$is_generated_name ->
7070
}
7171
7272
mir_transform_unaligned_packed_ref = reference to packed field is unaligned
73-
.note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
73+
.note = this field is only {$actual}-byte aligned, but its type requires {$expected ->
74+
[0] more
75+
*[other] {$expected}-byte
76+
} alignment
7477
.note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
7578
.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)
7679

compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops {
5151

5252
match terminator.kind {
5353
TerminatorKind::Drop { place, .. }
54-
if util::is_disaligned(tcx, body, typing_env, place) =>
54+
if util::is_disaligned(tcx, body, typing_env, place).is_some() =>
5555
{
5656
add_move_for_packed_drop(
5757
tcx,

compiler/rustc_mir_transform/src/check_packed_ref.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_abi::Align;
12
use rustc_middle::mir::visit::{PlaceContext, Visitor};
23
use rustc_middle::mir::*;
34
use rustc_middle::span_bug;
@@ -37,7 +38,9 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
3738
}
3839

3940
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
40-
if context.is_borrow() && util::is_disaligned(self.tcx, self.body, self.typing_env, *place)
41+
if context.is_borrow()
42+
&& let Some(disalign) =
43+
util::is_disaligned(self.tcx, self.body, self.typing_env, *place)
4144
{
4245
let def_id = self.body.source.instance.def_id();
4346
if let Some(impl_def_id) = self.tcx.trait_impl_of_assoc(def_id)
@@ -48,7 +51,11 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
4851
// shouldn't do.
4952
span_bug!(self.source_info.span, "builtin derive created an unaligned reference");
5053
} else {
51-
self.tcx.dcx().emit_err(errors::UnalignedPackedRef { span: self.source_info.span });
54+
self.tcx.dcx().emit_err(errors::UnalignedPackedRef {
55+
span: self.source_info.span,
56+
actual: disalign.actual.bytes(),
57+
expected: disalign.expected.map(Align::bytes).unwrap_or(0),
58+
});
5259
}
5360
}
5461
}

compiler/rustc_mir_transform/src/errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ pub(crate) enum ConstMutate {
9999
pub(crate) struct UnalignedPackedRef {
100100
#[primary_span]
101101
pub span: Span,
102+
pub actual: u64,
103+
pub expected: u64,
102104
}
103105

104106
#[derive(Diagnostic)]

tests/ui/binding/issue-53114-safety-checks.stderr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0793]: reference to packed field is unaligned
44
LL | let _ = &p.b;
55
| ^^^^
66
|
7-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
7+
= note: this field is only 1-byte aligned, but its type requires 8-byte alignment
88
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
99
= 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)
1010

@@ -14,7 +14,7 @@ error[E0793]: reference to packed field is unaligned
1414
LL | let (_,) = (&p.b,);
1515
| ^^^^
1616
|
17-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
17+
= note: this field is only 1-byte aligned, but its type requires 8-byte alignment
1818
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
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

@@ -56,7 +56,7 @@ error[E0793]: reference to packed field is unaligned
5656
LL | let _: _ = &p.b;
5757
| ^^^^
5858
|
59-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
59+
= note: this field is only 1-byte aligned, but its type requires 8-byte alignment
6060
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
6161
= 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)
6262

@@ -66,7 +66,7 @@ error[E0793]: reference to packed field is unaligned
6666
LL | let (_,): _ = (&p.b,);
6767
| ^^^^
6868
|
69-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
69+
= note: this field is only 1-byte aligned, but its type requires 8-byte alignment
7070
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
7171
= 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)
7272

@@ -108,7 +108,7 @@ error[E0793]: reference to packed field is unaligned
108108
LL | match &p.b { _ => { } }
109109
| ^^^^
110110
|
111-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
111+
= note: this field is only 1-byte aligned, but its type requires 8-byte alignment
112112
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
113113
= 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)
114114

@@ -118,7 +118,7 @@ error[E0793]: reference to packed field is unaligned
118118
LL | match (&p.b,) { (_,) => { } }
119119
| ^^^^
120120
|
121-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
121+
= note: this field is only 1-byte aligned, but its type requires 8-byte alignment
122122
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
123123
= 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)
124124

tests/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0793]: reference to packed field is unaligned
44
LL | println!("{}", foo.x);
55
| ^^^^^
66
|
7-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
7+
= note: this field is only 1-byte aligned, but its type requires 8-byte alignment
88
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
99
= 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)
1010
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

tests/ui/lint/unaligned_references.current.stderr

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0793]: reference to packed field is unaligned
44
LL | &self.x;
55
| ^^^^^^^
66
|
7-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
7+
= note: this field is only 2-byte aligned, but its type requires 4-byte alignment
88
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
99
= 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)
1010

@@ -14,7 +14,7 @@ error[E0793]: reference to packed field is unaligned
1414
LL | println!("{:?}", &*foo.0);
1515
| ^^^^^
1616
|
17-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
17+
= note: this field is only 1-byte aligned, but its type requires more alignment
1818
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
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

@@ -24,7 +24,7 @@ error[E0793]: reference to packed field is unaligned
2424
LL | println!("{:?}", &*foo.0);
2525
| ^^^^^
2626
|
27-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
27+
= note: this field is only 1-byte aligned, but its type requires 8-byte alignment
2828
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
2929
= 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)
3030

@@ -34,7 +34,7 @@ error[E0793]: reference to packed field is unaligned
3434
LL | println!("{:?}", &*foo.0);
3535
| ^^^^^
3636
|
37-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
37+
= note: this field is only 1-byte aligned, but its type requires more alignment
3838
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
3939
= 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)
4040

@@ -44,7 +44,7 @@ error[E0793]: reference to packed field is unaligned
4444
LL | let _ = &good.ptr;
4545
| ^^^^^^^^^
4646
|
47-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
47+
= note: this field is only 1-byte aligned, but its type requires 8-byte alignment
4848
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
4949
= 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)
5050

@@ -54,7 +54,7 @@ error[E0793]: reference to packed field is unaligned
5454
LL | let _ = &good.data;
5555
| ^^^^^^^^^^
5656
|
57-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
57+
= note: this field is only 1-byte aligned, but its type requires 8-byte alignment
5858
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
5959
= 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)
6060

@@ -64,7 +64,7 @@ error[E0793]: reference to packed field is unaligned
6464
LL | let _ = &good.data as *const _;
6565
| ^^^^^^^^^^
6666
|
67-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
67+
= note: this field is only 1-byte aligned, but its type requires 8-byte alignment
6868
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
6969
= 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)
7070

@@ -74,7 +74,7 @@ error[E0793]: reference to packed field is unaligned
7474
LL | let _: *const _ = &good.data;
7575
| ^^^^^^^^^^
7676
|
77-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
77+
= note: this field is only 1-byte aligned, but its type requires 8-byte alignment
7878
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
7979
= 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)
8080

@@ -84,7 +84,7 @@ error[E0793]: reference to packed field is unaligned
8484
LL | let _ = good.data.clone();
8585
| ^^^^^^^^^
8686
|
87-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
87+
= note: this field is only 1-byte aligned, but its type requires 8-byte alignment
8888
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
8989
= 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)
9090

@@ -94,7 +94,7 @@ error[E0793]: reference to packed field is unaligned
9494
LL | let _ = &good.data2[0];
9595
| ^^^^^^^^^^^^^^
9696
|
97-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
97+
= note: this field is only 1-byte aligned, but its type requires 8-byte alignment
9898
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
9999
= 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)
100100

@@ -104,7 +104,7 @@ error[E0793]: reference to packed field is unaligned
104104
LL | let _ = &packed2.x;
105105
| ^^^^^^^^^^
106106
|
107-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
107+
= note: this field is only 2-byte aligned, but its type requires 4-byte alignment
108108
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
109109
= 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)
110110

@@ -114,7 +114,7 @@ error[E0793]: reference to packed field is unaligned
114114
LL | let _ref = &m1.1.a;
115115
| ^^^^^^^
116116
|
117-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
117+
= note: this field is only 1-byte aligned, but its type requires 2-byte alignment
118118
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
119119
= 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)
120120

@@ -124,7 +124,7 @@ error[E0793]: reference to packed field is unaligned
124124
LL | let _ref = &m2.1.a;
125125
| ^^^^^^^
126126
|
127-
= note: packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
127+
= note: this field is only 1-byte aligned, but its type requires 2-byte alignment
128128
= note: creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
129129
= 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)
130130

0 commit comments

Comments
 (0)