Skip to content

Commit

Permalink
Provide a span if main function is not present in crate
Browse files Browse the repository at this point in the history
Unfortunately, the diagnotic machinery does not cope well with an empty
span which can happen if the crate is empty, in which case we merely set
a spanless note.
  • Loading branch information
Mark-Simulacrum committed Sep 12, 2019
1 parent 74d5c70 commit 6dc1483
Show file tree
Hide file tree
Showing 41 changed files with 167 additions and 125 deletions.
74 changes: 44 additions & 30 deletions src/librustc/middle/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ struct EntryContext<'a, 'tcx> {

map: &'a hir_map::Map<'tcx>,

/// The top-level function called 'main'.
/// The top-level function called `main`.
main_fn: Option<(HirId, Span)>,

/// The function that has attribute named 'main'.
/// The function that has attribute named `main`.
attr_main_fn: Option<(HirId, Span)>,

/// The function that has the attribute 'start' on it.
start_fn: Option<(HirId, 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.
/// main functions not defined at the top level. For diagnostics.
non_main_fns: Vec<(HirId, Span)> ,
}
Expand Down Expand Up @@ -88,7 +88,7 @@ fn entry_point_type(item: &Item, at_root: bool) -> EntryPointType {
EntryPointType::MainAttr
} else if item.ident.name == sym::main {
if at_root {
// This is a top-level function so can be 'main'.
// This is a top-level function so can be `main`.
EntryPointType::MainNamed
} else {
EntryPointType::OtherMain
Expand All @@ -109,7 +109,7 @@ fn find_item(item: &Item, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
ctxt.main_fn = Some((item.hir_id, item.span));
} else {
span_err!(ctxt.session, item.span, E0136,
"multiple 'main' functions");
"multiple `main` functions");
}
},
EntryPointType::OtherMain => {
Expand All @@ -130,7 +130,7 @@ fn find_item(item: &Item, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
if ctxt.start_fn.is_none() {
ctxt.start_fn = Some((item.hir_id, item.span));
} else {
struct_span_err!(ctxt.session, item.span, E0138, "multiple 'start' functions")
struct_span_err!(ctxt.session, item.span, E0138, "multiple `start` functions")
.span_label(ctxt.start_fn.unwrap().1, "previous `start` function here")
.span_label(item.span, "multiple `start` functions")
.emit();
Expand All @@ -148,34 +148,48 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(De
} else if let Some((hir_id, _)) = visitor.main_fn {
Some((tcx.hir().local_def_id(hir_id), EntryFnType::Main))
} else {
// There is no main function.
let mut err = struct_err!(tcx.sess, E0601,
"`main` function not found in crate `{}`", tcx.crate_name(LOCAL_CRATE));
if !visitor.non_main_fns.is_empty() {
// There were some functions named 'main' though. Try to give the user a hint.
err.note("the main function must be defined at the crate level \
but you have one or more functions named 'main' that are not \
defined at the crate level. Either move the definition or \
attach the `#[main]` attribute to override this behavior.");
for &(_, span) in &visitor.non_main_fns {
err.span_note(span, "here is a function named 'main'");
}
err.emit();
} else {
if let Some(ref filename) = tcx.sess.local_crate_source_file {
err.note(&format!("consider adding a `main` function to `{}`", filename.display()));
}
if tcx.sess.teach(&err.get_code().unwrap()) {
err.note("If you don't know the basics of Rust, you can go look to the Rust Book \
to get started: https://doc.rust-lang.org/book/");
}
err.emit();
}

no_main_err(tcx, visitor);
None
}
}

fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
// There is no main function.
let mut err = struct_err!(tcx.sess, E0601,
"`main` function not found in crate `{}`", tcx.crate_name(LOCAL_CRATE));
let filename = &tcx.sess.local_crate_source_file;
let note = if !visitor.non_main_fns.is_empty() {
for &(_, span) in &visitor.non_main_fns {
err.span_note(span, "here is a function named `main`");
}
err.note("you have one or more functions named `main` not defined at the crate level");
err.help("either move the `main` function definitions or attach the `#[main]` attribute \
to one of them");
// There were some functions named `main` though. Try to give the user a hint.
format!("the main function must be defined at the crate level{}",
filename.as_ref().map(|f| format!(" (in `{}`)", f.display())).unwrap_or_default())
} else if let Some(filename) = filename {
format!("consider adding a `main` function to `{}`", filename.display())
} else {
String::from("consider adding a `main` function at the crate level")
};
let sp = tcx.hir().krate().span;
// The file may be empty, which leads to the diagnostic machinery not emitting this
// note. This is a relatively simple way to detect that case and emit a span-less
// note instead.
if let Ok(_) = tcx.sess.source_map().lookup_line(sp.lo()) {
err.set_span(sp);
err.span_label(sp, &note);
} else {
err.note(&note);
}
if tcx.sess.teach(&err.get_code().unwrap()) {
err.note("If you don't know the basics of Rust, you can go look to the Rust Book \
to get started: https://doc.rust-lang.org/book/");
}
err.emit();
}

pub fn find_entry_point(tcx: TyCtxt<'_>) -> Option<(DefId, EntryFnType)> {
tcx.entry_fn(LOCAL_CRATE)
}
Expand Down
2 changes: 2 additions & 0 deletions src/test/ui-fulldeps/hash-stable-is-unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ use rustc_macros::HashStable;
#[derive(HashStable)]
//~^ use of unstable library feature 'rustc_private'
struct Test;

fn main() {}
9 changes: 2 additions & 7 deletions src/test/ui-fulldeps/hash-stable-is-unstable.stderr
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
error[E0601]: `main` function not found in crate `hash_stable_is_unstable`
|
= note: consider adding a `main` function to `$DIR/hash-stable-is-unstable.rs`

error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
--> $DIR/hash-stable-is-unstable.rs:3:1
|
Expand Down Expand Up @@ -47,7 +43,6 @@ LL | #[derive(HashStable)]
= note: for more information, see https://github.com/rust-lang/rust/issues/27812
= help: add `#![feature(rustc_private)]` to the crate attributes to enable

error: aborting due to 6 previous errors
error: aborting due to 5 previous errors

Some errors have detailed explanations: E0601, E0658.
For more information about an error, try `rustc --explain E0601`.
For more information about this error, try `rustc --explain E0658`.
2 changes: 2 additions & 0 deletions src/test/ui/associated-type-bounds/inside-adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ union U2 { f: Box<dyn Iterator<Item: Copy>> }
union U3 { f: dyn Iterator<Item: 'static> }
//~^ ERROR associated type bounds are not allowed within structs, enums, or unions
//~| ERROR could not find defining uses

fn main() {}
7 changes: 1 addition & 6 deletions src/test/ui/associated-type-bounds/inside-adt.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,6 @@ error: associated type bounds are not allowed within structs, enums, or unions
LL | union U3 { f: dyn Iterator<Item: 'static> }
| ^^^^^^^^^^^^^

error[E0601]: `main` function not found in crate `inside_adt`
|
= note: consider adding a `main` function to `$DIR/inside-adt.rs`

error: could not find defining uses
--> $DIR/inside-adt.rs:5:29
|
Expand Down Expand Up @@ -110,6 +106,5 @@ error: could not find defining uses
LL | union U3 { f: dyn Iterator<Item: 'static> }
| ^^^^^^^^^^^^^

error: aborting due to 19 previous errors
error: aborting due to 18 previous errors

For more information about this error, try `rustc --explain E0601`.
5 changes: 4 additions & 1 deletion src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
error[E0601]: `main` function not found in crate `cfg_attr_cfg_2`
--> $DIR/cfg-attr-cfg-2.rs:8:1
|
= note: consider adding a `main` function to `$DIR/cfg-attr-cfg-2.rs`
LL | / #[cfg_attr(foo, cfg(bar))]
LL | | fn main() { }
| |_____________^ consider adding a `main` function to `$DIR/cfg-attr-cfg-2.rs`

error: aborting due to previous error

Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/conditional-compilation/cfg-in-crate-1.stderr
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
error[E0601]: `main` function not found in crate `cfg_in_crate_1`
--> $DIR/cfg-in-crate-1.rs:3:1
|
= note: consider adding a `main` function to `$DIR/cfg-in-crate-1.rs`
LL | #![cfg(bar)]
| ^^^^^^^^^^^^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs`

error: aborting due to previous error

Expand Down
10 changes: 9 additions & 1 deletion src/test/ui/continue-after-missing-main.stderr
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
error[E0601]: `main` function not found in crate `continue_after_missing_main`
--> $DIR/continue-after-missing-main.rs:1:1
|
= note: consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
LL | / #![allow(dead_code)]
LL | |
LL | | // error-pattern:`main` function not found in crate
LL | |
... |
LL | |
LL | | }
| |_^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`

error[E0623]: lifetime mismatch
--> $DIR/continue-after-missing-main.rs:30:56
Expand Down
6 changes: 5 additions & 1 deletion src/test/ui/elided-test.stderr
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
error[E0601]: `main` function not found in crate `elided_test`
--> $DIR/elided-test.rs:5:1
|
= note: consider adding a `main` function to `$DIR/elided-test.rs`
LL | / #[test]
LL | | fn main() {
LL | | }
| |_^ consider adding a `main` function to `$DIR/elided-test.rs`

error: aborting due to previous error

Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/error-codes/E0138.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0138]: multiple 'start' functions
error[E0138]: multiple `start` functions
--> $DIR/E0138.rs:7:1
|
LL | fn foo(argc: isize, argv: *const *const u8) -> isize { 0 }
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/error-codes/E0601.rs
Original file line number Diff line number Diff line change
@@ -1 +1 @@
// Test for main function not found.
//~ ERROR `main` function not found
4 changes: 3 additions & 1 deletion src/test/ui/error-codes/E0601.stderr
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
error[E0601]: `main` function not found in crate `E0601`
--> $DIR/E0601.rs:1:37
|
= note: consider adding a `main` function to `$DIR/E0601.rs`
LL |
| ^ consider adding a `main` function to `$DIR/E0601.rs`

error: aborting due to previous error

Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/issues/issue-46101.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
trait Foo {}
#[derive(Foo::Anything)] //~ ERROR failed to resolve: partially resolved path in a derive macro
struct S;

fn main() {}
9 changes: 2 additions & 7 deletions src/test/ui/issues/issue-46101.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@ error[E0433]: failed to resolve: partially resolved path in a derive macro
LL | #[derive(Foo::Anything)]
| ^^^^^^^^^^^^^ partially resolved path in a derive macro

error[E0601]: `main` function not found in crate `issue_46101`
|
= note: consider adding a `main` function to `$DIR/issue-46101.rs`

error: aborting due to 2 previous errors
error: aborting due to previous error

Some errors have detailed explanations: E0433, E0601.
For more information about an error, try `rustc --explain E0433`.
For more information about this error, try `rustc --explain E0433`.
1 change: 1 addition & 0 deletions src/test/ui/issues/issue-49040.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
#![allow(unused_variables)]; //~ ERROR expected item, found `;`
//~^ ERROR `main` function
fn foo() {}
6 changes: 5 additions & 1 deletion src/test/ui/issues/issue-49040.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ LL | #![allow(unused_variables)];
| ^ help: remove this semicolon

error[E0601]: `main` function not found in crate `issue_49040`
--> $DIR/issue-49040.rs:1:1
|
= note: consider adding a `main` function to `$DIR/issue-49040.rs`
LL | / #![allow(unused_variables)];
LL | |
LL | | fn foo() {}
| |__^ consider adding a `main` function to `$DIR/issue-49040.rs`

error: aborting due to 2 previous errors

Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/issues/issue-60057.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ impl A {
}
}
}

fn main() {}
9 changes: 2 additions & 7 deletions src/test/ui/issues/issue-60057.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ error[E0425]: cannot find value `banana` in this scope
LL | banana: banana
| ^^^^^^ help: you might have meant to use the available field: `self.banana`

error[E0601]: `main` function not found in crate `issue_60057`
|
= note: consider adding a `main` function to `$DIR/issue-60057.rs`

error: aborting due to 3 previous errors
error: aborting due to 2 previous errors

Some errors have detailed explanations: E0425, E0601.
For more information about an error, try `rustc --explain E0425`.
For more information about this error, try `rustc --explain E0425`.
2 changes: 1 addition & 1 deletion src/test/ui/json-short.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn main() {

If you don't know the basics of Rust, you can go look to the Rust Book to get
started: https://doc.rust-lang.org/book/
"},"level":"error","spans":[],"children":[{"message":"consider adding a `main` function to `$DIR/json-short.rs`","code":null,"level":"note","spans":[],"children":[],"rendered":null}],"rendered":"error[E0601]: `main` function not found in crate `json_short`
"},"level":"error","spans":[{"file_name":"$DIR/json-short.rs","byte_start":76,"byte_end":76,"line_start":2,"line_end":2,"column_start":63,"column_end":63,"is_primary":true,"text":[{"text":"// compile-flags: --json=diagnostic-short --error-format=json","highlight_start":63,"highlight_end":63}],"label":"consider adding a `main` function to `$DIR/json-short.rs`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-short.rs:2:63: error[E0601]: `main` function not found in crate `json_short`
"}
{"message":"aborting due to previous error","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to previous error
"}
Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/lifetime-before-type-params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ fn third<T, U, 'a>() {}
//~^ ERROR lifetime parameters must be declared prior to type parameters
fn fourth<'a, T, 'b, U, 'c, V>() {}
//~^ ERROR lifetime parameters must be declared prior to type parameters

fn main() {}
7 changes: 1 addition & 6 deletions src/test/ui/lifetime-before-type-params.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,5 @@ error: lifetime parameters must be declared prior to type parameters
LL | fn fourth<'a, T, 'b, U, 'c, V>() {}
| --------^^-----^^---- help: reorder the parameters: lifetimes, then types: `<'a, 'b, 'c, T, U, V>`

error[E0601]: `main` function not found in crate `lifetime_before_type_params`
|
= note: consider adding a `main` function to `$DIR/lifetime-before-type-params.rs`

error: aborting due to 5 previous errors
error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0601`.
1 change: 1 addition & 0 deletions src/test/ui/main-wrong-location.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod m {
//~^ ERROR `main` function not found
// An inferred main entry point (that doesn't use #[main])
// must appear at the top of the crate
fn main() { }
Expand Down
16 changes: 13 additions & 3 deletions src/test/ui/main-wrong-location.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
error[E0601]: `main` function not found in crate `main_wrong_location`
--> $DIR/main-wrong-location.rs:1:1
|
= note: the main function must be defined at the crate level but you have one or more functions named 'main' that are not defined at the crate level. Either move the definition or attach the `#[main]` attribute to override this behavior.
note: here is a function named 'main'
--> $DIR/main-wrong-location.rs:4:5
LL | / mod m {
LL | |
LL | | // An inferred main entry point (that doesn't use #[main])
LL | | // must appear at the top of the crate
LL | | fn main() { }
LL | | }
| |_^ the main function must be defined at the crate level (in `$DIR/main-wrong-location.rs`)
|
note: here is a function named `main`
--> $DIR/main-wrong-location.rs:5:5
|
LL | fn main() { }
| ^^^^^^^^^^^^^
= note: you have one or more functions named `main` not defined at the crate level
= help: either move the `main` function definitions or attach the `#[main]` attribute to one of them

error: aborting due to previous error

Expand Down
4 changes: 3 additions & 1 deletion src/test/ui/missing/missing-main.stderr
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
error[E0601]: `main` function not found in crate `missing_main`
--> $DIR/missing-main.rs:2:1
|
= note: consider adding a `main` function to `$DIR/missing-main.rs`
LL | fn mian() { }
| ^^^^^^^^^^^^^ consider adding a `main` function to `$DIR/missing-main.rs`

error: aborting due to previous error

Expand Down
1 change: 1 addition & 0 deletions src/test/ui/parser-recovery-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// Test that we can recover from missing braces in the parser.

trait Foo {
//~^ ERROR `main` function not found
fn bar() {
let x = foo();
//~^ ERROR cannot find function `foo` in this scope
Expand Down
Loading

0 comments on commit 6dc1483

Please sign in to comment.