Skip to content

Commit 6238a57

Browse files
committed
Adjust the alignment when passing the niche as a pointer
1 parent 88f3114 commit 6238a57

File tree

2 files changed

+142
-7
lines changed

2 files changed

+142
-7
lines changed

compiler/rustc_middle/src/ty/layout.rs

+29-7
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,7 @@ where
999999
}
10001000

10011001
_ => {
1002-
let mut data_variant = match this.variants {
1002+
let (mut data_variant, align) = match this.variants {
10031003
// Within the discriminant field, only the niche itself is
10041004
// always initialized, so we only check for a pointer at its
10051005
// offset.
@@ -1012,13 +1012,32 @@ where
10121012
// using more niches than just null (e.g., the first page of
10131013
// the address space, or unaligned pointers).
10141014
Variants::Multiple {
1015-
tag_encoding: TagEncoding::Niche { untagged_variant, .. },
1015+
tag_encoding:
1016+
TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start },
10161017
tag_field,
1018+
ref variants,
10171019
..
10181020
} if this.fields.offset(tag_field) == offset => {
1019-
Some(this.for_variant(cx, untagged_variant))
1021+
// When a non-null niche is passed in, we might pass an unaligned value,
1022+
// so we need to adjust the alignment to an appropriate value.
1023+
let align = variants
1024+
.iter_enumerated()
1025+
.filter_map(|(idx, variant)| {
1026+
if untagged_variant == idx || variant.abi.is_uninhabited() {
1027+
None
1028+
} else {
1029+
Some(idx)
1030+
}
1031+
})
1032+
.fold(Align::MAX, |align, idx| {
1033+
let niche = (idx.as_u32() as u128
1034+
- niche_variants.start().as_u32() as u128)
1035+
.wrapping_add(niche_start);
1036+
align.restrict_for_offset(Size::from_bytes(niche))
1037+
});
1038+
(Some(this.for_variant(cx, untagged_variant)), Some(align))
10201039
}
1021-
_ => Some(this),
1040+
_ => (Some(this), None),
10221041
};
10231042

10241043
if let Some(variant) = data_variant {
@@ -1055,20 +1074,23 @@ where
10551074
}
10561075
}
10571076

1058-
// Fixup info for the first field of a `Box`. Recursive traversal will have found
1059-
// the raw pointer, so size and align are set to the boxed type, but `pointee.safe`
1060-
// will still be `None`.
10611077
if let Some(ref mut pointee) = result {
10621078
if offset.bytes() == 0
10631079
&& let Some(boxed_ty) = this.ty.boxed_ty()
10641080
{
1081+
// Fixup info for the first field of a `Box`. Recursive traversal will have found
1082+
// the raw pointer, so size and align are set to the boxed type, but `pointee.safe`
1083+
// will still be `None`.
10651084
debug_assert!(pointee.safe.is_none());
10661085
let optimize = tcx.sess.opts.optimize != OptLevel::No;
10671086
pointee.safe = Some(PointerKind::Box {
10681087
unpin: optimize && boxed_ty.is_unpin(tcx, cx.param_env()),
10691088
global: this.ty.is_box_global(tcx),
10701089
});
10711090
}
1091+
if let Some(align) = align {
1092+
pointee.align = pointee.align.min(align);
1093+
}
10721094
}
10731095

