Skip to content

Commit 5b00f61

Browse files
authored
Unrolled build for #159740
Rollup merge of #159740 - RalfJung:miri-dedup-exported-symbols, r=bjorn3 reuse regular exported_non_generic_symbols logic in Miri This is some gnarly code we have duplicated in Miri, let's try to reuse the version from rustc. r? @bjorn3
2 parents fdbd8ee + f8711a1 commit 5b00f61

10 files changed

Lines changed: 115 additions & 88 deletions

File tree

compiler/rustc_codegen_ssa/src/back/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ mod symbol_edit;
1515
pub mod symbol_export;
1616
pub mod write;
1717

18+
pub use symbol_export::{exported_non_generic_symbols_helper, reachable_non_generics_helper};
19+
1820
/// The target triple depends on the deployment target, and is required to
1921
/// enable features such as cross-language LTO, and for picking the right
2022
/// Mach-O commands.

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
5454
return Default::default();
5555
}
5656

57+
reachable_non_generics_helper(tcx)
58+
}
59+
60+
/// Exposed separately *without* the "should codegen" check so Miri can access it.
61+
pub fn reachable_non_generics_helper(tcx: TyCtxt<'_>) -> DefIdMap<SymbolExportInfo> {
5762
let is_compiler_builtins = tcx.is_compiler_builtins(LOCAL_CRATE);
5863

5964
let mut reachable_non_generics: DefIdMap<_> = tcx
@@ -176,6 +181,13 @@ fn exported_non_generic_symbols_provider_local<'tcx>(
176181
return &[];
177182
}
178183

