Skip to content

Commit 00ccd9a

Browse files
authored
Unrolled build for #147576
Rollup merge of #147576 - Mark-Simulacrum:fix-offset-zst, r=nnethercote,RalfJung Fix ICE on offsetted ZST pointer I'm not sure this is the *right* fix, but it's simple enough and does roughly what I'd expect. Like with the previous optimization to codegen usize rather than a zero-sized static, there's no guarantee that we continue returning a particular value from the offsetting. A grep for `const_usize.*align` found the same code copied to rustc_codegen_gcc and cranelift but a quick skim didn't find other cases of similar 'optimization'. That said, I'm not convinced I caught everything, it's not trivial to search for this. Closes #147516
2 parents 779e19d + a8c79b8 commit 00ccd9a

File tree

4 files changed

+32
-9
lines changed

4 files changed

+32
-9
lines changed

compiler/rustc_codegen_cranelift/src/constant.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use std::cmp::Ordering;
55
use cranelift_module::*;
66
use rustc_data_structures::fx::FxHashSet;
77
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
8-
use rustc_middle::mir::interpret::{AllocId, GlobalAlloc, Scalar, read_target_uint};
8+
use rustc_middle::mir::interpret::{
9+
AllocId, GlobalAlloc, PointerArithmetic, Scalar, read_target_uint,
10+
};
911
use rustc_middle::ty::{ExistentialTraitRef, ScalarInt};
1012

1113
use crate::prelude::*;
@@ -138,8 +140,11 @@ pub(crate) fn codegen_const_value<'tcx>(
138140
let base_addr = match fx.tcx.global_alloc(alloc_id) {
139141
GlobalAlloc::Memory(alloc) => {
140142
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)
143+
let val = alloc.inner().align.bytes().wrapping_add(offset.bytes());
144+
fx.bcx.ins().iconst(
145+
fx.pointer_type,
146+
fx.tcx.truncate_to_target_usize(val) as i64,
147+
)
143148
} else {
144149
let data_id = data_id_for_alloc_id(
145150
&mut fx.constants_cx,

compiler/rustc_codegen_gcc/src/common.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_codegen_ssa::traits::{
55
BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods,
66
};
77
use rustc_middle::mir::Mutability;
8-
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
8+
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, PointerArithmetic, Scalar};
99
use rustc_middle::ty::layout::LayoutOf;
1010

1111
use crate::context::CodegenCx;
@@ -247,8 +247,8 @@ 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 = alloc.inner().align.bytes().wrapping_add(offset.bytes());
251+
let val = self.const_usize(self.tcx.truncate_to_target_usize(val));
252252
return if matches!(layout.primitive(), Pointer(_)) {
253253
self.context.new_cast(None, val, ty)
254254
} else {

compiler/rustc_codegen_llvm/src/common.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
1212
use rustc_hashes::Hash128;
1313
use rustc_hir::def_id::DefId;
1414
use rustc_middle::bug;
15-
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
15+
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, PointerArithmetic, Scalar};
1616
use rustc_middle::ty::TyCtxt;
1717
use rustc_session::cstore::DllImport;
1818
use tracing::debug;
@@ -281,8 +281,8 @@ 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 val = alloc.inner().align.bytes().wrapping_add(offset.bytes());
285+
let llval = self.const_usize(self.tcx.truncate_to_target_usize(val));
286286
return if matches!(layout.primitive(), Pointer(_)) {
287287
unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
288288
} else {

tests/ui/consts/zst_no_llvm_alloc.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
//@ run-pass
22

3+
// We need some non-1 alignment to test we use the alignment of the type in the compiler.
34
#[repr(align(4))]
45
struct Foo;
56

67
static FOO: Foo = Foo;
78

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

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

0 commit comments

Comments
 (0)