1
1
use rustc_ast:: entry:: EntryPointType ;
2
2
use rustc_errors:: struct_span_err;
3
- use rustc_hir:: def_id:: { CrateNum , LocalDefId , CRATE_DEF_INDEX , LOCAL_CRATE } ;
3
+ use rustc_hir:: def_id:: { CrateNum , DefId , CRATE_DEF_INDEX , LOCAL_CRATE } ;
4
4
use rustc_hir:: itemlikevisit:: ItemLikeVisitor ;
5
5
use rustc_hir:: { ForeignItem , HirId , ImplItem , Item , ItemKind , TraitItem , CRATE_HIR_ID } ;
6
6
use rustc_middle:: hir:: map:: Map ;
7
7
use rustc_middle:: ty:: query:: Providers ;
8
8
use rustc_middle:: ty:: TyCtxt ;
9
9
use rustc_session:: config:: { CrateType , EntryFnType } ;
10
+ use rustc_session:: parse:: feature_err;
10
11
use rustc_session:: Session ;
11
12
use rustc_span:: symbol:: sym;
12
13
use rustc_span:: { Span , DUMMY_SP } ;
@@ -16,9 +17,6 @@ struct EntryContext<'a, 'tcx> {
16
17
17
18
map : Map < ' tcx > ,
18
19
19
- /// The top-level function called `main`.
20
- main_fn : Option < ( HirId , Span ) > ,
21
-
22
20
/// The function that has attribute named `main`.
23
21
attr_main_fn : Option < ( HirId , Span ) > ,
24
22
@@ -50,7 +48,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
50
48
}
51
49
}
52
50
53
- fn entry_fn ( tcx : TyCtxt < ' _ > , cnum : CrateNum ) -> Option < ( LocalDefId , EntryFnType ) > {
51
+ fn entry_fn ( tcx : TyCtxt < ' _ > , cnum : CrateNum ) -> Option < ( DefId , EntryFnType ) > {
54
52
assert_eq ! ( cnum, LOCAL_CRATE ) ;
55
53
56
54
let any_exe = tcx. sess . crate_types ( ) . iter ( ) . any ( |ty| * ty == CrateType :: Executable ) ;
@@ -67,7 +65,6 @@ fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)
67
65
let mut ctxt = EntryContext {
68
66
session : tcx. sess ,
69
67
map : tcx. hir ( ) ,
70
- main_fn : None ,
71
68
attr_main_fn : None ,
72
69
start_fn : None ,
73
70
non_main_fns : Vec :: new ( ) ,
@@ -115,14 +112,7 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
115
112
throw_attr_err ( & ctxt. session , attr. span , "rustc_main" ) ;
116
113
}
117
114
}
118
- EntryPointType :: MainNamed => {
119
- if ctxt. main_fn . is_none ( ) {
120
- ctxt. main_fn = Some ( ( item. hir_id ( ) , item. span ) ) ;
121
- } else {
122
- struct_span_err ! ( ctxt. session, item. span, E0136 , "multiple `main` functions" )
123
- . emit ( ) ;
124
- }
125
- }
115
+ EntryPointType :: MainNamed => ( ) ,
126
116
EntryPointType :: OtherMain => {
127
117
ctxt. non_main_fns . push ( ( item. hir_id ( ) , item. span ) ) ;
128
118
}
@@ -154,16 +144,23 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
154
144
}
155
145
}
156
146
157
- fn configure_main (
158
- tcx : TyCtxt < ' _ > ,
159
- visitor : & EntryContext < ' _ , ' _ > ,
160
- ) -> Option < ( LocalDefId , EntryFnType ) > {
147
+ fn configure_main ( tcx : TyCtxt < ' _ > , visitor : & EntryContext < ' _ , ' _ > ) -> Option < ( DefId , EntryFnType ) > {
161
148
if let Some ( ( hir_id, _) ) = visitor. start_fn {
162
- Some ( ( tcx. hir ( ) . local_def_id ( hir_id) , EntryFnType :: Start ) )
149
+ Some ( ( tcx. hir ( ) . local_def_id ( hir_id) . to_def_id ( ) , EntryFnType :: Start ) )
163
150
} else if let Some ( ( hir_id, _) ) = visitor. attr_main_fn {
164
- Some ( ( tcx. hir ( ) . local_def_id ( hir_id) , EntryFnType :: Main ) )
165
- } else if let Some ( ( hir_id, _) ) = visitor. main_fn {
166
- Some ( ( tcx. hir ( ) . local_def_id ( hir_id) , EntryFnType :: Main ) )
151
+ Some ( ( tcx. hir ( ) . local_def_id ( hir_id) . to_def_id ( ) , EntryFnType :: Main ) )
152
+ } else if let Some ( def_id) = tcx. main_def . and_then ( |main_def| main_def. opt_fn_def_id ( ) ) {
153
+ if tcx. main_def . unwrap ( ) . is_import && !tcx. features ( ) . imported_main {
154
+ let span = tcx. main_def . unwrap ( ) . span ;
155
+ feature_err (
156
+ & tcx. sess . parse_sess ,
157
+ sym:: imported_main,
158
+ span,
159
+ "using an imported function as entry point `main` is experimental" ,
160
+ )
161
+ . emit ( ) ;
162
+ }
163
+ Some ( ( def_id, EntryFnType :: Main ) )
167
164
} else {
168
165
no_main_err ( tcx, visitor) ;
169
166
None
@@ -213,6 +210,14 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
213
210
} else {
214
211
err. note ( & note) ;
215
212
}
213
+
214
+ if let Some ( main_def) = tcx. main_def {
215
+ if main_def. opt_fn_def_id ( ) . is_none ( ) {
216
+ // There is something at `crate::main`, but it is not a function definition.
217
+ err. span_label ( main_def. span , & format ! ( "non-function item at `crate::main` is found" ) ) ;
218
+ }
219
+ }
220
+
216
221
if tcx. sess . teach ( & err. get_code ( ) . unwrap ( ) ) {
217
222
err. note (
218
223
"If you don't know the basics of Rust, you can go look to the Rust Book \
@@ -222,7 +227,7 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
222
227
err. emit ( ) ;
223
228
}
224
229
225
- pub fn find_entry_point ( tcx : TyCtxt < ' _ > ) -> Option < ( LocalDefId , EntryFnType ) > {
230
+ pub fn find_entry_point ( tcx : TyCtxt < ' _ > ) -> Option < ( DefId , EntryFnType ) > {
226
231
tcx. entry_fn ( LOCAL_CRATE )
227
232
}
228
233
0 commit comments