From 973275268ed9abfe554e6e3f2f83cd77c94c76ba Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sun, 15 Nov 2020 20:40:17 -0500 Subject: [PATCH] overhaul "missing main" diagnostic --- compiler/rustc_passes/src/entry.rs | 48 +++++++------------ .../cfg-attr-cfg-2.stderr | 10 ++-- .../cfg-in-crate-1.stderr | 7 ++- .../ui/continue-after-missing-main.stderr | 13 ++--- src/test/ui/elided-test.stderr | 11 +++-- src/test/ui/error-codes/E0601.stderr | 7 ++- src/test/ui/issues/issue-49040.stderr | 9 ++-- src/test/ui/json-short.stderr | 3 +- src/test/ui/main-wrong-location.stderr | 17 ++----- src/test/ui/missing/missing-main.stderr | 7 ++- .../issue-59191-replace-root-with-fn.stderr | 11 +++-- 11 files changed, 70 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index e87adb378e7f7..c75f0809a2616 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -1,5 +1,5 @@ use rustc_ast::entry::EntryPointType; -use rustc_errors::struct_span_err; +use rustc_errors::{struct_span_err, Applicability}; use rustc_hir::def_id::{CrateNum, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{HirId, ImplItem, Item, ItemKind, TraitItem}; @@ -9,7 +9,7 @@ use rustc_middle::ty::TyCtxt; use rustc_session::config::{CrateType, EntryFnType}; use rustc_session::Session; use rustc_span::symbol::sym; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{MultiSpan, Span}; struct EntryContext<'a, 'tcx> { session: &'a Session, @@ -174,49 +174,33 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) { return; } - // There is no main function. let mut err = struct_span_err!( tcx.sess, - DUMMY_SP, + sp.shrink_to_lo(), 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") - }; - // 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 tcx.sess.source_map().lookup_line(sp.lo()).is_ok() { - err.set_span(sp); - err.span_label(sp, ¬e); - } else { - err.note(¬e); + + if !visitor.non_main_fns.is_empty() { + let span = MultiSpan::from_spans(visitor.non_main_fns.iter().map(|(_, sp)| *sp).collect()); + err.span_help(span, "consider moving one of these function definitions to the crate root"); } + + err.span_suggestion( + sp.shrink_to_lo(), + "define a function named `main` at the crate root", + String::from("fn main() {}\n"), + Applicability::MaybeIncorrect, + ); + 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(); } diff --git a/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr index e9df780def5df..95a70e17b812f 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-cfg-2.stderr @@ -1,9 +1,13 @@ error[E0601]: `main` function not found in crate `cfg_attr_cfg_2` --> $DIR/cfg-attr-cfg-2.rs:8:1 | -LL | / #[cfg_attr(foo, cfg(bar))] -LL | | fn main() { } - | |_____________^ consider adding a `main` function to `$DIR/cfg-attr-cfg-2.rs` +LL | #[cfg_attr(foo, cfg(bar))] + | ^ + | +help: define a function named `main` at the crate root + | +LL | fn main() {} + | error: aborting due to previous error diff --git a/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr b/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr index 0b5c3e0335586..2eaaf778b6b33 100644 --- a/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr +++ b/src/test/ui/conditional-compilation/cfg-in-crate-1.stderr @@ -2,7 +2,12 @@ error[E0601]: `main` function not found in crate `cfg_in_crate_1` --> $DIR/cfg-in-crate-1.rs:3:1 | LL | #![cfg(bar)] - | ^^^^^^^^^^^^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs` + | ^ + | +help: define a function named `main` at the crate root + | +LL | fn main() {} + | error: aborting due to previous error diff --git a/src/test/ui/continue-after-missing-main.stderr b/src/test/ui/continue-after-missing-main.stderr index 439f9e5221f66..06ea6bd9682d5 100644 --- a/src/test/ui/continue-after-missing-main.stderr +++ b/src/test/ui/continue-after-missing-main.stderr @@ -1,14 +1,9 @@ error[E0601]: `main` function not found in crate `continue_after_missing_main` - --> $DIR/continue-after-missing-main.rs:1:1 | -LL | / #![allow(dead_code)] -LL | | -LL | | struct Tableau<'a, MP> { -LL | | provider: &'a MP, -... | -LL | | -LL | | } - | |_^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs` +help: define a function named `main` at the crate root + | +LL | fn main() {} + | error[E0623]: lifetime mismatch --> $DIR/continue-after-missing-main.rs:28:56 diff --git a/src/test/ui/elided-test.stderr b/src/test/ui/elided-test.stderr index 175bd033067bc..1e869b6dd43ff 100644 --- a/src/test/ui/elided-test.stderr +++ b/src/test/ui/elided-test.stderr @@ -1,10 +1,13 @@ error[E0601]: `main` function not found in crate `elided_test` --> $DIR/elided-test.rs:5:1 | -LL | / #[test] -LL | | fn main() { -LL | | } - | |_^ consider adding a `main` function to `$DIR/elided-test.rs` +LL | #[test] + | ^ + | +help: define a function named `main` at the crate root + | +LL | fn main() {} + | error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0601.stderr b/src/test/ui/error-codes/E0601.stderr index a687f575615d7..870580c68d460 100644 --- a/src/test/ui/error-codes/E0601.stderr +++ b/src/test/ui/error-codes/E0601.stderr @@ -2,7 +2,12 @@ error[E0601]: `main` function not found in crate `E0601` --> $DIR/E0601.rs:1:37 | LL | - | ^ consider adding a `main` function to `$DIR/E0601.rs` + | ^ + | +help: define a function named `main` at the crate root + | +LL | + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-49040.stderr b/src/test/ui/issues/issue-49040.stderr index 4134d6aa54468..31aa3a39469e7 100644 --- a/src/test/ui/issues/issue-49040.stderr +++ b/src/test/ui/issues/issue-49040.stderr @@ -5,12 +5,11 @@ LL | #![allow(unused_variables)]; | ^ help: remove this semicolon error[E0601]: `main` function not found in crate `issue_49040` - --> $DIR/issue-49040.rs:1:1 | -LL | / #![allow(unused_variables)]; -LL | | -LL | | fn foo() {} - | |__^ consider adding a `main` function to `$DIR/issue-49040.rs` +help: define a function named `main` at the crate root + | +LL | fn main() {} + | error: aborting due to 2 previous errors diff --git a/src/test/ui/json-short.stderr b/src/test/ui/json-short.stderr index 3bd85b083d002..a7b80e077f889 100644 --- a/src/test/ui/json-short.stderr +++ b/src/test/ui/json-short.stderr @@ -13,7 +13,8 @@ If you don't know the basics of Rust, you can look at the [Rust Book][rust-book] to get started. [rust-book]: https://doc.rust-lang.org/book/ -"},"level":"error","spans":[{"file_name":"$DIR/json-short.rs","byte_start":62,"byte_end":62,"line_start":1,"line_end":1,"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:1:63: error[E0601]: `main` function not found in crate `json_short` +"},"level":"error","spans":[{"file_name":"$DIR/json-short.rs","byte_start":62,"byte_end":62,"line_start":1,"line_end":1,"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":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"define a function named `main` at the crate root","code":null,"level":"help","spans":[{"file_name":"$DIR/json-short.rs","byte_start":62,"byte_end":62,"line_start":1,"line_end":1,"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":null,"suggested_replacement":"fn main() {} +","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-short.rs:1: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 "} diff --git a/src/test/ui/main-wrong-location.stderr b/src/test/ui/main-wrong-location.stderr index e301c2ff09ad7..1d696881e99c8 100644 --- a/src/test/ui/main-wrong-location.stderr +++ b/src/test/ui/main-wrong-location.stderr @@ -1,21 +1,14 @@ error[E0601]: `main` function not found in crate `main_wrong_location` - --> $DIR/main-wrong-location.rs:1:1 | -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` +help: consider moving one of these function definitions to the crate root --> $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 +help: define a function named `main` at the crate root + | +LL | fn main() {} + | error: aborting due to previous error diff --git a/src/test/ui/missing/missing-main.stderr b/src/test/ui/missing/missing-main.stderr index 6a35f5117efd6..a6b7ccf363744 100644 --- a/src/test/ui/missing/missing-main.stderr +++ b/src/test/ui/missing/missing-main.stderr @@ -2,7 +2,12 @@ error[E0601]: `main` function not found in crate `missing_main` --> $DIR/missing-main.rs:2:1 | LL | fn mian() { } - | ^^^^^^^^^^^^^ consider adding a `main` function to `$DIR/missing-main.rs` + | ^ + | +help: define a function named `main` at the crate root + | +LL | fn main() {} + | error: aborting due to previous error diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr index 5995a4891f37d..61403362c5426 100644 --- a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr +++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr @@ -9,10 +9,13 @@ LL | #![issue_59191::no_main] error[E0601]: `main` function not found in crate `issue_59191_replace_root_with_fn` --> $DIR/issue-59191-replace-root-with-fn.rs:5:1 | -LL | / #![feature(custom_inner_attributes)] -LL | | -LL | | #![issue_59191::no_main] - | |________________________^ consider adding a `main` function to `$DIR/issue-59191-replace-root-with-fn.rs` +LL | #![feature(custom_inner_attributes)] + | ^ + | +help: define a function named `main` at the crate root + | +LL | fn main() {} + | error: aborting due to 2 previous errors