Skip to content

Commit 4ddaa5f

Browse files
authored
Unrolled build for #147743
Rollup merge of #147743 - 21aslade:packed-diagnostic, r=RalfJung Show packed field alignment in mir_transform_unaligned_packed_ref Fixes #147528 I left the expected padding for the field out of the error message so the message would be the same on all platforms. It also isn't always possible to know the expected alignment, so this makes the message simpler.
2 parents acda5e9 + 566a86b commit 4ddaa5f

25 files changed

+210
-141
lines changed
Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
use rustc_abi::Align;
22
use rustc_middle::mir::*;
3-
use rustc_middle::ty::{self, TyCtxt};
3+
use rustc_middle::ty::{self, AdtDef, 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).
9-
pub fn is_disaligned<'tcx, L>(
6+
/// If the place may be less aligned than its type requires
7+
/// (because it is in a packed type), returns the AdtDef
8+
/// and packed alignment of its most-unaligned projection.
9+
pub fn place_unalignment<'tcx, L>(
1010
tcx: TyCtxt<'tcx>,
1111
local_decls: &L,
1212
typing_env: ty::TypingEnv<'tcx>,
1313
place: Place<'tcx>,
14-
) -> bool
14+
) -> Option<(AdtDef<'tcx>, Align)>
1515
where
1616
L: HasLocalDecls<'tcx>,
1717
{
18-
debug!("is_disaligned({:?})", place);
19-
let Some(pack) = is_within_packed(tcx, local_decls, place) else {
20-
debug!("is_disaligned({:?}) - not within packed", place);
21-
return false;
18+
debug!("unalignment({:?})", place);
19+
let Some((descr, pack)) = most_packed_projection(tcx, local_decls, place) else {
20+
debug!("unalignment({:?}) - not within packed", place);
21+
return None;
2222
};
2323

2424
let ty = place.ty(local_decls, tcx).ty;
@@ -30,31 +30,34 @@ where
3030
|| matches!(unsized_tail().kind(), ty::Slice(..) | ty::Str)) =>
3131
{
3232
// If the packed alignment is greater or equal to the field alignment, the type won't be
33-
// further disaligned.
33+
// further unaligned.
3434
// However we need to ensure the field is sized; for unsized fields, `layout.align` is
3535
// just an approximation -- except when the unsized tail is a slice, where the alignment
3636
// is fully determined by the type.
3737
debug!(
38-
"is_disaligned({:?}) - align = {}, packed = {}; not disaligned",
38+
"unalignment({:?}) - align = {}, packed = {}; not unaligned",
3939
place,
4040
layout.align.bytes(),
4141
pack.bytes()
4242
);
43-
false
43+
None
4444
}
4545
_ => {
46-
// We cannot figure out the layout. Conservatively assume that this is disaligned.
47-
debug!("is_disaligned({:?}) - true", place);
48-
true
46+
// We cannot figure out the layout. Conservatively assume that this is unaligned.
47+
debug!("unalignment({:?}) - unaligned", place);
48+
Some((descr, pack))
4949
}
5050
}
5151
}
5252

