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:
parent
6d721dd0b8
commit
1572c0dcd7
@ -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