Skip to content

Commit

Permalink
Various improvements to entrypoint code
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Noratrieb committed May 1, 2024
1 parent 61a1dbd commit dfa695f
Show file tree
Hide file tree
Showing 13 changed files with 66 additions and 53 deletions.
25 changes: 24 additions & 1 deletion compiler/rustc_ast/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,34 @@ 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.
/// ```
/// mod meow {
/// fn main() {}
/// }
/// ```
OtherMain,
}

pub fn entry_point_type(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/test_harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 1 addition & 4 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,7 @@ 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()`
`{$attr}` attribute can only be used on the root `fn main()`
passes_both_ffi_const_and_pure =
`#[ffi_const]` function cannot be `#[ffi_pure]`
Expand Down
63 changes: 32 additions & 31 deletions compiler/rustc_passes/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};

use crate::errors::{
AttrOnlyInFunctions, AttrOnlyOnMain, AttrOnlyOnRootMain, ExternMain, MultipleRustcMain,
MultipleStartFunctions, NoMainErr, UnixSigpipeValues,
AttrOnlyInFunctions, AttrOnlyOnMain, ExternMain, MultipleRustcMain, MultipleStartFunctions,
NoMainErr, UnixSigpipeValues,
};

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.
Expand All @@ -43,10 +43,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)
Expand All @@ -57,7 +57,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());
Expand All @@ -66,41 +75,32 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
at_root,
ctxt.tcx.opt_item_name(id.owner_id.to_def_id()),
);

if let EntryPointType::None | EntryPointType::OtherMain | EntryPointType::Start =
entry_point_type
&& let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe)
{
ctxt.tcx.dcx().emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
}

match entry_point_type {
EntryPointType::None => {
if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
ctxt.tcx.dcx().emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
}
}
_ 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 => {
if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
ctxt.tcx.dcx().emit_err(AttrOnlyOnRootMain { span, attr: sym::unix_sigpipe });
}
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()),
});
}
}
EntryPointType::Start => {
if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
ctxt.tcx.dcx().emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
}
if ctxt.start_fn.is_none() {
ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
} else {
Expand All @@ -118,10 +118,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, def_id) }))
} 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()
{
Expand Down
8 changes: 0 additions & 8 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1214,14 +1214,6 @@ pub struct AttrOnlyOnMain {
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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![feature(unix_sigpipe)]

#[unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
#[unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute can only be used on the root `fn main()`
fn f() {}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: `unix_sigpipe` attribute can only be used on `fn main()`
error: `unix_sigpipe` attribute can only be used on the root `fn main()`
--> $DIR/unix_sigpipe-non-main-fn.rs:3:1
|
LL | #[unix_sigpipe = "sig_dfl"]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![feature(unix_sigpipe)]

mod m {
#[unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute can only be used on root `fn main()`
#[unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute can only be used on the root `fn main()`
fn main() {}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: `unix_sigpipe` attribute can only be used on root `fn main()`
error: `unix_sigpipe` attribute can only be used on the root `fn main()`
--> $DIR/unix_sigpipe-non-root-main.rs:4:5
|
LL | #[unix_sigpipe = "sig_dfl"]
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/attributes/unix_sigpipe/unix_sigpipe-start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
#![feature(unix_sigpipe)]

#[start]
#[unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
#[unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute can only be used on the root `fn main()`
fn custom_start(argc: isize, argv: *const *const u8) -> isize { 0 }
2 changes: 1 addition & 1 deletion tests/ui/attributes/unix_sigpipe/unix_sigpipe-start.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: `unix_sigpipe` attribute can only be used on `fn main()`
error: `unix_sigpipe` attribute can only be used on the root `fn main()`
--> $DIR/unix_sigpipe-start.rs:5:1
|
LL | #[unix_sigpipe = "sig_dfl"]
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/attributes/unix_sigpipe/unix_sigpipe-struct.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![feature(unix_sigpipe)]

#[unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute can only be used on `fn main()`
#[unix_sigpipe = "sig_dfl"] //~ error: `unix_sigpipe` attribute can only be used on the root `fn main()`
struct S;

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: `unix_sigpipe` attribute can only be used on `fn main()`
error: `unix_sigpipe` attribute can only be used on the root `fn main()`
--> $DIR/unix_sigpipe-struct.rs:3:1
|
LL | #[unix_sigpipe = "sig_dfl"]
Expand Down

0 comments on commit dfa695f

Please sign in to comment.