@@ -14,11 +14,14 @@ extern crate tracing;
1414extern crate rustc_data_structures;
1515extern crate rustc_driver;
1616extern crate rustc_hir;
17+ extern crate rustc_hir_analysis;
1718extern crate rustc_interface;
1819extern crate rustc_log;
1920extern crate rustc_metadata;
2021extern crate rustc_middle;
2122extern crate rustc_session;
23+ extern crate rustc_span;
24+ extern crate rustc_target;
2225
2326use std:: env:: { self , VarError } ;
2427use std:: num:: NonZero ;
@@ -27,24 +30,28 @@ use std::str::FromStr;
2730
2831use tracing:: debug;
2932
33+ use miri:: { BacktraceStyle , BorrowTrackerMethod , ProvenanceMode , RetagFields } ;
3034use rustc_data_structures:: sync:: Lrc ;
3135use rustc_driver:: Compilation ;
36+ use rustc_hir:: def_id:: LOCAL_CRATE ;
3237use rustc_hir:: { self as hir, Node } ;
38+ use rustc_hir_analysis:: check:: check_function_signature;
3339use rustc_interface:: interface:: Config ;
3440use rustc_middle:: {
3541 middle:: {
3642 codegen_fn_attrs:: CodegenFnAttrFlags ,
3743 exported_symbols:: { ExportedSymbol , SymbolExportInfo , SymbolExportKind , SymbolExportLevel } ,
3844 } ,
3945 query:: LocalCrate ,
40- ty:: TyCtxt ,
46+ traits:: { ObligationCause , ObligationCauseCode } ,
47+ ty:: { self , Ty , TyCtxt } ,
4148 util:: Providers ,
4249} ;
43- use rustc_session:: config:: { CrateType , ErrorOutputType , OptLevel } ;
50+ use rustc_session:: config:: { CrateType , EntryFnType , ErrorOutputType , OptLevel } ;
4451use rustc_session:: search_paths:: PathKind ;
4552use 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 ;
4855
4956struct MiriCompilerCalls {
5057 miri_config : miri:: MiriConfig ,
@@ -82,11 +89,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
8289 tcx. dcx ( ) . fatal ( "miri only makes sense on bin crates" ) ;
8390 }
8491
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) ;
9093 let mut config = self . miri_config . clone ( ) ;
9194
9295 // Add filename to `miri` arguments.
@@ -351,6 +354,56 @@ fn jemalloc_magic() {
351354 }
352355}
353356
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+
354407fn main ( ) {
355408 #[ cfg( any( target_os = "linux" , target_os = "macos" ) ) ]
356409 jemalloc_magic ( ) ;
0 commit comments