From e559172249af514ab2c3be6340d557dcbb6347eb Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 9 Dec 2023 00:48:17 -0500 Subject: [PATCH] Fix cases where std accidentally relied on inline(never) --- .../src/cross_crate_inline.rs | 19 ++++++++++++------- compiler/rustc_monomorphize/src/collector.rs | 16 ++++++++++++++++ .../rustc_monomorphize/src/partitioning.rs | 12 +++++++++--- library/std/src/rt.rs | 1 - 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs index 261d9dd448d..5f01b841867 100644 --- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs +++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs @@ -22,6 +22,18 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { return false; } + // This just reproduces the logic from Instance::requires_inline. + match tcx.def_kind(def_id) { + DefKind::Ctor(..) | DefKind::Closure => return true, + DefKind::Fn | DefKind::AssocFn => {} + _ => return false, + } + + // From this point on, it is valid to return true or false. + if tcx.sess.opts.unstable_opts.cross_crate_inline_threshold == InliningThreshold::Always { + return true; + } + // Obey source annotations first; this is important because it means we can use // #[inline(never)] to force code generation. match codegen_fn_attrs.inline { @@ -30,13 +42,6 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { _ => {} } - // This just reproduces the logic from Instance::requires_inline. - match tcx.def_kind(def_id) { - DefKind::Ctor(..) | DefKind::Closure => return true, - DefKind::Fn | DefKind::AssocFn => {} - _ => return false, - } - // Don't do any inference when incremental compilation is enabled; the additional inlining that // inference permits also creates more work for small edits. if tcx.sess.opts.incremental.is_some() { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 71b3754fac8..feceff10f95 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -176,6 +176,7 @@ use rustc_middle::mir::{self, Location}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion}; +use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ self, AssocKind, GenericParamDefKind, Instance, InstanceDef, Ty, TyCtxt, TypeFoldable, @@ -923,6 +924,21 @@ fn visit_instance_use<'tcx>( return; } + // The intrinsics assert_inhabited, assert_zero_valid, and assert_mem_uninitialized_valid will + // be lowered in codegen to nothing or a call to panic_nounwind. So if we encounter any + // of those intrinsics, we need to include a mono item for panic_nounwind, else we may try to + // codegen a call to that function without generating code for the function itself. + if let ty::InstanceDef::Intrinsic(def_id) = instance.def { + let name = tcx.item_name(def_id); + if let Some(_requirement) = ValidityRequirement::from_intrinsic(name) { + let def_id = tcx.lang_items().get(LangItem::PanicNounwind).unwrap(); + let panic_instance = Instance::mono(tcx, def_id); + if should_codegen_locally(tcx, &panic_instance) { + output.push(create_fn_mono_item(tcx, panic_instance, source)); + } + } + } + match instance.def { ty::InstanceDef::Virtual(..) | ty::InstanceDef::Intrinsic(_) => { if !is_direct_call { diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index c2b307910e4..d33e5a46be2 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -212,11 +212,17 @@ fn place_mono_items<'tcx, I>(cx: &PartitioningCx<'_, 'tcx>, mono_items: I) -> Pl let cgu_name_cache = &mut FxHashMap::default(); for mono_item in mono_items { - // Handle only root items directly here. Inlined items are handled at - // the bottom of the loop based on reachability. + // Handle only root (GloballyShared) items directly here. Inlined (LocalCopy) items + // are handled at the bottom of the loop based on reachability, with one exception. + // The #[lang = "start"] item is the program entrypoint, so there are no calls to it in MIR. + // So even if its mode is LocalCopy, we need to treat it like a root. match mono_item.instantiation_mode(cx.tcx) { InstantiationMode::GloballyShared { .. } => {} - InstantiationMode::LocalCopy => continue, + InstantiationMode::LocalCopy => { + if Some(mono_item.def_id()) != cx.tcx.lang_items().start_fn() { + continue; + } + } } let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item); diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 5c83f72f3c1..f1eeb75be7c 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -155,7 +155,6 @@ fn lang_start_internal( } #[cfg(not(test))] -#[inline(never)] #[lang = "start"] fn lang_start( main: fn() -> T,