diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 568fcc3f3cf49..cec2f30956e74 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -255,21 +255,34 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { let (prov, offset) = ptr.into_parts(); let (base_addr, base_addr_space) = match self.tcx.global_alloc(prov.alloc_id()) { GlobalAlloc::Memory(alloc) => { - let init = const_alloc_to_llvm(self, alloc); - let alloc = alloc.inner(); - let value = match alloc.mutability { - Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), - _ => self.static_addr_of(init, alloc.align, None), - }; - if !self.sess().fewer_names() && llvm::get_value_name(value).is_empty() { - let hash = self.tcx.with_stable_hashing_context(|mut hcx| { - let mut hasher = StableHasher::new(); - alloc.hash_stable(&mut hcx, &mut hasher); - hasher.finish::() - }); - llvm::set_value_name(value, format!("alloc_{hash:032x}").as_bytes()); + // For ZSTs directly codegen an aligned pointer. + // This avoids generating a zero-sized constant value and actually needing a + // real address at runtime. + if alloc.inner().len() == 0 { + let llval = self.const_usize(alloc.inner().align.bytes()); + let llval = unsafe { llvm::LLVMConstIntToPtr(llval, llty) }; + (llval, AddressSpace::DATA) + } else { + let init = const_alloc_to_llvm(self, alloc); + let alloc = alloc.inner(); + let value = match alloc.mutability { + Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), + _ => self.static_addr_of(init, alloc.align, None), + }; + if !self.sess().fewer_names() && llvm::get_value_name(value).is_empty() + { + let hash = self.tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + alloc.hash_stable(&mut hcx, &mut hasher); + hasher.finish::() + }); + llvm::set_value_name( + value, + format!("alloc_{hash:032x}").as_bytes(), + ); + } + (value, AddressSpace::DATA) } - (value, AddressSpace::DATA) } GlobalAlloc::Function(fn_instance) => ( self.get_fn_addr(fn_instance.polymorphize(self.tcx)), diff --git a/tests/ui/consts/zst_no_llvm_alloc.rs b/tests/ui/consts/zst_no_llvm_alloc.rs index 1622a199a7a40..48ef11e2b58cf 100644 --- a/tests/ui/consts/zst_no_llvm_alloc.rs +++ b/tests/ui/consts/zst_no_llvm_alloc.rs @@ -6,16 +6,21 @@ struct Foo; static FOO: Foo = Foo; fn main() { + // There's no stable guarantee that these are true. + // However, we want them to be true so that our LLVM IR and runtime are a bit faster: + // a constant address is cheap and doesn't result in relocations in comparison to a "real" + // global somewhere in the data section. let x: &'static () = &(); - assert_ne!(x as *const () as usize, 1); + assert_eq!(x as *const () as usize, 1); let x: &'static Foo = &Foo; - assert_ne!(x as *const Foo as usize, 4); + assert_eq!(x as *const Foo as usize, 4); - // statics must have a unique address - assert_ne!(&FOO as *const Foo as usize, 4); + // The exact addresses returned by these library functions are not necessarily stable guarantees + // but for now we assert that we're still matching. + assert_eq!(>::new().as_ptr(), <&[i32]>::default().as_ptr()); + assert_eq!(>::default().as_ptr(), (&[]).as_ptr()); - // FIXME this two tests should be assert_eq! - // this stopped working since we are promoting to constants instead of statics - assert_ne!(>::new().as_ptr(), <&[i32]>::default().as_ptr()); - assert_ne!(>::default().as_ptr(), (&[]).as_ptr()); + // statics must have a unique address (see https://github.com/rust-lang/rust/issues/18297, not + // clear whether this is a stable guarantee) + assert_ne!(&FOO as *const Foo as usize, 4); }