10741096
result
+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
//@ compile-flags: -Cno-prepopulate-passes -O
2+
//@ only-64bit (I don't care about alignment under different bits)
3+
4+
// Testing different niches updates to the corresponding alignment.
5+
6+
#![crate_type = "lib"]
7+
#![feature(rustc_attrs)]
8+
#![feature(never_type)]
9+
10+
#[rustc_layout_scalar_valid_range_start(0)]
11+
#[rustc_layout_scalar_valid_range_end(0x7fff)]
12+
struct RestrictedAddress_0_0x7fff(&'static i64);
13+
14+
#[rustc_layout_scalar_valid_range_start(1)]
15+
#[rustc_layout_scalar_valid_range_end(0x7fff)]
16+
struct RestrictedAddress_1_0x7fff(&'static i64);
17+
18+
#[rustc_layout_scalar_valid_range_start(0)]
19+
#[rustc_layout_scalar_valid_range_end(0xf000)]
20+
struct RestrictedAddress_0_0xf000(&'static i64);
21+
22+
enum MultipleAlign8 {
23+
Untag(RestrictedAddress_1_0x7fff),
24+
Niche_32768,
25+
Uninhabited_1(!),
26+
Uninhabited_2(!),
27+
Uninhabited_3(!),
28+
Uninhabited_4(!),
29+
Uninhabited_5(!),
30+
Uninhabited_6(!),
31+
Uninhabited_7(!),
32+
Niche_32776,
33+
}
34+
35+
// CHECK-LABEL: @multiple_niches_align_8
36+
// CHECK-SAME: align 8 {{.*}}%a)
37+
#[no_mangle]
38+
#[inline(never)]
39+
fn multiple_niches_align_8(a: MultipleAlign8) {}
40+
41+
// CHECK-LABEL: @call_multiple_niches_align_8
42+
#[no_mangle]
43+
fn call_multiple_niches_align_8() {
44+
// CHECK: call void @multiple_niches_align_8(ptr {{.*}}align 8 {{.*}}(i64 32768 to ptr)
45+
multiple_niches_align_8(MultipleAlign8::Niche_32768);
46+
// CHECK: call void @multiple_niches_align_8(ptr {{.*}}align 8 {{.*}}(i64 32776 to ptr)
47+
multiple_niches_align_8(MultipleAlign8::Niche_32776);
48+
}
49+
50+
enum MultipleAlign2 {
51+
Untag(RestrictedAddress_1_0x7fff),
52+
Niche_32768,
53+
Uninhabited_1(!),
54+
Niche_32770,
55+
}
56+
57+
// CHECK-LABEL: @multiple_niches_align_2
58+
// CHECK-SAME: align 2 {{.*}}%a)
59+
#[no_mangle]
60+
#[inline(never)]
61+
fn multiple_niches_align_2(a: MultipleAlign2) {}
62+
63+
// CHECK-LABEL: @call_multiple_niches_align_2
64+
#[no_mangle]
65+
fn call_multiple_niches_align_2() {
66+
// CHECK: call void @multiple_niches_align_2(ptr {{.*}}align 2 {{.*}}(i64 32768 to ptr)
67+
multiple_niches_align_2(MultipleAlign2::Niche_32768);
68+
// CHECK: call void @multiple_niches_align_2(ptr {{.*}}align 2 {{.*}}(i64 32770 to ptr)
69+
multiple_niches_align_2(MultipleAlign2::Niche_32770);
70+
}
71+
72+
enum SingleAlign8 {
73+
Untag(RestrictedAddress_0_0x7fff),
74+
Niche_32768,
75+
}
76+
77+
// CHECK-LABEL: @single_niche_align_8
78+
// CHECK-SAME: align 8 {{.*}}%a)
79+
#[no_mangle]
80+
#[inline(never)]
81+
fn single_niche_align_8(a: SingleAlign8) {}
82+
83+
// CHECK-LABEL: @call_single_niche_align_8
84+
#[no_mangle]
85+
fn call_single_niche_align_8() {
86+
// CHECK: call void @single_niche_align_8(ptr {{.*}}align 8 {{.*}}(i64 32768 to ptr)
87+
single_niche_align_8(SingleAlign8::Niche_32768);
88+
}
89+
90+
enum SingleAlign1 {
91+
Untag(RestrictedAddress_0_0xf000),
92+
Niche_61441,
93+
}
94+
95+
// CHECK-LABEL: @single_niche_align_1
96+
// CHECK-SAME: align 1 {{.*}}%a)
97+
#[no_mangle]
98+
#[inline(never)]
99+
fn single_niche_align_1(a: SingleAlign1) {}
100+
101+
// CHECK-LABEL: @call_single_niche_align_1
102+
#[no_mangle]
103+
fn call_single_niche_align_1() {
104+
// CHECK: call void @single_niche_align_1(ptr {{.*}}align 1 {{.*}}(i64 61441 to ptr)
105+
single_niche_align_1(SingleAlign1::Niche_61441);
106+
}
107+
108+
// Check that we only apply the new alignment on enum.
109+
110+
// CHECK-LABEL: @restricted_address
111+
// CHECK-SAME: align 8 {{.*}}%a)
112+
#[no_mangle]
113+
fn restricted_address(a: RestrictedAddress_0_0x7fff) {}

0 commit comments

Comments
 (0)