From 1572c0dcd7b5d9e4fcd400d3b34f1d675201f150 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 1 May 2024 17:37:22 +0200 Subject: [PATCH] Various improvements to entrypoint code This moves some code around and adds some documentation comments to make it easier to understand what's going on with the entrypoint logic, which is a bit complicated. The only change in behavior is consolidating the error messages for unix_sigpipe to make the code slightly simpler. --- compiler/rustc_ast/src/entry.rs | 26 +++++++++++- .../rustc_builtin_macros/src/test_harness.rs | 2 +- compiler/rustc_passes/messages.ftl | 6 --- compiler/rustc_passes/src/entry.rs | 42 ++++++++++--------- compiler/rustc_passes/src/errors.rs | 16 ------- 5 files changed, 49 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs index cd8a5a6692000..dd231e286d591 100644 --- a/compiler/rustc_ast/src/entry.rs +++ b/compiler/rustc_ast/src/entry.rs @@ -4,11 +4,35 @@ use rustc_span::Symbol; #[derive(Debug)] pub enum EntryPointType { + /// This function is not an entrypoint. None, + /// This is a function called `main` at the root level. + /// ``` + /// fn main() {} + /// ``` MainNamed, + /// This is a function with the `#[rustc_main]` attribute. + /// Used by the testing harness to create the test entrypoint. + /// ```ignore (clashes with test entrypoint) + /// #[rustc_main] + /// fn main() {} + /// ``` RustcMainAttr, + /// This is a function with the `#[start]` attribute. + /// ```ignore (clashes with test entrypoint) + /// #[start] + /// fn main() {} + /// ``` Start, - OtherMain, // Not an entry point, but some other function named main + /// This function is **not** an entrypoint but simply named `main` (not at the root). + /// This is only used for diagnostics. + /// ``` + /// #[allow(dead_code)] + /// mod meow { + /// fn main() {} + /// } + /// ``` + OtherMain, } pub fn entry_point_type( diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index a2015445b42c9..8cf431482ff73 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -266,7 +266,7 @@ fn generate_test_harness( /// /// By default this expands to /// -/// ```ignore UNSOLVED (I think I still need guidance for this one. Is it correct? Do we try to make it run? How do we nicely fill it out?) +/// ```ignore (messes with test internals) /// #[rustc_main] /// pub fn main() { /// extern crate test; diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 8878310d6e93f..9d58d301e2bc2 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -49,12 +49,6 @@ passes_attr_crate_level = passes_attr_only_in_functions = `{$attr}` attribute can only be used on functions -passes_attr_only_on_main = - `{$attr}` attribute can only be used on `fn main()` - -passes_attr_only_on_root_main = - `{$attr}` attribute can only be used on root `fn main()` - passes_both_ffi_const_and_pure = `#[ffi_const]` function cannot be `#[ffi_pure]` diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index d52092f2aa92a..b43c8282db1db 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -18,10 +18,10 @@ use crate::errors::{ struct EntryContext<'tcx> { tcx: TyCtxt<'tcx>, - /// The function that has attribute named `main`. - attr_main_fn: Option<(LocalDefId, Span)>, + /// The function has the `#[rustc_main]` attribute. + rustc_main_fn: Option<(LocalDefId, Span)>, - /// The function that has the attribute 'start' on it. + /// The function that has the attribute `#[start]` on it. start_fn: Option<(LocalDefId, Span)>, /// The functions that one might think are `main` but aren't, e.g. @@ -42,10 +42,10 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { } let mut ctxt = - EntryContext { tcx, attr_main_fn: None, start_fn: None, non_main_fns: Vec::new() }; + EntryContext { tcx, rustc_main_fn: None, start_fn: None, non_main_fns: Vec::new() }; for id in tcx.hir().items() { - find_item(id, &mut ctxt); + check_and_search_item(id, &mut ctxt); } configure_main(tcx, &ctxt) @@ -56,7 +56,16 @@ fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Opti attr::find_by_name(attrs, sym).map(|attr| attr.span) } -fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { +fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) { + if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) { + for attr in [sym::start, sym::rustc_main] { + if let Some(span) = attr_span_by_symbol(ctxt, id, attr) { + ctxt.tcx.dcx().emit_err(AttrOnlyInFunctions { span, attr }); + } + } + return; + } + let at_root = ctxt.tcx.opt_local_parent(id.owner_id.def_id) == Some(CRATE_DEF_ID); let attrs = ctxt.tcx.hir().attrs(id.hir_id()); @@ -65,26 +74,20 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { at_root, ctxt.tcx.opt_item_name(id.owner_id.to_def_id()), ); + match entry_point_type { - EntryPointType::None => (), - _ if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) => { - for attr in [sym::start, sym::rustc_main] { - if let Some(span) = attr_span_by_symbol(ctxt, id, attr) { - ctxt.tcx.dcx().emit_err(AttrOnlyInFunctions { span, attr }); - } - } - } - EntryPointType::MainNamed => (), + EntryPointType::None => {} + EntryPointType::MainNamed => {} EntryPointType::OtherMain => { ctxt.non_main_fns.push(ctxt.tcx.def_span(id.owner_id)); } EntryPointType::RustcMainAttr => { - if ctxt.attr_main_fn.is_none() { - ctxt.attr_main_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id))); + if ctxt.rustc_main_fn.is_none() { + ctxt.rustc_main_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id))); } else { ctxt.tcx.dcx().emit_err(MultipleRustcMain { span: ctxt.tcx.def_span(id.owner_id.to_def_id()), - first: ctxt.attr_main_fn.unwrap().1, + first: ctxt.rustc_main_fn.unwrap().1, additional: ctxt.tcx.def_span(id.owner_id.to_def_id()), }); } @@ -107,10 +110,11 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) { fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> { if let Some((def_id, _)) = visitor.start_fn { Some((def_id.to_def_id(), EntryFnType::Start)) - } else if let Some((local_def_id, _)) = visitor.attr_main_fn { + } else if let Some((local_def_id, _)) = visitor.rustc_main_fn { let def_id = local_def_id.to_def_id(); Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) })) } else { + // The actual resolution of main happens in the resolver, this here if let Some(main_def) = tcx.resolutions(()).main_def && let Some(def_id) = main_def.opt_fn_def_id() { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 743faf5456078..65cad82cc8c2b 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1206,22 +1206,6 @@ pub struct NakedFunctionsMustUseNoreturn { pub last_span: Span, } -#[derive(Diagnostic)] -#[diag(passes_attr_only_on_main)] -pub struct AttrOnlyOnMain { - #[primary_span] - pub span: Span, - pub attr: Symbol, -} - -#[derive(Diagnostic)] -#[diag(passes_attr_only_on_root_main)] -pub struct AttrOnlyOnRootMain { - #[primary_span] - pub span: Span, - pub attr: Symbol, -} - #[derive(Diagnostic)] #[diag(passes_attr_only_in_functions)] pub struct AttrOnlyInFunctions {