@@ -14,11 +14,14 @@ extern crate tracing;
14
14
extern crate rustc_data_structures;
15
15
extern crate rustc_driver;
16
16
extern crate rustc_hir;
17
+ extern crate rustc_hir_analysis;
17
18
extern crate rustc_interface;
18
19
extern crate rustc_log;
19
20
extern crate rustc_metadata;
20
21
extern crate rustc_middle;
21
22
extern crate rustc_session;
23
+ extern crate rustc_span;
24
+ extern crate rustc_target;
22
25
23
26
use std:: env:: { self , VarError } ;
24
27
use std:: num:: NonZero ;
@@ -27,24 +30,28 @@ use std::str::FromStr;
27
30
28
31
use tracing:: debug;
29
32
33
+ use miri:: { BacktraceStyle , BorrowTrackerMethod , ProvenanceMode , RetagFields } ;
30
34
use rustc_data_structures:: sync:: Lrc ;
31
35
use rustc_driver:: Compilation ;
36
+ use rustc_hir:: def_id:: LOCAL_CRATE ;
32
37
use rustc_hir:: { self as hir, Node } ;
38
+ use rustc_hir_analysis:: check:: check_function_signature;
33
39
use rustc_interface:: interface:: Config ;
34
40
use rustc_middle:: {
35
41
middle:: {
36
42
codegen_fn_attrs:: CodegenFnAttrFlags ,
37
43
exported_symbols:: { ExportedSymbol , SymbolExportInfo , SymbolExportKind , SymbolExportLevel } ,
38
44
} ,
39
45
query:: LocalCrate ,
40
- ty:: TyCtxt ,
46
+ traits:: { ObligationCause , ObligationCauseCode } ,
47
+ ty:: { self , Ty , TyCtxt } ,
41
48
util:: Providers ,
42
49
} ;
43
- use rustc_session:: config:: { CrateType , ErrorOutputType , OptLevel } ;
50
+ use rustc_session:: config:: { CrateType , EntryFnType , ErrorOutputType , OptLevel } ;
44
51
use rustc_session:: search_paths:: PathKind ;
45
52
use rustc_session:: { CtfeBacktrace , EarlyDiagCtxt } ;
46
-
47
- use miri :: { BacktraceStyle , BorrowTrackerMethod , ProvenanceMode , RetagFields } ;
53
+ use rustc_span :: def_id :: DefId ;
54
+ use rustc_target :: spec :: abi :: Abi ;
48
55
49
56
struct MiriCompilerCalls {
50
57
miri_config : miri:: MiriConfig ,
@@ -82,11 +89,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
82
89
tcx. dcx ( ) . fatal ( "miri only makes sense on bin crates" ) ;
83
90
}
84
91
85
- let ( entry_def_id, entry_type) = if let Some ( entry_def) = tcx. entry_fn ( ( ) ) {
86
- entry_def
87
- } else {
88
- tcx. dcx ( ) . fatal ( "miri can only run programs that have a main function" ) ;
89
- } ;
92
+ let ( entry_def_id, entry_type) = entry_fn ( tcx) ;
90
93
let mut config = self . miri_config . clone ( ) ;
91
94
92
95
// Add filename to `miri` arguments.
@@ -351,6 +354,56 @@ fn jemalloc_magic() {
351
354
}
352
355
}
353
356
357
+ fn entry_fn ( tcx : TyCtxt < ' _ > ) -> ( DefId , EntryFnType ) {
358
+ if let Some ( entry_def) = tcx. entry_fn ( ( ) ) {
359
+ return entry_def;
360
+ }
361
+ // Look for a symbol in the local crate named `miri_start`, and treat that as the entry point.
362
+ let sym = tcx. exported_symbols ( LOCAL_CRATE ) . iter ( ) . find_map ( |( sym, _) | {
363
+ if sym. symbol_name_for_local_instance ( tcx) . name == "miri_start" { Some ( sym) } else { None }
364
+ } ) ;
365
+ if let Some ( ExportedSymbol :: NonGeneric ( id) ) = sym {
366
+ let start_def_id = id. expect_local ( ) ;
367
+ let start_span = tcx. def_span ( start_def_id) ;
368
+
369
+ let expected_sig = ty:: Binder :: dummy ( tcx. mk_fn_sig (
370
+ [ tcx. types . isize , Ty :: new_imm_ptr ( tcx, Ty :: new_imm_ptr ( tcx, tcx. types . u8 ) ) ] ,
371
+ tcx. types . isize ,
372
+ false ,
373
+ hir:: Safety :: Safe ,
374
+ Abi :: Rust ,
375
+ ) ) ;
376
+
377
+ let correct_func_sig = check_function_signature (
378
+ tcx,
379
+ ObligationCause :: new ( start_span, start_def_id, ObligationCauseCode :: Misc ) ,
380
+ * id,
381
+ expected_sig,
382
+ )
383
+ . is_ok ( ) ;
384
+
385
+ if correct_func_sig {
386
+ ( * id, EntryFnType :: Start )
387
+ } else {
388
+ tcx. dcx ( ) . fatal (
389
+ "`miri_start` must have the following signature:\n \
390
+ fn miri_start(argc: isize, argv: *const *const u8) -> isize",
391
+ ) ;
392
+ }
393
+ } else {
394
+ tcx. dcx ( ) . fatal (
395
+ "Miri can only run programs that have a main function.\n \
396
+ Alternatively, you can export a `miri_start` function:\n \
397
+ \n \
398
+ #[cfg(miri)]\n \
399
+ #[no_mangle]\n \
400
+ fn miri_start(argc: isize, argv: *const *const u8) -> isize {\
401
+ \n // Call the actual start function that your project implements, based on your target's conventions.\n \
402
+ }"
403
+ ) ;
404
+ }
405
+ }
406
+
354
407
fn main ( ) {
355
408
#[ cfg( any( target_os = "linux" , target_os = "macos" ) ) ]
356
409
jemalloc_magic ( ) ;
0 commit comments