1010
1111// The rustc crates we need
1212extern crate rustc_abi;
13+ extern crate rustc_codegen_ssa;
1314extern crate rustc_data_structures;
1415extern crate rustc_driver;
1516extern crate rustc_hir;
@@ -19,6 +20,7 @@ extern crate rustc_log;
1920extern crate rustc_middle;
2021extern crate rustc_session;
2122extern crate rustc_span;
23+ extern crate rustc_target;
2224
2325/// See docs in https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc/src/main.rs
2426/// and https://github.com/rust-lang/rust/pull/146627 for why we need this.
@@ -36,19 +38,22 @@ use std::num::{NonZero, NonZeroI32};
3638use std:: ops:: Range ;
3739use std:: rc:: Rc ;
3840use std:: str:: FromStr ;
41+ use std:: sync:: Once ;
3942use std:: sync:: atomic:: { AtomicU32 , Ordering } ;
4043
4144use miri:: {
4245 BacktraceStyle , BorrowTrackerMethod , GenmcConfig , GenmcCtx , MiriConfig , MiriEntryFnType ,
4346 ProvenanceMode , TreeBorrowsParams , ValidationMode , run_genmc_mode,
4447} ;
4548use rustc_abi:: ExternAbi ;
49+ use rustc_codegen_ssa:: traits:: CodegenBackend ;
4650use rustc_data_structures:: sync:: { self , DynSync } ;
4751use rustc_driver:: Compilation ;
4852use rustc_hir:: def_id:: LOCAL_CRATE ;
4953use rustc_hir:: { self as hir, Node } ;
5054use rustc_hir_analysis:: check:: check_function_signature;
5155use rustc_interface:: interface:: Config ;
56+ use rustc_interface:: util:: DummyCodegenBackend ;
5257use rustc_log:: tracing:: debug;
5358use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
5459use rustc_middle:: middle:: exported_symbols:: {
@@ -58,8 +63,9 @@ use rustc_middle::query::LocalCrate;
5863use rustc_middle:: traits:: { ObligationCause , ObligationCauseCode } ;
5964use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
6065use rustc_session:: EarlyDiagCtxt ;
61- use rustc_session:: config:: { CrateType , ErrorOutputType , OptLevel } ;
66+ use rustc_session:: config:: { CrateType , ErrorOutputType , OptLevel , Options } ;
6267use rustc_span:: def_id:: DefId ;
68+ use rustc_target:: spec:: Target ;
6369
6470use crate :: log:: setup:: { deinit_loggers, init_early_loggers, init_late_loggers} ;
6571
@@ -161,7 +167,31 @@ fn run_many_seeds(
161167 }
162168}
163169
170+ /// Generates the codegen backend for code that Miri will interpret: we basically
171+ /// use the dummy backend, except that we put the LLVM backend in charge of
172+ /// target features.
173+ fn make_miri_codegen_backend ( opts : & Options , target : & Target ) -> Box < dyn CodegenBackend > {
174+ let early_dcx = EarlyDiagCtxt :: new ( opts. error_format ) ;
175+
176+ // Use the target_config method of the default codegen backend (eg LLVM) to ensure the
177+ // calculated target features match said backend by respecting eg -Ctarget-cpu.
178+ let target_config_backend =
179+ rustc_interface:: util:: get_codegen_backend ( & early_dcx, & opts. sysroot , None , & target) ;
180+ let target_config_backend_init = Once :: new ( ) ;
181+
182+ Box :: new ( DummyCodegenBackend {
183+ target_config_override : Some ( Box :: new ( move |sess| {
184+ target_config_backend_init. call_once ( || target_config_backend. init ( sess) ) ;
185+ target_config_backend. target_config ( sess)
186+ } ) ) ,
187+ } )
188+ }
189+
164190impl rustc_driver:: Callbacks for MiriCompilerCalls {
191+ fn config ( & mut self , config : & mut rustc_interface:: interface:: Config ) {
192+ config. make_codegen_backend = Some ( Box :: new ( make_miri_codegen_backend) ) ;
193+ }
194+
165195 fn after_analysis < ' tcx > (
166196 & mut self ,
167197 _: & rustc_interface:: interface:: Compiler ,
@@ -244,11 +274,20 @@ struct MiriBeRustCompilerCalls {
244274impl rustc_driver:: Callbacks for MiriBeRustCompilerCalls {
245275 #[ allow( rustc:: potential_query_instability) ] // rustc_codegen_ssa (where this code is copied from) also allows this lint
246276 fn config ( & mut self , config : & mut Config ) {
247- if config. opts . prints . is_empty ( ) && self . target_crate {
277+ if !self . target_crate {
278+ // For a host crate, we fully behave like rustc.
279+ return ;
280+ }
281+ // For a target crate, we emit an rlib that Miri can later consume.
282+ config. make_codegen_backend = Some ( Box :: new ( make_miri_codegen_backend) ) ;
283+
284+ // Avoid warnings about unsupported crate types. However, only do that we we are *not* being
285+ // queried by cargo about the supported crate types so that cargo still receives the
286+ // warnings it expects.
287+ if config. opts . prints . is_empty ( ) {
248288 #[ allow( rustc:: bad_opt_access) ] // tcx does not exist yet
249289 {
250290 let any_crate_types = !config. opts . crate_types . is_empty ( ) ;
251- // Avoid warnings about unsupported crate types.
252291 config
253292 . opts
254293 . crate_types
@@ -259,66 +298,63 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
259298 assert ! ( !config. opts. crate_types. is_empty( ) ) ;
260299 }
261300 }
262-
263- // Queries overridden here affect the data stored in `rmeta` files of dependencies,
264- // which will be used later in non-`MIRI_BE_RUSTC` mode.
265- config. override_queries = Some ( |_, local_providers| {
266- // We need to add #[used] symbols to exported_symbols for `lookup_link_section`.
267- // FIXME handle this somehow in rustc itself to avoid this hack.
268- local_providers. exported_non_generic_symbols = |tcx, LocalCrate | {
269- let reachable_set = tcx. with_stable_hashing_context ( |hcx| {
270- tcx. reachable_set ( ( ) ) . to_sorted ( & hcx, true )
271- } ) ;
272- tcx. arena . alloc_from_iter (
273- // This is based on:
274- // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L62-L63
275- // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L174
276- reachable_set. into_iter ( ) . filter_map ( |& local_def_id| {
277- // Do the same filtering that rustc does:
278- // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L84-L102
279- // Otherwise it may cause unexpected behaviours and ICEs
280- // (https://github.com/rust-lang/rust/issues/86261).
281- let is_reachable_non_generic = matches ! (
282- tcx. hir_node_by_def_id( local_def_id) ,
283- Node :: Item ( & hir:: Item {
284- kind: hir:: ItemKind :: Static ( ..) | hir:: ItemKind :: Fn { .. } ,
285- ..
286- } ) | Node :: ImplItem ( & hir:: ImplItem {
287- kind: hir:: ImplItemKind :: Fn ( ..) ,
288- ..
289- } )
290- if !tcx. generics_of( local_def_id) . requires_monomorphization( tcx)
291- ) ;
292- if !is_reachable_non_generic {
293- return None ;
294- }
295- let codegen_fn_attrs = tcx. codegen_fn_attrs ( local_def_id) ;
296- if codegen_fn_attrs. contains_extern_indicator ( )
297- || codegen_fn_attrs
298- . flags
299- . contains ( CodegenFnAttrFlags :: USED_COMPILER )
300- || codegen_fn_attrs. flags . contains ( CodegenFnAttrFlags :: USED_LINKER )
301- {
302- Some ( (
303- ExportedSymbol :: NonGeneric ( local_def_id. to_def_id ( ) ) ,
304- // Some dummy `SymbolExportInfo` here. We only use
305- // `exported_symbols` in shims/foreign_items.rs and the export info
306- // is ignored.
307- SymbolExportInfo {
308- level : SymbolExportLevel :: C ,
309- kind : SymbolExportKind :: Text ,
310- used : false ,
311- rustc_std_internal_symbol : false ,
312- } ,
313- ) )
314- } else {
315- None
316- }
317- } ) ,
318- )
319- }
320- } ) ;
321301 }
302+
303+ // Queries overridden here affect the data stored in `rmeta` files of dependencies,
304+ // which will be used later in non-`MIRI_BE_RUSTC` mode.
305+ config. override_queries = Some ( |_, local_providers| {
306+ // We need to add #[used] symbols to exported_symbols for `lookup_link_section`.
307+ // FIXME handle this somehow in rustc itself to avoid this hack.
308+ local_providers. exported_non_generic_symbols = |tcx, LocalCrate | {
309+ let reachable_set = tcx
310+ . with_stable_hashing_context ( |hcx| tcx. reachable_set ( ( ) ) . to_sorted ( & hcx, true ) ) ;
311+ tcx. arena . alloc_from_iter (
312+ // This is based on:
313+ // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L62-L63
314+ // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L174
315+ reachable_set. into_iter ( ) . filter_map ( |& local_def_id| {
316+ // Do the same filtering that rustc does:
317+ // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L84-L102
318+ // Otherwise it may cause unexpected behaviours and ICEs
319+ // (https://github.com/rust-lang/rust/issues/86261).
320+ let is_reachable_non_generic = matches ! (
321+ tcx. hir_node_by_def_id( local_def_id) ,
322+ Node :: Item ( & hir:: Item {
323+ kind: hir:: ItemKind :: Static ( ..) | hir:: ItemKind :: Fn { .. } ,
324+ ..
325+ } ) | Node :: ImplItem ( & hir:: ImplItem {
326+ kind: hir:: ImplItemKind :: Fn ( ..) ,
327+ ..
328+ } )
329+ if !tcx. generics_of( local_def_id) . requires_monomorphization( tcx)
330+ ) ;
331+ if !is_reachable_non_generic {
332+ return None ;
333+ }
334+ let codegen_fn_attrs = tcx. codegen_fn_attrs ( local_def_id) ;
335+ if codegen_fn_attrs. contains_extern_indicator ( )
336+ || codegen_fn_attrs. flags . contains ( CodegenFnAttrFlags :: USED_COMPILER )
337+ || codegen_fn_attrs. flags . contains ( CodegenFnAttrFlags :: USED_LINKER )
338+ {
339+ Some ( (
340+ ExportedSymbol :: NonGeneric ( local_def_id. to_def_id ( ) ) ,
341+ // Some dummy `SymbolExportInfo` here. We only use
342+ // `exported_symbols` in shims/foreign_items.rs and the export info
343+ // is ignored.
344+ SymbolExportInfo {
345+ level : SymbolExportLevel :: C ,
346+ kind : SymbolExportKind :: Text ,
347+ used : false ,
348+ rustc_std_internal_symbol : false ,
349+ } ,
350+ ) )
351+ } else {
352+ None
353+ }
354+ } ) ,
355+ )
356+ }
357+ } ) ;
322358 }
323359
324360 fn after_analysis < ' tcx > (
0 commit comments