Skip to content

Commit bcd696d

Browse files
committed
Auto merge of rust-lang#84401 - crlf0710:impl_main_by_path, r=petrochenkov
Implement RFC 1260 with feature_name `imported_main`. This is the second extraction part of rust-lang#84062 plus additional adjustments. This (mostly) implements RFC 1260. However there's still one test case failure in the extern crate case. Maybe `LocalDefId` doesn't work here? I'm not sure. cc rust-lang#28937 r? `@petrochenkov`
2 parents a45f0d7 + d261df4 commit bcd696d

38 files changed

+459
-189
lines changed

compiler/rustc_codegen_cranelift/src/driver/jit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
103103
});
104104

105105
let (main_def_id, entry_ty) = tcx.entry_fn(LOCAL_CRATE).unwrap();
106-
let instance = Instance::mono(tcx, main_def_id.to_def_id()).polymorphize(tcx);
106+
let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
107107

108108
match entry_ty {
109109
EntryFnType::Main => {

compiler/rustc_codegen_cranelift/src/main_shim.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub(crate) fn maybe_create_entry_wrapper(
1313
) {
1414
let (main_def_id, use_start_lang_item) = match tcx.entry_fn(LOCAL_CRATE) {
1515
Some((def_id, entry_ty)) => (
16-
def_id.to_def_id(),
16+
def_id,
1717
match entry_ty {
1818
EntryFnType::Main => true,
1919
EntryFnType::Start => false,

compiler/rustc_codegen_llvm/src/debuginfo/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
344344
spflags |= DISPFlags::SPFlagOptimized;
345345
}
346346
if let Some((id, _)) = self.tcx.entry_fn(LOCAL_CRATE) {
347-
if id.to_def_id() == def_id {
347+
if id == def_id {
348348
spflags |= DISPFlags::SPFlagMainSubprogram;
349349
}
350350
}

compiler/rustc_codegen_ssa/src/base.rs

+22-5
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashMap;
1515
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
1616
use rustc_data_structures::sync::{par_iter, ParallelIterator};
1717
use rustc_hir as hir;
18-
use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
18+
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
1919
use rustc_hir::lang_items::LangItem;
2020
use rustc_index::vec::Idx;
2121
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
@@ -348,12 +348,29 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
348348
cx: &'a Bx::CodegenCx,
349349
) -> Option<Bx::Function> {
350350
let main_def_id = cx.tcx().entry_fn(LOCAL_CRATE).map(|(def_id, _)| def_id)?;
351-
let instance = Instance::mono(cx.tcx(), main_def_id.to_def_id());
351+
let main_is_local = main_def_id.is_local();
352+
let instance = Instance::mono(cx.tcx(), main_def_id);
352353

353-
if !cx.codegen_unit().contains_item(&MonoItem::Fn(instance)) {
354+
if main_is_local {
354355
// We want to create the wrapper in the same codegen unit as Rust's main
355356
// function.
356-
return None;
357+
if !cx.codegen_unit().contains_item(&MonoItem::Fn(instance)) {
358+
return None;
359+
}
360+
} else {
361+
// FIXME: Add support for non-local main fn codegen
362+
let span = cx.tcx().main_def.unwrap().span;
363+
let n = 28937;
364+
cx.sess()
365+
.struct_span_err(span, "entry symbol `main` from foreign crate is not yet supported.")
366+
.note(&format!(
367+
"see issue #{} <https://github.com/rust-lang/rust/issues/{}> \
368+
for more information",
369+
n, n,
370+
))
371+
.emit();
372+
cx.sess().abort_if_errors();
373+
bug!();
357374
}
358375

359376
let main_llfn = cx.get_fn_addr(instance);
@@ -366,7 +383,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
366383
fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
367384
cx: &'a Bx::CodegenCx,
368385
rust_main: Bx::Value,
369-
rust_main_def_id: LocalDefId,
386+
rust_main_def_id: DefId,
370387
use_start_lang_item: bool,
371388
) -> Bx::Function {
372389
// The entry function is either `int main(void)` or `int main(int argc, char **argv)`,

compiler/rustc_error_codes/src/error_codes/E0136.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
#### Note: this error code is no longer emitted by the compiler.
2+
13
More than one `main` function was found.
24

35
Erroneous code example:
46

5-
```compile_fail,E0136
7+
```compile_fail
68
fn main() {
79
// ...
810
}

compiler/rustc_expand/src/expand.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use rustc_attr::{self as attr, is_builtin_attr};
2020
use rustc_data_structures::map_in_place::MapInPlace;
2121
use rustc_data_structures::stack::ensure_sufficient_stack;
2222
use rustc_data_structures::sync::Lrc;
23-
use rustc_errors::{Applicability, PResult};
23+
use rustc_errors::{Applicability, FatalError, PResult};
2424
use rustc_feature::Features;
2525
use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser, RecoverComma};
2626
use rustc_parse::validate_attr;
@@ -414,6 +414,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
414414
kind.article(), kind.descr()
415415
),
416416
);
417+
// FIXME: this workaround issue #84569
418+
FatalError.raise();
417419
}
418420
};
419421
self.cx.trace_macros_diag();

compiler/rustc_feature/src/active.rs

+3
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,9 @@ declare_features! (
653653
/// Allows unsizing coercions in `const fn`.
654654
(active, const_fn_unsize, "1.53.0", Some(64992), None),
655655

656+
/// Allows using imported `main` function
657+
(active, imported_main, "1.53.0", Some(28937), None),
658+
656659
// -------------------------------------------------------------------------
657660
// feature-group-end: actual feature gates
658661
// -------------------------------------------------------------------------

compiler/rustc_interface/src/queries.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ impl<'tcx> Queries<'tcx> {
307307
_ => return,
308308
};
309309

310-
let attrs = &*tcx.get_attrs(def_id.to_def_id());
310+
let attrs = &*tcx.get_attrs(def_id);
311311
let attrs = attrs.iter().filter(|attr| tcx.sess.check_name(attr, sym::rustc_error));
312312
for attr in attrs {
313313
match attr.meta_item_list() {

compiler/rustc_middle/src/mir/mono.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_data_structures::base_n;
66
use rustc_data_structures::fingerprint::Fingerprint;
77
use rustc_data_structures::fx::FxHashMap;
88
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
9-
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
9+
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
1010
use rustc_hir::{HirId, ItemId};
1111
use rustc_session::config::OptLevel;
1212
use rustc_span::source_map::Span;
@@ -93,7 +93,7 @@ impl<'tcx> MonoItem<'tcx> {
9393
// indicator, then we'll be creating a globally shared version.
9494
if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator()
9595
|| !instance.def.generates_cgu_internal_copy(tcx)
96-
|| Some(instance.def_id()) == entry_def_id.map(LocalDefId::to_def_id)
96+
|| Some(instance.def_id()) == entry_def_id
9797
{
9898
return InstantiationMode::GloballyShared { may_conflict: false };
9999
}

compiler/rustc_middle/src/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1194,7 +1194,7 @@ rustc_queries! {
11941194

11951195
/// Identifies the entry-point (e.g., the `main` function) for a given
11961196
/// crate, returning `None` if there is no entry point (such as for library crates).
1197-
query entry_fn(_: CrateNum) -> Option<(LocalDefId, EntryFnType)> {
1197+
query entry_fn(_: CrateNum) -> Option<(DefId, EntryFnType)> {
11981198
desc { "looking up the entry function of a crate" }
11991199
}
12001200
query plugin_registrar_fn(_: CrateNum) -> Option<DefId> {

compiler/rustc_middle/src/ty/context.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use crate::ty::TyKind::*;
2020
use crate::ty::{
2121
self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid,
2222
DefIdTree, ExistentialPredicate, FloatTy, FloatVar, FloatVid, GenericParamDefKind, InferConst,
23-
InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate,
24-
PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions,
23+
InferTy, IntTy, IntVar, IntVid, List, MainDefinition, ParamConst, ParamTy, PolyFnSig,
24+
Predicate, PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions,
2525
TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
2626
};
2727
use rustc_ast as ast;
@@ -1025,6 +1025,8 @@ pub struct GlobalCtxt<'tcx> {
10251025
layout_interner: ShardedHashMap<&'tcx Layout, ()>,
10261026

10271027
output_filenames: Arc<OutputFilenames>,
1028+
1029+
pub main_def: Option<MainDefinition>,
10281030
}
10291031

10301032
impl<'tcx> TyCtxt<'tcx> {
@@ -1185,6 +1187,7 @@ impl<'tcx> TyCtxt<'tcx> {
11851187
const_stability_interner: Default::default(),
11861188
alloc_map: Lock::new(interpret::AllocMap::new()),
11871189
output_filenames: Arc::new(output_filenames.clone()),
1190+
main_def: resolutions.main_def,
11881191
}
11891192
}
11901193

compiler/rustc_middle/src/ty/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,20 @@ pub struct ResolverOutputs {
124124
/// Extern prelude entries. The value is `true` if the entry was introduced
125125
/// via `extern crate` item and not `--extern` option or compiler built-in.
126126
pub extern_prelude: FxHashMap<Symbol, bool>,
127+
pub main_def: Option<MainDefinition>,
128+
}
129+
130+
#[derive(Clone, Copy)]
131+
pub struct MainDefinition {
132+
pub res: Res<ast::NodeId>,
133+
pub is_import: bool,
134+
pub span: Span,
135+
}
136+
137+
impl MainDefinition {
138+
pub fn opt_fn_def_id(self) -> Option<DefId> {
139+
if let Res::Def(DefKind::Fn, def_id) = self.res { Some(def_id) } else { None }
140+
}
127141
}
128142

129143
/// The "header" of an impl is everything outside the body: a Self type, a trait

compiler/rustc_mir/src/monomorphize/collector.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,7 @@ struct RootCollector<'a, 'tcx> {
10661066
tcx: TyCtxt<'tcx>,
10671067
mode: MonoItemCollectionMode,
10681068
output: &'a mut Vec<Spanned<MonoItem<'tcx>>>,
1069-
entry_fn: Option<(LocalDefId, EntryFnType)>,
1069+
entry_fn: Option<(DefId, EntryFnType)>,
10701070
}
10711071

10721072
impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> {
@@ -1154,7 +1154,7 @@ impl RootCollector<'_, 'v> {
11541154
&& match self.mode {
11551155
MonoItemCollectionMode::Eager => true,
11561156
MonoItemCollectionMode::Lazy => {
1157-
self.entry_fn.map(|(id, _)| id) == Some(def_id)
1157+
self.entry_fn.and_then(|(id, _)| id.as_local()) == Some(def_id)
11581158
|| self.tcx.is_reachable_non_generic(def_id)
11591159
|| self
11601160
.tcx

compiler/rustc_passes/src/dead.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,9 @@ fn create_and_seed_worklist<'tcx>(
472472
)
473473
.chain(
474474
// Seed entry point
475-
tcx.entry_fn(LOCAL_CRATE).map(|(def_id, _)| tcx.hir().local_def_id_to_hir_id(def_id)),
475+
tcx.entry_fn(LOCAL_CRATE).and_then(|(def_id, _)| {
476+
def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
477+
}),
476478
)
477479
.collect::<Vec<_>>();
478480

compiler/rustc_passes/src/entry.rs

+28-23
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use rustc_ast::entry::EntryPointType;
22
use rustc_errors::struct_span_err;
3-
use rustc_hir::def_id::{CrateNum, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
3+
use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
44
use rustc_hir::itemlikevisit::ItemLikeVisitor;
55
use rustc_hir::{ForeignItem, HirId, ImplItem, Item, ItemKind, TraitItem, CRATE_HIR_ID};
66
use rustc_middle::hir::map::Map;
77
use rustc_middle::ty::query::Providers;
88
use rustc_middle::ty::TyCtxt;
99
use rustc_session::config::{CrateType, EntryFnType};
10+
use rustc_session::parse::feature_err;
1011
use rustc_session::Session;
1112
use rustc_span::symbol::sym;
1213
use rustc_span::{Span, DUMMY_SP};
@@ -16,9 +17,6 @@ struct EntryContext<'a, 'tcx> {
1617

1718
map: Map<'tcx>,
1819

19-
/// The top-level function called `main`.
20-
main_fn: Option<(HirId, Span)>,
21-
2220
/// The function that has attribute named `main`.
2321
attr_main_fn: Option<(HirId, Span)>,
2422

@@ -50,7 +48,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
5048
}
5149
}
5250

53-
fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)> {
51+
fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(DefId, EntryFnType)> {
5452
assert_eq!(cnum, LOCAL_CRATE);
5553

5654
let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable);
@@ -67,7 +65,6 @@ fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)
6765
let mut ctxt = EntryContext {
6866
session: tcx.sess,
6967
map: tcx.hir(),
70-
main_fn: None,
7168
attr_main_fn: None,
7269
start_fn: None,
7370
non_main_fns: Vec::new(),
@@ -115,14 +112,7 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
115112
throw_attr_err(&ctxt.session, attr.span, "rustc_main");
116113
}
117114
}
118-
EntryPointType::MainNamed => {
119-
if ctxt.main_fn.is_none() {
120-
ctxt.main_fn = Some((item.hir_id(), item.span));
121-
} else {
122-
struct_span_err!(ctxt.session, item.span, E0136, "multiple `main` functions")
123-
.emit();
124-
}
125-
}
115+
EntryPointType::MainNamed => (),
126116
EntryPointType::OtherMain => {
127117
ctxt.non_main_fns.push((item.hir_id(), item.span));
128118
}
@@ -154,16 +144,23 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
154144
}
155145
}
156146

157-
fn configure_main(
158-
tcx: TyCtxt<'_>,
159-
visitor: &EntryContext<'_, '_>,
160-
) -> Option<(LocalDefId, EntryFnType)> {
147+
fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(DefId, EntryFnType)> {
161148
if let Some((hir_id, _)) = visitor.start_fn {
162-
Some((tcx.hir().local_def_id(hir_id), EntryFnType::Start))
149+
Some((tcx.hir().local_def_id(hir_id).to_def_id(), EntryFnType::Start))
163150
} else if let Some((hir_id, _)) = visitor.attr_main_fn {
164-
Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main))
165-
} else if let Some((hir_id, _)) = visitor.main_fn {
166-
Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main))
151+
Some((tcx.hir().local_def_id(hir_id).to_def_id(), EntryFnType::Main))
152+
} else if let Some(def_id) = tcx.main_def.and_then(|main_def| main_def.opt_fn_def_id()) {
153+
if tcx.main_def.unwrap().is_import && !tcx.features().imported_main {
154+
let span = tcx.main_def.unwrap().span;
155+
feature_err(
156+
&tcx.sess.parse_sess,
157+
sym::imported_main,
158+
span,
159+
"using an imported function as entry point `main` is experimental",
160+
)
161+
.emit();
162+
}
163+
Some((def_id, EntryFnType::Main))
167164
} else {
168165
no_main_err(tcx, visitor);
169166
None
@@ -213,6 +210,14 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
213210
} else {
214211
err.note(&note);
215212
}
213+
214+
if let Some(main_def) = tcx.main_def {
215+
if main_def.opt_fn_def_id().is_none() {
216+
// There is something at `crate::main`, but it is not a function definition.
217+
err.span_label(main_def.span, &format!("non-function item at `crate::main` is found"));
218+
}
219+
}
220+
216221
if tcx.sess.teach(&err.get_code().unwrap()) {
217222
err.note(
218223
"If you don't know the basics of Rust, you can go look to the Rust Book \
@@ -222,7 +227,7 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
222227
err.emit();
223228
}
224229

225-
pub fn find_entry_point(tcx: TyCtxt<'_>) -> Option<(LocalDefId, EntryFnType)> {
230+
pub fn find_entry_point(tcx: TyCtxt<'_>) -> Option<(DefId, EntryFnType)> {
226231
tcx.entry_fn(LOCAL_CRATE)
227232
}
228233

0 commit comments

Comments
 (0)