184+
exported_non_generic_symbols_helper(tcx)
185+
}
186+
187+
/// Exposed separately *without* the "should codegen" check so Miri can access it.
188+
pub fn exported_non_generic_symbols_helper<'tcx>(
189+
tcx: TyCtxt<'tcx>,
190+
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
179191
// FIXME: Sorting this is unnecessary since we are sorting later anyway.
180192
// Can we skip the later sorting?
181193
let sorted = tcx.with_stable_hashing_context(|mut hcx| {

compiler/rustc_passes/src/reachable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,8 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
444444
// FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
445445
// `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
446446
// `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
447+
// Also note that Miri is relying on this to be able to find private `link_section` statics
448+
// across all crates.
447449
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
448450
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
449451
// Right now, the only way to get "foreign item symbol aliases" is by being an EII-implementation.

src/bootstrap/src/core/build_steps/test.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,10 @@ impl Step for CargoMiri {
839839
SourceType::Submodule,
840840
&[],
841841
);
842+
// Run subcrate tests as well.
843+
cargo.arg("--workspace");
844+
// Some tests need isolation disabled.
845+
cargo.env("MIRIFLAGS", "-Zmiri-disable-isolation");
842846

843847
// If we are testing stage 2+ cargo miri, make sure that it works with the in-tree cargo.
844848
// We want to do this *somewhere* to ensure that Miri + nightly cargo actually works.

src/tools/miri/src/bin/miri.rs

Lines changed: 8 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
extern crate rustc_codegen_ssa;
1212
extern crate rustc_data_structures;
1313
extern crate rustc_driver;
14-
extern crate rustc_hir;
1514
extern crate rustc_interface;
1615
extern crate rustc_log;
1716
extern crate rustc_middle;
@@ -48,14 +47,9 @@ use miri::{
4847
use rustc_codegen_ssa::traits::CodegenBackend;
4948
use rustc_data_structures::sync::{self, DynSync};
5049
use rustc_driver::Compilation;
51-
use rustc_hir::{self as hir, Node};
5250
use rustc_interface::interface::Config;
5351
use rustc_interface::util::DummyCodegenBackend;
5452
use rustc_log::tracing::debug;
55-
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
56-
use rustc_middle::middle::exported_symbols::{
57-
ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel,
58-
};
5953
use rustc_middle::query::LocalCrate;
6054
use rustc_middle::ty::TyCtxt;
6155
use rustc_session::config::{CrateType, ErrorOutputType, OptLevel};
@@ -258,58 +252,14 @@ impl rustc_driver::Callbacks for MiriDepCompilerCalls {
258252
// Queries overridden here affect the data stored in `rmeta` files of dependencies,
259253
// which will be used later in non-`MIRI_BE_RUSTC` mode.
260254
config.override_queries = Some(|_, local_providers| {
261-
// We need to add #[used] symbols to exported_symbols for `lookup_link_section`.
262-
// FIXME handle this somehow in rustc itself to avoid this hack.
263-
local_providers.queries.exported_non_generic_symbols = |tcx, LocalCrate| {
264-
let reachable_set = tcx.with_stable_hashing_context(|mut hcx| {
265-
tcx.reachable_set(()).to_sorted(&mut hcx, true)
266-
});
267-
tcx.arena.alloc_from_iter(
268-
// This is based on:
269-
// https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L62-L63
270-
// https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L174
271-
reachable_set.into_iter().filter_map(|&local_def_id| {
272-
// Do the same filtering that rustc does:
273-
// https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L84-L102
274-
// Otherwise it may cause unexpected behaviours and ICEs
275-
// (https://github.com/rust-lang/rust/issues/86261).
276-
let is_reachable_non_generic = matches!(
277-
tcx.hir_node_by_def_id(local_def_id),
278-
Node::Item(&hir::Item {
279-
kind: hir::ItemKind::Static(..) | hir::ItemKind::Fn{ .. },
280-
..
281-
}) | Node::ImplItem(&hir::ImplItem {
282-
kind: hir::ImplItemKind::Fn(..),
283-
..
284-
})
285-
if !tcx.generics_of(local_def_id).requires_monomorphization(tcx)
286-
);
287-
if !is_reachable_non_generic {
288-
return None;
289-
}
290-
let codegen_fn_attrs = tcx.codegen_fn_attrs(local_def_id);
291-
if codegen_fn_attrs.contains_extern_indicator()
292-
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
293-
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
294-
{
295-
Some((
296-
ExportedSymbol::NonGeneric(local_def_id.to_def_id()),
297-
// Some dummy `SymbolExportInfo` here. We only use
298-
// `exported_symbols` in shims/foreign_items.rs and the export info
299-
// is ignored.
300-
SymbolExportInfo {
301-
level: SymbolExportLevel::C,
302-
kind: SymbolExportKind::Text,
303-
used: false,
304-
rustc_std_internal_symbol: false,
305-
},
306-
))
307-
} else {
308-
None
309-
}
310-
}),
311-
)
312-
}
255+
// `exported_non_generic_symbols` is usually empty because we don't codegen anything.
256+
// However, we need it for `lookup_link_section`.
257+
// So overwrite the query with a version that dooes something even without codegen.
258+
local_providers.queries.exported_non_generic_symbols =
259+
|tcx, LocalCrate| rustc_codegen_ssa::back::exported_non_generic_symbols_helper(tcx);
260+
// `exported_non_generic_symbols_helper` calls `reachable_non_generics`.
261+
local_providers.queries.reachable_non_generics =
262+
|tcx, LocalCrate| rustc_codegen_ssa::back::reachable_non_generics_helper(tcx);
313263
});
314264

315265
// Register our custom extra symbols.

src/tools/miri/src/helpers.rs

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -116,34 +116,36 @@ pub fn path_ty_layout<'tcx>(cx: &impl LayoutOf<'tcx>, path: &[&str]) -> TyAndLay
116116
/// Call `f` for each exported symbol.
117117
pub fn iter_exported_symbols<'tcx>(
118118
tcx: TyCtxt<'tcx>,
119-
mut f: impl FnMut(CrateNum, DefId) -> InterpResult<'tcx>,
119+
mut f: impl FnMut(CrateNum, DefId, /* used */ bool) -> InterpResult<'tcx>,
120120
) -> InterpResult<'tcx> {
121-
// First, the symbols in the local crate. We can't use `exported_symbols` here as that
122-
// skips `#[used]` statics (since `reachable_set` skips them in binary crates).
123-
// So we walk all HIR items ourselves instead.
121+
// First, the symbols in the local crate. We can't use `exported_symbols` here as that skips
122+
// `#[used]` statics (since `reachable_set` does not specifically include them in binary crates,
123+
// only in library crates). So we walk all HIR items ourselves instead.
124124
let crate_items = tcx.hir_crate_items(());
125125
for def_id in crate_items.definitions() {
126-
let exported = tcx.def_kind(def_id).has_codegen_attrs() && {
127-
let codegen_attrs = tcx.codegen_fn_attrs(def_id);
128-
codegen_attrs.contains_extern_indicator()
129-
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
130-
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
131-
};
126+
if !tcx.def_kind(def_id).has_codegen_attrs() || tcx.is_foreign_item(def_id) {
127+
continue;
128+
}
129+
let codegen_attrs = tcx.codegen_fn_attrs(def_id);
130+
let used = codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
131+
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER);
132+
if !(used || codegen_attrs.contains_extern_indicator()) {
133+
continue;
134+
}
132135
// FIXME: `#[no_mangle]` makes no sense on a generic item, but still causes it to be
133136
// considered "extern". Remove this once `no_mangle_generic_items` is a hard error.
134-
let exported_mono = exported && {
137+
let mono = {
135138
let generics = tcx.generics_of(def_id);
136139
!generics.requires_monomorphization(tcx)
137140
};
138-
if exported_mono {
139-
f(LOCAL_CRATE, def_id.into())?;
141+
if mono {
142+
f(LOCAL_CRATE, def_id.into(), used)?;
140143
}
141144
}
142145

143146
// Next, all our dependencies.
144-
// `dependency_formats` includes all the transitive information needed to link a crate,
145-
// which is what we need here since we need to dig out `exported_symbols` from all transitive
146-
// dependencies.
147+
// `dependency_formats` includes all the transitive information needed to link a crate, which is
148+
// what we need to dig out `exported_symbols` from all transitive dependencies.
147149
let dependency_formats = tcx.dependency_formats(());
148150
// Find the dependencies of the executable we are running.
149151
let dependency_format = dependency_formats
@@ -157,11 +159,12 @@ pub fn iter_exported_symbols<'tcx>(
157159
continue; // Already handled above
158160
}
159161

160-
// We can ignore `_export_info` here: we are a Rust crate, and everything is exported
161-
// from a Rust crate.
162-
for &(symbol, _export_info) in tcx.exported_non_generic_symbols(cnum) {
163-
if let ExportedSymbol::NonGeneric(def_id) = symbol {
164-
f(cnum, def_id)?;
162+
for &(symbol, export_info) in tcx.exported_non_generic_symbols(cnum) {
163+
if let ExportedSymbol::NonGeneric(def_id) = symbol
164+
// Sometimes Rust has to re-export FFI imports; skip those.
165+
&& !tcx.is_foreign_item(def_id)
166+
{
167+
f(cnum, def_id, export_info.used)?;
165168
}
166169
}
167170
}
@@ -961,8 +964,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
961964

962965
let mut array = vec![];
963966

964-
iter_exported_symbols(tcx, |_cnum, def_id| {
967+
iter_exported_symbols(tcx, |_cnum, def_id, used| {
965968
let attrs = tcx.codegen_fn_attrs(def_id);
969+
if !used {
970+
// We don't know if the symbol is actually going to be in the final binary,
971+
// so we conservatively skip it.
972+
return interp_ok(());
973+
}
966974
let Some(link_section) = attrs.link_section else {
967975
return interp_ok(());
968976
};

src/tools/miri/src/shims/foreign_items.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
132132
is_weak: bool,
133133
}
134134
let mut symbol_target: Option<SymbolTarget<'tcx>> = None;
135-
helpers::iter_exported_symbols(tcx, |cnum, def_id| {
135+
helpers::iter_exported_symbols(tcx, |cnum, def_id, _used| {
136136
let attrs = tcx.codegen_fn_attrs(def_id);
137-
// Skip over imports of items.
138-
if tcx.is_foreign_item(def_id) {
139-
return interp_ok(());
140-
}
141137
// Skip over items without an explicitly defined symbol name.
142138
if !(attrs.symbol_name.is_some()
143139
|| attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE)

src/tools/miri/test-cargo-miri/exported-symbol-dep/src/lib.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,49 @@ impl AssocFn {
1111
-123456
1212
}
1313
}
14+
15+
// Also check static constructors in dependencies are run.
16+
17+
#[rustfmt::skip]
18+
#[macro_export]
19+
macro_rules! ctor {
20+
($ident:ident = $ctor:ident) => {
21+
#[cfg_attr(
22+
all(any(
23+
target_os = "linux",
24+
target_os = "android",
25+
target_os = "dragonfly",
26+
target_os = "freebsd",
27+
target_os = "haiku",
28+
target_os = "illumos",
29+
target_os = "netbsd",
30+
target_os = "openbsd",
31+
target_os = "solaris",
32+
target_os = "none",
33+
target_family = "wasm",
34+
)),
35+
link_section = ".init_array"
36+
)]
37+
#[cfg_attr(windows, link_section = ".CRT$XCU")]
38+
#[cfg_attr(
39+
any(target_os = "macos", target_os = "ios"),
40+
// We do not set the `mod_init_funcs` flag here since ctor/inventory also do not do
41+
// that. See <https://github.com/rust-lang/miri/pull/4459#discussion_r2200115629>.
42+
link_section = "__DATA,__mod_init_func"
43+
)]
44+
#[used]
45+
static $ident: unsafe extern "C" fn() = $ctor;
46+
};
47+
}
48+
49+
static mut INITIALIZED: bool = false;
50+
51+
unsafe extern "C" fn ctor() {
52+
unsafe { INITIALIZED = true };
53+
}
54+
55+
pub fn check_initialized() {
56+
assert!(unsafe { INITIALIZED });
57+
}
58+
59+
ctor! { CTOR = ctor }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
extern crate exported_symbol_dep;
2+
pub use exported_symbol_dep::check_initialized;

src/tools/miri/test-cargo-miri/src/main.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ fn main() {
6767
mod test {
6868
use byteorder_2::{BigEndian, ByteOrder};
6969

70+
extern crate cargo_miri_test;
71+
extern crate exported_symbol;
72+
extern crate issue_rust_86261;
73+
7074
// Make sure in-crate tests with dev-dependencies work
7175
#[test]
7276
fn dev_dependency() {
@@ -75,9 +79,6 @@ mod test {
7579

7680
#[test]
7781
fn exported_symbol() {
78-
extern crate cargo_miri_test;
79-
extern crate exported_symbol;
80-
extern crate issue_rust_86261;
8182
// Test calling exported symbols in (transitive) dependencies.
8283
// Repeat calls to make sure the `Instance` cache is not broken.
8384
for _ in 0..3 {
@@ -95,4 +96,9 @@ mod test {
9596
unsafe { no_mangle_generic() }
9697
}
9798
}
99+
100+
#[test]
101+
fn static_initializer_in_dep() {
102+
exported_symbol::check_initialized();
103+
}
98104
}

0 commit comments

Comments
 (0)