Skip to content

Commit 8702a51

Browse files
authored
Rollup merge of rust-lang#144094 - saethlin:codegen-the-main-fn, r=petrochenkov
Ensure we codegen the main fn This fixes two bugs. The one that was identified in the linked issue is that when we have a `main` function, mono collection didn't consider it as an extra collection root. The other is that since CGU partitioning doesn't know about the call edges between the entrypoint functions, naively it can put them in different CGUs and mark them all as internal. Which would result in LLVM just deleting all of them. There was an existing hack to exclude `lang = "start"` from internalization, which I've extended to include `main`. Fixes rust-lang#144052
2 parents 8432fc2 + c4eb077 commit 8702a51

File tree

6 files changed

+44
-14
lines changed

6 files changed

+44
-14
lines changed

compiler/rustc_middle/src/mir/mono.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,8 @@ impl<'tcx> MonoItem<'tcx> {
143143
};
144144

145145
// Similarly, the executable entrypoint must be instantiated exactly once.
146-
if let Some((entry_def_id, _)) = tcx.entry_fn(()) {
147-
if instance.def_id() == entry_def_id {
148-
return InstantiationMode::GloballyShared { may_conflict: false };
149-
}
146+
if tcx.is_entrypoint(instance.def_id()) {
147+
return InstantiationMode::GloballyShared { may_conflict: false };
150148
}
151149

152150
// If the function is #[naked] or contains any other attribute that requires exactly-once

compiler/rustc_middle/src/ty/context.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3415,6 +3415,20 @@ impl<'tcx> TyCtxt<'tcx> {
34153415
pub fn do_not_recommend_impl(self, def_id: DefId) -> bool {
34163416
self.get_diagnostic_attr(def_id, sym::do_not_recommend).is_some()
34173417
}
3418+
3419+
/// Whether this def is one of the special bin crate entrypoint functions that must have a
3420+
/// monomorphization and also not be internalized in the bin crate.
3421+
pub fn is_entrypoint(self, def_id: DefId) -> bool {
3422+
if self.is_lang_item(def_id, LangItem::Start) {
3423+
return true;
3424+
}
3425+
if let Some((entry_def_id, _)) = self.entry_fn(())
3426+
&& entry_def_id == def_id
3427+
{
3428+
return true;
3429+
}
3430+
false
3431+
}
34183432
}
34193433

34203434
/// Parameter attributes that can only be determined by examining the body of a function instead

compiler/rustc_monomorphize/src/collector.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,6 +1582,15 @@ impl<'v> RootCollector<'_, 'v> {
15821582
return;
15831583
};
15841584

1585+
let main_instance = Instance::mono(self.tcx, main_def_id);
1586+
if self.tcx.should_codegen_locally(main_instance) {
1587+
self.output.push(create_fn_mono_item(
1588+
self.tcx,
1589+
main_instance,
1590+
self.tcx.def_span(main_def_id),
1591+
));
1592+
}
1593+
15851594
let Some(start_def_id) = self.tcx.lang_items().start_fn() else {
15861595
self.tcx.dcx().emit_fatal(errors::StartNotFound);
15871596
};

compiler/rustc_monomorphize/src/partitioning.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,7 @@ where
223223
// So even if its mode is LocalCopy, we need to treat it like a root.
224224
match mono_item.instantiation_mode(cx.tcx) {
225225
InstantiationMode::GloballyShared { .. } => {}
226-
InstantiationMode::LocalCopy => {
227-
if !cx.tcx.is_lang_item(mono_item.def_id(), LangItem::Start) {
228-
continue;
229-
}
230-
}
226+
InstantiationMode::LocalCopy => continue,
231227
}
232228

233229
let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item);
@@ -821,10 +817,9 @@ fn mono_item_visibility<'tcx>(
821817
| InstanceKind::FnPtrAddrShim(..) => return Visibility::Hidden,
822818
};
823819

824-
// The `start_fn` lang item is actually a monomorphized instance of a
825-
// function in the standard library, used for the `main` function. We don't
826-
// want to export it so we tag it with `Hidden` visibility but this symbol
827-
// is only referenced from the actual `main` symbol which we unfortunately
820+
// Both the `start_fn` lang item and `main` itself should not be exported,
821+
// so we give them with `Hidden` visibility but these symbols are
822+
// only referenced from the actual `main` symbol which we unfortunately
828823
// don't know anything about during partitioning/collection. As a result we
829824
// forcibly keep this symbol out of the `internalization_candidates` set.
830825
//
@@ -834,7 +829,7 @@ fn mono_item_visibility<'tcx>(
834829
// from the `main` symbol we'll generate later.
835830
//
836831
// This may be fixable with a new `InstanceKind` perhaps? Unsure!
837-
if tcx.is_lang_item(def_id, LangItem::Start) {
832+
if tcx.is_entrypoint(def_id) {
838833
*can_be_internalized = false;
839834
return Visibility::Hidden;
840835
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
pub fn boilerplate() {}
2+
3+
#[inline]
4+
pub fn local_codegen() {}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ run-pass
2+
//@ aux-build:main_functions.rs
3+
//@ compile-flags: -Ccodegen-units=1024
4+
5+
// This is a regression test for https://github.com/rust-lang/rust/issues/144052.
6+
// Entrypoint functions call each other in ways that CGU partitioning doesn't know about. So there
7+
// is a special check to not internalize any of them. But internalizing them can be okay if there
8+
// are few enough CGUs, so we use a lot of CGUs in this test to hit the bad case.
9+
10+
extern crate main_functions;
11+
pub use main_functions::local_codegen as main;

0 commit comments

Comments
 (0)