Skip to content

Commit 060e453

Browse files
Fix ICE on offsetted ZST pointer
A grep for `const_usize.*align` found the same code copied to rustc_codegen_gcc but I don't see other cases where we get this wrong.
1 parent 9725c4b commit 060e453

File tree

4 files changed

+27
-6
lines changed

4 files changed

+27
-6
lines changed

compiler/rustc_codegen_cranelift/src/constant.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,10 @@ pub(crate) fn codegen_const_value<'tcx>(
138138
let base_addr = match fx.tcx.global_alloc(alloc_id) {
139139
GlobalAlloc::Memory(alloc) => {
140140
if alloc.inner().len() == 0 {
141-
assert_eq!(offset, Size::ZERO);
142-
fx.bcx.ins().iconst(fx.pointer_type, alloc.inner().align.bytes() as i64)
141+
fx.bcx.ins().iconst(
142+
fx.pointer_type,
143+
alloc.inner().align.bytes().wrapping_add(offset.bytes()) as i64,
144+
)
143145
} else {
144146
let data_id = data_id_for_alloc_id(
145147
&mut fx.constants_cx,

compiler/rustc_codegen_gcc/src/common.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,9 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
247247
// This avoids generating a zero-sized constant value and actually needing a
248248
// real address at runtime.
249249
if alloc.inner().len() == 0 {
250-
assert_eq!(offset.bytes(), 0);
251-
let val = self.const_usize(alloc.inner().align.bytes());
250+
let val = self.const_usize(
251+
alloc.inner().align.bytes().wrapping_add(offset.bytes()),
252+
);
252253
return if matches!(layout.primitive(), Pointer(_)) {
253254
self.context.new_cast(None, val, ty)
254255
} else {

compiler/rustc_codegen_llvm/src/common.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,9 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> {
281281
// This avoids generating a zero-sized constant value and actually needing a
282282
// real address at runtime.
283283
if alloc.inner().len() == 0 {
284-
assert_eq!(offset.bytes(), 0);
285-
let llval = self.const_usize(alloc.inner().align.bytes());
284+
let llval = self.const_usize(
285+
alloc.inner().align.bytes().wrapping_add(offset.bytes()),
286+
);
286287
return if matches!(layout.primitive(), Pointer(_)) {
287288
unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
288289
} else {

tests/ui/consts/zst_no_llvm_alloc.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ struct Foo;
55

66
static FOO: Foo = Foo;
77

8+
// This tests for regression of https://github.com/rust-lang/rust/issues/147516
9+
//
10+
// THe compiler will codegen `&Zst` without creating a real allocation, just a properly aligned
11+
// `usize` (i.e., ptr::dangling). However, code can add an arbitrary offset from that base
12+
// allocation. We confirm here that we correctly codegen that offset combined with the necessary
13+
// alignment of the base &() as a 1-ZST and &Foo as a 4-ZST.
14+
const A: *const () = (&() as *const ()).wrapping_byte_add(2);
15+
const B: *const () = (&Foo as *const _ as *const ()).wrapping_byte_add(usize::MAX);
16+
const C: *const () = (&Foo as *const _ as *const ()).wrapping_byte_add(2);
17+
818
fn main() {
919
// There's no stable guarantee that these are true.
1020
// However, we want them to be true so that our LLVM IR and runtime are a bit faster:
@@ -15,6 +25,13 @@ fn main() {
1525
let x: &'static Foo = &Foo;
1626
assert_eq!(x as *const Foo as usize, 4);
1727

28+
// * A 1-aligned ZST (1-ZST) is placed at 0x1. Then offsetting that by 2 results in 3.
29+
// * Foo is a 4-aligned ZST, so is placed at 0x4. +2 = 6
30+
// * Foo is a 4-aligned ZST, so is placed at 0x4. +usize::MAX = -1 (same bit pattern) = 3
31+
assert_eq!(A.addr(), 3);
32+
assert_eq!(B.addr(), 3);
33+
assert_eq!(C.addr(), 6);
34+
1835
// The exact addresses returned by these library functions are not necessarily stable guarantees
1936
// but for now we assert that we're still matching.
2037
#[allow(dangling_pointers_from_temporaries)]

0 commit comments

Comments
 (0)