Rollup merge of #124584 - Nilstrieb:entrypointy, r=fee1-dead
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.
This commit is contained in:
commit
9af1e8ce42
@ -4,11 +4,35 @@
|
||||
|
||||
#[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(
|
||||
|
@ -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;
|
||||
|
@ -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]`
|
||||
|
||||
|
@ -18,10 +18,10 @@
|
||||
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()
|
||||
{
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user