diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ee46bdcf7d8bb..dc2a8be5b3cf1 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1379,7 +1379,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { this.dcx() .emit_err(errors::ScalableVectorNotTupleStruct { span: item.span }); } - if !self.sess.target.arch.supports_scalable_vectors() { + if !self.sess.target.arch.supports_scalable_vectors() + && !self.sess.opts.actually_rustdoc + { this.dcx().emit_err(errors::ScalableVectorBadArch { span: attr.span }); } } diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index aee164cf32229..401d4c244d5a0 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -31,7 +31,6 @@ use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_errors::{DiagCtxt, DiagCtxtHandle}; use rustc_log::tracing::info; -use rustc_session::config::Lto; use tempfile::{TempDir, tempdir}; use crate::back::write::{codegen, save_temp_bitcode}; @@ -45,11 +44,7 @@ struct LtoData { tmp_path: TempDir, } -fn prepare_lto( - cgcx: &CodegenContext, - each_linked_rlib_for_lto: &[PathBuf], - dcx: DiagCtxtHandle<'_>, -) -> LtoData { +fn prepare_lto(each_linked_rlib_for_lto: &[PathBuf], dcx: DiagCtxtHandle<'_>) -> LtoData { let tmp_path = match tempdir() { Ok(tmp_path) => tmp_path, Err(error) => { @@ -64,32 +59,30 @@ fn prepare_lto( // We save off all the bytecode and GCC module file path for later processing // with either fat or thin LTO let mut upstream_modules = Vec::new(); - if cgcx.lto != Lto::ThinLocal { - for path in each_linked_rlib_for_lto { - let archive_data = unsafe { - Mmap::map(File::open(path).expect("couldn't open rlib")).expect("couldn't map rlib") - }; - let archive = ArchiveFile::parse(&*archive_data).expect("wanted an rlib"); - let obj_files = archive - .members() - .filter_map(|child| { - child.ok().and_then(|c| { - std::str::from_utf8(c.name()).ok().map(|name| (name.trim(), c)) - }) - }) - .filter(|&(name, _)| looks_like_rust_object_file(name)); - for (name, child) in obj_files { - info!("adding bitcode from {}", name); - let path = tmp_path.path().join(name); - match save_as_file(child.data(&*archive_data).expect("corrupt rlib"), &path) { - Ok(()) => { - let buffer = ModuleBuffer::new(path); - let module = SerializedModule::Local(buffer); - upstream_modules.push((module, CString::new(name).unwrap())); - } - Err(e) => { - dcx.emit_fatal(e); - } + for path in each_linked_rlib_for_lto { + let archive_data = unsafe { + Mmap::map(File::open(path).expect("couldn't open rlib")).expect("couldn't map rlib") + }; + let archive = ArchiveFile::parse(&*archive_data).expect("wanted an rlib"); + let obj_files = archive + .members() + .filter_map(|child| { + child + .ok() + .and_then(|c| std::str::from_utf8(c.name()).ok().map(|name| (name.trim(), c))) + }) + .filter(|&(name, _)| looks_like_rust_object_file(name)); + for (name, child) in obj_files { + info!("adding bitcode from {}", name); + let path = tmp_path.path().join(name); + match save_as_file(child.data(&*archive_data).expect("corrupt rlib"), &path) { + Ok(()) => { + let buffer = ModuleBuffer::new(path); + let module = SerializedModule::Local(buffer); + upstream_modules.push((module, CString::new(name).unwrap())); + } + Err(e) => { + dcx.emit_fatal(e); } } } @@ -115,7 +108,7 @@ pub(crate) fn run_fat( ) -> 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); + let lto_data = prepare_lto(each_linked_rlib_for_lto, dcx); /*let symbols_below_threshold = lto_data.symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::>();*/ fat_lto( diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index bf13f0b2127b7..d50968bad2501 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -81,9 +81,9 @@ use gccjit::{CType, Context, OptimizationLevel}; #[cfg(feature = "master")] use gccjit::{TargetInfo, Version}; use rustc_ast::expand::allocator::AllocatorMethod; -use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule}; +use rustc_codegen_ssa::back::lto::ThinModule; use rustc_codegen_ssa::back::write::{ - CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryFn, + CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryFn, ThinLtoInput, }; use rustc_codegen_ssa::base::codegen_crate; use rustc_codegen_ssa::target_features::cfg_target_feature; @@ -449,8 +449,7 @@ impl WriteBackendMethods for GccCodegenBackend { // FIXME(bjorn3): Limit LTO exports to these symbols _exported_symbols_for_lto: &[String], _each_linked_rlib_for_lto: &[PathBuf], - _modules: Vec<(String, Self::ModuleBuffer)>, - _cached_modules: Vec<(SerializedModule, WorkProduct)>, + _modules: Vec>, ) -> (Vec>, Vec) { unreachable!() } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index f6cd229cb106d..09863961c9d69 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -9,7 +9,7 @@ use object::read::archive::ArchiveFile; use object::{Object, ObjectSection}; use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::write::{ - CodegenContext, FatLtoInput, SharedEmitter, TargetMachineFactoryFn, + CodegenContext, FatLtoInput, SharedEmitter, TargetMachineFactoryFn, ThinLtoInput, }; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind, looks_like_rust_object_file}; @@ -20,7 +20,7 @@ use rustc_errors::{DiagCtxt, DiagCtxtHandle}; use rustc_hir::attrs::SanitizerSet; use rustc_middle::bug; use rustc_middle::dep_graph::WorkProduct; -use rustc_session::config::{self, Lto}; +use rustc_session::config; use tracing::{debug, info}; use crate::back::write::{ @@ -90,33 +90,31 @@ fn prepare_lto( // We save off all the bytecode and LLVM module ids for later processing // with either fat or thin LTO let mut upstream_modules = Vec::new(); - if cgcx.lto != Lto::ThinLocal { - for path in each_linked_rlib_for_lto { - let archive_data = unsafe { - Mmap::map(std::fs::File::open(&path).expect("couldn't open rlib")) - .expect("couldn't map rlib") - }; - let archive = ArchiveFile::parse(&*archive_data).expect("wanted an rlib"); - let obj_files = archive - .members() - .filter_map(|child| { - child.ok().and_then(|c| { - std::str::from_utf8(c.name()).ok().map(|name| (name.trim(), c)) - }) - }) - .filter(|&(name, _)| looks_like_rust_object_file(name)); - for (name, child) in obj_files { - info!("adding bitcode from {}", name); - match get_bitcode_slice_from_object_data( - child.data(&*archive_data).expect("corrupt rlib"), - cgcx, - ) { - Ok(data) => { - let module = SerializedModule::FromRlib(data.to_vec()); - upstream_modules.push((module, CString::new(name).unwrap())); - } - Err(e) => dcx.emit_fatal(e), + for path in each_linked_rlib_for_lto { + let archive_data = unsafe { + Mmap::map(std::fs::File::open(&path).expect("couldn't open rlib")) + .expect("couldn't map rlib") + }; + let archive = ArchiveFile::parse(&*archive_data).expect("wanted an rlib"); + let obj_files = archive + .members() + .filter_map(|child| { + child + .ok() + .and_then(|c| std::str::from_utf8(c.name()).ok().map(|name| (name.trim(), c))) + }) + .filter(|&(name, _)| looks_like_rust_object_file(name)); + for (name, child) in obj_files { + info!("adding bitcode from {}", name); + match get_bitcode_slice_from_object_data( + child.data(&*archive_data).expect("corrupt rlib"), + cgcx, + ) { + Ok(data) => { + let module = SerializedModule::FromRlib(data.to_vec()); + upstream_modules.push((module, CString::new(name).unwrap())); } + Err(e) => dcx.emit_fatal(e), } } } @@ -187,8 +185,7 @@ pub(crate) fn run_thin( dcx: DiagCtxtHandle<'_>, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], - modules: Vec<(String, ModuleBuffer)>, - cached_modules: Vec<(SerializedModule, WorkProduct)>, + modules: Vec>, ) -> (Vec>, Vec) { let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, exported_symbols_for_lto, each_linked_rlib_for_lto, dcx); @@ -200,7 +197,7 @@ pub(crate) fn run_thin( is deferred to the linker" ); } - thin_lto(cgcx, prof, dcx, modules, upstream_modules, cached_modules, &symbols_below_threshold) + thin_lto(cgcx, prof, dcx, modules, upstream_modules, &symbols_below_threshold) } fn fat_lto( @@ -300,7 +297,7 @@ fn fat_lto( // For all serialized bitcode files we parse them and link them in as we did // above, this is all mostly handled in C++. - let mut linker = Linker::new(llmod); + let linker = unsafe { llvm::LLVMRustLinkerNew(llmod) }; for (bc_decoded, name) in serialized_modules { let _timer = prof .generic_activity_with_arg_recorder("LLVM_fat_lto_link_module", |recorder| { @@ -308,11 +305,19 @@ fn fat_lto( }); info!("linking {:?}", name); let data = bc_decoded.data(); - linker - .add(data) - .unwrap_or_else(|()| write::llvm_err(dcx, LlvmError::LoadBitcode { name })); + + unsafe { + if !llvm::LLVMRustLinkerAdd( + linker, + data.as_ptr() as *const libc::c_char, + data.len(), + ) { + llvm::LLVMRustLinkerFree(linker); + write::llvm_err(dcx, LlvmError::LoadBitcode { name }) + } + } } - drop(linker); + unsafe { llvm::LLVMRustLinkerFree(linker) }; save_temp_bitcode(cgcx, &module, "lto.input"); // Internalize everything below threshold to help strip out more modules and such. @@ -330,36 +335,6 @@ fn fat_lto( module } -pub(crate) struct Linker<'a>(&'a mut llvm::Linker<'a>); - -impl<'a> Linker<'a> { - pub(crate) fn new(llmod: &'a llvm::Module) -> Self { - unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) } - } - - pub(crate) fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { - unsafe { - if llvm::LLVMRustLinkerAdd( - self.0, - bytecode.as_ptr() as *const libc::c_char, - bytecode.len(), - ) { - Ok(()) - } else { - Err(()) - } - } - } -} - -impl Drop for Linker<'_> { - fn drop(&mut self) { - unsafe { - llvm::LLVMRustLinkerFree(&mut *(self.0 as *mut _)); - } - } -} - /// Prepare "thin" LTO to get run on these modules. /// /// The general structure of ThinLTO is quite different from the structure of @@ -394,24 +369,35 @@ fn thin_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, dcx: DiagCtxtHandle<'_>, - modules: Vec<(String, ModuleBuffer)>, + modules: Vec>, serialized_modules: Vec<(SerializedModule, CString)>, - cached_modules: Vec<(SerializedModule, WorkProduct)>, symbols_below_threshold: &[*const libc::c_char], ) -> (Vec>, Vec) { let _timer = prof.generic_activity("LLVM_thin_lto_global_analysis"); unsafe { info!("going for that thin, thin LTO"); - let green_modules: FxHashMap<_, _> = - cached_modules.iter().map(|(_, wp)| (wp.cgu_name.clone(), wp.clone())).collect(); + let green_modules: FxHashMap<_, _> = modules + .iter() + .filter_map(|module| { + if let ThinLtoInput::Green { wp, .. } = module { + Some((wp.cgu_name.clone(), wp.clone())) + } else { + None + } + }) + .collect(); - let full_scope_len = modules.len() + serialized_modules.len() + cached_modules.len(); + let full_scope_len = modules.len(); let mut thin_buffers = Vec::with_capacity(modules.len()); let mut module_names = Vec::with_capacity(full_scope_len); let mut thin_modules = Vec::with_capacity(full_scope_len); - for (i, (name, buffer)) in modules.into_iter().enumerate() { + for (i, module) in modules.into_iter().enumerate() { + let (name, buffer) = match module { + ThinLtoInput::Red { name, buffer } => (name, buffer), + ThinLtoInput::Green { wp, buffer } => (wp.cgu_name, buffer), + }; info!("local module: {} - {}", i, name); let cname = CString::new(name.as_bytes()).unwrap(); thin_modules.push(llvm::ThinLTOModule { @@ -439,19 +425,15 @@ fn thin_lto( // incremental ThinLTO first where we could actually avoid // looking at upstream modules entirely sometimes (the contents, // we must always unconditionally look at the index). - let mut serialized = Vec::with_capacity(serialized_modules.len() + cached_modules.len()); - - let cached_modules = - cached_modules.into_iter().map(|(sm, wp)| (sm, CString::new(wp.cgu_name).unwrap())); - for (module, name) in serialized_modules.into_iter().chain(cached_modules) { - info!("upstream or cached module {:?}", name); + for (module, name) in serialized_modules { + info!("upstream module {:?}", name); thin_modules.push(llvm::ThinLTOModule { identifier: name.as_ptr(), data: module.data().as_ptr(), len: module.data().len(), }); - serialized.push(module); + thin_buffers.push(module); module_names.push(name); } @@ -500,12 +482,7 @@ fn thin_lto( // also put all memory referenced by the C++ data (buffers, ids, etc) // into the arc as well. After this we'll create a thin module // codegen per module in this data. - let shared = Arc::new(ThinShared { - data, - thin_buffers, - serialized_modules: serialized, - module_names, - }); + let shared = Arc::new(ThinShared { data, modules: thin_buffers, module_names }); let mut copy_jobs = vec![]; let mut opt_jobs = vec![]; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 17b6956ebd533..65c70c754918d 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -25,10 +25,10 @@ use back::write::{create_informational_target_machine, create_target_machine}; use context::SimpleCx; use llvm_util::target_config; use rustc_ast::expand::allocator::AllocatorMethod; -use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule}; +use rustc_codegen_ssa::back::lto::ThinModule; use rustc_codegen_ssa::back::write::{ CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryConfig, - TargetMachineFactoryFn, + TargetMachineFactoryFn, ThinLtoInput, }; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, CompiledModules, CrateInfo, ModuleCodegen, TargetConfig}; @@ -163,8 +163,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { dcx: DiagCtxtHandle<'_>, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], - modules: Vec<(String, Self::ModuleBuffer)>, - cached_modules: Vec<(SerializedModule, WorkProduct)>, + modules: Vec>, ) -> (Vec>, Vec) { back::lto::run_thin( cgcx, @@ -173,7 +172,6 @@ impl WriteBackendMethods for LlvmCodegenBackend { exported_symbols_for_lto, each_linked_rlib_for_lto, modules, - cached_modules, ) } fn optimize( diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index a2c951c16d28d..cd380abb75e0e 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -32,18 +32,13 @@ impl ThinModule { } pub fn data(&self) -> &[u8] { - let a = self.shared.thin_buffers.get(self.idx).map(|b| b.data()); - a.unwrap_or_else(|| { - let len = self.shared.thin_buffers.len(); - self.shared.serialized_modules[self.idx - len].data() - }) + self.shared.modules[self.idx].data() } } pub struct ThinShared { pub data: B::ThinData, - pub thin_buffers: Vec, - pub serialized_modules: Vec>, + pub modules: Vec>, pub module_names: Vec, } @@ -110,11 +105,9 @@ pub(super) fn exported_symbols_for_lto( // If we're performing LTO for the entire crate graph, then for each of our // upstream dependencies, include their exported symbols. - if tcx.sess.lto() != Lto::ThinLocal { - for &cnum in each_linked_rlib_for_lto { - let _timer = tcx.prof.generic_activity("lto_generate_symbols_below_threshold"); - symbols_below_threshold.extend(copy_symbols(cnum)); - } + for &cnum in each_linked_rlib_for_lto { + let _timer = tcx.prof.generic_activity("lto_generate_symbols_below_threshold"); + symbols_below_threshold.extend(copy_symbols(cnum)); } // Mark allocator shim symbols as exported only if they were generated. diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 1770251fcba46..82d7e23602e25 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -359,8 +359,7 @@ fn generate_thin_lto_work( dcx: DiagCtxtHandle<'_>, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], - needs_thin_lto: Vec<(String, B::ModuleBuffer)>, - import_only_modules: Vec<(SerializedModule, WorkProduct)>, + needs_thin_lto: Vec>, ) -> Vec<(ThinLtoWorkItem, u64)> { let _prof_timer = prof.generic_activity("codegen_thin_generate_lto_work"); @@ -371,7 +370,6 @@ fn generate_thin_lto_work( exported_symbols_for_lto, each_linked_rlib_for_lto, needs_thin_lto, - import_only_modules, ); lto_modules .into_iter() @@ -398,16 +396,12 @@ enum MaybeLtoModules { exported_symbols_for_lto: Arc>, each_linked_rlib_file_for_lto: Vec, needs_fat_lto: Vec>, - lto_import_only_modules: - Vec<(SerializedModule<::ModuleBuffer>, WorkProduct)>, }, ThinLto { cgcx: CodegenContext, exported_symbols_for_lto: Arc>, each_linked_rlib_file_for_lto: Vec, - needs_thin_lto: Vec<(String, ::ModuleBuffer)>, - lto_import_only_modules: - Vec<(SerializedModule<::ModuleBuffer>, WorkProduct)>, + needs_thin_lto: Vec>, }, } @@ -603,30 +597,28 @@ pub fn produce_final_output_artifacts( // Clean up unwanted temporary files. // We create the following files by default: - // - #crate#.#module-name#.bc - // - #crate#.#module-name#.o - // - #crate#.crate.metadata.bc - // - #crate#.crate.metadata.o - // - #crate#.o (linked from crate.##.o) - // - #crate#.bc (copied from crate.##.bc) + // - #crate#.#module-name#.rcgu.bc + // - #crate#.#module-name#.rcgu.o + // - #crate#.o (linked from crate.##.rcgu.o) + // - #crate#.bc (copied from crate.##.rcgu.bc) // We may create additional files if requested by the user (through // `-C save-temps` or `--emit=` flags). if !sess.opts.cg.save_temps { - // Remove the temporary .#module-name#.o objects. If the user didn't + // Remove the temporary .#module-name#.rcgu.o objects. If the user didn't // explicitly request bitcode (with --emit=bc), and the bitcode is not // needed for building an rlib, then we must remove .#module-name#.bc as // well. - // Specific rules for keeping .#module-name#.bc: + // Specific rules for keeping .#module-name#.rcgu.bc: // - If the user requested bitcode (`user_wants_bitcode`), and // codegen_units > 1, then keep it. // - If the user requested bitcode but codegen_units == 1, then we - // can toss .#module-name#.bc because we copied it to .bc earlier. + // can toss .#module-name#.rcgu.bc because we copied it to .bc earlier. // - If we're not building an rlib and the user didn't request - // bitcode, then delete .#module-name#.bc. + // bitcode, then delete .#module-name#.rcgu.bc. // If you change how this works, also update back::link::link_rlib, - // where .#module-name#.bc files are (maybe) deleted after making an + // where .#module-name#.rcgu.bc files are (maybe) deleted after making an // rlib. let needs_crate_object = crate_output.outputs.contains_key(&OutputType::Exe); @@ -686,7 +678,6 @@ pub fn produce_final_output_artifacts( // We leave the following files around by default: // - #crate#.o - // - #crate#.crate.metadata.o // - #crate#.bc // These are used in linking steps and will be cleaned up afterward. } @@ -787,6 +778,11 @@ pub enum FatLtoInput { InMemory(ModuleCodegen), } +pub enum ThinLtoInput { + Red { name: String, buffer: SerializedModule }, + Green { wp: WorkProduct, buffer: SerializedModule }, +} + /// Actual LTO type we end up choosing based on multiple factors. pub(crate) enum ComputedLtoType { No, @@ -973,8 +969,7 @@ fn do_fat_lto( tm_factory: TargetMachineFactoryFn, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], - mut needs_fat_lto: Vec>, - import_only_modules: Vec<(SerializedModule, WorkProduct)>, + needs_fat_lto: Vec>, ) -> CompiledModule { let _timer = prof.verbose_generic_activity("LLVM_fatlto"); @@ -983,10 +978,6 @@ fn do_fat_lto( check_lto_allowed(&cgcx, dcx); - for (module, wp) in import_only_modules { - needs_fat_lto.push(FatLtoInput::Serialized { name: wp.cgu_name, buffer: module }) - } - B::optimize_and_codegen_fat_lto( cgcx, prof, @@ -1005,11 +996,7 @@ fn do_thin_lto( tm_factory: TargetMachineFactoryFn, exported_symbols_for_lto: Arc>, each_linked_rlib_for_lto: Vec, - needs_thin_lto: Vec<(String, ::ModuleBuffer)>, - lto_import_only_modules: Vec<( - SerializedModule<::ModuleBuffer>, - WorkProduct, - )>, + needs_thin_lto: Vec>, ) -> Vec { let _timer = prof.verbose_generic_activity("LLVM_thinlto"); @@ -1046,7 +1033,6 @@ fn do_thin_lto( &exported_symbols_for_lto, &each_linked_rlib_for_lto, needs_thin_lto, - lto_import_only_modules, ) { let insertion_index = work_items.binary_search_by_key(&cost, |&(_, cost)| cost).unwrap_or_else(|e| e); @@ -1264,13 +1250,16 @@ fn start_executing_work( let mut each_linked_rlib_for_lto = Vec::new(); let mut each_linked_rlib_file_for_lto = Vec::new(); - drop(link::each_linked_rlib(crate_info, None, &mut |cnum, path| { - if link::ignored_for_lto(sess, crate_info, cnum) { - return; - } - each_linked_rlib_for_lto.push(cnum); - each_linked_rlib_file_for_lto.push(path.to_path_buf()); - })); + if sess.lto() != Lto::No && sess.lto() != Lto::ThinLocal { + drop(link::each_linked_rlib(crate_info, None, &mut |cnum, path| { + if link::ignored_for_lto(sess, crate_info, cnum) { + return; + } + + each_linked_rlib_for_lto.push(cnum); + each_linked_rlib_file_for_lto.push(path.to_path_buf()); + })); + } // Compute the set of symbols we need to retain when doing LTO (if we need to) let exported_symbols_for_lto = @@ -1723,7 +1712,10 @@ fn start_executing_work( } Ok(WorkItemResult::NeedsThinLto(name, thin_buffer)) => { assert!(needs_fat_lto.is_empty()); - needs_thin_lto.push((name, thin_buffer)); + needs_thin_lto.push(ThinLtoInput::Red { + name, + buffer: SerializedModule::Local(thin_buffer), + }); } Err(Some(WorkerFatalError)) => { // Like `CodegenAborted`, wait for remaining work to finish. @@ -1766,17 +1758,24 @@ fn start_executing_work( needs_fat_lto.push(FatLtoInput::InMemory(allocator_module)); } + for (module, wp) in lto_import_only_modules { + needs_fat_lto.push(FatLtoInput::Serialized { name: wp.cgu_name, buffer: module }) + } + return Ok(MaybeLtoModules::FatLto { cgcx, exported_symbols_for_lto, each_linked_rlib_file_for_lto, needs_fat_lto, - lto_import_only_modules, }); } else if !needs_thin_lto.is_empty() || !lto_import_only_modules.is_empty() { assert!(compiled_modules.is_empty()); assert!(needs_fat_lto.is_empty()); + for (buffer, wp) in lto_import_only_modules { + needs_thin_lto.push(ThinLtoInput::Green { wp, buffer }) + } + if cgcx.lto == Lto::ThinLocal { compiled_modules.extend(do_thin_lto::( &cgcx, @@ -1786,12 +1785,14 @@ fn start_executing_work( exported_symbols_for_lto, each_linked_rlib_file_for_lto, needs_thin_lto, - lto_import_only_modules, )); } else { if let Some(allocator_module) = allocator_module.take() { let thin_buffer = B::serialize_module(allocator_module.module_llvm, true); - needs_thin_lto.push((allocator_module.name, thin_buffer)); + needs_thin_lto.push(ThinLtoInput::Red { + name: allocator_module.name, + buffer: SerializedModule::Local(thin_buffer), + }); } return Ok(MaybeLtoModules::ThinLto { @@ -1799,7 +1800,6 @@ fn start_executing_work( exported_symbols_for_lto, each_linked_rlib_file_for_lto, needs_thin_lto, - lto_import_only_modules, }); } } @@ -2173,7 +2173,6 @@ impl OngoingCodegen { exported_symbols_for_lto, each_linked_rlib_file_for_lto, needs_fat_lto, - lto_import_only_modules, } => { let tm_factory = self.backend.target_machine_factory( sess, @@ -2190,7 +2189,6 @@ impl OngoingCodegen { &exported_symbols_for_lto, &each_linked_rlib_file_for_lto, needs_fat_lto, - lto_import_only_modules, )], allocator_module: None, } @@ -2200,7 +2198,6 @@ impl OngoingCodegen { exported_symbols_for_lto, each_linked_rlib_file_for_lto, needs_thin_lto, - lto_import_only_modules, } => { let tm_factory = self.backend.target_machine_factory( sess, @@ -2217,7 +2214,6 @@ impl OngoingCodegen { exported_symbols_for_lto, each_linked_rlib_file_for_lto, needs_thin_lto, - lto_import_only_modules, ), allocator_module: None, } diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 5d2313092fa84..cca6db78e381e 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -6,9 +6,9 @@ use rustc_errors::DiagCtxtHandle; use rustc_middle::dep_graph::WorkProduct; use rustc_session::{Session, config}; -use crate::back::lto::{SerializedModule, ThinModule}; +use crate::back::lto::ThinModule; use crate::back::write::{ - CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryFn, + CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryFn, ThinLtoInput, }; use crate::{CompiledModule, ModuleCodegen}; @@ -47,8 +47,7 @@ pub trait WriteBackendMethods: Clone + 'static { dcx: DiagCtxtHandle<'_>, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], - modules: Vec<(String, Self::ModuleBuffer)>, - cached_modules: Vec<(SerializedModule, WorkProduct)>, + modules: Vec>, ) -> (Vec>, Vec); fn optimize( cgcx: &CodegenContext, diff --git a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs index fab0e9e863dc5..a211a1aaa6bdf 100644 --- a/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs +++ b/compiler/rustc_lint/src/early/diagnostics/check_cfg.rs @@ -316,9 +316,27 @@ pub(super) fn unexpected_cfg_value( let is_from_cargo = rustc_session::utils::was_invoked_from_cargo(); let is_from_external_macro = name_span.in_external_macro(sess.source_map()); - // Show the full list if all possible values for a given name, but don't do it - // for names as the possibilities could be very long - let code_sugg = if !possibilities.is_empty() { + let code_sugg = if let Some((value, _)) = value + && sess.psess.check_config.well_known_names.contains(&name) + && let valid_names = possible_well_known_names_for_cfg_value(sess, value) + && !valid_names.is_empty() + { + // Suggest changing the name to something for which `value` is an expected value. + let max_suggestions = 3; + let suggestions = valid_names + .iter() + .take(max_suggestions) + .copied() + .map(|name| lints::unexpected_cfg_value::ChangeNameSuggestion { + span: name_span, + name, + value, + }) + .collect::>(); + lints::unexpected_cfg_value::CodeSuggestion::ChangeName { suggestions } + } else if !possibilities.is_empty() { + // Show the full list if all possible values for a given name, but don't do it + // for names as the possibilities could be very long let expected_values = { let (possibilities, and_more) = sort_and_truncate_possibilities( sess, @@ -419,3 +437,22 @@ pub(super) fn unexpected_cfg_value( value: value.map_or_else(String::new, |(v, _span)| v.to_string()), } } + +/// Ordering of the output is not stable, use this only in diagnostic code. +fn possible_well_known_names_for_cfg_value(sess: &Session, value: Symbol) -> Vec { + #[allow(rustc::potential_query_instability)] + sess.psess + .check_config + .well_known_names + .iter() + .filter(|name| { + sess.psess + .check_config + .expecteds + .get(*name) + .map(|expected_values| expected_values.contains(&Some(value))) + .unwrap_or_default() + }) + .copied() + .collect() +} diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 5819f2bc151f9..0863a5e038a74 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2904,6 +2904,10 @@ pub(crate) mod unexpected_cfg_value { name: Symbol, }, + ChangeName { + #[subdiagnostic] + suggestions: Vec, + }, } #[derive(Subdiagnostic)] @@ -2961,6 +2965,20 @@ pub(crate) mod unexpected_cfg_value { pub and_more: usize, } + #[derive(Subdiagnostic)] + #[suggestion( + "`{$value}` is an expected value for `{$name}`", + code = "{name}", + applicability = "maybe-incorrect", + style = "verbose" + )] + pub(crate) struct ChangeNameSuggestion { + #[primary_span] + pub span: Span, + pub name: Symbol, + pub value: Symbol, + } + #[derive(Subdiagnostic)] pub(crate) enum InvocationHelp { #[note( diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 621ceeffac658..0e0715a8861bc 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1640,6 +1640,9 @@ impl<'tcx> Ty<'tcx> { TyKind::Coroutine(def_id, args) => { Some(args.as_coroutine().variant_range(*def_id, tcx)) } + TyKind::UnsafeBinder(bound_ty) => { + tcx.instantiate_bound_regions_with_erased((*bound_ty).into()).variant_range(tcx) + } _ => None, } } @@ -1661,6 +1664,9 @@ impl<'tcx> Ty<'tcx> { TyKind::Coroutine(def_id, args) => { Some(args.as_coroutine().discriminant_for_variant(*def_id, tcx, variant_index)) } + TyKind::UnsafeBinder(bound_ty) => tcx + .instantiate_bound_regions_with_erased((*bound_ty).into()) + .discriminant_for_variant(tcx, variant_index), _ => None, } } @@ -1679,6 +1685,9 @@ impl<'tcx> Ty<'tcx> { } ty::Pat(ty, _) => ty.discriminant_ty(tcx), + ty::UnsafeBinder(bound_ty) => { + tcx.instantiate_bound_regions_with_erased((*bound_ty).into()).discriminant_ty(tcx) + } ty::Bool | ty::Char @@ -1700,7 +1709,6 @@ impl<'tcx> Ty<'tcx> { | ty::CoroutineWitness(..) | ty::Never | ty::Tuple(_) - | ty::UnsafeBinder(_) | ty::Error(_) | ty::Infer(IntVar(_) | FloatVar(_)) => tcx.types.u8, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 79b79db6ccc07..e2f0f8fee0d8d 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -192,7 +192,22 @@ impl<'a> Parser<'a> { // At this point, we have failed to parse an item. if !matches!(vis.kind, VisibilityKind::Inherited) { - this.dcx().emit_err(errors::VisibilityNotFollowedByItem { span: vis.span, vis }); + let mut err = this + .dcx() + .create_err(errors::VisibilityNotFollowedByItem { span: vis.span, vis }); + if let Some((ident, _)) = this.token.ident() + && !ident.is_used_keyword() + && let Some((similar_kw, is_incorrect_case)) = ident + .name + .find_similar(&rustc_span::symbol::used_keywords(|| ident.span.edition())) + { + err.subdiagnostic(errors::MisspelledKw { + similar_kw: similar_kw.to_string(), + span: ident.span, + is_incorrect_case, + }); + } + err.emit(); } if let Defaultness::Default(span) = def { diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index a7b54e68a071d..1d5287cfd80ac 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -65,6 +65,13 @@ impl ExpectedValues { ExpectedValues::Any => false, } } + + pub fn contains(&self, value: &Option) -> bool { + match self { + ExpectedValues::Some(expecteds) => expecteds.contains(value), + ExpectedValues::Any => false, + } + } } impl Extend for ExpectedValues { diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index aff10c4320fe1..344b46f01b756 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -93,6 +93,7 @@ #![feature(async_iterator)] #![feature(bstr)] #![feature(bstr_internals)] +#![feature(case_ignorable)] #![feature(cast_maybe_uninit)] #![feature(cell_get_cloned)] #![feature(char_internals)] diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 46d48afbf5a14..ce33fd1d8f9df 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1074,18 +1074,20 @@ impl char { self > '\u{02FF}' && unicode::Grapheme_Extend(self) } - /// Returns `true` if this `char` has the `Case_Ignorable` property. + /// Returns `true` if this `char` has the `Case_Ignorable` property. This narrow-use property + /// is used to implement context-dependent casing for the Greek letter sigma (uppercase Σ), + /// which has two lowercase forms. /// - /// `Case_Ignorable` is described in Chapter 4 (Character Properties) of the [Unicode Standard] and - /// specified in the [Unicode Character Database][ucd] [`DerivedCoreProperties.txt`]. + /// `Case_Ignorable` is [described][D136] in Chapter 3 (Conformance) of the Unicode Core Specification, + /// and specified in the [Unicode Character Database][ucd] [`DerivedCoreProperties.txt`]; + /// see those resources for more information. /// - /// [Unicode Standard]: https://www.unicode.org/versions/latest/ + /// [D136]: https://www.unicode.org/versions/latest/core-spec/chapter-3/#G63116 /// [ucd]: https://www.unicode.org/reports/tr44/ /// [`DerivedCoreProperties.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt #[must_use] #[inline] - #[doc(hidden)] - #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] + #[unstable(feature = "case_ignorable", issue = "154848")] pub fn is_case_ignorable(self) -> bool { if self.is_ascii() { matches!(self, '\'' | '.' | ':' | '^' | '`') diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 943e869d74380..b2c11fff99fad 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -7,6 +7,7 @@ use super::super::{ use super::TrustedLen; use crate::array; use crate::cmp::{self, Ordering}; +use crate::marker::Destruct; use crate::num::NonZero; use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try}; @@ -254,13 +255,17 @@ pub const trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_non_const_trait_method] fn last(self) -> Option where - Self: Sized, + Self: Sized + [const] Destruct, + Self::Item: [const] Destruct, { #[inline] - fn some(_: Option, x: T) -> Option { + #[rustc_const_unstable(feature = "const_destruct", issue = "133214")] + const fn some(_: Option, x: T) -> Option + where + T: [const] Destruct, + { Some(x) } @@ -2497,12 +2502,11 @@ pub const trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_try_fold", since = "1.27.0")] - #[rustc_non_const_trait_method] fn try_fold(&mut self, init: B, mut f: F) -> R where Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try, + F: [const] FnMut(B, Self::Item) -> R + [const] Destruct, + R: [const] Try, { let mut accum = init; while let Some(x) = self.next() { @@ -2676,11 +2680,10 @@ pub const trait Iterator { #[doc(alias = "inject", alias = "foldl")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_non_const_trait_method] fn fold(mut self, init: B, mut f: F) -> B where - Self: Sized, - F: FnMut(B, Self::Item) -> B, + Self: Sized + [const] Destruct, + F: [const] FnMut(B, Self::Item) -> B + [const] Destruct, { let mut accum = init; while let Some(x) = self.next() { @@ -2714,11 +2717,10 @@ pub const trait Iterator { /// ``` #[inline] #[stable(feature = "iterator_fold_self", since = "1.51.0")] - #[rustc_non_const_trait_method] fn reduce(mut self, f: F) -> Option where - Self: Sized, - F: FnMut(Self::Item, Self::Item) -> Self::Item, + Self: Sized + [const] Destruct, + F: [const] FnMut(Self::Item, Self::Item) -> Self::Item + [const] Destruct, { let first = self.next()?; Some(self.fold(first, f)) @@ -2786,14 +2788,13 @@ pub const trait Iterator { /// ``` #[inline] #[unstable(feature = "iterator_try_reduce", issue = "87053")] - #[rustc_non_const_trait_method] fn try_reduce( &mut self, - f: impl FnMut(Self::Item, Self::Item) -> R, + f: impl [const] FnMut(Self::Item, Self::Item) -> R + [const] Destruct, ) -> ChangeOutputType> where Self: Sized, - R: Try>>, + R: [const] Try>>, { let first = match self.next() { Some(i) => i, diff --git a/tests/ui/cfg/suggest-alternative-name-on-target.rs b/tests/ui/cfg/suggest-alternative-name-on-target.rs new file mode 100644 index 0000000000000..e3810dbbc9c36 --- /dev/null +++ b/tests/ui/cfg/suggest-alternative-name-on-target.rs @@ -0,0 +1,39 @@ +#![deny(unexpected_cfgs)] +//~^ NOTE lint level is defined here + +// target arch used in `target_abi` +#[cfg(target_abi = "arm")] +//~^ ERROR unexpected `cfg` condition value: +//~| NOTE see $DIR/suggest-alternative-name-on-target.rs:5:7 + | +LL | #[cfg(target_abi = "arm")] + | ^^^^^^^^^^^^^^^^^^ + | + = note: see for more information about checking conditional configuration +note: the lint level is defined here + --> $DIR/suggest-alternative-name-on-target.rs:1:9 + | +LL | #![deny(unexpected_cfgs)] + | ^^^^^^^^^^^^^^^ +help: `arm` is an expected value for `target_arch` + | +LL - #[cfg(target_abi = "arm")] +LL + #[cfg(target_arch = "arm")] + | + +error: unexpected `cfg` condition value: `gnu` + --> $DIR/suggest-alternative-name-on-target.rs:12:7 + | +LL | #[cfg(target_arch = "gnu")] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see for more information about checking conditional configuration +help: `gnu` is an expected value for `target_env` + | +LL - #[cfg(target_arch = "gnu")] +LL + #[cfg(target_env = "gnu")] + | + +error: unexpected `cfg` condition value: `openbsd` + --> $DIR/suggest-alternative-name-on-target.rs:19:7 + | +LL | #[cfg(target_env = "openbsd")] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see for more information about checking conditional configuration +help: `openbsd` is an expected value for `target_os` + | +LL - #[cfg(target_env = "openbsd")] +LL + #[cfg(target_os = "openbsd")] + | + +error: unexpected `cfg` condition value: `eabi` + --> $DIR/suggest-alternative-name-on-target.rs:26:7 + | +LL | #[cfg(target_os = "eabi")] + | ^^^^^^^^^^^^^^^^^^ + | + = note: see for more information about checking conditional configuration +help: `eabi` is an expected value for `target_abi` + | +LL - #[cfg(target_os = "eabi")] +LL + #[cfg(target_abi = "eabi")] + | + +error: unexpected `cfg` condition value: `windows` + --> $DIR/suggest-alternative-name-on-target.rs:32:7 + | +LL | #[cfg(target_abi = "windows")] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see for more information about checking conditional configuration +help: `windows` is an expected value for `target_os` + | +LL - #[cfg(target_abi = "windows")] +LL + #[cfg(target_os = "windows")] + | +help: `windows` is an expected value for `target_family` + | +LL - #[cfg(target_abi = "windows")] +LL + #[cfg(target_family = "windows")] + | + +error: aborting due to 5 previous errors + diff --git a/tests/ui/parser/misspelled-keywords/pub-const-fn.rs b/tests/ui/parser/misspelled-keywords/pub-const-fn.rs new file mode 100644 index 0000000000000..1a291cdee32d8 --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/pub-const-fn.rs @@ -0,0 +1,5 @@ +pub cnst fn code() {} +//~^ ERROR visibility `pub` is not followed by an item +//~| ERROR expected item, found `cnst` + +fn main() {} diff --git a/tests/ui/parser/misspelled-keywords/pub-const-fn.stderr b/tests/ui/parser/misspelled-keywords/pub-const-fn.stderr new file mode 100644 index 0000000000000..c9b70a77f5d1f --- /dev/null +++ b/tests/ui/parser/misspelled-keywords/pub-const-fn.stderr @@ -0,0 +1,22 @@ +error: visibility `pub` is not followed by an item + --> $DIR/pub-const-fn.rs:1:1 + | +LL | pub cnst fn code() {} + | ^^^ the visibility + | + = help: you likely meant to define an item, e.g., `pub fn foo() {}` +help: there is a keyword `const` with a similar name + | +LL | pub const fn code() {} + | + + +error: expected item, found `cnst` + --> $DIR/pub-const-fn.rs:1:5 + | +LL | pub cnst fn code() {} + | ^^^^ expected item + | + = note: for a full list of items that can appear in modules, see + +error: aborting due to 2 previous errors + diff --git a/tests/ui/unsafe-binders/discriminant-for-variant.rs b/tests/ui/unsafe-binders/discriminant-for-variant.rs new file mode 100644 index 0000000000000..6a2ef22e92628 --- /dev/null +++ b/tests/ui/unsafe-binders/discriminant-for-variant.rs @@ -0,0 +1,11 @@ +#![feature(unsafe_binders)] + +const None: Option Option>> = None; +//~^ ERROR the trait bound `Box<(dyn Send + 'static)>: Copy` is not satisfied +//~| ERROR the trait bound `Box<(dyn Send + 'static)>: Copy` is not satisfied + +fn main() { + match None { + _ => {} + } +} diff --git a/tests/ui/unsafe-binders/discriminant-for-variant.stderr b/tests/ui/unsafe-binders/discriminant-for-variant.stderr new file mode 100644 index 0000000000000..ed1a38ae14e40 --- /dev/null +++ b/tests/ui/unsafe-binders/discriminant-for-variant.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `Box<(dyn Send + 'static)>: Copy` is not satisfied + --> $DIR/discriminant-for-variant.rs:3:13 + | +LL | const None: Option Option>> = None; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<(dyn Send + 'static)>` + | + = note: required for `Option>` to implement `Copy` + +error[E0277]: the trait bound `Box<(dyn Send + 'static)>: Copy` is not satisfied + --> $DIR/discriminant-for-variant.rs:3:54 + | +LL | const None: Option Option>> = None; + | ^^^^ the trait `Copy` is not implemented for `Box<(dyn Send + 'static)>` + | + = note: required for `Option>` to implement `Copy` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`.