@@ -16,16 +16,16 @@ struct EntryContext<'a, 'tcx> {
1616
1717 map : & ' a hir_map:: Map < ' tcx > ,
1818
19- /// The top-level function called ' main' .
19+ /// The top-level function called ` main` .
2020 main_fn : Option < ( HirId , Span ) > ,
2121
22- /// The function that has attribute named ' main' .
22+ /// The function that has attribute named ` main` .
2323 attr_main_fn : Option < ( HirId , Span ) > ,
2424
2525 /// The function that has the attribute 'start' on it.
2626 start_fn : Option < ( HirId , Span ) > ,
2727
28- /// The functions that one might think are ' main' but aren't, e.g.
28+ /// The functions that one might think are ` main` but aren't, e.g.
2929 /// main functions not defined at the top level. For diagnostics.
3030 non_main_fns : Vec < ( HirId , Span ) > ,
3131}
@@ -88,7 +88,7 @@ fn entry_point_type(item: &Item, at_root: bool) -> EntryPointType {
8888 EntryPointType :: MainAttr
8989 } else if item. ident . name == sym:: main {
9090 if at_root {
91- // This is a top-level function so can be ' main' .
91+ // This is a top-level function so can be ` main` .
9292 EntryPointType :: MainNamed
9393 } else {
9494 EntryPointType :: OtherMain
@@ -109,7 +109,7 @@ fn find_item(item: &Item, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
109109 ctxt. main_fn = Some ( ( item. hir_id , item. span ) ) ;
110110 } else {
111111 span_err ! ( ctxt. session, item. span, E0136 ,
112- "multiple ' main' functions" ) ;
112+ "multiple ` main` functions" ) ;
113113 }
114114 } ,
115115 EntryPointType :: OtherMain => {
@@ -130,7 +130,7 @@ fn find_item(item: &Item, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
130130 if ctxt. start_fn . is_none ( ) {
131131 ctxt. start_fn = Some ( ( item. hir_id , item. span ) ) ;
132132 } else {
133- struct_span_err ! ( ctxt. session, item. span, E0138 , "multiple ' start' functions" )
133+ struct_span_err ! ( ctxt. session, item. span, E0138 , "multiple ` start` functions" )
134134 . span_label ( ctxt. start_fn . unwrap ( ) . 1 , "previous `start` function here" )
135135 . span_label ( item. span , "multiple `start` functions" )
136136 . emit ( ) ;
@@ -148,34 +148,48 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(De
148148 } else if let Some ( ( hir_id, _) ) = visitor. main_fn {
149149 Some ( ( tcx. hir ( ) . local_def_id ( hir_id) , EntryFnType :: Main ) )
150150 } else {
151- // There is no main function.
152- let mut err = struct_err ! ( tcx. sess, E0601 ,
153- "`main` function not found in crate `{}`" , tcx. crate_name( LOCAL_CRATE ) ) ;
154- if !visitor. non_main_fns . is_empty ( ) {
155- // There were some functions named 'main' though. Try to give the user a hint.
156- err. note ( "the main function must be defined at the crate level \
157- but you have one or more functions named 'main' that are not \
158- defined at the crate level. Either move the definition or \
159- attach the `#[main]` attribute to override this behavior.") ;
160- for & ( _, span) in & visitor. non_main_fns {
161- err. span_note ( span, "here is a function named 'main'" ) ;
162- }
163- err. emit ( ) ;
164- } else {
165- if let Some ( ref filename) = tcx. sess . local_crate_source_file {
166- err. note ( & format ! ( "consider adding a `main` function to `{}`" , filename. display( ) ) ) ;
167- }
168- if tcx. sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
169- err. note ( "If you don't know the basics of Rust, you can go look to the Rust Book \
170- to get started: https://doc.rust-lang.org/book/") ;
171- }
172- err. emit ( ) ;
173- }
174-
151+ no_main_err ( tcx, visitor) ;
175152 None
176153 }
177154}
178155
156+ fn no_main_err ( tcx : TyCtxt < ' _ > , visitor : & EntryContext < ' _ , ' _ > ) {
157+ // There is no main function.
158+ let mut err = struct_err ! ( tcx. sess, E0601 ,
159+ "`main` function not found in crate `{}`" , tcx. crate_name( LOCAL_CRATE ) ) ;
160+ let filename = & tcx. sess . local_crate_source_file ;
161+ let note = if !visitor. non_main_fns . is_empty ( ) {
162+ for & ( _, span) in & visitor. non_main_fns {
163+ err. span_note ( span, "here is a function named `main`" ) ;
164+ }
165+ err. note ( "you have one or more functions named `main` not defined at the crate level" ) ;
166+ err. help ( "either move the `main` function definitions or attach the `#[main]` attribute \
167+ to one of them") ;
168+ // There were some functions named `main` though. Try to give the user a hint.
169+ format ! ( "the main function must be defined at the crate level{}" ,
170+ filename. as_ref( ) . map( |f| format!( " (in `{}`)" , f. display( ) ) ) . unwrap_or_default( ) )
171+ } else if let Some ( filename) = filename {
172+ format ! ( "consider adding a `main` function to `{}`" , filename. display( ) )
173+ } else {
174+ String :: from ( "consider adding a `main` function at the crate level" )
175+ } ;
176+ let sp = tcx. hir ( ) . krate ( ) . span ;
177+ // The file may be empty, which leads to the diagnostic machinery not emitting this
178+ // note. This is a relatively simple way to detect that case and emit a span-less
179+ // note instead.
180+ if let Ok ( _) = tcx. sess . source_map ( ) . lookup_line ( sp. lo ( ) ) {
181+ err. set_span ( sp) ;
182+ err. span_label ( sp, & note) ;
183+ } else {
184+ err. note ( & note) ;
185+ }
186+ if tcx. sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
187+ err. note ( "If you don't know the basics of Rust, you can go look to the Rust Book \
188+ to get started: https://doc.rust-lang.org/book/") ;
189+ }
190+ err. emit ( ) ;
191+ }
192+
179193pub fn find_entry_point ( tcx : TyCtxt < ' _ > ) -> Option < ( DefId , EntryFnType ) > {
180194 tcx. entry_fn ( LOCAL_CRATE )
181195}
0 commit comments