mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
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 @@ use rustc_span::Symbol;
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum EntryPointType {
|
pub enum EntryPointType {
|
||||||
|
/// This function is not an entrypoint.
|
||||||
None,
|
None,
|
||||||
|
/// This is a function called `main` at the root level.
|
||||||
|
/// ```
|
||||||
|
/// fn main() {}
|
||||||
|
/// ```
|
||||||
MainNamed,
|
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,
|
RustcMainAttr,
|
||||||
|
/// This is a function with the `#[start]` attribute.
|
||||||
|
/// ```ignore (clashes with test entrypoint)
|
||||||
|
/// #[start]
|
||||||
|
/// fn main() {}
|
||||||
|
/// ```
|
||||||
Start,
|
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(
|
pub fn entry_point_type(
|
||||||
|
@ -266,7 +266,7 @@ fn generate_test_harness(
|
|||||||
///
|
///
|
||||||
/// By default this expands to
|
/// 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]
|
/// #[rustc_main]
|
||||||
/// pub fn main() {
|
/// pub fn main() {
|
||||||
/// extern crate test;
|
/// extern crate test;
|
||||||
|
@ -49,12 +49,6 @@ passes_attr_crate_level =
|
|||||||
passes_attr_only_in_functions =
|
passes_attr_only_in_functions =
|
||||||
`{$attr}` attribute can only be used on 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 =
|
passes_both_ffi_const_and_pure =
|
||||||
`#[ffi_const]` function cannot be `#[ffi_pure]`
|
`#[ffi_const]` function cannot be `#[ffi_pure]`
|
||||||
|
|
||||||
|
@ -18,10 +18,10 @@ use crate::errors::{
|
|||||||
struct EntryContext<'tcx> {
|
struct EntryContext<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
|
||||||
/// The function that has attribute named `main`.
|
/// The function has the `#[rustc_main]` attribute.
|
||||||
attr_main_fn: Option<(LocalDefId, Span)>,
|
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)>,
|
start_fn: Option<(LocalDefId, Span)>,
|
||||||
|
|
||||||
/// The functions that one might think are `main` but aren't, e.g.
|
/// 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 =
|
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() {
|
for id in tcx.hir().items() {
|
||||||
find_item(id, &mut ctxt);
|
check_and_search_item(id, &mut ctxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
configure_main(tcx, &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)
|
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 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());
|
let attrs = ctxt.tcx.hir().attrs(id.hir_id());
|
||||||
@ -65,26 +74,20 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
|
|||||||
at_root,
|
at_root,
|
||||||
ctxt.tcx.opt_item_name(id.owner_id.to_def_id()),
|
ctxt.tcx.opt_item_name(id.owner_id.to_def_id()),
|
||||||
);
|
);
|
||||||
|
|
||||||
match entry_point_type {
|
match entry_point_type {
|
||||||
EntryPointType::None => (),
|
EntryPointType::None => {}
|
||||||
_ if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) => {
|
EntryPointType::MainNamed => {}
|
||||||
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::OtherMain => {
|
EntryPointType::OtherMain => {
|
||||||
ctxt.non_main_fns.push(ctxt.tcx.def_span(id.owner_id));
|
ctxt.non_main_fns.push(ctxt.tcx.def_span(id.owner_id));
|
||||||
}
|
}
|
||||||
EntryPointType::RustcMainAttr => {
|
EntryPointType::RustcMainAttr => {
|
||||||
if ctxt.attr_main_fn.is_none() {
|
if ctxt.rustc_main_fn.is_none() {
|
||||||
ctxt.attr_main_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
|
ctxt.rustc_main_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
|
||||||
} else {
|
} else {
|
||||||
ctxt.tcx.dcx().emit_err(MultipleRustcMain {
|
ctxt.tcx.dcx().emit_err(MultipleRustcMain {
|
||||||
span: ctxt.tcx.def_span(id.owner_id.to_def_id()),
|
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()),
|
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)> {
|
fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> {
|
||||||
if let Some((def_id, _)) = visitor.start_fn {
|
if let Some((def_id, _)) = visitor.start_fn {
|
||||||
Some((def_id.to_def_id(), EntryFnType::Start))
|
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();
|
let def_id = local_def_id.to_def_id();
|
||||||
Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) }))
|
Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) }))
|
||||||
} else {
|
} else {
|
||||||
|
// The actual resolution of main happens in the resolver, this here
|
||||||
if let Some(main_def) = tcx.resolutions(()).main_def
|
if let Some(main_def) = tcx.resolutions(()).main_def
|
||||||
&& let Some(def_id) = main_def.opt_fn_def_id()
|
&& let Some(def_id) = main_def.opt_fn_def_id()
|
||||||
{
|
{
|
||||||
|
@ -1206,22 +1206,6 @@ pub struct NakedFunctionsMustUseNoreturn {
|
|||||||
pub last_span: Span,
|
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)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(passes_attr_only_in_functions)]
|
#[diag(passes_attr_only_in_functions)]
|
||||||
pub struct AttrOnlyInFunctions {
|
pub struct AttrOnlyInFunctions {
|
||||||
|
Loading…
Reference in New Issue
Block a user