Skip to content

Commit 9bce05f

Browse files
Share inline(never) generics across crates
This reduces code sizes and better respects programmer intent when marking inline(never). Previously such a marking was essentially ignored for generic functions, as we'd still inline them in remote crates.
1 parent 39cb338 commit 9bce05f

26 files changed

+127
-52
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4137,6 +4137,7 @@ name = "rustc_monomorphize"
41374137
version = "0.0.0"
41384138
dependencies = [
41394139
"rustc_abi",
4140+
"rustc_attr",
41404141
"rustc_data_structures",
41414142
"rustc_errors",
41424143
"rustc_fluent_macro",

compiler/rustc_codegen_llvm/src/callee.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
104104

105105
let is_hidden = if is_generic {
106106
// This is a monomorphization of a generic function.
107-
if !cx.tcx.sess.opts.share_generics() {
107+
if !(cx.tcx.sess.opts.share_generics()
108+
|| tcx.codegen_fn_attrs(instance_def_id).inline
109+
== rustc_attr::InlineAttr::Never)
110+
{
108111
// When not sharing generics, all instances are in the same
109112
// crate and have hidden visibility.
110113
true

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ fn exported_symbols_provider_local(
282282
}));
283283
}
284284

285-
if tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics() {
285+
if tcx.local_crate_exports_generics() {
286286
use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility};
287287
use rustc_middle::ty::InstanceKind;
288288

@@ -310,6 +310,16 @@ fn exported_symbols_provider_local(
310310
continue;
311311
}
312312

313+
if !tcx.sess.opts.share_generics() {
314+
if tcx.codegen_fn_attrs(mono_item.def_id()).inline == rustc_attr::InlineAttr::Never
315+
{
316+
// this is OK, we explicitly allow sharing inline(never) across crates even
317+
// without share-generics.
318+
} else {
319+
continue;
320+
}
321+
}
322+
313323
match *mono_item {
314324
MonoItem::Fn(Instance { def: InstanceKind::Item(def), args }) => {
315325
if args.non_erasable_generics().next().is_some() {

compiler/rustc_middle/src/mir/mono.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ impl<'tcx> MonoItem<'tcx> {
111111
return InstantiationMode::GloballyShared { may_conflict: false };
112112
}
113113

114+
if let InlineAttr::Never = tcx.codegen_fn_attrs(instance.def_id()).inline
115+
&& self.is_generic_fn()
116+
{
117+
// Upgrade inline(never) to a globally shared instance.
118+
return InstantiationMode::GloballyShared { may_conflict: true };
119+
}
120+
114121
// At this point we don't have explicit linkage and we're an
115122
// inlined function. If we're inlining into all CGUs then we'll
116123
// be creating a local copy per CGU.

compiler/rustc_middle/src/ty/context.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,8 +1946,6 @@ impl<'tcx> TyCtxt<'tcx> {
19461946

19471947
#[inline]
19481948
pub fn local_crate_exports_generics(self) -> bool {
1949-
debug_assert!(self.sess.opts.share_generics());
1950-
19511949
self.crate_types().iter().any(|crate_type| {
19521950
match crate_type {
19531951
CrateType::Executable

compiler/rustc_middle/src/ty/instance.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -190,19 +190,23 @@ impl<'tcx> Instance<'tcx> {
190190
/// This method already takes into account the global `-Zshare-generics`
191191
/// setting, always returning `None` if `share-generics` is off.
192192
pub fn upstream_monomorphization(&self, tcx: TyCtxt<'tcx>) -> Option<CrateNum> {
193-
// If we are not in share generics mode, we don't link to upstream
194-
// monomorphizations but always instantiate our own internal versions
195-
// instead.
196-
if !tcx.sess.opts.share_generics() {
197-
return None;
198-
}
199-
200193
// If this is an item that is defined in the local crate, no upstream
201194
// crate can know about it/provide a monomorphization.
202195
if self.def_id().is_local() {
203196
return None;
204197
}
205198

199+
// If we are not in share generics mode, we don't link to upstream
200+
// monomorphizations but always instantiate our own internal versions
201+
// instead.
202+
if !tcx.sess.opts.share_generics()
203+
// However, if the def_id is marked inline(never), then it's fine to just reuse the
204+
// upstream monomorphization.
205+
&& tcx.codegen_fn_attrs(self.def_id()).inline != rustc_attr::InlineAttr::Never
206+
{
207+
return None;
208+
}
209+
206210
// If this a non-generic instance, it cannot be a shared monomorphization.
207211
self.args.non_erasable_generics().next()?;
208212

compiler/rustc_monomorphize/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ edition = "2021"
66
[dependencies]
77
# tidy-alphabetical-start
88
rustc_abi = { path = "../rustc_abi" }
9+
rustc_attr = { path = "../rustc_attr" }
910
rustc_data_structures = { path = "../rustc_data_structures" }
1011
rustc_errors = { path = "../rustc_errors" }
1112
rustc_fluent_macro = { path = "../rustc_fluent_macro" }

compiler/rustc_monomorphize/src/partitioning.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,8 @@ where
208208
// available to downstream crates. This depends on whether we are in
209209
// share-generics mode and whether the current crate can even have
210210
// downstream crates.
211-
let export_generics =
212-
cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics();
211+
let can_export_generics = cx.tcx.local_crate_exports_generics();
212+
let always_export_generics = can_export_generics && cx.tcx.sess.opts.share_generics();
213213

214214
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
215215
let cgu_name_cache = &mut UnordMap::default();
@@ -249,7 +249,8 @@ where
249249
cx.tcx,
250250
&mono_item,
251251
&mut can_be_internalized,
252-
export_generics,
252+
can_export_generics,
253+
always_export_generics,
253254
);
254255
if visibility == Visibility::Hidden && can_be_internalized {
255256
internalization_candidates.insert(mono_item);
@@ -739,12 +740,19 @@ fn mono_item_linkage_and_visibility<'tcx>(
739740
tcx: TyCtxt<'tcx>,
740741
mono_item: &MonoItem<'tcx>,
741742
can_be_internalized: &mut bool,
742-
export_generics: bool,
743+
can_export_generics: bool,
744+
always_export_generics: bool,
743745
) -> (Linkage, Visibility) {
744746
if let Some(explicit_linkage) = mono_item.explicit_linkage(tcx) {
745747
return (explicit_linkage, Visibility::Default);
746748
}
747-
let vis = mono_item_visibility(tcx, mono_item, can_be_internalized, export_generics);
749+
let vis = mono_item_visibility(
750+
tcx,
751+
mono_item,
752+
can_be_internalized,
753+
can_export_generics,
754+
always_export_generics,
755+
);
748756
(Linkage::External, vis)
749757
}
750758

@@ -767,7 +775,8 @@ fn mono_item_visibility<'tcx>(
767775
tcx: TyCtxt<'tcx>,
768776
mono_item: &MonoItem<'tcx>,
769777
can_be_internalized: &mut bool,
770-
export_generics: bool,
778+
can_export_generics: bool,
779+
always_export_generics: bool,
771780
) -> Visibility {
772781
let instance = match mono_item {
773782
// This is pretty complicated; see below.
@@ -826,7 +835,11 @@ fn mono_item_visibility<'tcx>(
826835

827836
// Upstream `DefId` instances get different handling than local ones.
828837
let Some(def_id) = def_id.as_local() else {
829-
return if export_generics && is_generic {
838+
return if is_generic
839+
&& (always_export_generics
840+
|| (can_export_generics
841+
&& tcx.codegen_fn_attrs(def_id).inline == rustc_attr::InlineAttr::Never))
842+
{
830843
// If it is an upstream monomorphization and we export generics, we must make
831844
// it available to downstream crates.
832845
*can_be_internalized = false;
@@ -837,7 +850,10 @@ fn mono_item_visibility<'tcx>(
837850
};
838851

839852
if is_generic {
840-
if export_generics {
853+
if always_export_generics
854+
|| (can_export_generics
855+
&& tcx.codegen_fn_attrs(def_id).inline == rustc_attr::InlineAttr::Never)
856+
{
841857
if tcx.is_unreachable_local_definition(def_id) {
842858
// This instance cannot be used from another crate.
843859
Visibility::Hidden

library/alloc/src/raw_vec.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,9 @@ impl<A: Allocator> RawVecInner<A> {
757757
}
758758
}
759759

760-
#[inline(never)]
760+
// not marked inline(never) since we want optimizers to be able to observe the specifics of this
761+
// function, see tests/codegen/vec-reserve-extend.rs.
762+
#[cold]
761763
fn finish_grow<A>(
762764
new_layout: Layout,
763765
current_memory: Option<(NonNull<u8>, Layout)>,

library/std/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@
362362
#![feature(strict_provenance_atomic_ptr)]
363363
#![feature(sync_unsafe_cell)]
364364
#![feature(ub_checks)]
365+
#![feature(used_with_arg)]
365366
// tidy-alphabetical-end
366367
//
367368
// Library features (alloc):

0 commit comments

Comments
 (0)