Skip to content

Commit cdf9a48

Browse files
committed
Set the pointer alignment to 1 whenever any niche is non-zero
1 parent 88f3114 commit cdf9a48

File tree

2 files changed

+51
-7
lines changed

2 files changed

+51
-7
lines changed

compiler/rustc_middle/src/ty/layout.rs

+21-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,24 @@ 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, .. },
10161017
tag_field,
10171018
..
10181019
} if this.fields.offset(tag_field) == offset => {
1019-
Some(this.for_variant(cx, untagged_variant))
1020+
// When a non-zero niche exists, we cannot safely keep
1021+
// the alignment of the pointer. These niches typically
1022+
// don't meet the alignment requirements of the pointer.
1023+
let align = if niche_variants.start().as_u32() != 0
1024+
|| niche_variants.end().as_u32() != 0
1025+
{
1026+
Some(Align::ONE)
1027+
} else {
1028+
None
1029+
};
1030+
(Some(this.for_variant(cx, untagged_variant)), align)
10201031
}
1021-
_ => Some(this),
1032+
_ => (Some(this), None),
10221033
};
10231034

10241035
if let Some(variant) = data_variant {
@@ -1055,10 +1066,10 @@ where
10551066
}
10561067
}
10571068

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`.
10611069
if let Some(ref mut pointee) = result {
1070+
// Fixup info for the first field of a `Box`. Recursive traversal will have found
1071+
// the raw pointer, so size and align are set to the boxed type, but `pointee.safe`
1072+
// will still be `None`.
10621073
if offset.bytes() == 0
10631074
&& let Some(boxed_ty) = this.ty.boxed_ty()
10641075
{
@@ -1069,6 +1080,9 @@ where
10691080
global: this.ty.is_box_global(tcx),
10701081
});
10711082
}
1083+
if let Some(align) = align {
1084+
pointee.align = align;
1085+
}
10721086
}
10731087

10741088
result
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//@ compile-flags: -Cno-prepopulate-passes
2+
//@ only-64bit (I don't care about alignment under different bits)
3+
//@ revisions: OPT0 OPT3
4+
//@ [OPT0] compile-flags: -Copt-level=0
5+
//@ [OPT3] compile-flags: -Copt-level=3
6+
7+
#![crate_type = "rlib"]
8+
#![feature(rustc_attrs)]
9+
10+
#[rustc_layout_scalar_valid_range_start(1)]
11+
#[rustc_layout_scalar_valid_range_end(0x7fff)]
12+
pub struct RestrictedAddress(&'static i64);
13+
14+
enum Variant {
15+
A,
16+
B(RestrictedAddress),
17+
C,
18+
}
19+
20+
// When a non-zero niche exists, we cannot safely keep the alignment of the pointer.
21+
// CHECK-LABEL: @multiple_niches
22+
// CHECK-SAME: align 1
23+
#[no_mangle]
24+
#[inline(never)]
25+
pub fn multiple_niches(a: Variant) {}
26+
27+
// CHECK-LABEL: @single_niche
28+
// CHECK-SAME: align 8
29+
#[no_mangle]
30+
pub fn single_niche(a: Option<&'static i64>) {}

0 commit comments

Comments
 (0)