53-
pub fn is_within_packed<'tcx, L>(
53+
/// If the place includes a projection from a packed struct,
54+
/// returns the AdtDef and packed alignment of the projection
55+
/// with the lowest pack
56+
pub fn most_packed_projection<'tcx, L>(
5457
tcx: TyCtxt<'tcx>,
5558
local_decls: &L,
5659
place: Place<'tcx>,
57-
) -> Option<Align>
60+
) -> Option<(AdtDef<'tcx>, Align)>
5861
where
5962
L: HasLocalDecls<'tcx>,
6063
{
@@ -65,9 +68,11 @@ where
6568
.take_while(|(_base, elem)| !matches!(elem, ProjectionElem::Deref))
6669
// Consider the packed alignments at play here...
6770
.filter_map(|(base, _elem)| {
68-
base.ty(local_decls, tcx).ty.ty_adt_def().and_then(|adt| adt.repr().pack)
71+
let adt = base.ty(local_decls, tcx).ty.ty_adt_def()?;
72+
let pack = adt.repr().pack?;
73+
Some((adt, pack))
6974
})
7075
// ... and compute their minimum.
7176
// The overall smallest alignment is what matters.
72-
.min()
77+
.min_by_key(|(_, align)| *align)
7378
}

compiler/rustc_const_eval/src/util/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ mod check_validity_requirement;
66
mod compare_types;
77
mod type_name;
88

9-
pub use self::alignment::{is_disaligned, is_within_packed};
9+
pub use self::alignment::{most_packed_projection, place_unalignment};
1010
pub use self::check_validity_requirement::check_validity_requirement;
1111
pub(crate) use self::check_validity_requirement::validate_scalar_in_layout;
1212
pub use self::compare_types::{relate_types, sub_types};

compiler/rustc_mir_transform/messages.ftl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,11 @@ mir_transform_tail_expr_local = {$is_generated_name ->
6969
*[false] `{$name}` calls a custom destructor
7070
}
7171
72-
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
72+
mir_transform_unaligned_packed_ref = reference to field of packed {$ty_descr} is unaligned
73+
.note = this {$ty_descr} is {$align ->
74+
[one] {""}
75+
*[other] {"at most "}
76+
}{$align}-byte aligned, but the type of this field may require higher 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::place_unalignment(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: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
3737
}
3838

3939
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)
40+
if context.is_borrow()
41+
&& let Some((adt, pack)) =
42+
util::place_unalignment(self.tcx, self.body, self.typing_env, *place)
4143
{
4244
let def_id = self.body.source.instance.def_id();
4345
if let Some(impl_def_id) = self.tcx.trait_impl_of_assoc(def_id)
@@ -48,7 +50,11 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
4850
// shouldn't do.
4951
span_bug!(self.source_info.span, "builtin derive created an unaligned reference");
5052
} else {
51-
self.tcx.dcx().emit_err(errors::UnalignedPackedRef { span: self.source_info.span });
53+
self.tcx.dcx().emit_err(errors::UnalignedPackedRef {
54+
span: self.source_info.span,
55+
ty_descr: adt.descr(),
56+
align: pack.bytes(),
57+
});
5258
}
5359
}
5460
}

compiler/rustc_mir_transform/src/dead_store_elimination.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use rustc_mir_dataflow::impls::{
2323
};
2424

2525
use crate::simplify::UsedInStmtLocals;
26-
use crate::util::is_within_packed;
26+
use crate::util::most_packed_projection;
2727

2828
/// Performs the optimization on the body
2929
///
@@ -65,7 +65,7 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
6565
// the move may be codegened as a pointer to that field.
6666
// Using that disaligned pointer may trigger UB in the callee,
6767
// so do nothing.
68-
&& is_within_packed(tcx, body, place).is_none()
68+
&& most_packed_projection(tcx, body, place).is_none()
6969
{
7070
call_operands_to_move.push((bb, index));
7171
}

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 ty_descr: &'static str,
103+
pub align: u64,
102104
}
103105

104106
#[derive(Diagnostic)]

compiler/rustc_mir_transform/src/validate.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use rustc_middle::{bug, span_bug};
2020
use rustc_mir_dataflow::debuginfo::debuginfo_locals;
2121
use rustc_trait_selection::traits::ObligationCtxt;
2222

23-
use crate::util::{self, is_within_packed};
23+
use crate::util::{self, most_packed_projection};
2424

