Skip to content

Commit 02a1532

Browse files
committed
Miri function identity hack: account for possible inlining
1 parent aca749e commit 02a1532

File tree

3 files changed

+18
-7
lines changed

3 files changed

+18
-7
lines changed

compiler/rustc_middle/src/mir/interpret/mod.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ use std::num::NonZero;
126126
use std::sync::atomic::{AtomicU32, Ordering};
127127

128128
use rustc_ast::LitKind;
129+
use rustc_attr::InlineAttr;
129130
use rustc_data_structures::fx::FxHashMap;
130131
use rustc_data_structures::sync::{HashMapExt, Lock};
131132
use rustc_data_structures::tiny_list::TinyList;
@@ -555,16 +556,24 @@ impl<'tcx> TyCtxt<'tcx> {
555556
pub fn reserve_and_set_fn_alloc(self, instance: Instance<'tcx>) -> AllocId {
556557
// Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
557558
// by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be
558-
// duplicated across crates.
559-
// We thus generate a new `AllocId` for every mention of a function. This means that
560-
// `main as fn() == main as fn()` is false, while `let x = main as fn(); x == x` is true.
561-
// However, formatting code relies on function identity (see #58320), so we only do
562-
// this for generic functions. Lifetime parameters are ignored.
559+
// duplicated across crates. We thus generate a new `AllocId` for every mention of a
560+
// function. This means that `main as fn() == main as fn()` is false, while `let x = main as
561+
// fn(); x == x` is true. However, as a quality-of-life feature it can be useful to identify
562+
// certain functions uniquely, e.g. for backtraces. So we identify whether codegen will
563+
// actually emit duplicate functions. It does that when they have non-lifetime generics, or
564+
// when they can be inlined. All other functions are given a unique address.
565+
// This is not a stable guarantee! The `inline` attribute is a hint and cannot be relied
566+
// upon for anything. But if we don't do this, backtraces look terrible and we risk breaking
567+
// the `USIZE_MARKER` hack in the formatting machinery.
563568
let is_generic = instance
564569
.args
565570
.into_iter()
566571
.any(|kind| !matches!(kind.unpack(), GenericArgKind::Lifetime(_)));
567-
if is_generic {
572+
let can_be_inlined = match self.codegen_fn_attrs(instance.def_id()).inline {
573+
InlineAttr::Never => false,
574+
_ => true,
575+
};
576+
if is_generic || can_be_inlined {
568577
// Get a fresh ID.
569578
let mut alloc_map = self.alloc_map.lock();
570579
let id = alloc_map.reserve();

src/tools/miri/tests/pass/function_pointers.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ fn h(i: i32, j: i32) -> i32 {
2323
j * i * 7
2424
}
2525

26+
#[inline(never)]
2627
fn i() -> i32 {
2728
73
2829
}
@@ -77,7 +78,7 @@ fn main() {
7778
assert_eq!(indirect_mut3(h), 210);
7879
assert_eq!(indirect_once3(h), 210);
7980
// Check that `i` always has the same address. This is not guaranteed
80-
// but Miri currently uses a fixed address for monomorphic functions.
81+
// but Miri currently uses a fixed address for non-inlineable monomorphic functions.
8182
assert!(return_fn_ptr(i) == i);
8283
assert!(return_fn_ptr(i) as unsafe fn() -> i32 == i as fn() -> i32 as unsafe fn() -> i32);
8384
// Miri gives different addresses to different reifications of a generic function.

src/tools/miri/tests/pass/issues/issue-91636.rs

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ impl Function {
1010
}
1111
}
1212

13+
#[inline(never)]
1314
fn dummy(_: &str) {}
1415

1516
fn main() {

0 commit comments

Comments
 (0)