Skip to content

Ensure we codegen the main fn #144094

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions compiler/rustc_middle/src/mir/mono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,8 @@ impl<'tcx> MonoItem<'tcx> {
};

// Similarly, the executable entrypoint must be instantiated exactly once.
if let Some((entry_def_id, _)) = tcx.entry_fn(()) {
if instance.def_id() == entry_def_id {
return InstantiationMode::GloballyShared { may_conflict: false };
}
if tcx.is_entrypoint(instance.def_id()) {
return InstantiationMode::GloballyShared { may_conflict: false };
}

// If the function is #[naked] or contains any other attribute that requires exactly-once
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3402,6 +3402,20 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn do_not_recommend_impl(self, def_id: DefId) -> bool {
self.get_diagnostic_attr(def_id, sym::do_not_recommend).is_some()
}

/// Whether this def is one of the special bin crate entrypoint functions that must have a
/// monomorphization and also not be internalized in the bin crate.
pub fn is_entrypoint(self, def_id: DefId) -> bool {
if self.is_lang_item(def_id, LangItem::Start) {
return true;
}
if let Some((entry_def_id, _)) = self.entry_fn(()) {
if entry_def_id == def_id {
return true;
}
}
false
}
}

/// Parameter attributes that can only be determined by examining the body of a function instead
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1582,6 +1582,11 @@ impl<'v> RootCollector<'_, 'v> {
return;
};

let main_instance = Instance::mono(self.tcx, main_def_id);
if self.tcx.should_codegen_locally(main_instance) {
self.output.push(create_fn_mono_item(self.tcx, main_instance, DUMMY_SP));
}

let Some(start_def_id) = self.tcx.lang_items().start_fn() else {
self.tcx.dcx().emit_fatal(errors::StartNotFound);
};
Expand Down
15 changes: 5 additions & 10 deletions compiler/rustc_monomorphize/src/partitioning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,7 @@ where
// 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 => {
if !cx.tcx.is_lang_item(mono_item.def_id(), LangItem::Start) {
continue;
}
}
InstantiationMode::LocalCopy => continue,
}

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

// The `start_fn` lang item is actually a monomorphized instance of a
// function in the standard library, used for the `main` function. We don't
// want to export it so we tag it with `Hidden` visibility but this symbol
// is only referenced from the actual `main` symbol which we unfortunately
// Both the `start_fn` lang item and `main` itself should not be exported,
// so we give them with `Hidden` visibility but these symbols are
// only referenced from the actual `main` symbol which we unfortunately
// don't know anything about during partitioning/collection. As a result we
// forcibly keep this symbol out of the `internalization_candidates` set.
//
Expand All @@ -834,7 +829,7 @@ fn mono_item_visibility<'tcx>(
// from the `main` symbol we'll generate later.
//
// This may be fixable with a new `InstanceKind` perhaps? Unsure!
if tcx.is_lang_item(def_id, LangItem::Start) {
if tcx.is_entrypoint(def_id) {
*can_be_internalized = false;
return Visibility::Hidden;
}
Expand Down
3 changes: 3 additions & 0 deletions tests/ui/entry-point/auxiliary/main_functions.rs
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
pub fn boilerplate() {}

#[inline]
pub fn local_codegen() {}
11 changes: 11 additions & 0 deletions tests/ui/entry-point/imported_main_local_codegen.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//@ run-pass
//@ aux-build:main_functions.rs
//@ compile-flags: -Ccodegen-units=1024

// This is a regression test for https://github.com/rust-lang/rust/issues/144052.
// Entrypoint functions call each other in ways that CGU partitioning doesn't know about. So there
// is a special check to not internalize any of them. But internalizing them can be okay if there
// are few enough CGUs, so we use a lot of CGUs in this test to hit the bad case.

extern crate main_functions;
pub use main_functions::local_codegen as main;
Loading