2525
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2626
enum EdgeKind {
@@ -409,7 +409,9 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
409409

410410
// The call destination place and Operand::Move place used as an argument might
411411
// be passed by a reference to the callee. Consequently they cannot be packed.
412-
if is_within_packed(self.tcx, &self.body.local_decls, destination).is_some() {
412+
if most_packed_projection(self.tcx, &self.body.local_decls, destination)
413+
.is_some()
414+
{
413415
// This is bad! The callee will expect the memory to be aligned.
414416
self.fail(
415417
location,
@@ -423,7 +425,9 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
423425

424426
for arg in args {
425427
if let Operand::Move(place) = &arg.node {
426-
if is_within_packed(self.tcx, &self.body.local_decls, *place).is_some() {
428+
if most_packed_projection(self.tcx, &self.body.local_decls, *place)
429+
.is_some()
430+
{
427431
// This is bad! The callee will expect the memory to be aligned.
428432
self.fail(
429433
location,

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ fn let_wild_gets_unsafe_field() {
2020
let u1 = U { a: I(0) };
2121
let u2 = U { a: I(1) };
2222
let p = P { a: &2, b: &3 };
23-
let _ = &p.b; //~ ERROR reference to packed field
23+
let _ = &p.b; //~ ERROR reference to field of packed struct
2424
let _ = u1.a; //~ ERROR [E0133]
2525
let _ = &u2.a; //~ ERROR [E0133]
2626

2727
// variation on above with `_` in substructure
28-
let (_,) = (&p.b,); //~ ERROR reference to packed field
28+
let (_,) = (&p.b,); //~ ERROR reference to field of packed struct
2929
let (_,) = (u1.a,); //~ ERROR [E0133]
3030
let (_,) = (&u2.a,); //~ ERROR [E0133]
3131
}
@@ -34,12 +34,12 @@ fn let_ascribe_gets_unsafe_field() {
3434
let u1 = U { a: I(0) };
3535
let u2 = U { a: I(1) };
3636
let p = P { a: &2, b: &3 };
37-
let _: _ = &p.b; //~ ERROR reference to packed field
37+
let _: _ = &p.b; //~ ERROR reference to field of packed struct
3838
let _: _ = u1.a; //~ ERROR [E0133]
3939
let _: _ = &u2.a; //~ ERROR [E0133]
4040

4141
// variation on above with `_` in substructure
42-
let (_,): _ = (&p.b,); //~ ERROR reference to packed field
42+
let (_,): _ = (&p.b,); //~ ERROR reference to field of packed struct
4343
let (_,): _ = (u1.a,); //~ ERROR [E0133]
4444
let (_,): _ = (&u2.a,); //~ ERROR [E0133]
4545
}
@@ -48,12 +48,12 @@ fn match_unsafe_field_to_wild() {
4848
let u1 = U { a: I(0) };
4949
let u2 = U { a: I(1) };
5050
let p = P { a: &2, b: &3 };
51-
match &p.b { _ => { } } //~ ERROR reference to packed field
51+
match &p.b { _ => { } } //~ ERROR reference to field of packed struct
5252
match u1.a { _ => { } } //~ ERROR [E0133]
5353
match &u2.a { _ => { } } //~ ERROR [E0133]
5454

5555
// variation on above with `_` in substructure
56-
match (&p.b,) { (_,) => { } } //~ ERROR reference to packed field
56+
match (&p.b,) { (_,) => { } } //~ ERROR reference to field of packed struct
5757
match (u1.a,) { (_,) => { } } //~ ERROR [E0133]
5858
match (&u2.a,) { (_,) => { } } //~ ERROR [E0133]
5959
}

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
error[E0793]: reference to packed field is unaligned
1+
error[E0793]: reference to field of packed struct is unaligned
22
--> $DIR/issue-53114-safety-checks.rs:23:13
33
|
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 struct is 1-byte aligned, but the type of this field may require higher 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

11-
error[E0793]: reference to packed field is unaligned
11+
error[E0793]: reference to field of packed struct is unaligned
1212
--> $DIR/issue-53114-safety-checks.rs:28:17
1313
|
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 struct is 1-byte aligned, but the type of this field may require higher 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

@@ -50,23 +50,23 @@ LL | let (_,) = (&u2.a,);
5050
|
5151
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
5252

53-
error[E0793]: reference to packed field is unaligned
53+
error[E0793]: reference to field of packed struct is unaligned
5454
--> $DIR/issue-53114-safety-checks.rs:37:16
5555
|
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 struct is 1-byte aligned, but the type of this field may require higher 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

63-
error[E0793]: reference to packed field is unaligned
63+
error[E0793]: reference to field of packed struct is unaligned
6464
--> $DIR/issue-53114-safety-checks.rs:42:20
6565
|
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 struct is 1-byte aligned, but the type of this field may require higher 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

@@ -102,23 +102,23 @@ LL | let (_,): _ = (&u2.a,);
102102
|
103103
= note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
104104

105-
error[E0793]: reference to packed field is unaligned
105+
error[E0793]: reference to field of packed struct is unaligned
106106
--> $DIR/issue-53114-safety-checks.rs:51:11
107107
|
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 struct is 1-byte aligned, but the type of this field may require higher 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

115-
error[E0793]: reference to packed field is unaligned
115+
error[E0793]: reference to field of packed struct is unaligned
116116
--> $DIR/issue-53114-safety-checks.rs:56:12
117117
|
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 struct is 1-byte aligned, but the type of this field may require higher 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

0 commit comments

Comments
 (0)