diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index a08e3dc0df87d..347a15a392af9 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -26,7 +26,7 @@ use object::read::archive::ArchiveFile; use rustc_codegen_ssa::back::lto::SerializedModule; use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput, SharedEmitter}; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file}; +use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind, looks_like_rust_object_file}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_errors::{DiagCtxt, DiagCtxtHandle}; @@ -34,7 +34,7 @@ use rustc_log::tracing::info; use rustc_session::config::Lto; use tempfile::{TempDir, tempdir}; -use crate::back::write::save_temp_bitcode; +use crate::back::write::{codegen, save_temp_bitcode}; use crate::errors::LtoBitcodeFromRlib; use crate::{GccCodegenBackend, GccContext, LtoMode, to_gcc_opt_level}; @@ -112,7 +112,7 @@ pub(crate) fn run_fat( shared_emitter: &SharedEmitter, each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, -) -> ModuleCodegen { +) -> CompiledModule { let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); let lto_data = prepare_lto(cgcx, each_linked_rlib_for_lto, dcx); @@ -132,12 +132,12 @@ pub(crate) fn run_fat( fn fat_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, - _dcx: DiagCtxtHandle<'_>, + dcx: DiagCtxtHandle<'_>, modules: Vec>, mut serialized_modules: Vec<(SerializedModule, CString)>, tmp_path: TempDir, //symbols_below_threshold: &[String], -) -> ModuleCodegen { +) -> CompiledModule { let _timer = prof.generic_activity("GCC_fat_lto_build_monolithic_module"); info!("going for a fat lto"); @@ -260,7 +260,7 @@ fn fat_lto( // of now. module.module_llvm.temp_dir = Some(tmp_path); - module + codegen(cgcx, prof, dcx, module, &cgcx.module_config) } pub struct ModuleBuffer(PathBuf); diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index ddf13558027bd..24ea2b66ba7d3 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -2,12 +2,10 @@ use std::{env, fs}; use gccjit::{Context, OutputKind}; use rustc_codegen_ssa::back::link::ensure_removed; -use rustc_codegen_ssa::back::write::{ - BitcodeSection, CodegenContext, EmitObj, ModuleConfig, SharedEmitter, -}; +use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig}; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_errors::DiagCtxt; +use rustc_errors::DiagCtxtHandle; use rustc_fs_util::link_or_copy; use rustc_log::tracing::debug; use rustc_session::config::OutputType; @@ -20,13 +18,10 @@ use crate::{GccContext, LtoMode}; pub(crate) fn codegen( cgcx: &CodegenContext, prof: &SelfProfilerRef, - shared_emitter: &SharedEmitter, + dcx: DiagCtxtHandle<'_>, module: ModuleCodegen, config: &ModuleConfig, ) -> CompiledModule { - let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); - let dcx = dcx.handle(); - let _timer = prof.generic_activity_with_arg("GCC_module_codegen", &*module.name); { let context = &module.module_llvm.context; diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 529a5085c30f4..592eb68ce2750 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -92,7 +92,7 @@ use rustc_codegen_ssa::{CompiledModule, CompiledModules, CrateInfo, ModuleCodege use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::IntoDynSyncSend; -use rustc_errors::DiagCtxtHandle; +use rustc_errors::{DiagCtxt, DiagCtxtHandle}; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; @@ -371,16 +371,6 @@ impl ExtraBackendMethods for GccCodegenBackend { self.lto_supported.load(Ordering::SeqCst), ) } - - fn target_machine_factory( - &self, - _sess: &Session, - _opt_level: OptLevel, - _features: &[String], - ) -> TargetMachineFactoryFn { - // TODO(antoyo): set opt level. - Arc::new(|_, _| ()) - } } #[derive(Clone, Copy, PartialEq)] @@ -429,7 +419,17 @@ impl WriteBackendMethods for GccCodegenBackend { type ModuleBuffer = ModuleBuffer; type ThinData = (); - fn run_and_optimize_fat_lto( + fn target_machine_factory( + &self, + _sess: &Session, + _opt_level: OptLevel, + _features: &[String], + ) -> TargetMachineFactoryFn { + // TODO(antoyo): set opt level. + Arc::new(|_, _| ()) + } + + fn optimize_and_codegen_fat_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, @@ -438,7 +438,7 @@ impl WriteBackendMethods for GccCodegenBackend { _exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, - ) -> ModuleCodegen { + ) -> CompiledModule { back::lto::run_fat(cgcx, prof, shared_emitter, each_linked_rlib_for_lto, modules) } @@ -455,14 +455,6 @@ impl WriteBackendMethods for GccCodegenBackend { unreachable!() } - fn print_pass_timings(&self) { - unimplemented!(); - } - - fn print_statistics(&self) { - unimplemented!() - } - fn optimize( _cgcx: &CodegenContext, _prof: &SelfProfilerRef, @@ -473,13 +465,13 @@ impl WriteBackendMethods for GccCodegenBackend { module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level)); } - fn optimize_thin( + fn optimize_and_codegen_thin( _cgcx: &CodegenContext, _prof: &SelfProfilerRef, _shared_emitter: &SharedEmitter, _tm_factory: TargetMachineFactoryFn, _thin: ThinModule, - ) -> ModuleCodegen { + ) -> CompiledModule { unreachable!() } @@ -490,7 +482,9 @@ impl WriteBackendMethods for GccCodegenBackend { module: ModuleCodegen, config: &ModuleConfig, ) -> CompiledModule { - back::write::codegen(cgcx, prof, shared_emitter, module, config) + let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); + let dcx = dcx.handle(); + back::write::codegen(cgcx, prof, dcx, module, config) } fn serialize_module(_module: Self::Module, _is_thin: bool) -> Self::ModuleBuffer { diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index c235437aee751..f6cd229cb106d 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -12,7 +12,7 @@ use rustc_codegen_ssa::back::write::{ CodegenContext, FatLtoInput, SharedEmitter, TargetMachineFactoryFn, }; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::{ModuleCodegen, ModuleKind, looks_like_rust_object_file}; +use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind, looks_like_rust_object_file}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::SelfProfilerRef; @@ -24,7 +24,8 @@ use rustc_session::config::{self, Lto}; use tracing::{debug, info}; use crate::back::write::{ - self, CodegenDiagnosticsStage, DiagnosticHandlers, bitcode_section_name, save_temp_bitcode, + self, CodegenDiagnosticsStage, DiagnosticHandlers, bitcode_section_name, codegen, + save_temp_bitcode, }; use crate::errors::{LlvmError, LtoBitcodeFromRlib}; use crate::llvm::{self, build_string}; @@ -709,13 +710,13 @@ impl ModuleBufferMethods for ModuleBuffer { } } -pub(crate) fn optimize_thin_module( +pub(crate) fn optimize_and_codegen_thin_module( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, tm_factory: TargetMachineFactoryFn, thin_module: ThinModule, -) -> ModuleCodegen { +) -> CompiledModule { let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); @@ -794,7 +795,7 @@ pub(crate) fn optimize_thin_module( save_temp_bitcode(cgcx, &module, "thin-lto-after-pm"); } } - module + codegen(cgcx, prof, shared_emitter, module, &cgcx.module_config) } /// Maps LLVM module identifiers to their corresponding LLVM LTO cache keys diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index d7ab1356fafe7..efd4e55d5a856 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -335,13 +335,13 @@ pub(crate) fn save_temp_bitcode( &module.name, cgcx.invocation_temp.as_deref(), ); - write_bitcode_to_file(module, &path) + write_bitcode_to_file(&module.module_llvm, &path) } -fn write_bitcode_to_file(module: &ModuleCodegen, path: &Path) { +fn write_bitcode_to_file(module: &ModuleLlvm, path: &Path) { unsafe { let path = path_to_c_string(&path); - let llmod = module.module_llvm.llmod(); + let llmod = module.llmod(); llvm::LLVMWriteBitcodeToFile(llmod, path.as_ptr()); } } @@ -905,13 +905,8 @@ pub(crate) fn optimize( let _handlers = DiagnosticHandlers::new(cgcx, shared_emitter, llcx, module, CodegenDiagnosticsStage::Opt); - if config.emit_no_opt_bc { - let out = cgcx.output_filenames.temp_path_ext_for_cgu( - "no-opt.bc", - &module.name, - cgcx.invocation_temp.as_deref(), - ); - write_bitcode_to_file(module, &out) + if module.kind == ModuleKind::Regular { + save_temp_bitcode(cgcx, module, "no-opt"); } // FIXME(ZuseZ4): support SanitizeHWAddress and prevent illegal/unsupported opts diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index c03b0ac9157a8..62bba6c9bfc21 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -79,24 +79,18 @@ pub(crate) use macros::TryFromU32; #[derive(Clone)] pub struct LlvmCodegenBackend(()); -struct TimeTraceProfiler { - enabled: bool, -} +struct TimeTraceProfiler {} impl TimeTraceProfiler { - fn new(enabled: bool) -> Self { - if enabled { - unsafe { llvm::LLVMRustTimeTraceProfilerInitialize() } - } - TimeTraceProfiler { enabled } + fn new() -> Self { + unsafe { llvm::LLVMRustTimeTraceProfilerInitialize() } + TimeTraceProfiler {} } } impl Drop for TimeTraceProfiler { fn drop(&mut self) { - if self.enabled { - unsafe { llvm::LLVMRustTimeTraceProfilerFinishThread() } - } + unsafe { llvm::LLVMRustTimeTraceProfilerFinishThread() } } } @@ -122,30 +116,6 @@ impl ExtraBackendMethods for LlvmCodegenBackend { ) -> (ModuleCodegen, u64) { base::compile_codegen_unit(tcx, cgu_name) } - fn target_machine_factory( - &self, - sess: &Session, - optlvl: OptLevel, - target_features: &[String], - ) -> TargetMachineFactoryFn { - back::write::target_machine_factory(sess, optlvl, target_features) - } - - fn spawn_named_thread( - time_trace: bool, - name: String, - f: F, - ) -> std::io::Result> - where - F: FnOnce() -> T, - F: Send + 'static, - T: Send + 'static, - { - std::thread::Builder::new().name(name).spawn(move || { - let _profiler = TimeTraceProfiler::new(time_trace); - f() - }) - } } impl WriteBackendMethods for LlvmCodegenBackend { @@ -153,15 +123,18 @@ impl WriteBackendMethods for LlvmCodegenBackend { type ModuleBuffer = back::lto::ModuleBuffer; type TargetMachine = OwnedTargetMachine; type ThinData = back::lto::ThinData; - fn print_pass_timings(&self) { - let timings = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintPassTimings(s) }).unwrap(); - print!("{timings}"); + fn thread_profiler() -> Box { + Box::new(TimeTraceProfiler::new()) } - fn print_statistics(&self) { - let stats = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatistics(s) }).unwrap(); - print!("{stats}"); + fn target_machine_factory( + &self, + sess: &Session, + optlvl: OptLevel, + target_features: &[String], + ) -> TargetMachineFactoryFn { + back::write::target_machine_factory(sess, optlvl, target_features) } - fn run_and_optimize_fat_lto( + fn optimize_and_codegen_fat_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, @@ -169,7 +142,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, - ) -> ModuleCodegen { + ) -> CompiledModule { let mut module = back::lto::run_fat( cgcx, prof, @@ -184,7 +157,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { let dcx = dcx.handle(); back::lto::run_pass_manager(cgcx, prof, dcx, &mut module, false); - module + back::write::codegen(cgcx, prof, shared_emitter, module, &cgcx.module_config) } fn run_thin_lto( cgcx: &CodegenContext, @@ -214,14 +187,14 @@ impl WriteBackendMethods for LlvmCodegenBackend { ) { back::write::optimize(cgcx, prof, shared_emitter, module, config) } - fn optimize_thin( + fn optimize_and_codegen_thin( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, tm_factory: TargetMachineFactoryFn, thin: ThinModule, - ) -> ModuleCodegen { - back::lto::optimize_thin_module(cgcx, prof, shared_emitter, tm_factory, thin) + ) -> CompiledModule { + back::lto::optimize_and_codegen_thin_module(cgcx, prof, shared_emitter, tm_factory, thin) } fn codegen( cgcx: &CodegenContext, @@ -389,6 +362,16 @@ impl CodegenBackend for LlvmCodegenBackend { (compiled_modules, work_products) } + fn print_pass_timings(&self) { + let timings = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintPassTimings(s) }).unwrap(); + print!("{timings}"); + } + + fn print_statistics(&self) { + let stats = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatistics(s) }).unwrap(); + print!("{stats}"); + } + fn link( &self, sess: &Session, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 0d210eacf9a83..3734e273e0b5d 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -94,7 +94,6 @@ pub struct ModuleConfig { // Flags indicating which outputs to produce. pub emit_pre_lto_bc: bool, - pub emit_no_opt_bc: bool, pub emit_bc: bool, pub emit_ir: bool, pub emit_asm: bool, @@ -195,7 +194,6 @@ impl ModuleConfig { save_temps || need_pre_lto_bitcode_for_incr_comp(sess), false ), - emit_no_opt_bc: if_regular!(save_temps, false), emit_bc: if_regular!( save_temps || sess.opts.output_types.contains_key(&OutputType::Bitcode), save_temps @@ -356,7 +354,7 @@ pub struct CodegenContext { pub parallel: bool, } -fn generate_thin_lto_work( +fn generate_thin_lto_work( cgcx: &CodegenContext, prof: &SelfProfilerRef, dcx: DiagCtxtHandle<'_>, @@ -824,7 +822,7 @@ pub(crate) fn compute_per_cgu_lto_type( } } -fn execute_optimize_work_item( +fn execute_optimize_work_item( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: SharedEmitter, @@ -969,7 +967,7 @@ fn execute_copy_from_cache_work_item( } } -fn do_fat_lto( +fn do_fat_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: SharedEmitter, @@ -990,7 +988,7 @@ fn do_fat_lto( needs_fat_lto.push(FatLtoInput::Serialized { name: wp.cgu_name, buffer: module }) } - let module = B::run_and_optimize_fat_lto( + B::optimize_and_codegen_fat_lto( cgcx, prof, &shared_emitter, @@ -998,11 +996,10 @@ fn do_fat_lto( exported_symbols_for_lto, each_linked_rlib_for_lto, needs_fat_lto, - ); - B::codegen(cgcx, prof, &shared_emitter, module, &cgcx.module_config) + ) } -fn do_thin_lto( +fn do_thin_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: SharedEmitter, @@ -1155,7 +1152,7 @@ fn do_thin_lto( compiled_modules } -fn execute_thin_lto_work_item( +fn execute_thin_lto_work_item( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: SharedEmitter, @@ -1164,8 +1161,7 @@ fn execute_thin_lto_work_item( ) -> CompiledModule { let _timer = prof.generic_activity_with_arg("codegen_module_perform_lto", module.name()); - let module = B::optimize_thin(cgcx, prof, &shared_emitter, tm_factory, module); - B::codegen(cgcx, prof, &shared_emitter, module, &cgcx.module_config) + B::optimize_and_codegen_thin(cgcx, prof, &shared_emitter, tm_factory, module) } /// Messages sent to the coordinator. @@ -1472,7 +1468,9 @@ fn start_executing_work( // Each LLVM module is automatically sent back to the coordinator for LTO if // necessary. There's already optimizations in place to avoid sending work // back to the coordinator if LTO isn't requested. - return B::spawn_named_thread(cgcx.time_trace, "coordinator".to_string(), move || { + let f = move || { + let _profiler = if cgcx.time_trace { B::thread_profiler() } else { Box::new(()) }; + // This is where we collect codegen units that have gone all the way // through codegen and LLVM. let mut compiled_modules = vec![]; @@ -1813,8 +1811,11 @@ fn start_executing_work( B::codegen(&cgcx, &prof, &shared_emitter, allocator_module, &allocator_config) }), })) - }) - .expect("failed to spawn coordinator thread"); + }; + return std::thread::Builder::new() + .name("coordinator".to_owned()) + .spawn(f) + .expect("failed to spawn coordinator thread"); // A heuristic that determines if we have enough LLVM WorkItems in the // queue so that the main thread can do LLVM work instead of codegen @@ -1878,7 +1879,7 @@ fn start_executing_work( #[must_use] pub(crate) struct WorkerFatalError; -fn spawn_work<'a, B: ExtraBackendMethods>( +fn spawn_work<'a, B: WriteBackendMethods>( cgcx: &CodegenContext, prof: &'a SelfProfilerRef, shared_emitter: SharedEmitter, @@ -1893,7 +1894,10 @@ fn spawn_work<'a, B: ExtraBackendMethods>( let cgcx = cgcx.clone(); let prof = prof.clone(); - B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || { + let name = work.short_description(); + let f = move || { + let _profiler = if cgcx.time_trace { B::thread_profiler() } else { Box::new(()) }; + let result = std::panic::catch_unwind(AssertUnwindSafe(|| match work { WorkItem::Optimize(m) => execute_optimize_work_item(&cgcx, &prof, shared_emitter, m), WorkItem::CopyPostLtoArtifacts(m) => WorkItemResult::Finished( @@ -1914,11 +1918,11 @@ fn spawn_work<'a, B: ExtraBackendMethods>( Err(_) => Message::WorkItem:: { result: Err(None) }, }; drop(coordinator_send.send(msg)); - }) - .expect("failed to spawn work thread"); + }; + std::thread::Builder::new().name(name).spawn(f).expect("failed to spawn work thread"); } -fn spawn_thin_lto_work( +fn spawn_thin_lto_work( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: SharedEmitter, @@ -1929,7 +1933,10 @@ fn spawn_thin_lto_work( let cgcx = cgcx.clone(); let prof = prof.clone(); - B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || { + let name = work.short_description(); + let f = move || { + let _profiler = if cgcx.time_trace { B::thread_profiler() } else { Box::new(()) }; + let result = std::panic::catch_unwind(AssertUnwindSafe(|| match work { ThinLtoWorkItem::CopyPostLtoArtifacts(m) => { execute_copy_from_cache_work_item(&cgcx, &prof, shared_emitter, m) @@ -1952,8 +1959,8 @@ fn spawn_thin_lto_work( Err(_) => ThinLtoMessage::WorkItem { result: Err(None) }, }; drop(coordinator_send.send(msg)); - }) - .expect("failed to spawn work thread"); + }; + std::thread::Builder::new().name(name).spawn(f).expect("failed to spawn work thread"); } enum SharedEmitterMessage { @@ -2102,20 +2109,20 @@ impl SharedEmitterMain { } } -pub struct Coordinator { +pub struct Coordinator { sender: Sender>, future: Option, ()>>>, // Only used for the Message type. phantom: PhantomData, } -impl Coordinator { +impl Coordinator { fn join(mut self) -> std::thread::Result, ()>> { self.future.take().unwrap().join() } } -impl Drop for Coordinator { +impl Drop for Coordinator { fn drop(&mut self) { if let Some(future) = self.future.take() { // If we haven't joined yet, signal to the coordinator that it should spawn no more @@ -2126,7 +2133,7 @@ impl Drop for Coordinator { } } -pub struct OngoingCodegen { +pub struct OngoingCodegen { pub backend: B, pub output_filenames: Arc, // Field order below is intended to terminate the coordinator thread before two fields below @@ -2137,7 +2144,7 @@ pub struct OngoingCodegen { pub shared_emitter_main: SharedEmitterMain, } -impl OngoingCodegen { +impl OngoingCodegen { pub fn join(self, sess: &Session) -> (CompiledModules, FxIndexMap) { self.shared_emitter_main.check(sess, true); @@ -2234,16 +2241,6 @@ impl OngoingCodegen { copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess, &compiled_modules); produce_final_output_artifacts(sess, &compiled_modules, &self.output_filenames); - // FIXME: time_llvm_passes support - does this use a global context or - // something? - if sess.codegen_units().as_usize() == 1 && sess.opts.unstable_opts.time_llvm_passes { - self.backend.print_pass_timings() - } - - if sess.print_llvm_stats() { - self.backend.print_statistics() - } - (compiled_modules, work_products) } @@ -2270,7 +2267,7 @@ impl OngoingCodegen { } } -pub(crate) fn submit_codegened_module_to_llvm( +pub(crate) fn submit_codegened_module_to_llvm( coordinator: &Coordinator, module: ModuleCodegen, cost: u64, @@ -2279,7 +2276,7 @@ pub(crate) fn submit_codegened_module_to_llvm( drop(coordinator.sender.send(Message::CodegenDone:: { llvm_work_item, cost })); } -pub(crate) fn submit_post_lto_module_to_llvm( +pub(crate) fn submit_post_lto_module_to_llvm( coordinator: &Coordinator, module: CachedModuleCodegen, ) { @@ -2287,7 +2284,7 @@ pub(crate) fn submit_post_lto_module_to_llvm( drop(coordinator.sender.send(Message::CodegenDone:: { llvm_work_item, cost: 0 })); } -pub(crate) fn submit_pre_lto_module_to_llvm( +pub(crate) fn submit_pre_lto_module_to_llvm( tcx: TyCtxt<'_>, coordinator: &Coordinator, module: CachedModuleCodegen, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 0d42ccc1a73c9..cf643931717be 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1256,55 +1256,37 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } CallKind::Tail => { - match fn_abi.args[i].mode { - PassMode::Indirect { on_stack: false, .. } => { - let Some(tmp) = tail_call_temporaries[i].take() else { - span_bug!( - fn_span, - "missing temporary for indirect tail call argument #{i}" - ) - }; - - let local = self.mir.args_iter().nth(i).unwrap(); - - match &self.locals[local] { - LocalRef::Place(arg) => { - bx.typed_place_copy(arg.val, tmp.val, fn_abi.args[i].layout); - op.val = Ref(arg.val); - } - LocalRef::Operand(arg) => { - let Ref(place_value) = arg.val else { - bug!("only `Ref` should use `PassMode::Indirect`"); - }; - bx.typed_place_copy( - place_value, - tmp.val, - fn_abi.args[i].layout, - ); - op.val = arg.val; - } - LocalRef::UnsizedPlace(_) => { - span_bug!(fn_span, "unsized types are not supported") - } - LocalRef::PendingOperand => { - span_bug!(fn_span, "argument local should not be pending") - } - }; - - bx.lifetime_end(tmp.val.llval, tmp.layout.size); - } - PassMode::Indirect { on_stack: true, .. } => { - // FIXME: some LLVM backends (notably x86) do not correctly pass byval - // arguments to tail calls (as of LLVM 21). See also: - // - // - https://github.com/rust-lang/rust/pull/144232#discussion_r2218543841 - // - https://github.com/rust-lang/rust/issues/144855 + if let PassMode::Indirect { on_stack: false, .. } = fn_abi.args[i].mode { + let Some(tmp) = tail_call_temporaries[i].take() else { span_bug!( fn_span, - "arguments using PassMode::Indirect {{ on_stack: true, .. }} are currently not supported for tail calls" + "missing temporary for indirect tail call argument #{i}" ) - } - _ => (), + }; + + let local = self.mir.args_iter().nth(i).unwrap(); + + match &self.locals[local] { + LocalRef::Place(arg) => { + bx.typed_place_copy(arg.val, tmp.val, fn_abi.args[i].layout); + op.val = Ref(arg.val); + } + LocalRef::Operand(arg) => { + let Ref(place_value) = arg.val else { + bug!("only `Ref` should use `PassMode::Indirect`"); + }; + bx.typed_place_copy(place_value, tmp.val, fn_abi.args[i].layout); + op.val = arg.val; + } + LocalRef::UnsizedPlace(_) => { + span_bug!(fn_span, "unsized types are not supported") + } + LocalRef::PendingOperand => { + span_bug!(fn_span, "argument local should not be pending") + } + }; + + bx.lifetime_end(tmp.val.llval, tmp.layout.size); } } } diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 8df1ecc0fff57..7b95562ddda37 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -10,14 +10,13 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; use rustc_session::Session; -use rustc_session::config::{self, CrateType, OutputFilenames, PrintRequest}; +use rustc_session::config::{CrateType, OutputFilenames, PrintRequest}; use rustc_span::Symbol; use super::CodegenObject; use super::write::WriteBackendMethods; use crate::back::archive::ArArchiveBuilderBuilder; use crate::back::link::link_binary; -use crate::back::write::TargetMachineFactoryFn; use crate::{CompiledModules, CrateInfo, ModuleCodegen, TargetConfig}; pub trait BackendTypes { @@ -119,6 +118,10 @@ pub trait CodegenBackend { outputs: &OutputFilenames, ) -> (CompiledModules, FxIndexMap); + fn print_pass_timings(&self) {} + + fn print_statistics(&self) {} + /// This is called on the returned [`CompiledModules`] from [`join_codegen`](Self::join_codegen). fn link( &self, @@ -158,26 +161,6 @@ pub trait ExtraBackendMethods: cgu_name: Symbol, ) -> (ModuleCodegen, u64); - fn target_machine_factory( - &self, - sess: &Session, - opt_level: config::OptLevel, - target_features: &[String], - ) -> TargetMachineFactoryFn; - - fn spawn_named_thread( - _time_trace: bool, - name: String, - f: F, - ) -> std::io::Result> - where - F: FnOnce() -> T, - F: Send + 'static, - T: Send + 'static, - { - std::thread::Builder::new().name(name).spawn(f) - } - /// Returns `true` if this backend can be safely called from multiple threads. /// /// Defaults to `true`. diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index d33dfc1d014b5..5d2313092fa84 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -1,8 +1,10 @@ +use std::any::Any; use std::path::PathBuf; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_errors::DiagCtxtHandle; use rustc_middle::dep_graph::WorkProduct; +use rustc_session::{Session, config}; use crate::back::lto::{SerializedModule, ThinModule}; use crate::back::write::{ @@ -16,9 +18,18 @@ pub trait WriteBackendMethods: Clone + 'static { type ModuleBuffer: ModuleBufferMethods; type ThinData: Send + Sync; + fn thread_profiler() -> Box { + Box::new(()) + } + fn target_machine_factory( + &self, + sess: &Session, + opt_level: config::OptLevel, + target_features: &[String], + ) -> TargetMachineFactoryFn; /// Performs fat LTO by merging all modules into a single one, running autodiff /// if necessary and running any further optimizations - fn run_and_optimize_fat_lto( + fn optimize_and_codegen_fat_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, @@ -26,7 +37,7 @@ pub trait WriteBackendMethods: Clone + 'static { exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, - ) -> ModuleCodegen; + ) -> CompiledModule; /// Performs thin LTO by performing necessary global analysis and returning two /// lists, one of the modules that need optimization and another for modules that /// can simply be copied over from the incr. comp. cache. @@ -39,8 +50,6 @@ pub trait WriteBackendMethods: Clone + 'static { modules: Vec<(String, Self::ModuleBuffer)>, cached_modules: Vec<(SerializedModule, WorkProduct)>, ) -> (Vec>, Vec); - fn print_pass_timings(&self); - fn print_statistics(&self); fn optimize( cgcx: &CodegenContext, prof: &SelfProfilerRef, @@ -48,13 +57,13 @@ pub trait WriteBackendMethods: Clone + 'static { module: &mut ModuleCodegen, config: &ModuleConfig, ); - fn optimize_thin( + fn optimize_and_codegen_thin( cgcx: &CodegenContext, prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, tm_factory: TargetMachineFactoryFn, thin: ThinModule, - ) -> ModuleCodegen; + ) -> CompiledModule; fn codegen( cgcx: &CodegenContext, prof: &SelfProfilerRef, diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 86d902b1c6993..8fec629161eac 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -338,7 +338,11 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) } } - Some(Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend)) + let linker = Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend); + + tcx.report_unused_features(); + + Some(linker) }); // Linking is done outside the `compiler.enter()` so that the diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 4ef4d58074639..6c68dfccf86af 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -7,9 +7,7 @@ #![allow(rustc::direct_use_of_rustc_type_ir)] #![cfg_attr(bootstrap, feature(assert_matches))] #![feature(associated_type_defaults)] -#![feature(box_patterns)] #![feature(default_field_values)] -#![feature(error_reporter)] #![feature(macro_metavar_expr_concat)] #![feature(negative_impls)] #![feature(never_type)] diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index db8f459ef0451..db6e9298e235e 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1330,7 +1330,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ safety: AttributeSafety::Normal, template: template!(NameValueStr: "name"), duplicates: ErrorFollowing, - gate: Gated{ + gate: Gated { feature: sym::rustc_attrs, message: "use of an internal attribute", check: Features::rustc_attrs, diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 619726f0d5d8f..9d046bdef1cf3 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -137,5 +137,5 @@ pub use builtin_attrs::{ pub use removed::REMOVED_LANG_FEATURES; pub use unstable::{ DEPENDENT_FEATURES, EnabledLangFeature, EnabledLibFeature, Features, INCOMPATIBLE_FEATURES, - UNSTABLE_LANG_FEATURES, + TRACK_FEATURE, UNSTABLE_LANG_FEATURES, }; diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 49be9cb3382d9..3b15183be0b2d 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -3,11 +3,18 @@ use std::path::PathBuf; use std::time::{SystemTime, UNIX_EPOCH}; +use rustc_data_structures::AtomicRef; use rustc_data_structures::fx::FxHashSet; use rustc_span::{Span, Symbol, sym}; use super::{Feature, to_nonzero}; +fn default_track_feature(_: Symbol) {} + +/// Recording used features in the dependency graph so incremental can +/// replay used features when needed. +pub static TRACK_FEATURE: AtomicRef = AtomicRef::new(&(default_track_feature as _)); + #[derive(PartialEq)] enum FeatureStatus { Default, @@ -103,7 +110,12 @@ impl Features { /// Is the given feature enabled (via `#[feature(...)]`)? pub fn enabled(&self, feature: Symbol) -> bool { - self.enabled_features.contains(&feature) + if self.enabled_features.contains(&feature) { + TRACK_FEATURE(feature); + true + } else { + false + } } } @@ -124,7 +136,7 @@ macro_rules! declare_features { impl Features { $( pub fn $feature(&self) -> bool { - self.enabled_features.contains(&sym::$feature) + self.enabled(sym::$feature) } )* diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 0b6165c02baba..38025f74b2f69 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -997,7 +997,7 @@ fn check_type_defn<'tcx>( item: &hir::Item<'tcx>, all_sized: bool, ) -> Result<(), ErrorGuaranteed> { - let _ = tcx.representability(item.owner_id.def_id); + let _ = tcx.check_representability(item.owner_id.def_id); let adt_def = tcx.adt_def(item.owner_id); enter_wf_checking_ctxt(tcx, item.owner_id.def_id, |wfcx| { diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs index 4a1da0f50cc23..9ddbc496e6d43 100644 --- a/compiler/rustc_interface/src/callbacks.rs +++ b/compiler/rustc_interface/src/callbacks.rs @@ -12,8 +12,9 @@ use std::fmt; use rustc_errors::DiagInner; -use rustc_middle::dep_graph::TaskDepsRef; +use rustc_middle::dep_graph::{DepNodeIndex, QuerySideEffect, TaskDepsRef}; use rustc_middle::ty::tls; +use rustc_span::Symbol; fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) { tls::with_context_opt(|icx| { @@ -51,6 +52,25 @@ fn track_diagnostic(diagnostic: DiagInner, f: &mut dyn FnMut(DiagInner) -> R) }) } +fn track_feature(feature: Symbol) { + tls::with_context_opt(|icx| { + let Some(icx) = icx else { + return; + }; + let tcx = icx.tcx; + + if let Some(dep_node_index) = tcx.sess.used_features.lock().get(&feature).copied() { + tcx.dep_graph.read_index(DepNodeIndex::from_u32(dep_node_index)); + } else { + let dep_node_index = tcx + .dep_graph + .encode_side_effect(tcx, QuerySideEffect::CheckFeature { symbol: feature }); + tcx.sess.used_features.lock().insert(feature, dep_node_index.as_u32()); + tcx.dep_graph.read_index(dep_node_index); + } + }) +} + /// This is a callback from `rustc_hir` as it cannot access the implicit state /// in `rustc_middle` otherwise. fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -70,4 +90,5 @@ pub fn setup_callbacks() { rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_))); rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _)); rustc_errors::TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _)); + rustc_feature::TRACK_FEATURE.swap(&(track_feature as _)); } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index f4fcd4471d3fd..170393f3b8179 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -58,6 +58,15 @@ impl Linker { } } }); + + if sess.codegen_units().as_usize() == 1 && sess.opts.unstable_opts.time_llvm_passes { + codegen_backend.print_pass_timings() + } + + if sess.print_llvm_stats() { + codegen_backend.print_statistics() + } + sess.timings.end_section(sess.dcx(), TimingSection::Codegen); if sess.opts.incremental.is_some() diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 8d498b32cd8af..c1df8aac6f319 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1088,11 +1088,6 @@ declare_lint! { /// crate-level [`feature` attributes]. /// /// [`feature` attributes]: https://doc.rust-lang.org/nightly/unstable-book/ - /// - /// Note: This lint is currently not functional, see [issue #44232] for - /// more details. - /// - /// [issue #44232]: https://github.com/rust-lang/rust/issues/44232 pub UNUSED_FEATURES, Warn, "unused features found in crate-level `#[feature]` directives" diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 0a741d32ed61d..8f0bfed2035c8 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -144,7 +144,6 @@ struct QueryModifiers { arena_cache: Option, cache_on_disk_if: Option, cycle_delay_bug: Option, - cycle_fatal: Option, cycle_stash: Option, depth_limit: Option, desc: Desc, @@ -160,7 +159,6 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { let mut arena_cache = None; let mut cache_on_disk_if = None; let mut desc = None; - let mut cycle_fatal = None; let mut cycle_delay_bug = None; let mut cycle_stash = None; let mut no_hash = None; @@ -197,8 +195,6 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { try_insert!(cache_on_disk_if = CacheOnDiskIf { modifier, block }); } else if modifier == "arena_cache" { try_insert!(arena_cache = modifier); - } else if modifier == "cycle_fatal" { - try_insert!(cycle_fatal = modifier); } else if modifier == "cycle_delay_bug" { try_insert!(cycle_delay_bug = modifier); } else if modifier == "cycle_stash" { @@ -228,7 +224,6 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { arena_cache, cache_on_disk_if, desc, - cycle_fatal, cycle_delay_bug, cycle_stash, no_hash, @@ -248,7 +243,6 @@ fn make_modifiers_stream(query: &Query, modifiers: &QueryModifiers) -> proc_macr arena_cache, cache_on_disk_if, cycle_delay_bug, - cycle_fatal, cycle_stash, depth_limit, desc: _, @@ -266,8 +260,6 @@ fn make_modifiers_stream(query: &Query, modifiers: &QueryModifiers) -> proc_macr let cycle_error_handling = if cycle_delay_bug.is_some() { quote! { DelayBug } - } else if cycle_fatal.is_some() { - quote! { Fatal } } else if cycle_stash.is_some() { quote! { Stash } } else { @@ -407,7 +399,6 @@ fn add_to_analyzer_stream(query: &Query, analyzer_stream: &mut proc_macro2::Toke doc_link!( arena_cache, - cycle_fatal, cycle_delay_bug, cycle_stash, no_hash, diff --git a/compiler/rustc_middle/src/dep_graph/graph.rs b/compiler/rustc_middle/src/dep_graph/graph.rs index a71373c62f38e..882e859247782 100644 --- a/compiler/rustc_middle/src/dep_graph/graph.rs +++ b/compiler/rustc_middle/src/dep_graph/graph.rs @@ -17,6 +17,7 @@ use rustc_index::IndexVec; use rustc_macros::{Decodable, Encodable}; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::Session; +use rustc_span::Symbol; use tracing::{debug, instrument}; #[cfg(debug_assertions)] use {super::debug::EdgeFilter, std::env}; @@ -45,6 +46,11 @@ pub enum QuerySideEffect { /// the query as green, as that query will have the side /// effect dep node as a dependency. Diagnostic(DiagInner), + /// Records the feature used during query execution. + /// This feature will be inserted into `sess.used_features` + /// if we mark the query as green, as that query will have + /// the side effect dep node as a dependency. + CheckFeature { symbol: Symbol }, } #[derive(Clone)] pub struct DepGraph { @@ -514,29 +520,40 @@ impl DepGraph { } } - /// This encodes a diagnostic by creating a node with an unique index and associating - /// `diagnostic` with it, for use in the next session. + /// This encodes a side effect by creating a node with an unique index and associating + /// it with the node, for use in the next session. #[inline] pub fn record_diagnostic<'tcx>(&self, tcx: TyCtxt<'tcx>, diagnostic: &DiagInner) { if let Some(ref data) = self.data { read_deps(|task_deps| match task_deps { TaskDepsRef::EvalAlways | TaskDepsRef::Ignore => return, TaskDepsRef::Forbid | TaskDepsRef::Allow(..) => { - self.read_index(data.encode_diagnostic(tcx, diagnostic)); + let dep_node_index = data + .encode_side_effect(tcx, QuerySideEffect::Diagnostic(diagnostic.clone())); + self.read_index(dep_node_index); } }) } } - /// This forces a diagnostic node green by running its side effect. `prev_index` would - /// refer to a node created used `encode_diagnostic` in the previous session. + /// This forces a side effect node green by running its side effect. `prev_index` would + /// refer to a node created used `encode_side_effect` in the previous session. #[inline] - pub fn force_diagnostic_node<'tcx>( + pub fn force_side_effect<'tcx>(&self, tcx: TyCtxt<'tcx>, prev_index: SerializedDepNodeIndex) { + if let Some(ref data) = self.data { + data.force_side_effect(tcx, prev_index); + } + } + + #[inline] + pub fn encode_side_effect<'tcx>( &self, tcx: TyCtxt<'tcx>, - prev_index: SerializedDepNodeIndex, - ) { + side_effect: QuerySideEffect, + ) -> DepNodeIndex { if let Some(ref data) = self.data { - data.force_diagnostic_node(tcx, prev_index); + data.encode_side_effect(tcx, side_effect) + } else { + self.next_virtual_depnode_index() } } @@ -673,10 +690,14 @@ impl DepGraphData { self.debug_loaded_from_disk.lock().insert(dep_node); } - /// This encodes a diagnostic by creating a node with an unique index and associating - /// `diagnostic` with it, for use in the next session. + /// This encodes a side effect by creating a node with an unique index and associating + /// it with the node, for use in the next session. #[inline] - fn encode_diagnostic<'tcx>(&self, tcx: TyCtxt<'tcx>, diagnostic: &DiagInner) -> DepNodeIndex { + fn encode_side_effect<'tcx>( + &self, + tcx: TyCtxt<'tcx>, + side_effect: QuerySideEffect, + ) -> DepNodeIndex { // Use `send_new` so we get an unique index, even though the dep node is not. let dep_node_index = self.current.encoder.send_new( DepNode { @@ -684,28 +705,21 @@ impl DepGraphData { key_fingerprint: PackedFingerprint::from(Fingerprint::ZERO), }, Fingerprint::ZERO, - // We want the side effect node to always be red so it will be forced and emit the - // diagnostic. + // We want the side effect node to always be red so it will be forced and run the + // side effect. std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(), ); - let side_effect = QuerySideEffect::Diagnostic(diagnostic.clone()); tcx.store_side_effect(dep_node_index, side_effect); dep_node_index } - /// This forces a diagnostic node green by running its side effect. `prev_index` would - /// refer to a node created used `encode_diagnostic` in the previous session. + /// This forces a side effect node green by running its side effect. `prev_index` would + /// refer to a node created used `encode_side_effect` in the previous session. #[inline] - fn force_diagnostic_node<'tcx>(&self, tcx: TyCtxt<'tcx>, prev_index: SerializedDepNodeIndex) { + fn force_side_effect<'tcx>(&self, tcx: TyCtxt<'tcx>, prev_index: SerializedDepNodeIndex) { with_deps(TaskDepsRef::Ignore, || { let side_effect = tcx.load_side_effect(prev_index).unwrap(); - match &side_effect { - QuerySideEffect::Diagnostic(diagnostic) => { - tcx.dcx().emit_diagnostic(diagnostic.clone()); - } - } - // Use `send_and_color` as `promote_node_and_deps_to_current` expects all // green dependencies. `send_and_color` will also prevent multiple nodes // being encoded for concurrent calls. @@ -720,6 +734,16 @@ impl DepGraphData { std::iter::once(DepNodeIndex::FOREVER_RED_NODE).collect(), true, ); + + match &side_effect { + QuerySideEffect::Diagnostic(diagnostic) => { + tcx.dcx().emit_diagnostic(diagnostic.clone()); + } + QuerySideEffect::CheckFeature { symbol } => { + tcx.sess.used_features.lock().insert(*symbol, dep_node_index.as_u32()); + } + } + // This will just overwrite the same value for concurrent calls. tcx.store_side_effect(dep_node_index, side_effect); }) diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 932d0855c6016..495070310c3c9 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -32,7 +32,6 @@ //! - `arena_cache`: Use an arena for in-memory caching of the query result. //! - `cache_on_disk_if { ... }`: Cache the query result to disk if the provided block evaluates to //! true. The query key identifier is available for use within the block, as is `tcx`. -//! - `cycle_fatal`: If a dependency cycle is detected, abort compilation with a fatal error. //! - `cycle_delay_bug`: If a dependency cycle is detected, emit a delayed bug instead of aborting immediately. //! - `cycle_stash`: If a dependency cycle is detected, stash the error for later handling. //! - `no_hash`: Do not hash the query result for incremental compilation; just mark as dirty if recomputed. @@ -149,11 +148,11 @@ use crate::{dep_graph, mir, thir}; // which memoizes and does dep-graph tracking, wrapping around the actual // `Providers` that the driver creates (using several `rustc_*` crates). // -// The result type of each query must implement `Clone`, and additionally -// `ty::query::from_cycle_error::FromCycleError`, which produces an appropriate +// The result type of each query must implement `Clone`. Additionally +// `ty::query::from_cycle_error::FromCycleError` can be implemented which produces an appropriate // placeholder (error) value if the query resulted in a query cycle. -// Queries marked with `cycle_fatal` do not need the latter implementation, -// as they will raise a fatal error on query cycles instead. +// Queries without a `FromCycleError` implementation will raise a fatal error on query +// cycles instead. rustc_queries! { /// Caches the expansion of a derive proc macro, e.g. `#[derive(Serialize)]`. /// The key is: @@ -587,24 +586,28 @@ rustc_queries! { } query is_panic_runtime(_: CrateNum) -> bool { - cycle_fatal desc { "checking if the crate is_panic_runtime" } separate_provide_extern } /// Checks whether a type is representable or infinitely sized - query representability(key: LocalDefId) -> rustc_middle::ty::Representability { + query check_representability(key: LocalDefId) -> rustc_middle::ty::Representability { desc { "checking if `{}` is representable", tcx.def_path_str(key) } - // infinitely sized types will cause a cycle + // Infinitely sized types will cause a cycle. The custom `FromCycleError` impl for + // `Representability` will print a custom error about the infinite size and then abort + // compilation. (In the past we recovered and continued, but in practice that leads to + // confusing subsequent error messages about cycles that then abort.) cycle_delay_bug - // we don't want recursive representability calls to be forced with + // We don't want recursive representability calls to be forced with // incremental compilation because, if a cycle occurs, we need the - // entire cycle to be in memory for diagnostics + // entire cycle to be in memory for diagnostics. This means we can't + // use `ensure_ok()` with this query. anon } - /// An implementation detail for the `representability` query - query representability_adt_ty(key: Ty<'tcx>) -> rustc_middle::ty::Representability { + /// An implementation detail for the `check_representability` query. See that query for more + /// details, particularly on the modifiers. + query check_representability_adt_ty(key: Ty<'tcx>) -> rustc_middle::ty::Representability { desc { "checking if `{}` is representable", key } cycle_delay_bug anon @@ -1318,7 +1321,6 @@ rustc_queries! { /// Return the set of (transitive) callees that may result in a recursive call to `key`, /// if we were able to walk all callees. query mir_callgraph_cyclic(key: LocalDefId) -> &'tcx Option> { - cycle_fatal arena_cache desc { "computing (transitive) callees of `{}` that may recurse", @@ -1329,7 +1331,6 @@ rustc_queries! { /// Obtain all the calls into other local functions query mir_inliner_callees(key: ty::InstanceKind<'tcx>) -> &'tcx [(DefId, GenericArgsRef<'tcx>)] { - cycle_fatal desc { "computing all local function calls in `{}`", tcx.def_path_str(key.def_id()), @@ -1824,31 +1825,26 @@ rustc_queries! { } query is_compiler_builtins(_: CrateNum) -> bool { - cycle_fatal desc { "checking if the crate is_compiler_builtins" } separate_provide_extern } query has_global_allocator(_: CrateNum) -> bool { // This query depends on untracked global state in CStore eval_always - cycle_fatal desc { "checking if the crate has_global_allocator" } separate_provide_extern } query has_alloc_error_handler(_: CrateNum) -> bool { // This query depends on untracked global state in CStore eval_always - cycle_fatal desc { "checking if the crate has_alloc_error_handler" } separate_provide_extern } query has_panic_handler(_: CrateNum) -> bool { - cycle_fatal desc { "checking if the crate has_panic_handler" } separate_provide_extern } query is_profiler_runtime(_: CrateNum) -> bool { - cycle_fatal desc { "checking if a crate is `#![profiler_runtime]`" } separate_provide_extern } @@ -1857,22 +1853,18 @@ rustc_queries! { cache_on_disk_if { true } } query required_panic_strategy(_: CrateNum) -> Option { - cycle_fatal desc { "getting a crate's required panic strategy" } separate_provide_extern } query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy { - cycle_fatal desc { "getting a crate's configured panic-in-drop strategy" } separate_provide_extern } query is_no_builtins(_: CrateNum) -> bool { - cycle_fatal desc { "getting whether a crate has `#![no_builtins]`" } separate_provide_extern } query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion { - cycle_fatal desc { "getting a crate's symbol mangling version" } separate_provide_extern } diff --git a/compiler/rustc_middle/src/query/modifiers.rs b/compiler/rustc_middle/src/query/modifiers.rs index 44aaa6a3ce3d9..c305f65a9ef35 100644 --- a/compiler/rustc_middle/src/query/modifiers.rs +++ b/compiler/rustc_middle/src/query/modifiers.rs @@ -28,11 +28,6 @@ pub(crate) struct cache_on_disk_if; /// A cycle error results in a delay_bug call pub(crate) struct cycle_delay_bug; -/// # `cycle_fatal` query modifier -/// -/// A cycle error for this query aborting the compilation with a fatal error. -pub(crate) struct cycle_fatal; - /// # `cycle_stash` query modifier /// /// A cycle error results in a stashed cycle error that can be unstashed and canceled later diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 815c8a1baab61..ae348c668fb50 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -57,7 +57,6 @@ pub enum ActiveKeyStatus<'tcx> { #[derive(Copy, Clone)] pub enum CycleErrorHandling { Error, - Fatal, DelayBug, Stash, } diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index c141eb0311dcf..6a51ea4deffee 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -741,8 +741,7 @@ impl<'tcx> AdtDef<'tcx> { } } +/// This type exists just so a `FromCycleError` impl can be made for the `check_representability` +/// query. #[derive(Clone, Copy, Debug, HashStable)] -pub enum Representability { - Representable, - Infinite(ErrorGuaranteed), -} +pub struct Representability; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 27f2a534adb59..68819445a06c4 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -36,7 +36,7 @@ use rustc_hir::definitions::{DefPathData, Definitions, DisambiguatorState}; use rustc_hir::intravisit::VisitorExt; use rustc_hir::lang_items::LangItem; use rustc_hir::limit::Limit; -use rustc_hir::{self as hir, HirId, Node, TraitCandidate, find_attr}; +use rustc_hir::{self as hir, CRATE_HIR_ID, HirId, Node, TraitCandidate, find_attr}; use rustc_index::IndexVec; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::Session; @@ -1688,6 +1688,36 @@ impl<'tcx> TyCtxt<'tcx> { self.sess.dcx().emit_fatal(crate::error::FailedWritingFile { path: &path, error }); } } + + pub fn report_unused_features(self) { + // Collect first to avoid holding the lock while linting. + let used_features = self.sess.used_features.lock(); + let unused_features = self + .features() + .enabled_features_iter_stable_order() + .filter(|(f, _)| { + !used_features.contains_key(f) + // FIXME: `restricted_std` is used to tell a standard library built + // for a platform that it doesn't know how to support. But it + // could only gate a private mod (see `__restricted_std_workaround`) + // with `cfg(not(restricted_std))`, so it cannot be recorded as used + // in downstream crates. It should never be linted, but should we + // hack this in the linter to ignore it? + && f.as_str() != "restricted_std" + }) + .collect::>(); + + for (feature, span) in unused_features { + self.node_span_lint( + rustc_session::lint::builtin::UNUSED_FEATURES, + CRATE_HIR_ID, + span, + |lint| { + lint.primary_message(format!("feature `{}` is declared but not used", feature)); + }, + ); + } + } } macro_rules! nop_lift { diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 5c4c1733be29e..b454689e243d2 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -61,10 +61,9 @@ pub(crate) fn provide(providers: &mut Providers) { /// requires calling [`InhabitedPredicate::instantiate`] fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> { if let Some(def_id) = def_id.as_local() { - if matches!(tcx.representability(def_id), ty::Representability::Infinite(_)) { - return InhabitedPredicate::True; - } + let _ = tcx.check_representability(def_id); } + let adt = tcx.adt_def(def_id); InhabitedPredicate::any( tcx, diff --git a/compiler/rustc_query_impl/src/dep_kind_vtables.rs b/compiler/rustc_query_impl/src/dep_kind_vtables.rs index 0f3ef34d936a4..c3e423aa0ddee 100644 --- a/compiler/rustc_query_impl/src/dep_kind_vtables.rs +++ b/compiler/rustc_query_impl/src/dep_kind_vtables.rs @@ -40,7 +40,7 @@ mod non_query { is_eval_always: false, key_fingerprint_style: KeyFingerprintStyle::Unit, force_from_dep_node_fn: Some(|tcx, _, prev_index| { - tcx.dep_graph.force_diagnostic_node(tcx, prev_index); + tcx.dep_graph.force_side_effect(tcx, prev_index); true }), promote_from_disk_fn: None, diff --git a/compiler/rustc_query_impl/src/execution.rs b/compiler/rustc_query_impl/src/execution.rs index 323d40fdbaabb..34be511ad3121 100644 --- a/compiler/rustc_query_impl/src/execution.rs +++ b/compiler/rustc_query_impl/src/execution.rs @@ -131,10 +131,6 @@ fn mk_cycle<'tcx, C: QueryCache>( let guar = error.emit(); query.value_from_cycle_error(tcx, cycle_error, guar) } - CycleErrorHandling::Fatal => { - let guar = error.emit(); - guar.raise_fatal(); - } CycleErrorHandling::DelayBug => { let guar = error.delay_as_bug(); query.value_from_cycle_error(tcx, cycle_error, guar) diff --git a/compiler/rustc_query_impl/src/from_cycle_error.rs b/compiler/rustc_query_impl/src/from_cycle_error.rs index a13db9004d678..eb6942ba491ff 100644 --- a/compiler/rustc_query_impl/src/from_cycle_error.rs +++ b/compiler/rustc_query_impl/src/from_cycle_error.rs @@ -95,7 +95,7 @@ impl<'tcx> FromCycleError<'tcx> for Representability { let mut item_and_field_ids = Vec::new(); let mut representable_ids = FxHashSet::default(); for info in &cycle_error.cycle { - if info.frame.dep_kind == DepKind::representability + if info.frame.dep_kind == DepKind::check_representability && let Some(field_id) = info.frame.def_id && let Some(field_id) = field_id.as_local() && let Some(DefKind::Field) = info.frame.info.def_kind @@ -109,7 +109,7 @@ impl<'tcx> FromCycleError<'tcx> for Representability { } } for info in &cycle_error.cycle { - if info.frame.dep_kind == DepKind::representability_adt_ty + if info.frame.dep_kind == DepKind::check_representability_adt_ty && let Some(def_id) = info.frame.def_id_for_ty_in_cycle && let Some(def_id) = def_id.as_local() && !item_and_field_ids.iter().any(|&(id, _)| id == def_id) @@ -117,8 +117,10 @@ impl<'tcx> FromCycleError<'tcx> for Representability { representable_ids.insert(def_id); } } + // We used to continue here, but the cycle error printed next is actually less useful than + // the error produced by `recursive_type_error`. let guar = recursive_type_error(tcx, item_and_field_ids, &representable_ids); - Representability::Infinite(guar) + guar.raise_fatal(); } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index dc18b05c75763..30840a4872733 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -166,6 +166,11 @@ pub struct Session { /// Used by `-Zmir-opt-bisect-limit` to assign an index to each /// optimization-pass execution candidate during this compilation. pub mir_opt_bisect_eval_count: AtomicUsize, + + /// Enabled features that are used in the current compilation. + /// + /// The value is the `DepNodeIndex` of the node encodes the used feature. + pub used_features: Lock>, } #[derive(Clone, Copy)] @@ -1096,6 +1101,7 @@ pub fn build_session( replaced_intrinsics: FxHashSet::default(), // filled by `run_compiler` thin_lto_supported: true, // filled by `run_compiler` mir_opt_bisect_eval_count: AtomicUsize::new(0), + used_features: Lock::default(), }; validate_commandline_args_with_session_available(&sess); diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index 33d334092ba9c..1814e7604a2d1 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -6,69 +6,71 @@ use rustc_middle::ty::{self, Representability, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; pub(crate) fn provide(providers: &mut Providers) { - *providers = - Providers { representability, representability_adt_ty, params_in_repr, ..*providers }; -} - -macro_rules! rtry { - ($e:expr) => { - match $e { - e @ Representability::Infinite(_) => return e, - Representability::Representable => {} - } + *providers = Providers { + check_representability, + check_representability_adt_ty, + params_in_repr, + ..*providers }; } -fn representability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Representability { +fn check_representability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Representability { match tcx.def_kind(def_id) { DefKind::Struct | DefKind::Union | DefKind::Enum => { for variant in tcx.adt_def(def_id).variants() { for field in variant.fields.iter() { - rtry!(tcx.representability(field.did.expect_local())); + let _ = tcx.check_representability(field.did.expect_local()); } } - Representability::Representable } - DefKind::Field => representability_ty(tcx, tcx.type_of(def_id).instantiate_identity()), + DefKind::Field => { + check_representability_ty(tcx, tcx.type_of(def_id).instantiate_identity()); + } def_kind => bug!("unexpected {def_kind:?}"), } + Representability } -fn representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representability { +fn check_representability_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) { match *ty.kind() { - ty::Adt(..) => tcx.representability_adt_ty(ty), + // This one must be a query rather than a vanilla `check_representability_adt_ty` call. See + // the comment on `check_representability_adt_ty` below for why. + ty::Adt(..) => { + let _ = tcx.check_representability_adt_ty(ty); + } // FIXME(#11924) allow zero-length arrays? - ty::Array(ty, _) => representability_ty(tcx, ty), + ty::Array(ty, _) => { + check_representability_ty(tcx, ty); + } ty::Tuple(tys) => { for ty in tys { - rtry!(representability_ty(tcx, ty)); + check_representability_ty(tcx, ty); } - Representability::Representable } - _ => Representability::Representable, + _ => {} } } -/* -The reason for this being a separate query is very subtle: -Consider this infinitely sized struct: `struct Foo(Box, Bar)`: -When calling representability(Foo), a query cycle will occur: - representability(Foo) - -> representability_adt_ty(Bar) - -> representability(Foo) -For the diagnostic output (in `Value::from_cycle_error`), we want to detect that -the `Foo` in the *second* field of the struct is culpable. This requires -traversing the HIR of the struct and calling `params_in_repr(Bar)`. But we can't -call params_in_repr for a given type unless it is known to be representable. -params_in_repr will cycle/panic on infinitely sized types. Looking at the query -cycle above, we know that `Bar` is representable because -representability_adt_ty(Bar<..>) is in the cycle and representability(Bar) is -*not* in the cycle. -*/ -fn representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representability { +// The reason for this being a separate query is very subtle. Consider this +// infinitely sized struct: `struct Foo(Box, Bar)`. When calling +// check_representability(Foo), a query cycle will occur: +// +// check_representability(Foo) +// -> check_representability_adt_ty(Bar) +// -> check_representability(Foo) +// +// For the diagnostic output (in `Value::from_cycle_error`), we want to detect +// that the `Foo` in the *second* field of the struct is culpable. This +// requires traversing the HIR of the struct and calling `params_in_repr(Bar)`. +// But we can't call params_in_repr for a given type unless it is known to be +// representable. params_in_repr will cycle/panic on infinitely sized types. +// Looking at the query cycle above, we know that `Bar` is representable +// because `check_representability_adt_ty(Bar<..>)` is in the cycle and +// `check_representability(Bar)` is *not* in the cycle. +fn check_representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representability { let ty::Adt(adt, args) = ty.kind() else { bug!("expected adt") }; if let Some(def_id) = adt.did().as_local() { - rtry!(tcx.representability(def_id)); + let _ = tcx.check_representability(def_id); } // At this point, we know that the item of the ADT type is representable; // but the type parameters may cause a cycle with an upstream type @@ -76,11 +78,11 @@ fn representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representab for (i, arg) in args.iter().enumerate() { if let ty::GenericArgKind::Type(ty) = arg.kind() { if params_in_repr.contains(i as u32) { - rtry!(representability_ty(tcx, ty)); + check_representability_ty(tcx, ty); } } } - Representability::Representable + Representability } fn params_in_repr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> DenseBitSet { diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index d6a29aba22b90..78f3a19228870 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -116,11 +116,10 @@ fn adt_sizedness_constraint<'tcx>( tcx: TyCtxt<'tcx>, (def_id, sizedness): (DefId, SizedTraitKind), ) -> Option>> { - if let Some(def_id) = def_id.as_local() - && let ty::Representability::Infinite(_) = tcx.representability(def_id) - { - return None; + if let Some(def_id) = def_id.as_local() { + let _ = tcx.check_representability(def_id); } + let def = tcx.adt_def(def_id); if !def.is_struct() { diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 60b26126cf6be..699a5010282b0 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -1,6 +1,5 @@ #![feature(allocator_api)] #![feature(binary_heap_pop_if)] -#![feature(btree_merge)] #![feature(const_heap)] #![feature(deque_extend_front)] #![feature(iter_array_chunks)] diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index ef937fccb47f3..ff483f4062ac9 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -1521,7 +1521,11 @@ impl f16 { // Functions in this module fall into `core_float_math` // #[unstable(feature = "core_float_math", issue = "137578")] #[cfg(not(test))] -#[doc(test(attr(feature(cfg_target_has_reliable_f16_f128), expect(internal_features))))] +#[doc(test(attr( + feature(cfg_target_has_reliable_f16_f128), + expect(internal_features), + allow(unused_features) +)))] impl f16 { /// Returns the largest integer less than or equal to `self`. /// diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index aac81d48c1b45..63abb5adcbfb1 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -393,6 +393,7 @@ pub mod consts { pub const LN_10: f32 = 2.30258509299404568401799145468436421_f32; } +#[doc(test(attr(allow(unused_features))))] impl f32 { /// The radix or base of the internal representation of `f32`. #[stable(feature = "assoc_int_consts", since = "1.43.0")] diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index bacf429e77fab..1294e094e4a07 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -393,6 +393,7 @@ pub mod consts { pub const LN_10: f64 = 2.30258509299404568401799145468436421_f64; } +#[doc(test(attr(allow(unused_features))))] impl f64 { /// The radix or base of the internal representation of `f64`. #[stable(feature = "assoc_int_consts", since = "1.43.0")] diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index efd5123055fe6..5e303a3c6b790 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -50,7 +50,6 @@ #![feature(f16)] #![feature(f128)] #![feature(float_algebraic)] -#![feature(float_bits_const)] #![feature(float_exact_integer_constants)] #![feature(float_gamma)] #![feature(float_minimum_maximum)] diff --git a/library/std/src/num/f16.rs b/library/std/src/num/f16.rs index 318a0b3af86a2..7ca266c8a5f60 100644 --- a/library/std/src/num/f16.rs +++ b/library/std/src/num/f16.rs @@ -16,6 +16,7 @@ use crate::intrinsics; use crate::sys::cmath; #[cfg(not(test))] +#[doc(test(attr(allow(unused_features))))] impl f16 { /// Raises a number to a floating point power. /// diff --git a/library/std/src/process.rs b/library/std/src/process.rs index a682873f969c8..321b68b3225ad 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1381,6 +1381,7 @@ impl Output { /// # Examples /// /// ``` + /// # #![allow(unused_features)] /// #![feature(exit_status_error)] /// # #[cfg(all(unix, not(target_os = "android"), not(all(target_vendor = "apple", not(target_os = "macos")))))] { /// use std::process::Command; @@ -1960,6 +1961,7 @@ impl crate::sealed::Sealed for ExitStatusError {} pub struct ExitStatusError(imp::ExitStatusError); #[unstable(feature = "exit_status_error", issue = "84908")] +#[doc(test(attr(allow(unused_features))))] impl ExitStatusError { /// Reports the exit code, if applicable, from an `ExitStatusError`. /// diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index f9cb60c66d916..852ea26ab89e0 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -189,6 +189,8 @@ you can visualize in [Perfetto](https://ui.perfetto.dev/). For example: MIRI_TRACING=1 ./miri run --features=tracing tests/pass/hello.rs ``` +See [doc/tracing.md](./doc/tracing.md) for more information. + ### UI testing We use ui-testing in Miri, meaning we generate `.stderr` and `.stdout` files for the output diff --git a/src/tools/miri/doc/tracing.md b/src/tools/miri/doc/tracing.md index d7114af947dc1..1fbdd945d977e 100644 --- a/src/tools/miri/doc/tracing.md +++ b/src/tools/miri/doc/tracing.md @@ -2,6 +2,9 @@ Miri can be traced to understand how much time is spent in its various components (e.g. borrow tracker, data race checker, etc.). When tracing is enabled, running Miri will create a `.json` trace file that can be opened and analyzed in [Perfetto](https://ui.perfetto.dev/). For any questions regarding this documentation you may contact [Stypox](https://rust-lang.zulipchat.com/#narrow/dm/627563-Stypox) on Zulip. +> [!WARNING] +> Tracing in Miri at the moment is broken due to two bugs in tracing libraries: https://github.com/tokio-rs/tracing/pull/3392 and https://github.com/davidbarsky/tracing-tree/issues/93. Also see https://github.com/rust-lang/miri/issues/4752. + ## Obtaining a trace file ### From the Miri codebase @@ -240,7 +243,7 @@ let _trace = enter_trace_span!(M, "borrow_tracker", borrow_tracker = "on_stack_p ### `tracing_separate_thread` parameter -Miri saves traces using the the `tracing_chrome` `tracing::Layer` so that they can be visualized in Perfetto. To instruct `tracing_chrome` to put some spans on a separate trace thread/line than other spans when viewed in Perfetto, you can pass `tracing_separate_thread = tracing::field::Empty` to the tracing macros. This is useful to separate out spans which just indicate the current step or program frame being processed by the interpreter. As explained in [The timeline](#the-timeline), those spans end up under the "Global Legacy Events" track. You should use a value of `tracing::field::Empty` so that other tracing layers (e.g. the logger) will ignore the `tracing_separate_thread` field. For example: +Miri saves traces using the `tracing_chrome` `tracing::Layer` so that they can be visualized in Perfetto. To instruct `tracing_chrome` to put some spans on a separate trace thread/line than other spans when viewed in Perfetto, you can pass `tracing_separate_thread = tracing::field::Empty` to the tracing macros. This is useful to separate out spans which just indicate the current step or program frame being processed by the interpreter. As explained in [The timeline](#the-timeline), those spans end up under the "Global Legacy Events" track. You should use a value of `tracing::field::Empty` so that other tracing layers (e.g. the logger) will ignore the `tracing_separate_thread` field. For example: ```rust let _trace = enter_trace_span!(M, step::eval_statement, tracing_separate_thread = tracing::field::Empty); ``` @@ -277,9 +280,12 @@ So the solution was to copy-paste [the only file](https://github.com/thoren-d/tr ### Time measurements -tracing-chrome originally used `std::time::Instant` to measure time, however on some x86/x86_64 Linux systems it might be unbearably slow since the underlying system call (`clock_gettime`) would take ≈1.3µs. Read more [here](https://btorpey.github.io/blog/2014/02/18/clock-sources-in-linux/) about how the Linux kernel chooses the clock source. +tracing-chrome uses `std::time::Instant` to measure time. On most modern systems this is ok, since the underlying system call (`clock_gettime`) uses very fast hardware counters (e.g. `tsc`) and has a latency of ≈16ns. + +On some x86/x86_64 Linux systems, however, `tsc` is not "reliable" and the system thus relies on other timers, e.g. `hpet` which takes ≈1.3µs. Read [here](https://btorpey.github.io/blog/2014/02/18/clock-sources-in-linux/) how the Linux kernel chooses the clock source, and how to check if your system is using `tsc`. If it doesn't use `tsc`, then expect most of the trace time being spent in time measurements, which degrades traces' usefulness... See [here](https://github.com/rust-lang/miri/issues/4563) for some discussion. -Therefore, on x86/x86_64 Linux systems with a CPU that has an invariant TSC counter, we read from that instead to measure time, which takes only ≈13ns. There are unfortunately a lot of caveats to this approach though, as explained [in the code](https://github.com/rust-lang/miri/blob/master/src/bin/log/tracing_chrome_instant.rs) and [in the PR](https://github.com/rust-lang/miri/pull/4524). The most impactful one is that: every thread spawned in Miri that wants to trace something (which requires measuring time) needs to pin itself to a single CPU core (using `sched_setaffinity`). +> [!WARNING] +> A (somewhat risky) workaround is to add `tsc=reliable clocksource=tsc hpet=disable` to the kernel boot parameters, which forces it to use `tsc` even if it is unreliable. But this may render the system unstable, so try it at your own risk! ## Other useful stuff diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 28c3e88535f61..90a48de0fcb00 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -7bee525095c0872e87c038c412c781b9bbb3f5dc +d933cf483edf1605142ac6899ff32536c0ad8b22 diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 32897eb89a83c..91559e76e68c6 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -168,7 +168,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { if let Some(GlobalAlloc::Function { instance, .. }) = this.tcx.try_get_global_alloc(alloc_id) { - let fn_sig = this.tcx.fn_sig(instance.def_id()).skip_binder().skip_binder(); + let fn_sig = this.tcx.instantiate_bound_regions_with_erased( + this.tcx + .fn_sig(instance.def_id()) + .instantiate(*this.tcx, instance.args), + ); let fn_ptr = crate::shims::native_lib::build_libffi_closure(this, fn_sig)?; #[expect( diff --git a/src/tools/miri/src/bin/log/mod.rs b/src/tools/miri/src/bin/log/mod.rs index 22f74dd46b540..f3b2fdb5348e0 100644 --- a/src/tools/miri/src/bin/log/mod.rs +++ b/src/tools/miri/src/bin/log/mod.rs @@ -1,3 +1,2 @@ pub mod setup; mod tracing_chrome; -mod tracing_chrome_instant; diff --git a/src/tools/miri/src/bin/log/tracing_chrome.rs b/src/tools/miri/src/bin/log/tracing_chrome.rs index 85b4de62a5ec4..2caea73a6e3da 100644 --- a/src/tools/miri/src/bin/log/tracing_chrome.rs +++ b/src/tools/miri/src/bin/log/tracing_chrome.rs @@ -50,9 +50,8 @@ use std::{ thread::JoinHandle, }; -use crate::log::tracing_chrome_instant::TracingChromeInstant; - /// Contains thread-local data for threads that send tracing spans or events. +#[derive(Clone)] struct ThreadData { /// A unique ID for this thread, will populate "tid" field in the output trace file. tid: usize, @@ -61,7 +60,7 @@ struct ThreadData { out: Sender, /// The instant in time this thread was started. All events happening on this thread will be /// saved to the trace file with a timestamp (the "ts" field) measured relative to this instant. - start: TracingChromeInstant, + start: std::time::Instant, } thread_local! { @@ -562,28 +561,46 @@ where #[inline(always)] fn with_elapsed_micros_subtracting_tracing(&self, f: impl Fn(f64, usize, &Sender)) { THREAD_DATA.with(|value| { - let mut thread_data = value.borrow_mut(); - let (ThreadData { tid, out, start }, new_thread) = match thread_data.as_mut() { - Some(thread_data) => (thread_data, false), - None => { - let tid = self.max_tid.fetch_add(1, Ordering::SeqCst); - let out = self.out.lock().unwrap().clone(); - let start = TracingChromeInstant::setup_for_thread_and_start(tid); - *thread_data = Some(ThreadData { tid, out, start }); - (thread_data.as_mut().unwrap(), true) + // Make sure not to keep `value` borrowed when calling `f` below, since the user tracing + // code that `f` might invoke (e.g. fmt::Debug argument formatting) may contain nested + // tracing calls that would cause `value` to be doubly-borrowed mutably. + let (ThreadData { tid, out, start }, new_thread) = { + let mut thread_data = value.borrow_mut(); + match thread_data.as_mut() { + Some(thread_data) => (thread_data.clone(), false), + None => { + let tid = self.max_tid.fetch_add(1, Ordering::SeqCst); + let out = self.out.lock().unwrap().clone(); + let start = std::time::Instant::now(); + *thread_data = Some(ThreadData { tid, out: out.clone(), start }); + (ThreadData { tid, out, start }, true) + } } }; - start.with_elapsed_micros_subtracting_tracing(|ts| { - if new_thread { - let name = match std::thread::current().name() { - Some(name) => name.to_owned(), - None => tid.to_string(), - }; - let _ignored = out.send(Message::NewThread(*tid, name)); - } - f(ts, *tid, out); - }); + // Obtain the current time (before executing `f`). + let instant_before_f = std::time::Instant::now(); + + // Using the current time (`instant_before_f`), calculate the elapsed time (in + // microseconds) since `start` was instantiated, accounting for any time that was + // previously spent executing `f`. The "accounting" part is not computed in this + // line, but is rather done by shifting forward the `start` down below. + let ts = (instant_before_f - start).as_nanos() as f64 / 1000.0; + + // Run the function (supposedly a function internal to the tracing infrastructure). + if new_thread { + let name = match std::thread::current().name() { + Some(name) => name.to_owned(), + None => tid.to_string(), + }; + let _ignored = out.send(Message::NewThread(tid, name)); + } + f(ts, tid, &out); + + // Measure how much time was spent executing `f` and shift `start` forward + // by that amount. This "removes" that time from the trace. + // See comment at the top of this function for why we have to re-borrow here. + value.borrow_mut().as_mut().unwrap().start += std::time::Instant::now() - instant_before_f; }); } } diff --git a/src/tools/miri/src/bin/log/tracing_chrome_instant.rs b/src/tools/miri/src/bin/log/tracing_chrome_instant.rs deleted file mode 100644 index 04705b8846d9c..0000000000000 --- a/src/tools/miri/src/bin/log/tracing_chrome_instant.rs +++ /dev/null @@ -1,183 +0,0 @@ -//! Code in this class was in part inspired by -//! . -//! A useful resource is also -//! , -//! although this file does not implement TSC synchronization but instead pins threads to CPUs, -//! since the former is not reliable (i.e. it might lead to non-monotonic time measurements). -//! Another useful resource for future improvements might be measureme's time measurement utils: -//! . -//! Documentation about how the Linux kernel chooses a clock source can be found here: -//! . -#![cfg(feature = "tracing")] - -/// This alternative `TracingChromeInstant` implementation was made entirely to suit the needs of -/// [crate::log::tracing_chrome], and shouldn't be used for anything else. It features two functions: -/// - [TracingChromeInstant::setup_for_thread_and_start], which sets up the current thread to do -/// proper time tracking and returns a point in time to use as "t=0", and -/// - [TracingChromeInstant::with_elapsed_micros_subtracting_tracing], which allows -/// obtaining how much time elapsed since [TracingChromeInstant::setup_for_thread_and_start] was -/// called while accounting for (and subtracting) the time spent inside tracing-related functions. -/// -/// This measures time using [std::time::Instant], except for x86/x86_64 Linux machines, where -/// [std::time::Instant] is too slow (~1.5us) and thus `rdtsc` is used instead (~5ns). -pub enum TracingChromeInstant { - WallTime { - /// The time at which this instant was created, shifted forward to account - /// for time spent in tracing functions as explained in - /// [TracingChromeInstant::with_elapsed_micros_subtracting_tracing]'s comments. - start_instant: std::time::Instant, - }, - #[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))] - Tsc { - /// The value in the TSC counter when this instant was created, shifted forward to account - /// for time spent in tracing functions as explained in - /// [TracingChromeInstant::with_elapsed_micros_subtracting_tracing]'s comments. - start_tsc: u64, - /// The period of the TSC counter in microseconds. - tsc_to_microseconds: f64, - }, -} - -impl TracingChromeInstant { - /// Can be thought of as the same as [std::time::Instant::now()], but also does some setup to - /// make TSC stable in case TSC is available. This is supposed to be called (at most) once per - /// thread since the thread setup takes a few milliseconds. - /// - /// WARNING: If TSC is available, `incremental_thread_id` is used to pick to which CPU to pin - /// the current thread. Thread IDs should be assigned contiguously starting from 0. Be aware - /// that the current thread will be restricted to one CPU for the rest of the execution! - pub fn setup_for_thread_and_start(incremental_thread_id: usize) -> TracingChromeInstant { - #[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))] - if *tsc::IS_TSC_AVAILABLE.get_or_init(tsc::is_tsc_available) { - // We need to lock this thread to a specific CPU, because CPUs' TSC timers might be out - // of sync. - tsc::set_cpu_affinity(incremental_thread_id); - - // Can only use tsc_to_microseconds() and rdtsc() after having set the CPU affinity! - // We compute tsc_to_microseconds anew for every new thread just in case some CPU core - // has a different TSC frequency. - let tsc_to_microseconds = tsc::tsc_to_microseconds(); - let start_tsc = tsc::rdtsc(); - return TracingChromeInstant::Tsc { start_tsc, tsc_to_microseconds }; - } - - let _ = incremental_thread_id; // otherwise we get a warning when the TSC branch is disabled - TracingChromeInstant::WallTime { start_instant: std::time::Instant::now() } - } - - /// Calls `f` with the time elapsed in microseconds since this [TracingChromeInstant] was built - /// by [TracingChromeInstant::setup_for_thread_and_start], while subtracting all time previously - /// spent executing other `f`s passed to this function. This behavior allows subtracting time - /// spent in functions that log tracing data (which `f` is supposed to be) from the tracing time - /// measurements. - /// - /// Note: microseconds are used as the time unit since that's what Chrome trace files should - /// contain, see the definition of the "ts" field in - /// . - #[inline(always)] - pub fn with_elapsed_micros_subtracting_tracing(&mut self, f: impl Fn(f64)) { - match self { - TracingChromeInstant::WallTime { start_instant } => { - // Obtain the current time (before executing `f`). - let instant_before_f = std::time::Instant::now(); - - // Using the current time (`instant_before_f`) and the `start_instant` stored in - // `self`, calculate the elapsed time (in microseconds) since this instant was - // instantiated, accounting for any time that was previously spent executing `f`. - // The "accounting" part is not computed in this line, but is rather done by - // shifting forward the `start_instant` down below. - let ts = (instant_before_f - *start_instant).as_nanos() as f64 / 1000.0; - - // Run the function (supposedly a function internal to the tracing infrastructure). - f(ts); - - // Measure how much time was spent executing `f` and shift `start_instant` forward - // by that amount. This "removes" that time from the trace. - *start_instant += std::time::Instant::now() - instant_before_f; - } - - #[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))] - TracingChromeInstant::Tsc { start_tsc, tsc_to_microseconds } => { - // the comments above also apply here, since it's the same logic - let tsc_before_f = tsc::rdtsc(); - let ts = ((tsc_before_f - *start_tsc) as f64) * (*tsc_to_microseconds); - f(ts); - *start_tsc += tsc::rdtsc() - tsc_before_f; - } - } - } -} - -#[cfg(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")))] -mod tsc { - - pub static IS_TSC_AVAILABLE: std::sync::OnceLock = std::sync::OnceLock::new(); - - /// Reads the timestamp-counter register. Will give monotonic answers only when called from the - /// same thread, because the TSC of different CPUs might be out of sync. - #[inline(always)] - pub(super) fn rdtsc() -> u64 { - #[cfg(target_arch = "x86")] - use core::arch::x86::_rdtsc; - #[cfg(target_arch = "x86_64")] - use core::arch::x86_64::_rdtsc; - - unsafe { _rdtsc() } - } - - /// Estimates the frequency of the TSC counter by waiting 10ms in a busy loop and - /// looking at how much the TSC increased in the meantime. - pub(super) fn tsc_to_microseconds() -> f64 { - const BUSY_WAIT: std::time::Duration = std::time::Duration::from_millis(10); - let tsc_start = rdtsc(); - let instant_start = std::time::Instant::now(); - while instant_start.elapsed() < BUSY_WAIT { - // `thread::sleep()` is not very precise at waking up the program at the right time, - // so use a busy loop instead. - core::hint::spin_loop(); - } - let tsc_end = rdtsc(); - (BUSY_WAIT.as_nanos() as f64) / 1000.0 / ((tsc_end - tsc_start) as f64) - } - - /// Checks whether the TSC counter is available and runs at a constant rate independently - /// of CPU frequency even across different power states of the CPU (i.e. checks for the - /// `invariant_tsc` CPUID flag). - pub(super) fn is_tsc_available() -> bool { - #[cfg(target_arch = "x86")] - use core::arch::x86::__cpuid; - #[cfg(target_arch = "x86_64")] - use core::arch::x86_64::__cpuid; - - // implemented like https://docs.rs/raw-cpuid/latest/src/raw_cpuid/extended.rs.html#965-967 - const LEAF: u32 = 0x80000007; // this is the leaf for "advanced power management info" - let cpuid = __cpuid(LEAF); - (cpuid.edx & (1 << 8)) != 0 // EDX bit 8 indicates invariant TSC - } - - /// Forces the current thread to run on a single CPU, which ensures the TSC counter is monotonic - /// (since TSCs of different CPUs might be out-of-sync). `incremental_thread_id` is used to pick - /// to which CPU to pin the current thread, and should be an incremental number that starts from - /// 0. - pub(super) fn set_cpu_affinity(incremental_thread_id: usize) { - let cpu_id = match std::thread::available_parallelism() { - Ok(available_parallelism) => incremental_thread_id % available_parallelism, - _ => panic!("Could not determine CPU count to properly set CPU affinity"), - }; - - let mut set = unsafe { std::mem::zeroed::() }; - unsafe { libc::CPU_SET(cpu_id, &mut set) }; - - // Set the current thread's core affinity. - if unsafe { - libc::sched_setaffinity( - 0, // Defaults to current thread - size_of::(), - &set as *const _, - ) - } != 0 - { - panic!("Could not set CPU affinity") - } - } -} diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 14528759472c8..3766debb159d0 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -193,7 +193,11 @@ fn make_miri_codegen_backend(opts: &Options, target: &Target) -> Box( @@ -354,6 +358,9 @@ impl rustc_driver::Callbacks for MiriDepCompilerCalls { ) } }); + + // Register our custom extra symbols. + config.extra_symbols = miri::sym::EXTRA_SYMBOLS.into(); } fn after_analysis<'tcx>( diff --git a/src/tools/miri/src/concurrency/genmc/scheduling.rs b/src/tools/miri/src/concurrency/genmc/scheduling.rs index c760126d787d1..54e87c05818de 100644 --- a/src/tools/miri/src/concurrency/genmc/scheduling.rs +++ b/src/tools/miri/src/concurrency/genmc/scheduling.rs @@ -5,7 +5,8 @@ use rustc_middle::ty::{self, Ty}; use super::GenmcCtx; use crate::{ - InterpCx, InterpResult, MiriMachine, TerminationInfo, ThreadId, interp_ok, throw_machine_stop, + InterpCx, InterpResult, MiriMachine, TerminationInfo, ThreadId, interp_ok, sym, + throw_machine_stop, }; enum NextInstrKind { @@ -76,11 +77,11 @@ fn get_function_kind<'tcx>( // NOTE: Functions intercepted by Miri in `concurrency/genmc/intercep.rs` must also be added here. // Such intercepted functions, like `sys::Mutex::lock`, should be treated as atomics to ensure we call the scheduler when we encounter one of them. // These functions must also be classified whether they may have load semantics. - if ecx.tcx.is_diagnostic_item(rustc_span::sym::sys_mutex_lock, callee_def_id) - || ecx.tcx.is_diagnostic_item(rustc_span::sym::sys_mutex_try_lock, callee_def_id) + if ecx.tcx.is_diagnostic_item(sym::sys_mutex_lock, callee_def_id) + || ecx.tcx.is_diagnostic_item(sym::sys_mutex_try_lock, callee_def_id) { return interp_ok(MaybeAtomic(ActionKind::Load)); - } else if ecx.tcx.is_diagnostic_item(rustc_span::sym::sys_mutex_unlock, callee_def_id) { + } else if ecx.tcx.is_diagnostic_item(sym::sys_mutex_unlock, callee_def_id) { return interp_ok(MaybeAtomic(ActionKind::NonLoad)); } // The next step is a call to a regular Rust function. diff --git a/src/tools/miri/src/concurrency/genmc/shims.rs b/src/tools/miri/src/concurrency/genmc/shims.rs index 4685dfd1b8dd7..ff9d43e70a46d 100644 --- a/src/tools/miri/src/concurrency/genmc/shims.rs +++ b/src/tools/miri/src/concurrency/genmc/shims.rs @@ -24,24 +24,22 @@ impl GenmcCtx { } } +/// Small helper to get the arguments of an intercepted function call. +fn get_fn_args<'tcx, const N: usize>( + instance: ty::Instance<'tcx>, + args: &[FnArg<'tcx>], +) -> InterpResult<'tcx, [OpTy<'tcx>; N]> { + let args = MiriInterpCx::copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit? + if let Ok(ops) = args.try_into() { + return interp_ok(ops); + } + panic!("{} is a diagnostic item expected to have {} arguments", instance, N); +} + // Handling of code intercepted by Miri in GenMC mode, such as assume statement or `std::sync::Mutex`. impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { - /// Small helper to get the arguments of an intercepted function call. - fn get_fn_args( - &self, - instance: ty::Instance<'tcx>, - args: &[FnArg<'tcx>], - ) -> InterpResult<'tcx, [OpTy<'tcx>; N]> { - let this = self.eval_context_ref(); - let args = this.copy_fn_args(args); // FIXME: Should `InPlace` arguments be reset to uninit? - if let Ok(ops) = args.try_into() { - return interp_ok(ops); - } - panic!("{} is a diagnostic item expected to have {} arguments", instance, N); - } - /**** Blocking functionality ****/ /// Handle a thread getting blocked by a user assume (not an automatically generated assume). @@ -200,17 +198,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); // NOTE: When adding new intercepted functions here, they must also be added to `fn get_function_kind` in `concurrency/genmc/scheduling.rs`. - use rustc_span::sym; if this.tcx.is_diagnostic_item(sym::sys_mutex_lock, instance.def_id()) { - let [mutex] = this.get_fn_args(instance, args)?; + let [mutex] = get_fn_args(instance, args)?; let mutex = this.deref_pointer(&mutex)?; this.intercept_mutex_lock(mutex)?; } else if this.tcx.is_diagnostic_item(sym::sys_mutex_try_lock, instance.def_id()) { - let [mutex] = this.get_fn_args(instance, args)?; + let [mutex] = get_fn_args(instance, args)?; let mutex = this.deref_pointer(&mutex)?; this.intercept_mutex_try_lock(mutex, dest)?; } else if this.tcx.is_diagnostic_item(sym::sys_mutex_unlock, instance.def_id()) { - let [mutex] = this.get_fn_args(instance, args)?; + let [mutex] = get_fn_args(instance, args)?; let mutex = this.deref_pointer(&mutex)?; this.intercept_mutex_unlock(mutex)?; } else { diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 35217da37e5b5..367012e56ad9c 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -149,6 +149,7 @@ pub enum NonHaltingDiagnostic { failure_ordering: AtomicReadOrd, effective_failure_ordering: AtomicReadOrd, }, + FileInProcOpened, } /// Level of Miri specific diagnostics @@ -655,6 +656,7 @@ impl<'tcx> MiriMachine<'tcx> { | ProgressReport { .. } | WeakMemoryOutdatedLoad { .. } => ("tracking was triggered here".to_string(), DiagLevel::Note), + FileInProcOpened => ("open a file in `/proc`".to_string(), DiagLevel::Warning), }; let title = match &e { @@ -702,6 +704,7 @@ impl<'tcx> MiriMachine<'tcx> { }; format!("GenMC currently does not model the failure ordering for `compare_exchange`. {was_upgraded_msg}. Miri with GenMC might miss bugs related to this memory access.") } + FileInProcOpened => format!("files in `/proc` can bypass the Abstract Machine and might not work properly in Miri") }; let notes = match &e { diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index f09fc6c187896..ae7ec1fdcce51 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -10,7 +10,7 @@ pub use self::atomic::AtomicRmwOp; use rand::Rng; use rustc_abi::Size; use rustc_middle::{mir, ty}; -use rustc_span::{Symbol, sym}; +use rustc_span::Symbol; use self::atomic::EvalContextExt as _; use self::math::EvalContextExt as _; diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 32cadddc33aa3..1551401654582 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(bootstrap, feature(if_let_guard))] +#![cfg_attr(bootstrap, feature(cfg_select))] #![feature(abort_unwind)] #![feature(rustc_private)] #![feature(float_gamma)] @@ -16,7 +17,7 @@ #![feature(derive_coerce_pointee)] #![feature(arbitrary_self_types)] #![feature(iter_advance_by)] -#![cfg_attr(bootstrap, feature(cfg_select))] +#![feature(macro_metavar_expr)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, @@ -39,8 +40,11 @@ clippy::needless_lifetimes, clippy::too_long_first_doc_paragraph, clippy::len_zero, + clippy::collapsible_match, // We are not implementing queries here so it's fine rustc::potential_query_instability, + // FIXME: Unused features should be removed in the future + unused_features, )] #![warn( rust_2018_idioms, @@ -87,6 +91,7 @@ mod math; mod operator; mod provenance_gc; mod shims; +pub mod sym; // Establish a "crate-wide prelude": we often import `crate::*`. // Make all those symbols available in the same place as our own. diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 7883673cdd6a2..000f4ac4cecaa 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -300,7 +300,8 @@ pub enum ProvenanceExtra { #[cfg(target_pointer_width = "64")] static_assert_size!(StrictPointer, 24); -// FIXME: this would with in 24bytes but layout optimizations are not smart enough +// Pointer does not fit as the layout algorithm isn't smart enough (but also, we tried using +// pattern types to get a larger niche that makes this fit and it didn't improve performance). // #[cfg(target_pointer_width = "64")] //static_assert_size!(Pointer, 24); #[cfg(target_pointer_width = "64")] diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 3c2e14c181682..460015d4c3ccc 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -196,7 +196,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [flag] = check_min_vararg_count("fcntl(fd, F_SETFL, ...)", varargs)?; let flag = this.read_scalar(flag)?.to_i32()?; - fd.set_flags(flag, this) + // Ignore flags that never get stored by SETFL. + // "File access mode (O_RDONLY, O_WRONLY, O_RDWR) and file + // creation flags (i.e., O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC) + // in arg are ignored." + let ignored_flags = this.eval_libc_i32("O_RDONLY") + | this.eval_libc_i32("O_WRONLY") + | this.eval_libc_i32("O_RDWR") + | this.eval_libc_i32("O_CREAT") + | this.eval_libc_i32("O_EXCL") + | this.eval_libc_i32("O_NOCTTY") + | this.eval_libc_i32("O_TRUNC"); + + fd.set_flags(flag & !ignored_flags, this) } cmd if this.tcx.sess.target.os == Os::MacOs && cmd == this.eval_libc_i32("F_FULLFSYNC") => diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 48e2ebd0f13ea..130643ec680d2 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -539,6 +539,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } + // Network sockets + "socket" => { + let [domain, type_, protocol] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, i32, i32) -> i32), + link_name, + abi, + args, + )?; + let result = this.socket(domain, type_, protocol)?; + this.write_scalar(result, dest)?; + } + // Time "gettimeofday" => { let [tv, tz] = this.check_shim_sig( diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index a01755ef95ae7..9873af85b989b 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -7,7 +7,7 @@ use std::fs::{ rename, }; use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write}; -use std::path::{Path, PathBuf}; +use std::path::{self, Path, PathBuf}; use std::time::SystemTime; use rustc_abi::Size; @@ -354,9 +354,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let path_raw = this.read_pointer(path_raw)?; - let path = this.read_path_from_c_str(path_raw)?; let flag = this.read_scalar(flag)?.to_i32()?; + let path = this.read_path_from_c_str(path_raw)?; + // Files in `/proc` won't work properly. + if matches!(this.tcx.sess.target.os, Os::Linux | Os::Android | Os::Illumos | Os::Solaris) + && path::absolute(&path).is_ok_and(|path| path.starts_with("/proc")) + { + this.machine.emit_diagnostic(NonHaltingDiagnostic::FileInProcOpened); + } + let mut options = OpenOptions::new(); let o_rdonly = this.eval_libc_i32("O_RDONLY"); diff --git a/src/tools/miri/src/shims/unix/mod.rs b/src/tools/miri/src/shims/unix/mod.rs index 660e4ded5cda7..5ea49926fb9fd 100644 --- a/src/tools/miri/src/shims/unix/mod.rs +++ b/src/tools/miri/src/shims/unix/mod.rs @@ -4,6 +4,7 @@ mod env; mod fd; mod fs; mod mem; +mod socket; mod sync; mod thread; mod unnamed_socket; @@ -21,6 +22,7 @@ pub use self::fd::{EvalContextExt as _, UnixFileDescription}; pub use self::fs::{DirTable, EvalContextExt as _}; pub use self::linux_like::epoll::EpollInterestTable; pub use self::mem::EvalContextExt as _; +pub use self::socket::EvalContextExt as _; pub use self::sync::EvalContextExt as _; pub use self::thread::{EvalContextExt as _, ThreadNameResult}; pub use self::unnamed_socket::EvalContextExt as _; diff --git a/src/tools/miri/src/shims/unix/socket.rs b/src/tools/miri/src/shims/unix/socket.rs new file mode 100644 index 0000000000000..66fe5d8a44a40 --- /dev/null +++ b/src/tools/miri/src/shims/unix/socket.rs @@ -0,0 +1,157 @@ +use std::cell::Cell; +use std::net::{TcpListener, TcpStream}; + +use rustc_const_eval::interpret::{InterpResult, interp_ok}; +use rustc_middle::throw_unsup_format; +use rustc_target::spec::Os; + +use crate::shims::files::{FdId, FileDescription}; +use crate::{OpTy, Scalar, *}; + +#[derive(Debug, PartialEq)] +enum SocketFamily { + // IPv4 internet protocols + IPv4, + // IPv6 internet protocols + IPv6, +} + +#[derive(Debug)] +enum SocketType { + /// Reliable full-duplex communication, based on connections. + Stream, +} + +#[allow(unused)] +#[derive(Debug)] +enum SocketKind { + TcpListener(TcpListener), + TcpStream(TcpStream), +} + +#[allow(unused)] +#[derive(Debug)] +struct Socket { + /// Family of the socket, used to ensure socket only binds/connects to address of + /// same family. + family: SocketFamily, + /// Type of the socket, either datagram or stream. + /// Only stream is supported at the moment! + socket_type: SocketType, + /// Whether this fd is non-blocking or not. + is_non_block: Cell, +} + +impl FileDescription for Socket { + fn name(&self) -> &'static str { + "socket" + } + + fn destroy<'tcx>( + self, + _self_id: FdId, + _communicate_allowed: bool, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, std::io::Result<()>> + where + Self: Sized, + { + interp_ok(Ok(())) + } + + fn get_flags<'tcx>(&self, ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx, Scalar> { + let mut flags = ecx.eval_libc_i32("O_RDWR"); + + if self.is_non_block.get() { + flags |= ecx.eval_libc_i32("O_NONBLOCK"); + } + + interp_ok(Scalar::from_i32(flags)) + } + + fn set_flags<'tcx>( + &self, + mut _flag: i32, + _ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, Scalar> { + throw_unsup_format!("fcntl: socket flags aren't supported") + } +} + +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + /// For more information on the arguments see the socket manpage: + /// + fn socket( + &mut self, + domain: &OpTy<'tcx>, + type_: &OpTy<'tcx>, + protocol: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + let domain = this.read_scalar(domain)?.to_i32()?; + let mut flags = this.read_scalar(type_)?.to_i32()?; + let protocol = this.read_scalar(protocol)?.to_i32()?; + + // Reject if isolation is enabled + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`socket`", reject_with)?; + this.set_last_error(LibcError("EACCES"))?; + return interp_ok(Scalar::from_i32(-1)); + } + + let mut is_sock_nonblock = false; + + // Interpret the flag. Every flag we recognize is "subtracted" from `flags`, so + // if there is anything left at the end, that's an unsupported flag. + if matches!(this.tcx.sess.target.os, Os::Linux | Os::Android | Os::FreeBsd) { + // SOCK_NONBLOCK and SOCK_CLOEXEC only exist on Linux, Android and FreeBSD. + let sock_nonblock = this.eval_libc_i32("SOCK_NONBLOCK"); + let sock_cloexec = this.eval_libc_i32("SOCK_CLOEXEC"); + if flags & sock_nonblock == sock_nonblock { + is_sock_nonblock = true; + flags &= !sock_nonblock; + } + if flags & sock_cloexec == sock_cloexec { + // We don't support `exec` so we can ignore this. + flags &= !sock_cloexec; + } + } + + let family = if domain == this.eval_libc_i32("AF_INET") { + SocketFamily::IPv4 + } else if domain == this.eval_libc_i32("AF_INET6") { + SocketFamily::IPv6 + } else { + throw_unsup_format!( + "socket: domain {:#x} is unsupported, only AF_INET and \ + AF_INET6 are allowed.", + domain + ); + }; + + if flags != this.eval_libc_i32("SOCK_STREAM") { + throw_unsup_format!( + "socket: type {:#x} is unsupported, only SOCK_STREAM, \ + SOCK_CLOEXEC and SOCK_NONBLOCK are allowed", + flags + ); + } + if protocol != 0 { + throw_unsup_format!( + "socket: socket protocol {protocol} is unsupported, \ + only 0 is allowed" + ); + } + + let fds = &mut this.machine.fds; + let fd = fds.new_ref(Socket { + family, + is_non_block: Cell::new(is_sock_nonblock), + socket_type: SocketType::Stream, + }); + + interp_ok(Scalar::from_i32(fds.insert(fd))) + } +} diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs index cc371b43a6815..ea34f72feee5b 100644 --- a/src/tools/miri/src/shims/unix/unnamed_socket.rs +++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs @@ -170,12 +170,7 @@ impl FileDescription for AnonSocket { mut flag: i32, ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx, Scalar> { - // FIXME: File creation flags should be ignored. - let o_nonblock = ecx.eval_libc_i32("O_NONBLOCK"); - let o_rdonly = ecx.eval_libc_i32("O_RDONLY"); - let o_wronly = ecx.eval_libc_i32("O_WRONLY"); - let o_rdwr = ecx.eval_libc_i32("O_RDWR"); // O_NONBLOCK flag can be set / unset by user. if flag & o_nonblock == o_nonblock { @@ -185,9 +180,6 @@ impl FileDescription for AnonSocket { self.is_nonblock.set(false); } - // Ignore all file access mode flags. - flag &= !(o_rdonly | o_wronly | o_rdwr); - // Throw error if there is any unsupported flag. if flag != 0 { throw_unsup_format!( diff --git a/src/tools/miri/src/sym.rs b/src/tools/miri/src/sym.rs new file mode 100644 index 0000000000000..7c870494f216c --- /dev/null +++ b/src/tools/miri/src/sym.rs @@ -0,0 +1,36 @@ +#![allow(non_upper_case_globals)] + +#[doc(no_inline)] +pub use rustc_span::sym::*; + +macro_rules! val { + ($name:ident) => { + stringify!($name) + }; + ($name:ident $value:literal) => { + $value + }; +} + +macro_rules! generate { + ($($name:ident $(: $value:literal)? ,)*) => { + /// To be supplied to `rustc_interface::Config` + pub const EXTRA_SYMBOLS: &[&str] = &[ + $( + val!($name $($value)?), + )* + ]; + + $( + pub const $name: rustc_span::Symbol = rustc_span::Symbol::new(rustc_span::symbol::PREDEFINED_SYMBOLS_COUNT + ${index()}); + )* + }; +} + +// List of extra symbols to be included in Miri. +// An alternative content can be specified using a colon after the symbol name. +generate! { + sys_mutex_lock, + sys_mutex_try_lock, + sys_mutex_unlock, +} diff --git a/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.rs b/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.rs new file mode 100644 index 0000000000000..73776827aec06 --- /dev/null +++ b/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.rs @@ -0,0 +1,18 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows + +use std::alloc; +use std::cell::Cell; + +type T = (Cell, i32); + +// Deallocating `x` is UB because not all bytes are in an `UnsafeCell`. +fn foo(x: &T) { + let layout = alloc::Layout::new::(); + unsafe { alloc::dealloc(x as *const _ as *mut T as *mut u8, layout) }; //~ERROR: dealloc +} + +fn main() { + let b: Box = Box::new((Cell::new(0), 0)); + foo(unsafe { std::mem::transmute(Box::into_raw(b)) }); +} diff --git a/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.stack.stderr b/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.stack.stderr new file mode 100644 index 0000000000000..ae99f17fd9c22 --- /dev/null +++ b/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.stack.stderr @@ -0,0 +1,23 @@ +error: Undefined Behavior: attempting deallocation using at ALLOC, but that tag only grants SharedReadOnly permission for this location + --> tests/fail/both_borrows/mixed_cell_deallocate.rs:LL:CC + | +LL | unsafe { alloc::dealloc(x as *const _ as *mut T as *mut u8, layout) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a SharedReadOnly retag at offsets [0x4..0xc] + --> tests/fail/both_borrows/mixed_cell_deallocate.rs:LL:CC + | +LL | unsafe { alloc::dealloc(x as *const _ as *mut T as *mut u8, layout) }; + | ^ + = note: stack backtrace: + 0: foo + at tests/fail/both_borrows/mixed_cell_deallocate.rs:LL:CC + 1: main + at tests/fail/both_borrows/mixed_cell_deallocate.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.tree.stderr b/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.tree.stderr new file mode 100644 index 0000000000000..5dc2ffc27c1c7 --- /dev/null +++ b/src/tools/miri/tests/fail/both_borrows/mixed_cell_deallocate.tree.stderr @@ -0,0 +1,24 @@ +error: Undefined Behavior: deallocation through at ALLOC[0x4] is forbidden + --> tests/fail/both_borrows/mixed_cell_deallocate.rs:LL:CC + | +LL | unsafe { alloc::dealloc(x as *const _ as *mut T as *mut u8, layout) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: the accessed tag has state Frozen which forbids this deallocation (acting as a child write access) +help: the accessed tag was created here, in the initial state Cell + --> tests/fail/both_borrows/mixed_cell_deallocate.rs:LL:CC + | +LL | fn foo(x: &T) { + | ^ + = note: stack backtrace: + 0: foo + at tests/fail/both_borrows/mixed_cell_deallocate.rs:LL:CC + 1: main + at tests/fail/both_borrows/mixed_cell_deallocate.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/native-lib/fail/call_function_ptr.notrace.stderr b/src/tools/miri/tests/native-lib/fail/call_fn_ptr.notrace.stderr similarity index 77% rename from src/tools/miri/tests/native-lib/fail/call_function_ptr.notrace.stderr rename to src/tools/miri/tests/native-lib/fail/call_fn_ptr.notrace.stderr index faabba9ca7257..5e7764652fa74 100644 --- a/src/tools/miri/tests/native-lib/fail/call_function_ptr.notrace.stderr +++ b/src/tools/miri/tests/native-lib/fail/call_fn_ptr.notrace.stderr @@ -1,5 +1,5 @@ warning: sharing memory with a native function called via FFI - --> tests/native-lib/fail/call_function_ptr.rs:LL:CC + --> tests/native-lib/fail/call_fn_ptr.rs:LL:CC | LL | call_fn_ptr(Some(nop)); | ^^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function @@ -10,12 +10,12 @@ LL | call_fn_ptr(Some(nop)); = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free = note: stack backtrace: 0: pass_fn_ptr - at tests/native-lib/fail/call_function_ptr.rs:LL:CC + at tests/native-lib/fail/call_fn_ptr.rs:LL:CC 1: main - at tests/native-lib/fail/call_function_ptr.rs:LL:CC + at tests/native-lib/fail/call_fn_ptr.rs:LL:CC error: unsupported operation: calling a function pointer through the FFI boundary - --> tests/native-lib/fail/call_function_ptr.rs:LL:CC + --> tests/native-lib/fail/call_fn_ptr.rs:LL:CC | LL | call_fn_ptr(Some(nop)); | ^^^^^^^^^^^^^^^^^^^^^^ unsupported operation occurred here @@ -23,9 +23,9 @@ LL | call_fn_ptr(Some(nop)); = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: stack backtrace: 0: pass_fn_ptr - at tests/native-lib/fail/call_function_ptr.rs:LL:CC + at tests/native-lib/fail/call_fn_ptr.rs:LL:CC 1: main - at tests/native-lib/fail/call_function_ptr.rs:LL:CC + at tests/native-lib/fail/call_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/native-lib/fail/call_function_ptr.rs b/src/tools/miri/tests/native-lib/fail/call_fn_ptr.rs similarity index 100% rename from src/tools/miri/tests/native-lib/fail/call_function_ptr.rs rename to src/tools/miri/tests/native-lib/fail/call_fn_ptr.rs diff --git a/src/tools/miri/tests/native-lib/fail/call_function_ptr.trace.stderr b/src/tools/miri/tests/native-lib/fail/call_fn_ptr.trace.stderr similarity index 79% rename from src/tools/miri/tests/native-lib/fail/call_function_ptr.trace.stderr rename to src/tools/miri/tests/native-lib/fail/call_fn_ptr.trace.stderr index e56a5ece782b5..7418b08ebe110 100644 --- a/src/tools/miri/tests/native-lib/fail/call_function_ptr.trace.stderr +++ b/src/tools/miri/tests/native-lib/fail/call_fn_ptr.trace.stderr @@ -1,5 +1,5 @@ warning: sharing memory with a native function called via FFI - --> tests/native-lib/fail/call_function_ptr.rs:LL:CC + --> tests/native-lib/fail/call_fn_ptr.rs:LL:CC | LL | call_fn_ptr(Some(nop)); | ^^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function @@ -11,12 +11,12 @@ LL | call_fn_ptr(Some(nop)); = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here = note: stack backtrace: 0: pass_fn_ptr - at tests/native-lib/fail/call_function_ptr.rs:LL:CC + at tests/native-lib/fail/call_fn_ptr.rs:LL:CC 1: main - at tests/native-lib/fail/call_function_ptr.rs:LL:CC + at tests/native-lib/fail/call_fn_ptr.rs:LL:CC error: unsupported operation: calling a function pointer through the FFI boundary - --> tests/native-lib/fail/call_function_ptr.rs:LL:CC + --> tests/native-lib/fail/call_fn_ptr.rs:LL:CC | LL | call_fn_ptr(Some(nop)); | ^^^^^^^^^^^^^^^^^^^^^^ unsupported operation occurred here @@ -24,9 +24,9 @@ LL | call_fn_ptr(Some(nop)); = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support = note: stack backtrace: 0: pass_fn_ptr - at tests/native-lib/fail/call_function_ptr.rs:LL:CC + at tests/native-lib/fail/call_fn_ptr.rs:LL:CC 1: main - at tests/native-lib/fail/call_function_ptr.rs:LL:CC + at tests/native-lib/fail/call_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.notrace.stderr b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.notrace.stderr new file mode 100644 index 0000000000000..e0536a4afe583 --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.notrace.stderr @@ -0,0 +1,31 @@ +warning: sharing memory with a native function called via FFI + --> tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + | +LL | call_fn_ptr(id::); + | ^^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function + | + = help: when memory is shared with a native function call, Miri stops tracking initialization and provenance for that memory + = help: in particular, Miri assumes that the native call initializes all memory it has access to + = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory + = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + 1: main + at tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + +error: unsupported operation: calling a function pointer through the FFI boundary + --> tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + | +LL | call_fn_ptr(id::); + | ^^^^^^^^^^^^^^^^^^^^^^ unsupported operation occurred here + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + 1: main + at tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + diff --git a/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.rs b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.rs new file mode 100644 index 0000000000000..8be29c0c121a2 --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.rs @@ -0,0 +1,22 @@ +//@revisions: trace notrace +//@[trace] only-target: x86_64-unknown-linux-gnu i686-unknown-linux-gnu +//@[trace] compile-flags: -Zmiri-native-lib-enable-tracing +//@compile-flags: -Zmiri-permissive-provenance + +fn main() { + pass_fn_ptr() +} + +fn pass_fn_ptr() { + extern "C" { + fn call_fn_ptr(s: extern "C" fn(i32) -> i32); + } + + extern "C" fn id(x: T) -> T { + x + } + + unsafe { + call_fn_ptr(id::); //~ ERROR: unsupported operation: calling a function pointer through the FFI boundary + } +} diff --git a/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.trace.stderr b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.trace.stderr new file mode 100644 index 0000000000000..24a33e6458685 --- /dev/null +++ b/src/tools/miri/tests/native-lib/fail/call_fn_ptr_with_generic.trace.stderr @@ -0,0 +1,32 @@ +warning: sharing memory with a native function called via FFI + --> tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + | +LL | call_fn_ptr(id::); + | ^^^^^^^^^^^^^^^^^^^^^^ sharing memory with a native function + | + = help: when memory is shared with a native function call, Miri can only track initialisation and provenance on a best-effort basis + = help: in particular, Miri assumes that the native call initializes all memory it has written to + = help: Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory + = help: what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free + = help: tracing memory accesses in native code is not yet fully implemented, so there can be further imprecisions beyond what is documented here + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + 1: main + at tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + +error: unsupported operation: calling a function pointer through the FFI boundary + --> tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + | +LL | call_fn_ptr(id::); + | ^^^^^^^^^^^^^^^^^^^^^^ unsupported operation occurred here + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = note: stack backtrace: + 0: pass_fn_ptr + at tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + 1: main + at tests/native-lib/fail/call_fn_ptr_with_generic.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + diff --git a/src/tools/miri/tests/native-lib/fn_ptr.c b/src/tools/miri/tests/native-lib/fn_ptr.c new file mode 100644 index 0000000000000..752e27b3e8a0a --- /dev/null +++ b/src/tools/miri/tests/native-lib/fn_ptr.c @@ -0,0 +1,17 @@ +#include +#include + +// See comments in build_native_lib() +#define EXPORT __attribute__((visibility("default"))) + +EXPORT void call_fn_ptr(void f(void)) { + if (f != NULL) { + f(); + } +} + +EXPORT void call_fn_ptr_with_arg(int32_t f(int32_t)) { + if (f != NULL) { + f(42); + } +} diff --git a/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs b/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs index 36eff04a03c05..ad4c84d3e83b8 100644 --- a/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs +++ b/src/tools/miri/tests/native-lib/pass/ptr_read_access.rs @@ -10,7 +10,6 @@ fn main() { test_access_simple(); test_access_nested(); test_access_static(); - pass_fn_ptr(); } /// Test function that dereferences an int pointer and prints its contents from C. @@ -82,16 +81,3 @@ fn test_access_static() { assert_eq!(unsafe { access_static(&STATIC) }, 9001); } - -fn pass_fn_ptr() { - extern "C" { - fn pass_fn_ptr(s: Option); - } - - extern "C" fn nop() {} - - unsafe { - pass_fn_ptr(None); // this one is fine - pass_fn_ptr(Some(nop)); // this one is not - } -} diff --git a/src/tools/miri/tests/native-lib/ptr_read_access.c b/src/tools/miri/tests/native-lib/ptr_read_access.c index 44ba13aa54a62..58017d809af89 100644 --- a/src/tools/miri/tests/native-lib/ptr_read_access.c +++ b/src/tools/miri/tests/native-lib/ptr_read_access.c @@ -62,16 +62,3 @@ EXPORT int32_t access_static(const Static *s_ptr) { EXPORT uintptr_t do_one_deref(const int32_t ***ptr) { return (uintptr_t)*ptr; } - -/* Test: pass_fn_ptr */ - -EXPORT void pass_fn_ptr(void f(void)) { - (void)f; // suppress unused warning -} - -/* Test: function_ptrs */ -EXPORT void call_fn_ptr(void f(void)) { - if (f != NULL) { - f(); - } -} diff --git a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs index db68daed53961..8f8d4f85c0109 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs @@ -148,6 +148,24 @@ fn test_pipe_setfl_getfl() { errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(), libc::O_RDONLY ); + + // Test if ignored flags are indeed ignored. + errno_check(unsafe { + libc::fcntl( + fds[0], + libc::F_SETFL, + libc::O_RDWR + | libc::O_CREAT + | libc::O_EXCL + | libc::O_NOCTTY + | libc::O_TRUNC + | libc::O_NONBLOCK, + ) + }); + assert_eq!( + errno_result(unsafe { libc::fcntl(fds[0], libc::F_GETFL) }).unwrap(), + libc::O_NONBLOCK | libc::O_RDONLY + ); } /// Test the behaviour of F_SETFL/F_GETFL when a fd is blocking. diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.rs b/src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.rs new file mode 100644 index 0000000000000..ce4df4de72b6d --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.rs @@ -0,0 +1,19 @@ +//@ignore-target: windows # No libc socket on Windows +//@ignore-target: solaris # Socket is a macro for __xnet7_socket which has no shim +//@ignore-target: illumos # Socket is a macro for __xnet7_socket which has no shim +//@compile-flags: -Zmiri-isolation-error=warn-nobacktrace + +use std::io::ErrorKind; + +#[path = "../../utils/libc.rs"] +mod libc_utils; +use libc_utils::*; + +fn main() { + unsafe { + let err = errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap_err(); + assert_eq!(err.kind(), ErrorKind::PermissionDenied); + // check that it is the right kind of `PermissionDenied` + assert_eq!(err.raw_os_error(), Some(libc::EACCES)); + } +} diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.stderr b/src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.stderr new file mode 100644 index 0000000000000..36fc0a5aac328 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/libc-socket-with-isolation.stderr @@ -0,0 +1,2 @@ +warning: `socket` was made to return an error due to isolation + diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socket.rs b/src/tools/miri/tests/pass-dep/libc/libc-socket.rs new file mode 100644 index 0000000000000..ac9f13367642d --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/libc-socket.rs @@ -0,0 +1,19 @@ +//@ignore-target: windows # No libc socket on Windows +//@ignore-target: solaris # Does socket is a macro for __xnet7_socket which has no shim +//@ignore-target: illumos # Does socket is a macro for __xnet7_socket which has no shim +//@compile-flags: -Zmiri-disable-isolation + +#[path = "../../utils/libc.rs"] +mod libc_utils; +use libc_utils::*; + +fn main() { + test_socket_close(); +} + +fn test_socket_close() { + unsafe { + let sockfd = errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap(); + errno_check(libc::close(sockfd)); + } +} diff --git a/src/tools/miri/tests/pass/open_a_file_in_proc.rs b/src/tools/miri/tests/pass/open_a_file_in_proc.rs new file mode 100644 index 0000000000000..8c9887656d384 --- /dev/null +++ b/src/tools/miri/tests/pass/open_a_file_in_proc.rs @@ -0,0 +1,11 @@ +//@compile-flags: -Zmiri-disable-isolation +//@only-target: linux android illumos +//@ignore-host: windows + +fn main() { + let _ = match std::fs::File::open("/proc/doesnotexist ") { + Ok(_f) => {} + Err(_msg) => {} + }; + (); +} diff --git a/src/tools/miri/tests/pass/open_a_file_in_proc.stderr b/src/tools/miri/tests/pass/open_a_file_in_proc.stderr new file mode 100644 index 0000000000000..0ba31ed5adac0 --- /dev/null +++ b/src/tools/miri/tests/pass/open_a_file_in_proc.stderr @@ -0,0 +1,32 @@ +warning: files in `/proc` can bypass the Abstract Machine and might not work properly in Miri + --> RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + | +LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ open a file in `/proc` + | + = note: stack backtrace: + 0: std::sys::fs::PLATFORM::File::open_c::{closure#0} + at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + 1: std::sys::pal::PLATFORM::cvt_r + at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC + 2: std::sys::fs::PLATFORM::File::open_c + at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + 3: std::sys::fs::PLATFORM::File::open::{closure#0} + at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + 4: std::sys::helpers::small_c_string::run_with_cstr_stack + at RUSTLIB/std/src/sys/helpers/small_c_string.rs:LL:CC + 5: std::sys::helpers::small_c_string::run_with_cstr + at RUSTLIB/std/src/sys/helpers/small_c_string.rs:LL:CC + 6: std::sys::helpers::small_c_string::run_path_with_cstr + at RUSTLIB/std/src/sys/helpers/small_c_string.rs:LL:CC + 7: std::sys::fs::PLATFORM::File::open + at RUSTLIB/std/src/sys/fs/PLATFORM.rs:LL:CC + 8: std::fs::OpenOptions::_open + at RUSTLIB/std/src/fs.rs:LL:CC + 9: std::fs::OpenOptions::open + at RUSTLIB/std/src/fs.rs:LL:CC + 10: std::fs::File::open + at RUSTLIB/std/src/fs.rs:LL:CC + 11: main + at tests/pass/open_a_file_in_proc.rs:LL:CC + diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs index 047cdeb357c20..2a6151737d6c0 100644 --- a/src/tools/miri/tests/ui.rs +++ b/src/tools/miri/tests/ui.rs @@ -42,7 +42,7 @@ fn build_native_lib(target: &str) -> PathBuf { std::fs::create_dir_all(&so_target_dir) .expect("Failed to create directory for shared object file"); // We use a platform-neutral file extension to avoid having to hard-code alternatives. - let native_lib_path = so_target_dir.join("native-lib.module"); + let native_lib_path = so_target_dir.join("native-lib-tests.so"); let cc_output = Command::new(cc) .args([ "-shared", @@ -58,6 +58,7 @@ fn build_native_lib(target: &str) -> PathBuf { "tests/native-lib/aggregate_arguments.c", "tests/native-lib/ptr_read_access.c", "tests/native-lib/ptr_write_access.c", + "tests/native-lib/fn_ptr.c", // Ensure we notice serious problems in the C code. "-Wall", "-Wextra", diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs index 68b3afc3e8414..e83ddb859498b 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs @@ -10,7 +10,7 @@ feature = "sysroot-abi", feature(proc_macro_internals, proc_macro_diagnostic, proc_macro_span) )] -#![allow(internal_features)] +#![allow(internal_features, unused_features)] #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #[cfg(feature = "in-rust-tree")] diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs index 65de804404831..734cb4ecc1693 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs @@ -18,7 +18,8 @@ internal_features, clippy::disallowed_types, clippy::print_stderr, - unused_crate_dependencies + unused_crate_dependencies, + unused_features )] #![deny(deprecated_safe, clippy::undocumented_unsafe_blocks)] diff --git a/src/tools/test-float-parse/src/lib.rs b/src/tools/test-float-parse/src/lib.rs index 1321a3c335499..da83aeea3c132 100644 --- a/src/tools/test-float-parse/src/lib.rs +++ b/src/tools/test-float-parse/src/lib.rs @@ -1,5 +1,5 @@ -#![feature(f16)] #![feature(cfg_target_has_reliable_f16_f128)] +#![cfg_attr(target_has_reliable_f16, feature(f16))] #![expect(internal_features)] // reliable_f16_f128 mod traits; diff --git a/tests/incremental/add_private_fn_at_krate_root_cc/struct_point.rs b/tests/incremental/add_private_fn_at_krate_root_cc/struct_point.rs index 0367af8d53b8d..be1f27e7bae3e 100644 --- a/tests/incremental/add_private_fn_at_krate_root_cc/struct_point.rs +++ b/tests/incremental/add_private_fn_at_krate_root_cc/struct_point.rs @@ -9,7 +9,6 @@ //@ ignore-backends: gcc #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![allow(dead_code)] #![crate_type = "rlib"] diff --git a/tests/incremental/change_add_field/struct_point.rs b/tests/incremental/change_add_field/struct_point.rs index fb363c9ce496f..024812bd4bebb 100644 --- a/tests/incremental/change_add_field/struct_point.rs +++ b/tests/incremental/change_add_field/struct_point.rs @@ -9,7 +9,6 @@ //@ ignore-backends: gcc #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![allow(dead_code)] #![crate_type = "rlib"] diff --git a/tests/incremental/change_crate_dep_kind.rs b/tests/incremental/change_crate_dep_kind.rs index 4fd0c345aad21..d08e76c47527b 100644 --- a/tests/incremental/change_crate_dep_kind.rs +++ b/tests/incremental/change_crate_dep_kind.rs @@ -8,7 +8,7 @@ //@ build-pass (FIXME(62277): could be check-pass?) //@ ignore-backends: gcc -#![feature(panic_unwind)] +#![cfg_attr(cfail1, feature(panic_unwind))] // Turn the panic_unwind crate from an explicit into an implicit query: #[cfg(cfail1)] diff --git a/tests/incremental/change_private_fn/struct_point.rs b/tests/incremental/change_private_fn/struct_point.rs index cce26fa7a3e6e..2c2560309d27e 100644 --- a/tests/incremental/change_private_fn/struct_point.rs +++ b/tests/incremental/change_private_fn/struct_point.rs @@ -7,7 +7,6 @@ //@ ignore-backends: gcc #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![allow(dead_code)] #![crate_type = "rlib"] diff --git a/tests/incremental/change_private_fn_cc/struct_point.rs b/tests/incremental/change_private_fn_cc/struct_point.rs index 87392ca857ed7..cfe26be225d30 100644 --- a/tests/incremental/change_private_fn_cc/struct_point.rs +++ b/tests/incremental/change_private_fn_cc/struct_point.rs @@ -9,7 +9,6 @@ #![crate_type = "rlib"] #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![allow(dead_code)] #![rustc_partition_reused(module="struct_point-fn_calls_methods_in_same_impl", cfg="cfail2")] diff --git a/tests/incremental/change_private_impl_method/struct_point.rs b/tests/incremental/change_private_impl_method/struct_point.rs index dc0ba82c0a311..42793b53378d4 100644 --- a/tests/incremental/change_private_impl_method/struct_point.rs +++ b/tests/incremental/change_private_impl_method/struct_point.rs @@ -7,7 +7,6 @@ //@ ignore-backends: gcc #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![allow(dead_code)] #![crate_type = "rlib"] diff --git a/tests/incremental/change_private_impl_method_cc/struct_point.rs b/tests/incremental/change_private_impl_method_cc/struct_point.rs index eb51af7209495..c554a2f3db96b 100644 --- a/tests/incremental/change_private_impl_method_cc/struct_point.rs +++ b/tests/incremental/change_private_impl_method_cc/struct_point.rs @@ -9,7 +9,6 @@ #![crate_type = "rlib"] #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![allow(dead_code)] #![rustc_partition_reused(module="struct_point-fn_read_field", cfg="cfail2")] diff --git a/tests/incremental/change_pub_inherent_method_body/struct_point.rs b/tests/incremental/change_pub_inherent_method_body/struct_point.rs index b8e06d070a3c7..d024432266694 100644 --- a/tests/incremental/change_pub_inherent_method_body/struct_point.rs +++ b/tests/incremental/change_pub_inherent_method_body/struct_point.rs @@ -7,7 +7,6 @@ #![crate_type = "rlib"] #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![allow(dead_code)] #![rustc_partition_codegened(module="struct_point-point", cfg="cfail2")] diff --git a/tests/incremental/change_pub_inherent_method_sig/struct_point.rs b/tests/incremental/change_pub_inherent_method_sig/struct_point.rs index 3672ec268010e..5c24199df6aa8 100644 --- a/tests/incremental/change_pub_inherent_method_sig/struct_point.rs +++ b/tests/incremental/change_pub_inherent_method_sig/struct_point.rs @@ -7,7 +7,6 @@ #![crate_type = "rlib"] #![feature(rustc_attrs)] -#![feature(stmt_expr_attributes)] #![allow(dead_code)] // These are expected to require codegen. diff --git a/tests/incremental/lint-unused-features.rs b/tests/incremental/lint-unused-features.rs new file mode 100644 index 0000000000000..a7f66504f6a0c --- /dev/null +++ b/tests/incremental/lint-unused-features.rs @@ -0,0 +1,41 @@ +//@ revisions: rpass cfail +//@ ignore-backends: gcc + +#![deny(unused_features)] + +// Used language features +#![feature(box_patterns)] +#![feature(decl_macro)] +#![cfg_attr(all(), feature(rustc_attrs))] + +// Used library features +#![feature(error_iter)] +//[cfail]~^ ERROR feature `error_iter` is declared but not used +#![cfg_attr(all(), feature(allocator_api))] +//[cfail]~^ ERROR feature `allocator_api` is declared but not used + +pub fn use_box_patterns(b: Box) -> i32 { + let box x = b; + x +} + +macro m() {} +pub fn use_decl_macro() { + m!(); +} + +#[rustc_dummy] +pub fn use_rustc_attrs() {} + +#[cfg(rpass)] +pub fn use_error_iter(e: &(dyn std::error::Error + 'static)) { + for _ in e.sources() {} +} + +#[cfg(rpass)] +pub fn use_allocator_api() { + use std::alloc::Global; + let _ = Vec::::new_in(Global); +} + +fn main() {} diff --git a/tests/ui-fulldeps/rustc_public/check_abi.rs b/tests/ui-fulldeps/rustc_public/check_abi.rs index 8e97b773db567..d823e76b93cd0 100644 --- a/tests/ui-fulldeps/rustc_public/check_abi.rs +++ b/tests/ui-fulldeps/rustc_public/check_abi.rs @@ -6,7 +6,6 @@ //@ ignore-remote #![feature(rustc_private)] -#![feature(ascii_char, ascii_char_variants)] extern crate rustc_driver; extern crate rustc_hir; diff --git a/tests/ui-fulldeps/rustc_public/check_transform.rs b/tests/ui-fulldeps/rustc_public/check_transform.rs index f8aa40e474468..000f1f4cb365a 100644 --- a/tests/ui-fulldeps/rustc_public/check_transform.rs +++ b/tests/ui-fulldeps/rustc_public/check_transform.rs @@ -6,7 +6,6 @@ //@ ignore-remote #![feature(rustc_private)] -#![feature(ascii_char, ascii_char_variants)] extern crate rustc_hir; extern crate rustc_middle; diff --git a/tests/ui/allocator/xcrate-use2.rs b/tests/ui/allocator/xcrate-use2.rs index a48b0beeb07e3..4580d0f908bbc 100644 --- a/tests/ui/allocator/xcrate-use2.rs +++ b/tests/ui/allocator/xcrate-use2.rs @@ -5,7 +5,6 @@ //@ aux-build:helper.rs //@ no-prefer-dynamic -#![feature(allocator_api)] extern crate custom; extern crate custom_as_global; diff --git a/tests/ui/associated-types/associated-types-impl-redirect.rs b/tests/ui/associated-types/associated-types-impl-redirect.rs index 64cae31e5693b..11812c7212bb6 100644 --- a/tests/ui/associated-types/associated-types-impl-redirect.rs +++ b/tests/ui/associated-types/associated-types-impl-redirect.rs @@ -9,7 +9,6 @@ // for `ByRef`. The right answer was to consider the result ambiguous // until more type information was available. -#![feature(lang_items)] #![no_implicit_prelude] use std::marker::Sized; diff --git a/tests/ui/associated-types/associated-types-where-clause-impl-ambiguity.rs b/tests/ui/associated-types/associated-types-where-clause-impl-ambiguity.rs index 0de7617943c65..fd40438704420 100644 --- a/tests/ui/associated-types/associated-types-where-clause-impl-ambiguity.rs +++ b/tests/ui/associated-types/associated-types-where-clause-impl-ambiguity.rs @@ -8,7 +8,6 @@ // for `ByRef`. The right answer was to consider the result ambiguous // until more type information was available. -#![feature(lang_items)] #![no_implicit_prelude] use std::marker::Sized; diff --git a/tests/ui/async-await/async-drop/async-drop-initial.rs b/tests/ui/async-await/async-drop/async-drop-initial.rs index cd33c143fba01..427ed54fa6caa 100644 --- a/tests/ui/async-await/async-drop/async-drop-initial.rs +++ b/tests/ui/async-await/async-drop/async-drop-initial.rs @@ -5,7 +5,7 @@ // please consider modifying miri's async drop test at // `src/tools/miri/tests/pass/async-drop.rs`. -#![feature(async_drop, impl_trait_in_assoc_type)] +#![feature(async_drop)] #![allow(incomplete_features, dead_code)] //@ edition: 2021 diff --git a/tests/ui/backtrace/line-tables-only.rs b/tests/ui/backtrace/line-tables-only.rs index 7dac41119a324..b3ae8a1971b98 100644 --- a/tests/ui/backtrace/line-tables-only.rs +++ b/tests/ui/backtrace/line-tables-only.rs @@ -18,7 +18,6 @@ //@ needs-unwind //@ aux-build: line-tables-only-helper.rs -#![feature(backtrace_frames)] extern crate line_tables_only_helper; diff --git a/tests/ui/borrowck/super-let-lifetime-and-drop.rs b/tests/ui/borrowck/super-let-lifetime-and-drop.rs index 380470f792fe1..a103a6a804cc0 100644 --- a/tests/ui/borrowck/super-let-lifetime-and-drop.rs +++ b/tests/ui/borrowck/super-let-lifetime-and-drop.rs @@ -7,7 +7,7 @@ //@ [borrowck] check-fail #![allow(dropping_references)] -#![feature(super_let, stmt_expr_attributes)] +#![feature(super_let)] use std::convert::identity; diff --git a/tests/ui/cfg/cfg_stmt_expr.rs b/tests/ui/cfg/cfg_stmt_expr.rs index 361b159a354fd..128321a23320a 100644 --- a/tests/ui/cfg/cfg_stmt_expr.rs +++ b/tests/ui/cfg/cfg_stmt_expr.rs @@ -3,7 +3,6 @@ #![allow(unused_mut)] #![allow(unused_variables)] #![deny(non_snake_case)] -#![feature(stmt_expr_attributes)] fn main() { let a = 413; diff --git a/tests/ui/const-generics/transmute.rs b/tests/ui/const-generics/transmute.rs index e8ab8637932dd..6108139f3ce5c 100644 --- a/tests/ui/const-generics/transmute.rs +++ b/tests/ui/const-generics/transmute.rs @@ -1,6 +1,5 @@ //@ run-pass #![feature(generic_const_exprs)] -#![feature(transmute_generic_consts)] #![allow(incomplete_features)] fn ident(v: [[u32; H]; W]) -> [[u32; H]; W] { diff --git a/tests/ui/consts/const-fn-type-name.rs b/tests/ui/consts/const-fn-type-name.rs index 733ab79b7cdb8..5da86de8f67c8 100644 --- a/tests/ui/consts/const-fn-type-name.rs +++ b/tests/ui/consts/const-fn-type-name.rs @@ -1,7 +1,6 @@ //@ run-pass #![feature(core_intrinsics)] -#![feature(const_type_name)] #![allow(dead_code)] const fn type_name_wrapper(_: &T) -> &'static str { diff --git a/tests/ui/consts/const-ptr-nonnull-rpass.rs b/tests/ui/consts/const-ptr-nonnull-rpass.rs index 48ad72df63091..ebea036c16476 100644 --- a/tests/ui/consts/const-ptr-nonnull-rpass.rs +++ b/tests/ui/consts/const-ptr-nonnull-rpass.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(ptr_internals, test)] +#![feature(test)] extern crate test; use test::black_box as b; // prevent promotion of the argument and const-propagation of the result diff --git a/tests/ui/consts/try-operator.rs b/tests/ui/consts/try-operator.rs index cd0bf8ea57167..54a6ed26241c6 100644 --- a/tests/ui/consts/try-operator.rs +++ b/tests/ui/consts/try-operator.rs @@ -1,7 +1,6 @@ //@ ignore-backends: gcc //@ run-pass -#![feature(try_trait_v2)] #![feature(const_trait_impl)] #![feature(const_try)] diff --git a/tests/ui/contracts/internal_machinery/lowering/basics.rs b/tests/ui/contracts/internal_machinery/lowering/basics.rs index 7b3a769af8258..f4f5dc5ab1056 100644 --- a/tests/ui/contracts/internal_machinery/lowering/basics.rs +++ b/tests/ui/contracts/internal_machinery/lowering/basics.rs @@ -1,6 +1,6 @@ //@ run-pass #![expect(incomplete_features)] -#![feature(contracts, cfg_contract_checks, contracts_internals, core_intrinsics)] +#![feature(contracts, contracts_internals, core_intrinsics)] extern crate core; diff --git a/tests/ui/coroutine/control-flow.rs b/tests/ui/coroutine/control-flow.rs index f64b6f7388366..fe611b1c1c319 100644 --- a/tests/ui/coroutine/control-flow.rs +++ b/tests/ui/coroutine/control-flow.rs @@ -3,7 +3,7 @@ //@ revisions: default nomiropt //@[nomiropt]compile-flags: -Z mir-opt-level=0 -#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] +#![feature(coroutines, coroutine_trait)] use std::ops::{CoroutineState, Coroutine}; use std::pin::Pin; diff --git a/tests/ui/coroutine/missing_coroutine_attr_suggestion.fixed b/tests/ui/coroutine/missing_coroutine_attr_suggestion.fixed index 128f09a118439..9bda140ce58c5 100644 --- a/tests/ui/coroutine/missing_coroutine_attr_suggestion.fixed +++ b/tests/ui/coroutine/missing_coroutine_attr_suggestion.fixed @@ -1,6 +1,6 @@ //@ run-rustfix -#![feature(coroutines, gen_blocks, stmt_expr_attributes)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { let _ = #[coroutine] || yield; diff --git a/tests/ui/coroutine/missing_coroutine_attr_suggestion.rs b/tests/ui/coroutine/missing_coroutine_attr_suggestion.rs index dc95259149609..d8af486e6d05a 100644 --- a/tests/ui/coroutine/missing_coroutine_attr_suggestion.rs +++ b/tests/ui/coroutine/missing_coroutine_attr_suggestion.rs @@ -1,6 +1,6 @@ //@ run-rustfix -#![feature(coroutines, gen_blocks, stmt_expr_attributes)] +#![feature(coroutines, stmt_expr_attributes)] fn main() { let _ = || yield; diff --git a/tests/ui/coroutine/non-static-is-unpin.rs b/tests/ui/coroutine/non-static-is-unpin.rs index b28bf1977145b..7dc036077f90c 100644 --- a/tests/ui/coroutine/non-static-is-unpin.rs +++ b/tests/ui/coroutine/non-static-is-unpin.rs @@ -3,7 +3,7 @@ //@[next] compile-flags: -Znext-solver //@ run-pass -#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] +#![feature(coroutines)] #![allow(dropping_copy_types)] use std::marker::PhantomPinned; diff --git a/tests/ui/coroutine/other-attribute-on-gen.rs b/tests/ui/coroutine/other-attribute-on-gen.rs index 5f4584ee0226e..e13a0abcbfd63 100644 --- a/tests/ui/coroutine/other-attribute-on-gen.rs +++ b/tests/ui/coroutine/other-attribute-on-gen.rs @@ -2,7 +2,6 @@ //@ run-pass #![feature(gen_blocks)] #![feature(optimize_attribute)] -#![feature(stmt_expr_attributes)] #![feature(async_iterator)] #![allow(dead_code)] diff --git a/tests/ui/coroutine/pin-box-coroutine.rs b/tests/ui/coroutine/pin-box-coroutine.rs index d030f3ef214d1..d9674ed7341be 100644 --- a/tests/ui/coroutine/pin-box-coroutine.rs +++ b/tests/ui/coroutine/pin-box-coroutine.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(coroutines, coroutine_trait, stmt_expr_attributes)] +#![feature(coroutines, coroutine_trait)] use std::ops::Coroutine; diff --git a/tests/ui/coroutine/xcrate.rs b/tests/ui/coroutine/xcrate.rs index 406152a0bf10c..6b4d81fc983f8 100644 --- a/tests/ui/coroutine/xcrate.rs +++ b/tests/ui/coroutine/xcrate.rs @@ -2,7 +2,7 @@ //@ aux-build:xcrate.rs -#![feature(coroutines, coroutine_trait)] +#![feature(coroutine_trait)] extern crate xcrate; diff --git a/tests/ui/eii/default/call_default.rs b/tests/ui/eii/default/call_default.rs index c13df48e99217..b60a1dd0b2156 100644 --- a/tests/ui/eii/default/call_default.rs +++ b/tests/ui/eii/default/call_default.rs @@ -7,7 +7,6 @@ //@ ignore-windows // Tests EIIs with default implementations. // When there's no explicit declaration, the default should be called from the declaring crate. -#![feature(extern_item_impls)] extern crate decl_with_default; diff --git a/tests/ui/eii/default/call_default_panics.rs b/tests/ui/eii/default/call_default_panics.rs index f71fddb71ba26..96b2742aa8e0a 100644 --- a/tests/ui/eii/default/call_default_panics.rs +++ b/tests/ui/eii/default/call_default_panics.rs @@ -23,7 +23,6 @@ // ``` // This is a simple test to make sure that we can unwind through these, // and that this wrapper function effectively doesn't show up in the trace. -#![feature(extern_item_impls)] extern crate decl_with_default_panics; diff --git a/tests/ui/eii/default/call_impl.rs b/tests/ui/eii/default/call_impl.rs index 94b2aa552a1e1..b887697574892 100644 --- a/tests/ui/eii/default/call_impl.rs +++ b/tests/ui/eii/default/call_impl.rs @@ -9,7 +9,6 @@ // Tests EIIs with default implementations. // When an explicit implementation is given in one dependency, and the declaration is in another, // the explicit implementation is preferred. -#![feature(extern_item_impls)] extern crate decl_with_default; extern crate impl1; diff --git a/tests/ui/eii/linking/codegen_cross_crate.rs b/tests/ui/eii/linking/codegen_cross_crate.rs index 4016712e7504a..2958a0f10521b 100644 --- a/tests/ui/eii/linking/codegen_cross_crate.rs +++ b/tests/ui/eii/linking/codegen_cross_crate.rs @@ -6,7 +6,6 @@ // FIXME: linking on windows (speciifcally mingw) not yet supported, see tracking issue #125418 //@ ignore-windows // Tests whether calling EIIs works with the declaration in another crate. -#![feature(extern_item_impls)] extern crate codegen_cross_crate_other_crate as codegen; diff --git a/tests/ui/eii/privacy1.rs b/tests/ui/eii/privacy1.rs index 72aec83d2cee0..60bf36074e0ae 100644 --- a/tests/ui/eii/privacy1.rs +++ b/tests/ui/eii/privacy1.rs @@ -5,7 +5,6 @@ // FIXME: linking on windows (specifically mingw) not yet supported, see tracking issue #125418 //@ ignore-windows // Tests whether re-exports work. -#![feature(extern_item_impls)] extern crate other_crate_privacy1 as codegen; diff --git a/tests/ui/enum-discriminant/issue-72554.rs b/tests/ui/enum-discriminant/issue-72554.rs index 1fe9a5f4faa7d..54f7e9ac592eb 100644 --- a/tests/ui/enum-discriminant/issue-72554.rs +++ b/tests/ui/enum-discriminant/issue-72554.rs @@ -3,7 +3,6 @@ use std::collections::BTreeSet; #[derive(Hash)] pub enum ElemDerived { //~^ ERROR recursive type `ElemDerived` has infinite size - //~| ERROR cycle detected A(ElemDerived) } diff --git a/tests/ui/enum-discriminant/issue-72554.stderr b/tests/ui/enum-discriminant/issue-72554.stderr index 648680c6031da..381f24d351e9c 100644 --- a/tests/ui/enum-discriminant/issue-72554.stderr +++ b/tests/ui/enum-discriminant/issue-72554.stderr @@ -3,7 +3,7 @@ error[E0072]: recursive type `ElemDerived` has infinite size | LL | pub enum ElemDerived { | ^^^^^^^^^^^^^^^^^^^^ -... +LL | LL | A(ElemDerived) | ----------- recursive without indirection | @@ -12,21 +12,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | A(Box) | ++++ + -error[E0391]: cycle detected when computing drop-check constraints for `ElemDerived` - --> $DIR/issue-72554.rs:4:1 - | -LL | pub enum ElemDerived { - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: ...which immediately requires computing drop-check constraints for `ElemDerived` again -note: cycle used when computing drop-check constraints for `Elem` - --> $DIR/issue-72554.rs:11:1 - | -LL | pub enum Elem { - | ^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/explicit-tail-calls/support/basic.rs b/tests/ui/explicit-tail-calls/support/basic.rs new file mode 100644 index 0000000000000..b4c5ebf139250 --- /dev/null +++ b/tests/ui/explicit-tail-calls/support/basic.rs @@ -0,0 +1,98 @@ +//@ build-pass +//@ ignore-backends: gcc +//@ add-minicore +//@ min-llvm-version: 22 +// +//@ revisions: host +//@ revisions: i686 +//@[i686] compile-flags: --target i686-unknown-linux-gnu +//@[i686] needs-llvm-components: x86 +//@ revisions: x86-64 +//@[x86-64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86-64] needs-llvm-components: x86 +//@ revisions: x86-64-win +//@[x86-64-win] compile-flags: --target x86_64-pc-windows-msvc +//@[x86-64-win] needs-llvm-components: x86 +//@ revisions: arm +//@[arm] compile-flags: --target arm-unknown-linux-gnueabi +//@[arm] needs-llvm-components: arm +//@ revisions: thumb +//@[thumb] compile-flags: --target thumbv8m.main-none-eabi +//@[thumb] needs-llvm-components: arm +//@ revisions: aarch64 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] needs-llvm-components: aarch64 +//@ revisions: s390x +//@[s390x] compile-flags: --target s390x-unknown-linux-gnu +//@[s390x] needs-llvm-components: systemz +//@ revisions: sparc +//@[sparc] compile-flags: --target sparc-unknown-linux-gnu +//@[sparc] needs-llvm-components: sparc +//@ revisions: sparc64 +//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu +//@[sparc64] needs-llvm-components: sparc +//@ revisions: powerpc64 +//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu +//@[powerpc64] needs-llvm-components: powerpc +//@ revisions: riscv +//@[riscv] compile-flags: --target riscv64gc-unknown-linux-gnu +//@[riscv] needs-llvm-components: riscv +//@ revisions: loongarch32 +//@[loongarch32] compile-flags: --target loongarch32-unknown-none +//@[loongarch32] needs-llvm-components: loongarch +//@ revisions: loongarch64 +//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu +//@[loongarch64] needs-llvm-components: loongarch +//@ revisions: bpf +//@[bpf] compile-flags: --target bpfeb-unknown-none +//@[bpf] needs-llvm-components: bpf +//@ revisions: m68k +//@[m68k] compile-flags: --target m68k-unknown-linux-gnu +//@[m68k] needs-llvm-components: m68k +//@ revisions: nvptx64 +//@[nvptx64] compile-flags: --target nvptx64-nvidia-cuda +//@[nvptx64] needs-llvm-components: nvptx +// +// Wasm needs a special target feature. +// +//@ revisions: wasm +//@[wasm] compile-flags: --target wasm32-unknown-unknown -Ctarget-feature=+tail-call +//@[wasm] needs-llvm-components: webassembly +//@ revisions: wasip1 +//@[wasip1] compile-flags: --target wasm32-wasip1 -Ctarget-feature=+tail-call +//@[wasip1] needs-llvm-components: webassembly +// +// Failing cases (just zero support) +// +// //@ revisions: powerpc +// //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu +// //@[powerpc] needs-llvm-components: powerpc +// //@ revisions: aix +// //@[aix] compile-flags: --target powerpc64-ibm-aix +// //@[aix] needs-llvm-components: powerpc +// //@ revisions: csky +// //@[csky] compile-flags: --target csky-unknown-linux-gnuabiv2 +// //@[csky] needs-llvm-components: csky +// //@ revisions: mips +// //@[mips] compile-flags: --target mips-unknown-linux-gnu +// //@[mips] needs-llvm-components: mips +// //@ revisions: mips64 +// //@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 +// //@[mips64] needs-llvm-components: mips +#![feature(no_core, explicit_tail_calls)] +#![expect(incomplete_features)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +#[inline(never)] +fn simple1(x: u64) -> u64 { + x +} + +#[unsafe(no_mangle)] +fn simple2(x: u64) -> u64 { + become simple1(x); +} diff --git a/tests/ui/explicit-tail-calls/support/bystack.rs b/tests/ui/explicit-tail-calls/support/bystack.rs new file mode 100644 index 0000000000000..f0a399e9c07e8 --- /dev/null +++ b/tests/ui/explicit-tail-calls/support/bystack.rs @@ -0,0 +1,109 @@ +//@ build-pass +//@ ignore-backends: gcc +//@ add-minicore +//@ min-llvm-version: 22 +// +//@ revisions: host +//@ revisions: i686 +//@[i686] compile-flags: --target i686-unknown-linux-gnu +//@[i686] needs-llvm-components: x86 +//@ revisions: x86-64 +//@[x86-64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86-64] needs-llvm-components: x86 +//@ revisions: x86-64-win +//@[x86-64-win] compile-flags: --target x86_64-pc-windows-msvc +//@[x86-64-win] needs-llvm-components: x86 +//@ revisions: arm +//@[arm] compile-flags: --target arm-unknown-linux-gnueabi +//@[arm] needs-llvm-components: arm +//@ revisions: thumb +//@[thumb] compile-flags: --target thumbv8m.main-none-eabi +//@[thumb] needs-llvm-components: arm +//@ revisions: aarch64 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] needs-llvm-components: aarch64 +//@ revisions: s390x +//@[s390x] compile-flags: --target s390x-unknown-linux-gnu +//@[s390x] needs-llvm-components: systemz +//@ revisions: sparc +//@[sparc] compile-flags: --target sparc-unknown-linux-gnu +//@[sparc] needs-llvm-components: sparc +//@ revisions: sparc64 +//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu +//@[sparc64] needs-llvm-components: sparc +//@ revisions: powerpc64 +//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu +//@[powerpc64] needs-llvm-components: powerpc +//@ revisions: loongarch32 +//@[loongarch32] compile-flags: --target loongarch32-unknown-none +//@[loongarch32] needs-llvm-components: loongarch +//@ revisions: loongarch64 +//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu +//@[loongarch64] needs-llvm-components: loongarch +//@ revisions: bpf +//@[bpf] compile-flags: --target bpfeb-unknown-none +//@[bpf] needs-llvm-components: bpf +//@ revisions: m68k +//@[m68k] compile-flags: --target m68k-unknown-linux-gnu +//@[m68k] needs-llvm-components: m68k +//@ revisions: nvptx64 +//@[nvptx64] compile-flags: --target nvptx64-nvidia-cuda +//@[nvptx64] needs-llvm-components: nvptx +// +// Riscv does not support byval in LLVM 22 (but wil in LLVM 23) +// +// //@ revisions: riscv +// //@[riscv] compile-flags: --target riscv64gc-unknown-linux-gnu +// //@[riscv] needs-llvm-components: riscv +// +// Wasm needs a special target feature. +// +//@ revisions: wasm +//@[wasm] compile-flags: --target wasm32-unknown-unknown -Ctarget-feature=+tail-call +//@[wasm] needs-llvm-components: webassembly +//@ revisions: wasip1 +//@[wasip1] compile-flags: --target wasm32-wasip1 -Ctarget-feature=+tail-call +//@[wasip1] needs-llvm-components: webassembly +// +// Failing cases (just zero support) +// +// //@ revisions: powerpc +// //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu +// //@[powerpc] needs-llvm-components: powerpc +// //@ revisions: aix +// //@[aix] compile-flags: --target powerpc64-ibm-aix +// //@[aix] needs-llvm-components: powerpc +// //@ revisions: csky +// //@[csky] compile-flags: --target csky-unknown-linux-gnuabiv2 +// //@[csky] needs-llvm-components: csky +// //@ revisions: mips +// //@[mips] compile-flags: --target mips-unknown-linux-gnu +// //@[mips] needs-llvm-components: mips +// //@ revisions: mips64 +// //@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 +// //@[mips64] needs-llvm-components: mips +#![feature(no_core, explicit_tail_calls)] +#![expect(incomplete_features)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +#[repr(C)] +struct PassedByVal { + a: u64, + b: u64, + c: u64, + d: u64, +} + +#[inline(never)] +extern "C" fn callee(x: PassedByVal) -> PassedByVal { + x +} + +#[unsafe(no_mangle)] +extern "C" fn byval(x: PassedByVal) -> PassedByVal { + become callee(x); +} diff --git a/tests/ui/explicit-tail-calls/support/byval.rs b/tests/ui/explicit-tail-calls/support/byval.rs new file mode 100644 index 0000000000000..7e29ae5f0644d --- /dev/null +++ b/tests/ui/explicit-tail-calls/support/byval.rs @@ -0,0 +1,109 @@ +//@ build-pass +//@ ignore-backends: gcc +//@ add-minicore +//@ min-llvm-version: 22 +// +//@ revisions: host +//@ revisions: i686 +//@[i686] compile-flags: --target i686-unknown-linux-gnu +//@[i686] needs-llvm-components: x86 +//@ revisions: x86-64 +//@[x86-64] compile-flags: --target x86_64-unknown-linux-gnu +//@[x86-64] needs-llvm-components: x86 +//@ revisions: x86-64-win +//@[x86-64-win] compile-flags: --target x86_64-pc-windows-msvc +//@[x86-64-win] needs-llvm-components: x86 +//@ revisions: arm +//@[arm] compile-flags: --target arm-unknown-linux-gnueabi +//@[arm] needs-llvm-components: arm +//@ revisions: thumb +//@[thumb] compile-flags: --target thumbv8m.main-none-eabi +//@[thumb] needs-llvm-components: arm +//@ revisions: aarch64 +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] needs-llvm-components: aarch64 +//@ revisions: s390x +//@[s390x] compile-flags: --target s390x-unknown-linux-gnu +//@[s390x] needs-llvm-components: systemz +//@ revisions: sparc +//@[sparc] compile-flags: --target sparc-unknown-linux-gnu +//@[sparc] needs-llvm-components: sparc +//@ revisions: sparc64 +//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu +//@[sparc64] needs-llvm-components: sparc +//@ revisions: powerpc64 +//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu +//@[powerpc64] needs-llvm-components: powerpc +//@ revisions: loongarch32 +//@[loongarch32] compile-flags: --target loongarch32-unknown-none +//@[loongarch32] needs-llvm-components: loongarch +//@ revisions: loongarch64 +//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu +//@[loongarch64] needs-llvm-components: loongarch +//@ revisions: bpf +//@[bpf] compile-flags: --target bpfeb-unknown-none +//@[bpf] needs-llvm-components: bpf +//@ revisions: m68k +//@[m68k] compile-flags: --target m68k-unknown-linux-gnu +//@[m68k] needs-llvm-components: m68k +//@ revisions: nvptx64 +//@[nvptx64] compile-flags: --target nvptx64-nvidia-cuda +//@[nvptx64] needs-llvm-components: nvptx +// +// Riscv does not support byval in LLVM 22 (but wil in LLVM 23) +// +// //@ revisions: riscv +// //@[riscv] compile-flags: --target riscv64gc-unknown-linux-gnu +// //@[riscv] needs-llvm-components: riscv +// +// Wasm needs a special target feature. +// +//@ revisions: wasm +//@[wasm] compile-flags: --target wasm32-unknown-unknown -Ctarget-feature=+tail-call +//@[wasm] needs-llvm-components: webassembly +//@ revisions: wasip1 +//@[wasip1] compile-flags: --target wasm32-wasip1 -Ctarget-feature=+tail-call +//@[wasip1] needs-llvm-components: webassembly +// +// Failing cases (just zero support) +// +// //@ revisions: powerpc +// //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu +// //@[powerpc] needs-llvm-components: powerpc +// //@ revisions: aix +// //@[aix] compile-flags: --target powerpc64-ibm-aix +// //@[aix] needs-llvm-components: powerpc +// //@ revisions: csky +// //@[csky] compile-flags: --target csky-unknown-linux-gnuabiv2 +// //@[csky] needs-llvm-components: csky +// //@ revisions: mips +// //@[mips] compile-flags: --target mips-unknown-linux-gnu +// //@[mips] needs-llvm-components: mips +// //@ revisions: mips64 +// //@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 +// //@[mips64] needs-llvm-components: mips +#![feature(no_core, explicit_tail_calls)] +#![expect(incomplete_features)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; +use minicore::*; + +// The rust calling convention will pass this by-value. +struct PassedByVal { + a: u64, + b: u64, + c: u64, + d: u64, +} + +#[inline(never)] +fn callee(x: PassedByVal) -> PassedByVal { + x +} + +#[unsafe(no_mangle)] +fn byval(x: PassedByVal) -> PassedByVal { + become callee(x); +} diff --git a/tests/ui/extern/extern-prelude-core.rs b/tests/ui/extern/extern-prelude-core.rs index 5108c02517c3d..05d3750ae6563 100644 --- a/tests/ui/extern/extern-prelude-core.rs +++ b/tests/ui/extern/extern-prelude-core.rs @@ -1,5 +1,4 @@ //@ run-pass -#![feature(lang_items)] #![no_std] extern crate std as other; diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed index 525f78d162fc0..a2b920880221f 100644 --- a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed @@ -22,7 +22,6 @@ //@ [future_feature] compile-flags: -Z unstable-options #![cfg_attr(future_feature, feature(explicit_extern_abis))] -#![cfg_attr(current_feature, feature(explicit_extern_abis))] extern "C" fn _foo() {} //[current]~^ WARN `extern` declarations without an explicit ABI are deprecated diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr index cf927807c7c3c..f5cc09bef5e5d 100644 --- a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr @@ -1,5 +1,5 @@ warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:27:1 + --> $DIR/feature-gate-explicit-extern-abis.rs:26:1 | LL | extern fn _foo() {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` @@ -7,13 +7,13 @@ LL | extern fn _foo() {} = note: `#[warn(missing_abi)]` on by default warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:33:8 + --> $DIR/feature-gate-explicit-extern-abis.rs:32:8 | LL | unsafe extern fn _bar() {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:39:8 + --> $DIR/feature-gate-explicit-extern-abis.rs:38:8 | LL | unsafe extern {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed index 525f78d162fc0..a2b920880221f 100644 --- a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed @@ -22,7 +22,6 @@ //@ [future_feature] compile-flags: -Z unstable-options #![cfg_attr(future_feature, feature(explicit_extern_abis))] -#![cfg_attr(current_feature, feature(explicit_extern_abis))] extern "C" fn _foo() {} //[current]~^ WARN `extern` declarations without an explicit ABI are deprecated diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr index cf927807c7c3c..f5cc09bef5e5d 100644 --- a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr @@ -1,5 +1,5 @@ warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:27:1 + --> $DIR/feature-gate-explicit-extern-abis.rs:26:1 | LL | extern fn _foo() {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` @@ -7,13 +7,13 @@ LL | extern fn _foo() {} = note: `#[warn(missing_abi)]` on by default warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:33:8 + --> $DIR/feature-gate-explicit-extern-abis.rs:32:8 | LL | unsafe extern fn _bar() {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:39:8 + --> $DIR/feature-gate-explicit-extern-abis.rs:38:8 | LL | unsafe extern {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed index 525f78d162fc0..a2b920880221f 100644 --- a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed @@ -22,7 +22,6 @@ //@ [future_feature] compile-flags: -Z unstable-options #![cfg_attr(future_feature, feature(explicit_extern_abis))] -#![cfg_attr(current_feature, feature(explicit_extern_abis))] extern "C" fn _foo() {} //[current]~^ WARN `extern` declarations without an explicit ABI are deprecated diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr index cf927807c7c3c..f5cc09bef5e5d 100644 --- a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr @@ -1,5 +1,5 @@ warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:27:1 + --> $DIR/feature-gate-explicit-extern-abis.rs:26:1 | LL | extern fn _foo() {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` @@ -7,13 +7,13 @@ LL | extern fn _foo() {} = note: `#[warn(missing_abi)]` on by default warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:33:8 + --> $DIR/feature-gate-explicit-extern-abis.rs:32:8 | LL | unsafe extern fn _bar() {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` warning: `extern` declarations without an explicit ABI are deprecated - --> $DIR/feature-gate-explicit-extern-abis.rs:39:8 + --> $DIR/feature-gate-explicit-extern-abis.rs:38:8 | LL | unsafe extern {} | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"` diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr index 096a6f4341699..3fad1cc76dd7c 100644 --- a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr @@ -1,5 +1,5 @@ error: `extern` declarations without an explicit ABI are disallowed - --> $DIR/feature-gate-explicit-extern-abis.rs:27:1 + --> $DIR/feature-gate-explicit-extern-abis.rs:26:1 | LL | extern fn _foo() {} | ^^^^^^ help: specify an ABI: `extern ""` @@ -7,7 +7,7 @@ LL | extern fn _foo() {} = help: prior to Rust 2024, a default ABI was inferred error: `extern` declarations without an explicit ABI are disallowed - --> $DIR/feature-gate-explicit-extern-abis.rs:33:8 + --> $DIR/feature-gate-explicit-extern-abis.rs:32:8 | LL | unsafe extern fn _bar() {} | ^^^^^^ help: specify an ABI: `extern ""` @@ -15,7 +15,7 @@ LL | unsafe extern fn _bar() {} = help: prior to Rust 2024, a default ABI was inferred error: `extern` declarations without an explicit ABI are disallowed - --> $DIR/feature-gate-explicit-extern-abis.rs:39:8 + --> $DIR/feature-gate-explicit-extern-abis.rs:38:8 | LL | unsafe extern {} | ^^^^^^ help: specify an ABI: `extern ""` diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs index 379c45f589907..2ddc817768a16 100644 --- a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs +++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs @@ -22,7 +22,6 @@ //@ [future_feature] compile-flags: -Z unstable-options #![cfg_attr(future_feature, feature(explicit_extern_abis))] -#![cfg_attr(current_feature, feature(explicit_extern_abis))] extern fn _foo() {} //[current]~^ WARN `extern` declarations without an explicit ABI are deprecated diff --git a/tests/ui/float/classify-runtime-const.rs b/tests/ui/float/classify-runtime-const.rs index ca852ea2468bc..fb7361f9cbad5 100644 --- a/tests/ui/float/classify-runtime-const.rs +++ b/tests/ui/float/classify-runtime-const.rs @@ -6,8 +6,6 @@ // This tests the float classification functions, for regular runtime code and for const evaluation. -#![feature(f16)] -#![feature(f128)] use std::num::FpCategory::*; diff --git a/tests/ui/float/conv-bits-runtime-const.rs b/tests/ui/float/conv-bits-runtime-const.rs index 1373001b74dab..e7b306714bb85 100644 --- a/tests/ui/float/conv-bits-runtime-const.rs +++ b/tests/ui/float/conv-bits-runtime-const.rs @@ -3,9 +3,10 @@ // This tests the float classification functions, for regular runtime code and for const evaluation. -#![feature(f16)] -#![feature(f128)] #![feature(cfg_target_has_reliable_f16_f128)] +#![cfg_attr(target_has_reliable_f16, feature(f16))] +#![cfg_attr(target_has_reliable_f128, feature(f128))] + #![allow(unused_macro_rules)] // expect the unexpected (`target_has_reliable_*` are not "known" configs since they are unstable) #![expect(unexpected_cfgs)] diff --git a/tests/ui/fmt/format-macro-no-std.rs b/tests/ui/fmt/format-macro-no-std.rs index d096b4de01390..31c3a9a950668 100644 --- a/tests/ui/fmt/format-macro-no-std.rs +++ b/tests/ui/fmt/format-macro-no-std.rs @@ -4,7 +4,6 @@ //@ ignore-emscripten no no_std executables //@ ignore-wasm different `main` convention -#![feature(lang_items)] #![no_std] #![no_main] diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs index df1b9e164c768..2f25f0078eecd 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs @@ -6,8 +6,8 @@ #![allow(unreachable_patterns)] #![feature(cfg_target_has_reliable_f16_f128)] -#![feature(f128)] -#![feature(f16)] +#![cfg_attr(target_has_reliable_f16, feature(f16))] +#![cfg_attr(target_has_reliable_f128, feature(f128))] macro_rules! yes { ($scrutinee:expr, $($t:tt)+) => { diff --git a/tests/ui/hygiene/xcrate.rs b/tests/ui/hygiene/xcrate.rs index 0dd9136e4d562..aa221cb5ad2a3 100644 --- a/tests/ui/hygiene/xcrate.rs +++ b/tests/ui/hygiene/xcrate.rs @@ -3,7 +3,6 @@ //@ aux-build:xcrate.rs -#![feature(decl_macro)] extern crate xcrate; diff --git a/tests/ui/impl-trait/example-calendar.rs b/tests/ui/impl-trait/example-calendar.rs index c3c01f0103669..972ee5f4b63b4 100644 --- a/tests/ui/impl-trait/example-calendar.rs +++ b/tests/ui/impl-trait/example-calendar.rs @@ -1,7 +1,6 @@ //@ run-pass -#![feature(fn_traits, - step_trait, +#![feature(step_trait, unboxed_closures, )] diff --git a/tests/ui/infinite/infinite-struct.rs b/tests/ui/infinite/infinite-struct.rs index d784455824604..f08e10f6bdbc0 100644 --- a/tests/ui/infinite/infinite-struct.rs +++ b/tests/ui/infinite/infinite-struct.rs @@ -1,7 +1,5 @@ struct Take(Take); //~^ ERROR has infinite size -//~| ERROR cycle -//~| ERROR reached the recursion limit finding the struct tail for `Take` // check that we don't hang trying to find the tail of a recursive struct (#79437) fn foo() -> Take { diff --git a/tests/ui/infinite/infinite-struct.stderr b/tests/ui/infinite/infinite-struct.stderr index 0d1ec4989aa53..b6c72b1de4695 100644 --- a/tests/ui/infinite/infinite-struct.stderr +++ b/tests/ui/infinite/infinite-struct.stderr @@ -10,7 +10,7 @@ LL | struct Take(Box); | ++++ + error[E0072]: recursive type `Foo` has infinite size - --> $DIR/infinite-struct.rs:12:1 + --> $DIR/infinite-struct.rs:10:1 | LL | struct Foo { | ^^^^^^^^^^ @@ -22,25 +22,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | x: Bar>, | ++++ + -error: reached the recursion limit finding the struct tail for `Take` - --> $DIR/infinite-struct.rs:1:1 - | -LL | struct Take(Take); - | ^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` - -error[E0391]: cycle detected when computing when `Take` needs drop - --> $DIR/infinite-struct.rs:1:1 - | -LL | struct Take(Take); - | ^^^^^^^^^^^ - | - = note: ...which immediately requires computing when `Take` needs drop again - = note: cycle used when computing whether `Take` needs drop - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/infinite/infinite-tag-type-recursion.rs b/tests/ui/infinite/infinite-tag-type-recursion.rs index 1b5cb55b4e4d1..87a9e08dd381a 100644 --- a/tests/ui/infinite/infinite-tag-type-recursion.rs +++ b/tests/ui/infinite/infinite-tag-type-recursion.rs @@ -1,5 +1,4 @@ enum MList { Cons(isize, MList), Nil } //~^ ERROR recursive type `MList` has infinite size -//~| ERROR cycle fn main() { let a = MList::Cons(10, MList::Cons(11, MList::Nil)); } diff --git a/tests/ui/infinite/infinite-tag-type-recursion.stderr b/tests/ui/infinite/infinite-tag-type-recursion.stderr index 8745224a45e13..4ca408260b84a 100644 --- a/tests/ui/infinite/infinite-tag-type-recursion.stderr +++ b/tests/ui/infinite/infinite-tag-type-recursion.stderr @@ -9,17 +9,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | enum MList { Cons(isize, Box), Nil } | ++++ + -error[E0391]: cycle detected when computing when `MList` needs drop - --> $DIR/infinite-tag-type-recursion.rs:1:1 - | -LL | enum MList { Cons(isize, MList), Nil } - | ^^^^^^^^^^ - | - = note: ...which immediately requires computing when `MList` needs drop again - = note: cycle used when computing whether `MList` needs drop - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/intrinsics/intrinsic-alignment.rs b/tests/ui/intrinsics/intrinsic-alignment.rs index 5fee6b0b39783..242eea1f8407d 100644 --- a/tests/ui/intrinsics/intrinsic-alignment.rs +++ b/tests/ui/intrinsics/intrinsic-alignment.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(core_intrinsics, rustc_attrs)] +#![feature(rustc_attrs)] #[cfg(any( target_os = "aix", diff --git a/tests/ui/io-checks/write-macro-error.rs b/tests/ui/io-checks/write-macro-error.rs index 857ea0024e16c..90b9537b56da6 100644 --- a/tests/ui/io-checks/write-macro-error.rs +++ b/tests/ui/io-checks/write-macro-error.rs @@ -4,7 +4,6 @@ //@ run-pass //@ needs-unwind -#![feature(io_error_uncategorized)] use std::fmt; use std::io::{self, Error, Write}; diff --git a/tests/ui/linkage-attr/raw-dylib/elf/as_needed.rs b/tests/ui/linkage-attr/raw-dylib/elf/as_needed.rs index 48ca39300f41c..6f66e6c0f67fd 100644 --- a/tests/ui/linkage-attr/raw-dylib/elf/as_needed.rs +++ b/tests/ui/linkage-attr/raw-dylib/elf/as_needed.rs @@ -15,7 +15,7 @@ #![allow(incomplete_features)] #![feature(raw_dylib_elf)] -#![feature(native_link_modifiers_as_needed)] +#![cfg_attr(not(no_modifier), feature(native_link_modifiers_as_needed))] #[cfg_attr( as_needed, diff --git a/tests/ui/lint/lint-expr-stmt-attrs-for-early-lints.rs b/tests/ui/lint/lint-expr-stmt-attrs-for-early-lints.rs index eb110869e44e8..77ef6fab16cd1 100644 --- a/tests/ui/lint/lint-expr-stmt-attrs-for-early-lints.rs +++ b/tests/ui/lint/lint-expr-stmt-attrs-for-early-lints.rs @@ -1,6 +1,5 @@ //@ run-pass -#![feature(stmt_expr_attributes)] #![deny(unused_parens)] // Tests that lint attributes on statements/expressions are diff --git a/tests/ui/lint/lint-unknown-feature.rs b/tests/ui/lint/lint-unknown-feature.rs index 188617467974e..b598f0d0106b1 100644 --- a/tests/ui/lint/lint-unknown-feature.rs +++ b/tests/ui/lint/lint-unknown-feature.rs @@ -4,6 +4,5 @@ #![allow(stable_features)] // FIXME(#44232) we should warn that this isn't used. -#![feature(rust1)] fn main() {} diff --git a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed index d554bbfcc98c9..a3d8b1d32a89c 100644 --- a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed +++ b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.fixed @@ -2,7 +2,7 @@ //@ edition:2021 #![deny(unused_qualifications)] #![deny(unused_imports)] -#![feature(coroutines, coroutine_trait)] +#![feature(coroutine_trait)] use std::ops::{ Coroutine, diff --git a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs index 4d79f5ab74530..2da45507e3e74 100644 --- a/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs +++ b/tests/ui/lint/unnecessary-qualification/lint-unnecessary-qualification-issue-121331.rs @@ -2,7 +2,7 @@ //@ edition:2021 #![deny(unused_qualifications)] #![deny(unused_imports)] -#![feature(coroutines, coroutine_trait)] +#![feature(coroutine_trait)] use std::ops::{ Coroutine, diff --git a/tests/ui/lint/unused-features/unused-language-features.rs b/tests/ui/lint/unused-features/unused-language-features.rs new file mode 100644 index 0000000000000..9334c1df0408a --- /dev/null +++ b/tests/ui/lint/unused-features/unused-language-features.rs @@ -0,0 +1,25 @@ +#![crate_type = "lib"] +#![deny(unused_features)] + +// Unused language features +#![feature(coroutines)] +//~^ ERROR feature `coroutines` is declared but not used +#![feature(coroutine_clone)] +//~^ ERROR feature `coroutine_clone` is declared but not used +#![feature(stmt_expr_attributes)] +//~^ ERROR feature `stmt_expr_attributes` is declared but not used +#![feature(asm_unwind)] +//~^ ERROR feature `asm_unwind` is declared but not used + +// Enabled via cfg_attr, unused +#![cfg_attr(all(), feature(negative_impls))] +//~^ ERROR feature `negative_impls` is declared but not used + +// Not enabled via cfg_attr, so should not warn even if unused +#![cfg_attr(any(), feature(never_type))] + +macro_rules! use_asm_unwind { + () => { + unsafe { std::arch::asm!("", options(may_unwind)) }; + } +} diff --git a/tests/ui/lint/unused-features/unused-language-features.stderr b/tests/ui/lint/unused-features/unused-language-features.stderr new file mode 100644 index 0000000000000..3cede1a6fe726 --- /dev/null +++ b/tests/ui/lint/unused-features/unused-language-features.stderr @@ -0,0 +1,38 @@ +error: feature `coroutines` is declared but not used + --> $DIR/unused-language-features.rs:5:12 + | +LL | #![feature(coroutines)] + | ^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/unused-language-features.rs:2:9 + | +LL | #![deny(unused_features)] + | ^^^^^^^^^^^^^^^ + +error: feature `coroutine_clone` is declared but not used + --> $DIR/unused-language-features.rs:7:12 + | +LL | #![feature(coroutine_clone)] + | ^^^^^^^^^^^^^^^ + +error: feature `stmt_expr_attributes` is declared but not used + --> $DIR/unused-language-features.rs:9:12 + | +LL | #![feature(stmt_expr_attributes)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: feature `asm_unwind` is declared but not used + --> $DIR/unused-language-features.rs:11:12 + | +LL | #![feature(asm_unwind)] + | ^^^^^^^^^^ + +error: feature `negative_impls` is declared but not used + --> $DIR/unused-language-features.rs:15:28 + | +LL | #![cfg_attr(all(), feature(negative_impls))] + | ^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/lint/unused-features/unused-library-features.rs b/tests/ui/lint/unused-features/unused-library-features.rs new file mode 100644 index 0000000000000..75afd32e56cb3 --- /dev/null +++ b/tests/ui/lint/unused-features/unused-library-features.rs @@ -0,0 +1,13 @@ +#![crate_type = "lib"] +#![deny(unused_features)] + +// Unused library features +#![feature(step_trait)] +//~^ ERROR feature `step_trait` is declared but not used +#![feature(is_sorted)] +//~^ ERROR feature `is_sorted` is declared but not used +//~^^ WARN the feature `is_sorted` has been stable since 1.82.0 and no longer requires an attribute to enable + +// Enabled via cfg_attr, unused +#![cfg_attr(all(), feature(slice_ptr_get))] +//~^ ERROR feature `slice_ptr_get` is declared but not used diff --git a/tests/ui/lint/unused-features/unused-library-features.stderr b/tests/ui/lint/unused-features/unused-library-features.stderr new file mode 100644 index 0000000000000..e259058d6c33b --- /dev/null +++ b/tests/ui/lint/unused-features/unused-library-features.stderr @@ -0,0 +1,34 @@ +warning: the feature `is_sorted` has been stable since 1.82.0 and no longer requires an attribute to enable + --> $DIR/unused-library-features.rs:7:12 + | +LL | #![feature(is_sorted)] + | ^^^^^^^^^ + | + = note: `#[warn(stable_features)]` on by default + +error: feature `step_trait` is declared but not used + --> $DIR/unused-library-features.rs:5:12 + | +LL | #![feature(step_trait)] + | ^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/unused-library-features.rs:2:9 + | +LL | #![deny(unused_features)] + | ^^^^^^^^^^^^^^^ + +error: feature `is_sorted` is declared but not used + --> $DIR/unused-library-features.rs:7:12 + | +LL | #![feature(is_sorted)] + | ^^^^^^^^^ + +error: feature `slice_ptr_get` is declared but not used + --> $DIR/unused-library-features.rs:12:28 + | +LL | #![cfg_attr(all(), feature(slice_ptr_get))] + | ^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors; 1 warning emitted + diff --git a/tests/ui/lint/unused-features/used-language-features.rs b/tests/ui/lint/unused-features/used-language-features.rs new file mode 100644 index 0000000000000..7da4866a00d15 --- /dev/null +++ b/tests/ui/lint/unused-features/used-language-features.rs @@ -0,0 +1,22 @@ +//@ check-pass + +#![crate_type = "lib"] +#![deny(unused_features)] + +// Used language features +#![feature(box_patterns)] +#![feature(decl_macro)] +#![cfg_attr(all(), feature(rustc_attrs))] + +pub fn use_box_patterns(b: Box) -> i32 { + let box x = b; + x +} + +macro m() {} +pub fn use_decl_macro() { + m!(); +} + +#[rustc_dummy] +pub fn use_rustc_attrs() {} diff --git a/tests/ui/lint/unused-features/used-library-features.rs b/tests/ui/lint/unused-features/used-library-features.rs new file mode 100644 index 0000000000000..1747c7741880e --- /dev/null +++ b/tests/ui/lint/unused-features/used-library-features.rs @@ -0,0 +1,17 @@ +//@ check-pass + +#![crate_type = "lib"] +#![deny(unused_features)] + +// Used library features +#![feature(error_iter)] +#![cfg_attr(all(), feature(allocator_api))] + +pub fn use_error_iter(e: &(dyn std::error::Error + 'static)) { + for _ in e.sources() {} +} + +pub fn use_allocator_api() { + use std::alloc::Global; + let _ = Vec::::new_in(Global); +} diff --git a/tests/ui/lint/unused/unused_attributes-must_use.fixed b/tests/ui/lint/unused/unused_attributes-must_use.fixed index fa596da95ccd1..082096f12080a 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.fixed +++ b/tests/ui/lint/unused/unused_attributes-must_use.fixed @@ -1,6 +1,6 @@ //@ run-rustfix -#![allow(dead_code, path_statements)] +#![allow(dead_code, path_statements, unused_features)] #![deny(unused_attributes, unused_must_use)] #![feature(asm_experimental_arch, stmt_expr_attributes, trait_alias)] diff --git a/tests/ui/lint/unused/unused_attributes-must_use.rs b/tests/ui/lint/unused/unused_attributes-must_use.rs index 3e72dd1e43833..b4b17476d0b1b 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.rs +++ b/tests/ui/lint/unused/unused_attributes-must_use.rs @@ -1,6 +1,6 @@ //@ run-rustfix -#![allow(dead_code, path_statements)] +#![allow(dead_code, path_statements, unused_features)] #![deny(unused_attributes, unused_must_use)] #![feature(asm_experimental_arch, stmt_expr_attributes, trait_alias)] diff --git a/tests/ui/lowering/issue-96847.rs b/tests/ui/lowering/issue-96847.rs index a1fd105d9dd4a..6ee40338043f6 100644 --- a/tests/ui/lowering/issue-96847.rs +++ b/tests/ui/lowering/issue-96847.rs @@ -3,7 +3,6 @@ // Test that this doesn't abort during AST lowering. In #96847 it did abort // because the attribute was being lowered twice. -#![feature(stmt_expr_attributes)] #![feature(lang_items)] fn main() { diff --git a/tests/ui/lowering/issue-96847.stderr b/tests/ui/lowering/issue-96847.stderr index 2cded32f9fb86..26bc6645ce6d4 100644 --- a/tests/ui/lowering/issue-96847.stderr +++ b/tests/ui/lowering/issue-96847.stderr @@ -1,5 +1,5 @@ error[E0522]: definition of an unknown lang item: `foo` - --> $DIR/issue-96847.rs:11:9 + --> $DIR/issue-96847.rs:10:9 | LL | #![lang="foo"] | ^^^^^^^^^^^^^^ definition of unknown lang item `foo` diff --git a/tests/ui/macros/metavar_cross_edition_recursive_macros.rs b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs index ae1bc00236f0f..4382c00ab13cd 100644 --- a/tests/ui/macros/metavar_cross_edition_recursive_macros.rs +++ b/tests/ui/macros/metavar_cross_edition_recursive_macros.rs @@ -6,7 +6,6 @@ // This test captures the behavior of macro-generating-macros with fragment // specifiers across edition boundaries. -#![feature(macro_metavar_expr)] #![allow(incomplete_features)] extern crate metavar_2018; diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs index de7dbb9052edb..b470cd622d03c 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs @@ -5,7 +5,7 @@ //@ needs-unwind Asserting on contents of error message #![allow(path_statements, unused_allocation)] -#![feature(core_intrinsics, generic_assert)] +#![feature(generic_assert)] macro_rules! test { ( diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs index 1600fd0af3f30..2165037244dca 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/all-not-available-cases.rs @@ -4,7 +4,7 @@ //@ run-pass //@ needs-unwind Asserting on contents of error message -#![feature(core_intrinsics, generic_assert)] +#![feature(generic_assert)] extern crate common; diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs index 2a27164f9cba2..d75eb8b0d761b 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs @@ -3,7 +3,6 @@ //@ compile-flags: --test -Zpanic_abort_tests //@ run-pass -#![feature(core_intrinsics, generic_assert)] #[should_panic(expected = "Custom user message")] #[test] diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs index 6e5f8d6cd12d4..be4456604f627 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs @@ -3,7 +3,7 @@ //@ run-pass //@ needs-unwind Asserting on contents of error message -#![feature(core_intrinsics, generic_assert)] +#![feature(generic_assert)] extern crate common; diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs index 254d59076e531..a5ceb3d2ecd4c 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs @@ -4,7 +4,7 @@ // ignore-tidy-linelength //@ run-pass -#![feature(core_intrinsics, generic_assert)] +#![feature(generic_assert)] use std::fmt::{Debug, Formatter}; diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index f4f66745372b5..3f331b0dd5f14 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -9,12 +9,10 @@ #![feature(const_trait_impl)] #![feature(coroutines)] #![feature(decl_macro)] -#![feature(explicit_tail_calls)] #![feature(more_qualified_paths)] #![feature(never_patterns)] #![feature(trait_alias)] #![feature(try_blocks)] -#![feature(type_ascription)] #![feature(yeet_expr)] #![deny(unused_macros)] diff --git a/tests/ui/match/match-float.rs b/tests/ui/match/match-float.rs index 279bb5927ac45..504740add5371 100644 --- a/tests/ui/match/match-float.rs +++ b/tests/ui/match/match-float.rs @@ -3,8 +3,8 @@ // Makes sure we use `==` (not bitwise) semantics for float comparison. #![feature(cfg_target_has_reliable_f16_f128)] -#![feature(f128)] -#![feature(f16)] +#![cfg_attr(target_has_reliable_f16, feature(f16))] +#![cfg_attr(target_has_reliable_f128, feature(f128))] #[cfg(target_has_reliable_f16)] fn check_f16() { diff --git a/tests/ui/methods/supertrait-shadowing/out-of-scope.rs b/tests/ui/methods/supertrait-shadowing/out-of-scope.rs index bd263be59cc7d..8e0f5ba978e3a 100644 --- a/tests/ui/methods/supertrait-shadowing/out-of-scope.rs +++ b/tests/ui/methods/supertrait-shadowing/out-of-scope.rs @@ -1,7 +1,6 @@ //@ run-pass //@ check-run-results -#![feature(supertrait_item_shadowing)] #![allow(dead_code)] mod out_of_scope { diff --git a/tests/ui/nll/issue-48623-coroutine.rs b/tests/ui/nll/issue-48623-coroutine.rs index 63348a2047c07..57f579106b7a9 100644 --- a/tests/ui/nll/issue-48623-coroutine.rs +++ b/tests/ui/nll/issue-48623-coroutine.rs @@ -2,7 +2,7 @@ #![allow(path_statements)] #![allow(dead_code)] -#![feature(coroutines, coroutine_trait)] +#![feature(coroutines)] struct WithDrop; diff --git a/tests/ui/overloaded/overloaded-calls-simple.rs b/tests/ui/overloaded/overloaded-calls-simple.rs index 34b674357d89c..b53686aa94643 100644 --- a/tests/ui/overloaded/overloaded-calls-simple.rs +++ b/tests/ui/overloaded/overloaded-calls-simple.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(lang_items, unboxed_closures, fn_traits)] +#![feature(unboxed_closures, fn_traits)] struct S1 { x: i32, diff --git a/tests/ui/query-system/query-cycle-printing-issue-151226.rs b/tests/ui/query-system/query-cycle-printing-issue-151226.rs index 9d0a20737c9fa..551321619ddd0 100644 --- a/tests/ui/query-system/query-cycle-printing-issue-151226.rs +++ b/tests/ui/query-system/query-cycle-printing-issue-151226.rs @@ -1,8 +1,6 @@ struct A(std::sync::OnceLock); //~^ ERROR recursive type `A` has infinite size -//~| ERROR cycle detected when computing layout of `A<()>` static B: A<()> = todo!(); -//~^ ERROR cycle occurred during layout computation fn main() {} diff --git a/tests/ui/query-system/query-cycle-printing-issue-151226.stderr b/tests/ui/query-system/query-cycle-printing-issue-151226.stderr index 7e574b5911a39..bb05cf5f915d7 100644 --- a/tests/ui/query-system/query-cycle-printing-issue-151226.stderr +++ b/tests/ui/query-system/query-cycle-printing-issue-151226.stderr @@ -9,28 +9,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | struct A(Box>); | ++++ + -error[E0391]: cycle detected when computing layout of `A<()>` - | - = note: ...which requires computing layout of `std::sync::once_lock::OnceLock>`... - = note: ...which requires computing layout of `core::cell::UnsafeCell>>`... - = note: ...which requires computing layout of `core::mem::maybe_uninit::MaybeUninit>`... - = note: ...which requires computing layout of `core::mem::manually_drop::ManuallyDrop>`... - = note: ...which requires computing layout of `core::mem::maybe_dangling::MaybeDangling>`... - = note: ...which again requires computing layout of `A<()>`, completing the cycle -note: cycle used when checking that `B` is well-formed - --> $DIR/query-cycle-printing-issue-151226.rs:5:1 - | -LL | static B: A<()> = todo!(); - | ^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error[E0080]: a cycle occurred during layout computation - --> $DIR/query-cycle-printing-issue-151226.rs:5:1 - | -LL | static B: A<()> = todo!(); - | ^^^^^^^^^^^^^^^ evaluation of `B` failed here - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0072, E0080, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/sanitizer/memory-passing.rs b/tests/ui/sanitizer/memory-passing.rs index 6ac41b178fe7f..d41f62b310b05 100644 --- a/tests/ui/sanitizer/memory-passing.rs +++ b/tests/ui/sanitizer/memory-passing.rs @@ -13,7 +13,6 @@ // This test case intentionally limits the usage of the std, // since it will be linked with an uninstrumented version of it. -#![feature(core_intrinsics)] #![allow(invalid_value)] #![no_main] diff --git a/tests/ui/simd/monomorphize-shuffle-index.rs b/tests/ui/simd/monomorphize-shuffle-index.rs index ba952cdb0dc60..c86c2448cc683 100644 --- a/tests/ui/simd/monomorphize-shuffle-index.rs +++ b/tests/ui/simd/monomorphize-shuffle-index.rs @@ -4,12 +4,12 @@ //@ ignore-backends: gcc #![feature( repr_simd, - core_intrinsics, intrinsics, adt_const_params, unsized_const_params, generic_const_exprs )] +#![cfg_attr(old, feature(core_intrinsics))] #![allow(incomplete_features)] #[path = "../../auxiliary/minisimd.rs"] diff --git a/tests/ui/structs-enums/enum-rec/issue-17431-6.rs b/tests/ui/structs-enums/enum-rec/issue-17431-6.rs index a3b510848dcd3..c89b69d3c2f2e 100644 --- a/tests/ui/structs-enums/enum-rec/issue-17431-6.rs +++ b/tests/ui/structs-enums/enum-rec/issue-17431-6.rs @@ -2,7 +2,6 @@ use std::cell::UnsafeCell; enum Foo { X(UnsafeCell>) } //~^ ERROR recursive type `Foo` has infinite size -//~| ERROR cycle detected impl Foo { fn bar(self) {} } diff --git a/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr b/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr index b192593d266b7..8939b603c7985 100644 --- a/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr +++ b/tests/ui/structs-enums/enum-rec/issue-17431-6.stderr @@ -9,17 +9,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | enum Foo { X(UnsafeCell>>) } | ++++ + -error[E0391]: cycle detected when computing when `Foo` needs drop - --> $DIR/issue-17431-6.rs:3:1 - | -LL | enum Foo { X(UnsafeCell>) } - | ^^^^^^^^ - | - = note: ...which immediately requires computing when `Foo` needs drop again - = note: cycle used when computing whether `Foo` needs drop - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/structs-enums/rec-align-u32.rs b/tests/ui/structs-enums/rec-align-u32.rs index 058f06732b927..b86cdebfe19ae 100644 --- a/tests/ui/structs-enums/rec-align-u32.rs +++ b/tests/ui/structs-enums/rec-align-u32.rs @@ -3,7 +3,7 @@ #![allow(unused_unsafe)] // Issue #2303 -#![feature(core_intrinsics, rustc_attrs)] +#![feature(rustc_attrs)] use std::mem; diff --git a/tests/ui/structs-enums/rec-align-u64.rs b/tests/ui/structs-enums/rec-align-u64.rs index 41b196dc5c222..e49726c7d438f 100644 --- a/tests/ui/structs-enums/rec-align-u64.rs +++ b/tests/ui/structs-enums/rec-align-u64.rs @@ -4,7 +4,7 @@ // Issue #2303 -#![feature(core_intrinsics, rustc_attrs)] +#![feature(rustc_attrs)] use std::mem; diff --git a/tests/ui/threads-sendsync/auxiliary/thread-local-extern-static.rs b/tests/ui/threads-sendsync/auxiliary/thread-local-extern-static.rs index 4d3c4e8accd88..4eda8fab1b63b 100644 --- a/tests/ui/threads-sendsync/auxiliary/thread-local-extern-static.rs +++ b/tests/ui/threads-sendsync/auxiliary/thread-local-extern-static.rs @@ -1,4 +1,5 @@ -#![feature(cfg_target_thread_local, thread_local)] +#![feature(cfg_target_thread_local)] +#![cfg_attr(target_thread_local, feature(thread_local))] #![crate_type = "lib"] #[cfg(target_thread_local)] diff --git a/tests/ui/threads-sendsync/thread-local-extern-static.rs b/tests/ui/threads-sendsync/thread-local-extern-static.rs index ce2a221ec2e41..0da4e398f335c 100644 --- a/tests/ui/threads-sendsync/thread-local-extern-static.rs +++ b/tests/ui/threads-sendsync/thread-local-extern-static.rs @@ -2,7 +2,8 @@ //@ ignore-windows FIXME(134939): thread_local + no_mangle doesn't work on Windows //@ aux-build:thread-local-extern-static.rs -#![feature(cfg_target_thread_local, thread_local)] +#![feature(cfg_target_thread_local)] +#![cfg_attr(target_thread_local, feature(thread_local))] #[cfg(target_thread_local)] extern crate thread_local_extern_static; diff --git a/tests/ui/traits/alias/import-cross-crate.rs b/tests/ui/traits/alias/import-cross-crate.rs index 65e7c90965b85..f77aa3cd05a3b 100644 --- a/tests/ui/traits/alias/import-cross-crate.rs +++ b/tests/ui/traits/alias/import-cross-crate.rs @@ -1,7 +1,6 @@ //@ run-pass //@ aux-build:greeter.rs -#![feature(trait_alias)] extern crate greeter; diff --git a/tests/ui/traits/issue-105231.rs b/tests/ui/traits/issue-105231.rs index 83c3158c106b6..9e47ded7c8c81 100644 --- a/tests/ui/traits/issue-105231.rs +++ b/tests/ui/traits/issue-105231.rs @@ -6,5 +6,4 @@ struct B(A>); trait Foo {} impl Foo for T where T: Send {} impl Foo for B {} -//~^ ERROR conflicting implementations of trait `Foo` for type `B` fn main() {} diff --git a/tests/ui/traits/issue-105231.stderr b/tests/ui/traits/issue-105231.stderr index b048548018a71..6732d4f5803c9 100644 --- a/tests/ui/traits/issue-105231.stderr +++ b/tests/ui/traits/issue-105231.stderr @@ -37,18 +37,6 @@ LL | struct B(A>); = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` = note: all type parameters must be used in a non-recursive way in order to constrain their variance -error[E0119]: conflicting implementations of trait `Foo` for type `B` - --> $DIR/issue-105231.rs:8:1 - | -LL | impl Foo for T where T: Send {} - | ------------------------------- first implementation here -LL | impl Foo for B {} - | ^^^^^^^^^^^^^^^^^^ conflicting implementation for `B` - | - = note: overflow evaluating the requirement `B: Send` - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_105231`) - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0072, E0119. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/traits/overlap-permitted-for-marker-traits.rs b/tests/ui/traits/overlap-permitted-for-marker-traits.rs index c05e5fddae635..310516f4e4ace 100644 --- a/tests/ui/traits/overlap-permitted-for-marker-traits.rs +++ b/tests/ui/traits/overlap-permitted-for-marker-traits.rs @@ -4,7 +4,6 @@ // `MyMarker` if it is either `Debug` or `Display`. #![feature(marker_trait_attr)] -#![feature(negative_impls)] use std::fmt::{Debug, Display}; diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs index 8d291054365f9..d3a6ba94b68fb 100644 --- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs @@ -1,4 +1,3 @@ -//~ ERROR: cycle detected //! Safe transmute did not handle cycle errors that could occur during //! layout computation. This test checks that we do not ICE in such //! situations (see #117491). diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr index a96876a2c25a1..0b5689e1912f0 100644 --- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr @@ -1,5 +1,5 @@ error[E0072]: recursive type `ExplicitlyPadded` has infinite size - --> $DIR/transmute_infinitely_recursive_type.rs:21:5 + --> $DIR/transmute_infinitely_recursive_type.rs:20:5 | LL | struct ExplicitlyPadded(ExplicitlyPadded); | ^^^^^^^^^^^^^^^^^^^^^^^ ---------------- recursive without indirection @@ -9,13 +9,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle LL | struct ExplicitlyPadded(Box); | ++++ + -error[E0391]: cycle detected when computing layout of `should_pad_explicitly_packed_field::ExplicitlyPadded` - | - = note: ...which immediately requires computing layout of `should_pad_explicitly_packed_field::ExplicitlyPadded` again - = note: cycle used when evaluating trait selection obligation `(): core::mem::transmutability::TransmuteFrom` - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0072, E0391. -For more information about an error, try `rustc --explain E0072`. +For more information about this error, try `rustc --explain E0072`. diff --git a/tests/ui/type/typeid-consistency.rs b/tests/ui/type/typeid-consistency.rs index 67ee1b6d839ab..fb22ae3ac3050 100644 --- a/tests/ui/type/typeid-consistency.rs +++ b/tests/ui/type/typeid-consistency.rs @@ -3,7 +3,6 @@ //@ run-pass #![allow(deprecated)] -#![feature(core_intrinsics)] //@ aux-build:typeid-consistency-aux1.rs //@ aux-build:typeid-consistency-aux2.rs diff --git a/tests/ui/typeck/type-name-intrinsic-usage-61894.rs b/tests/ui/typeck/type-name-intrinsic-usage-61894.rs index 8131bb273909d..f587e5fe53f97 100644 --- a/tests/ui/typeck/type-name-intrinsic-usage-61894.rs +++ b/tests/ui/typeck/type-name-intrinsic-usage-61894.rs @@ -1,7 +1,6 @@ // https://github.com/rust-lang/rust/issues/61894 //@ run-pass -#![feature(core_intrinsics)] use std::any::type_name;