diff options
Diffstat (limited to 'compiler/rustc_codegen_ssa/src')
26 files changed, 660 insertions, 290 deletions
diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs index 11bcd727501..ab65319e3d3 100644 --- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs +++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs @@ -26,15 +26,14 @@ use std::borrow::Cow; use std::fmt; -use rustc_ast as ast; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::{DiagArgValue, IntoDiagArg}; +use rustc_hir as hir; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::mir::mono::CodegenUnitNameBuilder; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::symbol::sym; -use rustc_span::{Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; use tracing::debug; @@ -77,7 +76,7 @@ struct AssertModuleSource<'tcx> { } impl<'tcx> AssertModuleSource<'tcx> { - fn check_attr(&mut self, attr: &ast::Attribute) { + fn check_attr(&mut self, attr: &hir::Attribute) { let (expected_reuse, comp_kind) = if attr.has_name(sym::rustc_partition_reused) { (CguReuse::PreLto, ComparisonKind::AtLeast) } else if attr.has_name(sym::rustc_partition_codegened) { @@ -158,7 +157,7 @@ impl<'tcx> AssertModuleSource<'tcx> { ); } - fn field(&self, attr: &ast::Attribute, name: Symbol) -> Symbol { + fn field(&self, attr: &hir::Attribute, name: Symbol) -> Symbol { for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { if item.has_name(name) { if let Some(value) = item.value_str() { @@ -177,7 +176,7 @@ impl<'tcx> AssertModuleSource<'tcx> { /// Scan for a `cfg="foo"` attribute and check whether we have a /// cfg flag called `foo`. - fn check_config(&self, attr: &ast::Attribute) -> bool { + fn check_config(&self, attr: &hir::Attribute) -> bool { let config = &self.tcx.sess.psess.config; let value = self.field(attr, sym::cfg); debug!("check_config(config={:?}, value={:?})", config, value); diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index d4836eb7a1d..58eb137c068 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -2,7 +2,7 @@ use std::env; use std::error::Error; use std::ffi::OsString; use std::fs::{self, File}; -use std::io::{self, Write}; +use std::io::{self, BufWriter, Write}; use std::path::{Path, PathBuf}; use ar_archive_writer::{ @@ -14,7 +14,7 @@ use object::read::macho::FatArch; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::memmap::Mmap; use rustc_session::Session; -use rustc_span::symbol::Symbol; +use rustc_span::Symbol; use tempfile::Builder as TempFileBuilder; use tracing::trace; @@ -509,9 +509,10 @@ impl<'a> ArArchiveBuilder<'a> { io_error_context("couldn't create a directory for the temp file", err) })?; let archive_tmpfile_path = archive_tmpdir.path().join("tmp.a"); - let mut archive_tmpfile = File::create_new(&archive_tmpfile_path) + let archive_tmpfile = File::create_new(&archive_tmpfile_path) .map_err(|err| io_error_context("couldn't create the temp file", err))?; + let mut archive_tmpfile = BufWriter::new(archive_tmpfile); write_archive_to_stream( &mut archive_tmpfile, &entries, @@ -519,6 +520,8 @@ impl<'a> ArArchiveBuilder<'a> { false, /* is_ec = */ self.sess.target.arch == "arm64ec", )?; + archive_tmpfile.flush()?; + drop(archive_tmpfile); let any_entries = !entries.is_empty(); drop(entries); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index c3281c8c2e5..2587d6dfdc4 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -15,7 +15,7 @@ use rustc_ast::CRATE_NODE_ID; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError}; +use rustc_errors::DiagCtxtHandle; use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file}; @@ -35,7 +35,7 @@ use rustc_session::utils::NativeLibKind; /// For all the linkers we support, and information they might /// need out of the shared crate context before we get rid of it. use rustc_session::{Session, filesearch}; -use rustc_span::symbol::Symbol; +use rustc_span::Symbol; use rustc_target::spec::crt_objects::CrtObjects; use rustc_target::spec::{ Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFeatures, @@ -71,7 +71,7 @@ pub fn link_binary( archive_builder_builder: &dyn ArchiveBuilderBuilder, codegen_results: CodegenResults, outputs: &OutputFilenames, -) -> Result<(), ErrorGuaranteed> { +) { let _timer = sess.timer("link_binary"); let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); let mut tempfiles_for_stdout_output: Vec<PathBuf> = Vec::new(); @@ -119,7 +119,7 @@ pub fn link_binary( &codegen_results, RlibFlavor::Normal, &path, - )? + ) .build(&out_filename); } CrateType::Staticlib => { @@ -129,7 +129,7 @@ pub fn link_binary( &codegen_results, &out_filename, &path, - )?; + ); } _ => { link_natively( @@ -139,7 +139,7 @@ pub fn link_binary( &out_filename, &codegen_results, path.as_ref(), - )?; + ); } } if sess.opts.json_artifact_notifications { @@ -225,8 +225,6 @@ pub fn link_binary( maybe_remove_temps_from_module(preserve_objects, preserve_dwarf_objects, module); } }); - - Ok(()) } // Crate type is not passed when calculating the dylibs to include for LTO. In that case all @@ -236,9 +234,13 @@ pub fn each_linked_rlib( crate_type: Option<CrateType>, f: &mut dyn FnMut(CrateNum, &Path), ) -> Result<(), errors::LinkRlibError> { - let crates = info.used_crates.iter(); + let fmts = if let Some(crate_type) = crate_type { + let Some(fmts) = info.dependency_formats.get(&crate_type) else { + return Err(errors::LinkRlibError::MissingFormat); + }; - let fmts = if crate_type.is_none() { + fmts + } else { for combination in info.dependency_formats.iter().combinations(2) { let (ty1, list1) = &combination[0]; let (ty2, list2) = &combination[1]; @@ -254,22 +256,12 @@ pub fn each_linked_rlib( if info.dependency_formats.is_empty() { return Err(errors::LinkRlibError::MissingFormat); } - &info.dependency_formats[0].1 - } else { - let fmts = info - .dependency_formats - .iter() - .find_map(|&(ty, ref list)| if Some(ty) == crate_type { Some(list) } else { None }); - - let Some(fmts) = fmts else { - return Err(errors::LinkRlibError::MissingFormat); - }; - - fmts + info.dependency_formats.first().unwrap().1 }; - for &cnum in crates { - match fmts.get(cnum.as_usize() - 1) { + let used_dep_crates = info.used_crates.iter(); + for &cnum in used_dep_crates { + match fmts.get(cnum) { Some(&Linkage::NotLinked | &Linkage::Dynamic | &Linkage::IncludedFromDylib) => continue, Some(_) => {} None => return Err(errors::LinkRlibError::MissingFormat), @@ -298,7 +290,7 @@ fn link_rlib<'a>( codegen_results: &CodegenResults, flavor: RlibFlavor, tmpdir: &MaybeTempDir, -) -> Result<Box<dyn ArchiveBuilder + 'a>, ErrorGuaranteed> { +) -> Box<dyn ArchiveBuilder + 'a> { let mut ab = archive_builder_builder.new_archive_builder(sess); let trailing_metadata = match flavor { @@ -374,7 +366,7 @@ fn link_rlib<'a>( { let path = find_native_static_library(filename.as_str(), true, sess); let src = read(path) - .map_err(|e| sess.dcx().emit_fatal(errors::ReadFileError { message: e }))?; + .unwrap_or_else(|e| sess.dcx().emit_fatal(errors::ReadFileError { message: e })); let (data, _) = create_wrapper_file(sess, ".bundled_lib".to_string(), &src); let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str()); packed_bundled_libs.push(wrapper_file); @@ -392,7 +384,7 @@ fn link_rlib<'a>( codegen_results.crate_info.used_libraries.iter(), tmpdir.as_ref(), true, - )? { + ) { ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| { sess.dcx().emit_fatal(errors::AddNativeLibrary { library_path: output_path, error }); }); @@ -433,7 +425,7 @@ fn link_rlib<'a>( ab.add_file(&lib) } - Ok(ab) + ab } /// Extract all symbols defined in raw-dylib libraries, collated by library name. @@ -445,7 +437,7 @@ fn link_rlib<'a>( fn collate_raw_dylibs<'a>( sess: &Session, used_libraries: impl IntoIterator<Item = &'a NativeLib>, -) -> Result<Vec<(String, Vec<DllImport>)>, ErrorGuaranteed> { +) -> Vec<(String, Vec<DllImport>)> { // Use index maps to preserve original order of imports and libraries. let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default(); @@ -469,15 +461,13 @@ fn collate_raw_dylibs<'a>( } } } - if let Some(guar) = sess.dcx().has_errors() { - return Err(guar); - } - Ok(dylib_table + sess.dcx().abort_if_errors(); + dylib_table .into_iter() .map(|(name, imports)| { (name, imports.into_iter().map(|(_, import)| import.clone()).collect()) }) - .collect()) + .collect() } fn create_dll_import_libs<'a>( @@ -486,8 +476,8 @@ fn create_dll_import_libs<'a>( used_libraries: impl IntoIterator<Item = &'a NativeLib>, tmpdir: &Path, is_direct_dependency: bool, -) -> Result<Vec<PathBuf>, ErrorGuaranteed> { - Ok(collate_raw_dylibs(sess, used_libraries)? +) -> Vec<PathBuf> { + collate_raw_dylibs(sess, used_libraries) .into_iter() .map(|(raw_dylib_name, raw_dylib_imports)| { let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" }; @@ -537,7 +527,7 @@ fn create_dll_import_libs<'a>( output_path }) - .collect()) + .collect() } /// Create a static archive. @@ -557,7 +547,7 @@ fn link_staticlib( codegen_results: &CodegenResults, out_filename: &Path, tempdir: &MaybeTempDir, -) -> Result<(), ErrorGuaranteed> { +) { info!("preparing staticlib to {:?}", out_filename); let mut ab = link_rlib( sess, @@ -565,7 +555,7 @@ fn link_staticlib( codegen_results, RlibFlavor::StaticlibBase, tempdir, - )?; + ); let mut all_native_libs = vec![]; let res = each_linked_rlib( @@ -628,13 +618,12 @@ fn link_staticlib( let fmts = codegen_results .crate_info .dependency_formats - .iter() - .find_map(|&(ty, ref list)| if ty == CrateType::Staticlib { Some(list) } else { None }) + .get(&CrateType::Staticlib) .expect("no dependency formats for staticlib"); let mut all_rust_dylibs = vec![]; for &cnum in crates { - match fmts.get(cnum.as_usize() - 1) { + match fmts.get(cnum) { Some(&Linkage::Dynamic) => {} _ => continue, } @@ -656,8 +645,6 @@ fn link_staticlib( print_native_static_libs(sess, &print.out, &all_native_libs, &all_rust_dylibs); } } - - Ok(()) } /// Use `thorin` (rust implementation of a dwarf packaging utility) to link DWARF objects into a @@ -773,7 +760,7 @@ fn link_natively( out_filename: &Path, codegen_results: &CodegenResults, tmpdir: &Path, -) -> Result<(), ErrorGuaranteed> { +) { info!("preparing {:?} to {:?}", crate_type, out_filename); let (linker_path, flavor) = linker_and_flavor(sess); let self_contained_components = self_contained_components(sess, crate_type); @@ -797,7 +784,7 @@ fn link_natively( temp_filename, codegen_results, self_contained_components, - )?; + ); linker::disable_localization(&mut cmd); @@ -998,12 +985,12 @@ fn link_natively( let mut output = prog.stderr.clone(); output.extend_from_slice(&prog.stdout); let escaped_output = escape_linker_output(&output, flavor); - // FIXME: Add UI tests for this error. let err = errors::LinkingFailed { linker_path: &linker_path, exit_status: prog.status, - command: &cmd, + command: cmd, escaped_output, + verbose: sess.opts.verbose, }; sess.dcx().emit_err(err); // If MSVC's `link.exe` was expected but the return code @@ -1047,22 +1034,22 @@ fn link_natively( Err(e) => { let linker_not_found = e.kind() == io::ErrorKind::NotFound; - if linker_not_found { - sess.dcx().emit_err(errors::LinkerNotFound { linker_path, error: e }); + let err = if linker_not_found { + sess.dcx().emit_err(errors::LinkerNotFound { linker_path, error: e }) } else { sess.dcx().emit_err(errors::UnableToExeLinker { linker_path, error: e, command_formatted: format!("{cmd:?}"), - }); - } + }) + }; if sess.target.is_like_msvc && linker_not_found { sess.dcx().emit_note(errors::MsvcMissingLinker); sess.dcx().emit_note(errors::CheckInstalledVisualStudio); sess.dcx().emit_note(errors::InsufficientVSCodeProduct); } - FatalError.raise(); + err.raise_fatal(); } } @@ -1113,14 +1100,14 @@ fn link_natively( let stripcmd = "rust-objcopy"; match (strip, crate_type) { (Strip::Debuginfo, _) => { - strip_symbols_with_external_utility(sess, stripcmd, out_filename, &["-S"]) + strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-debug"]) } // Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988) (Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => { - strip_symbols_with_external_utility(sess, stripcmd, out_filename, &["-x"]) + strip_with_external_utility(sess, stripcmd, out_filename, &["-x"]) } (Strip::Symbols, _) => { - strip_symbols_with_external_utility(sess, stripcmd, out_filename, &[]) + strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-all"]) } (Strip::None, _) => {} } @@ -1136,9 +1123,7 @@ fn link_natively( let stripcmd = if !sess.host.is_like_solaris { "rust-objcopy" } else { "/usr/bin/strip" }; match strip { // Always preserve the symbol table (-x). - Strip::Debuginfo => { - strip_symbols_with_external_utility(sess, stripcmd, out_filename, &["-x"]) - } + Strip::Debuginfo => strip_with_external_utility(sess, stripcmd, out_filename, &["-x"]), // Strip::Symbols is handled via the --strip-all linker option. Strip::Symbols => {} Strip::None => {} @@ -1154,15 +1139,11 @@ fn link_natively( match strip { Strip::Debuginfo => { // FIXME: AIX's strip utility only offers option to strip line number information. - strip_symbols_with_external_utility(sess, stripcmd, out_filename, &[ - "-X32_64", "-l", - ]) + strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-l"]) } Strip::Symbols => { // Must be noted this option might remove symbol __aix_rust_metadata and thus removes .info section which contains metadata. - strip_symbols_with_external_utility(sess, stripcmd, out_filename, &[ - "-X32_64", "-r", - ]) + strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-r"]) } Strip::None => {} } @@ -1173,16 +1154,9 @@ fn link_natively( ab.add_file(temp_filename); ab.build(out_filename); } - - Ok(()) } -fn strip_symbols_with_external_utility( - sess: &Session, - util: &str, - out_filename: &Path, - options: &[&str], -) { +fn strip_with_external_utility(sess: &Session, util: &str, out_filename: &Path, options: &[&str]) { let mut cmd = Command::new(util); cmd.args(options); @@ -2228,7 +2202,7 @@ fn linker_with_args( out_filename: &Path, codegen_results: &CodegenResults, self_contained_components: LinkSelfContainedComponents, -) -> Result<Command, ErrorGuaranteed> { +) -> Command { let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled(); let cmd = &mut *super::linker::get_linker( sess, @@ -2352,18 +2326,17 @@ fn linker_with_args( codegen_results.crate_info.used_libraries.iter(), tmpdir, true, - )? { + ) { cmd.add_object(&output_path); } // As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case // they are used within inlined functions or instantiated generic functions. We do this *after* // handling the raw-dylib symbols in the current crate to make sure that those are chosen first // by the linker. - let (_, dependency_linkage) = codegen_results + let dependency_linkage = codegen_results .crate_info .dependency_formats - .iter() - .find(|(ty, _)| *ty == crate_type) + .get(&crate_type) .expect("failed to find crate type in dependency format list"); // We sort the libraries below @@ -2372,8 +2345,8 @@ fn linker_with_args( .crate_info .native_libraries .iter() - .filter_map(|(cnum, libraries)| { - (dependency_linkage[cnum.as_usize() - 1] != Linkage::Static).then_some(libraries) + .filter_map(|(&cnum, libraries)| { + (dependency_linkage[cnum] != Linkage::Static).then_some(libraries) }) .flatten() .collect::<Vec<_>>(); @@ -2384,7 +2357,7 @@ fn linker_with_args( native_libraries_from_nonstatics, tmpdir, false, - )? { + ) { cmd.add_object(&output_path); } @@ -2431,7 +2404,7 @@ fn linker_with_args( // to it and remove the option. Currently the last holdout is wasm32-unknown-emscripten. add_post_link_args(cmd, sess, flavor); - Ok(cmd.take_cmd()) + cmd.take_cmd() } fn add_order_independent_options( @@ -2742,13 +2715,21 @@ fn add_upstream_rust_crates( // Linking to a rlib involves just passing it to the linker (the linker // will slurp up the object files inside), and linking to a dynamic library // involves just passing the right -l flag. - let (_, data) = codegen_results + let data = codegen_results .crate_info .dependency_formats - .iter() - .find(|(ty, _)| *ty == crate_type) + .get(&crate_type) .expect("failed to find crate type in dependency format list"); + if sess.target.is_like_aix { + // Unlike ELF linkers, AIX doesn't feature `DT_SONAME` to override + // the dependency name when outputing a shared library. Thus, `ld` will + // use the full path to shared libraries as the dependency if passed it + // by default unless `noipath` is passed. + // https://www.ibm.com/docs/en/aix/7.3?topic=l-ld-command. + cmd.link_or_cc_arg("-bnoipath"); + } + for &cnum in &codegen_results.crate_info.used_crates { // We may not pass all crates through to the linker. Some crates may appear statically in // an existing dylib, meaning we'll pick up all the symbols from the dylib. @@ -2757,7 +2738,7 @@ fn add_upstream_rust_crates( // (e.g. `libstd` when `-C prefer-dynamic` is used). // FIXME: `dependency_formats` can report `profiler_builtins` as `NotLinked` for some // reason, it shouldn't do that because `profiler_builtins` should indeed be linked. - let linkage = data[cnum.as_usize() - 1]; + let linkage = data[cnum]; let link_static_crate = linkage == Linkage::Static || (linkage == Linkage::IncludedFromDylib || linkage == Linkage::NotLinked) && (codegen_results.crate_info.compiler_builtins == Some(cnum) @@ -2985,7 +2966,7 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { match lib.cfg { - Some(ref cfg) => rustc_attr::cfg_matches(cfg, sess, CRATE_NODE_ID, None), + Some(ref cfg) => rustc_attr_parsing::cfg_matches(cfg, sess, CRATE_NODE_ID, None), None => true, } } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 17323f67ffa..8fb831471a9 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -16,7 +16,7 @@ use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, S use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; -use rustc_span::symbol::sym; +use rustc_span::sym; use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld}; use tracing::{debug, warn}; @@ -1693,6 +1693,8 @@ impl<'a> Linker for AixLinker<'a> { fn pgo_gen(&mut self) { self.link_arg("-bdbg:namedsects:ss"); + self.link_arg("-u"); + self.link_arg("__llvm_profile_runtime"); } fn control_flow_guard(&mut self) {} @@ -1741,15 +1743,10 @@ fn for_each_exported_symbols_include_dep<'tcx>( crate_type: CrateType, mut callback: impl FnMut(ExportedSymbol<'tcx>, SymbolExportInfo, CrateNum), ) { - for &(symbol, info) in tcx.exported_symbols(LOCAL_CRATE).iter() { - callback(symbol, info, LOCAL_CRATE); - } - let formats = tcx.dependency_formats(()); - let deps = formats.iter().find_map(|(t, list)| (*t == crate_type).then_some(list)).unwrap(); + let deps = &formats[&crate_type]; - for (index, dep_format) in deps.iter().enumerate() { - let cnum = CrateNum::new(index + 1); + for (cnum, dep_format) in deps.iter_enumerated() { // For each dependency that we are linking to statically ... if *dep_format == Linkage::Static { for &(symbol, info) in tcx.exported_symbols(cnum).iter() { diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs index ab8b06a05fc..efccf7687a1 100644 --- a/compiler/rustc_codegen_ssa/src/back/lto.rs +++ b/compiler/rustc_codegen_ssa/src/back/lto.rs @@ -1,11 +1,14 @@ use std::ffi::CString; use std::sync::Arc; +use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_data_structures::memmap::Mmap; use rustc_errors::FatalError; +use rustc_middle::ty::TyCtxt; use super::write::CodegenContext; use crate::ModuleCodegen; +use crate::back::write::ModuleConfig; use crate::traits::*; pub struct ThinModule<B: WriteBackendMethods> { @@ -81,6 +84,24 @@ impl<B: WriteBackendMethods> LtoModuleCodegen<B> { LtoModuleCodegen::Thin(ref m) => m.cost(), } } + + /// Run autodiff on Fat LTO module + pub unsafe fn autodiff( + self, + cgcx: &CodegenContext<B>, + tcx: TyCtxt<'_>, + diff_fncs: Vec<AutoDiffItem>, + config: &ModuleConfig, + ) -> Result<LtoModuleCodegen<B>, FatalError> { + match &self { + LtoModuleCodegen::Fat(module) => { + B::autodiff(cgcx, tcx, &module, diff_fncs, config)?; + } + _ => panic!("autodiff called with non-fat LTO module"), + } + + Ok(self) + } } pub enum SerializedModule<M: ModuleBufferMethods> { diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 788a8a13b3e..60ab2919352 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -311,7 +311,8 @@ fn exported_symbols_provider_local( } if !tcx.sess.opts.share_generics() { - if tcx.codegen_fn_attrs(mono_item.def_id()).inline == rustc_attr::InlineAttr::Never + if tcx.codegen_fn_attrs(mono_item.def_id()).inline + == rustc_attr_parsing::InlineAttr::Never { // this is OK, we explicitly allow sharing inline(never) across crates even // without share-generics. diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 7c0e9cfd5a7..b40bb4ed5d2 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -6,9 +6,9 @@ use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender, channel}; use std::{fs, io, mem, str, thread}; -use jobserver::{Acquired, Client}; use rustc_ast::attr; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use rustc_data_structures::jobserver::{self, Acquired}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard}; use rustc_errors::emitter::Emitter; @@ -33,8 +33,7 @@ use rustc_session::config::{ self, CrateType, Lto, OutFileName, OutputFilenames, OutputType, Passes, SwitchWithOptPath, }; use rustc_span::source_map::SourceMap; -use rustc_span::symbol::sym; -use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span}; +use rustc_span::{FileName, InnerSpan, Span, SpanData, sym}; use rustc_target::spec::{MergeFunctions, SanitizerSet}; use tracing::debug; @@ -456,7 +455,6 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>( metadata_module: Option<CompiledModule>, ) -> OngoingCodegen<B> { let (coordinator_send, coordinator_receive) = channel(); - let sess = tcx.sess; let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins); @@ -477,7 +475,6 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>( shared_emitter, codegen_worker_send, coordinator_receive, - sess.jobserver.clone(), Arc::new(regular_config), Arc::new(metadata_config), Arc::new(allocator_config), @@ -1093,7 +1090,6 @@ fn start_executing_work<B: ExtraBackendMethods>( shared_emitter: SharedEmitter, codegen_worker_send: Sender<CguMessage>, coordinator_receive: Receiver<Box<dyn Any + Send>>, - jobserver: Client, regular_config: Arc<ModuleConfig>, metadata_config: Arc<ModuleConfig>, allocator_config: Arc<ModuleConfig>, @@ -1145,7 +1141,7 @@ fn start_executing_work<B: ExtraBackendMethods>( // get tokens on `coordinator_receive` which will // get managed in the main loop below. let coordinator_send2 = coordinator_send.clone(); - let helper = jobserver + let helper = jobserver::client() .into_helper_thread(move |token| { drop(coordinator_send2.send(Box::new(Message::Token::<B>(token)))); }) @@ -1837,7 +1833,7 @@ fn spawn_work<'a, B: ExtraBackendMethods>( enum SharedEmitterMessage { Diagnostic(Diagnostic), - InlineAsmError(u32, String, Level, Option<(String, Vec<InnerSpan>)>), + InlineAsmError(SpanData, String, Level, Option<(String, Vec<InnerSpan>)>), Fatal(String), } @@ -1859,12 +1855,12 @@ impl SharedEmitter { pub fn inline_asm_error( &self, - cookie: u32, + span: SpanData, msg: String, level: Level, source: Option<(String, Vec<InnerSpan>)>, ) { - drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source))); + drop(self.sender.send(SharedEmitterMessage::InlineAsmError(span, msg, level, source))); } fn fatal(&self, msg: &str) { @@ -1883,7 +1879,11 @@ impl Translate for SharedEmitter { } impl Emitter for SharedEmitter { - fn emit_diagnostic(&mut self, mut diag: rustc_errors::DiagInner) { + fn emit_diagnostic( + &mut self, + mut diag: rustc_errors::DiagInner, + _registry: &rustc_errors::registry::Registry, + ) { // Check that we aren't missing anything interesting when converting to // the cut-down local `DiagInner`. assert_eq!(diag.span, MultiSpan::new()); @@ -1949,17 +1949,12 @@ impl SharedEmitterMain { dcx.emit_diagnostic(d); sess.dcx().abort_if_errors(); } - Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => { + Ok(SharedEmitterMessage::InlineAsmError(span, msg, level, source)) => { assert_matches!(level, Level::Error | Level::Warning | Level::Note); - let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string(); let mut err = Diag::<()>::new(sess.dcx(), level, msg); - - // If the cookie is 0 then we don't have span information. - if cookie != 0 { - let pos = BytePos::from_u32(cookie); - let span = Span::with_root_ctxt(pos, pos); - err.span(span); - }; + if !span.is_dummy() { + err.span(span.span()); + } // Point to the generated assembly if it is available. if let Some((buffer, spans)) = source { @@ -2028,8 +2023,6 @@ pub struct OngoingCodegen<B: ExtraBackendMethods> { impl<B: ExtraBackendMethods> OngoingCodegen<B> { pub fn join(self, sess: &Session) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) { - let _timer = sess.timer("finish_ongoing_codegen"); - self.shared_emitter_main.check(sess, true); let compiled_modules = sess.time("join_worker_thread", || match self.coordinator.join() { Ok(Ok(compiled_modules)) => compiled_modules, diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 27c9cb0b31e..77e1fed720d 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -5,7 +5,6 @@ use std::time::{Duration, Instant}; use itertools::Itertools; use rustc_abi::FIRST_VARIANT; use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_name}; -use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::{Lrc, par_map}; @@ -25,12 +24,12 @@ use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::Session; use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType}; -use rustc_span::symbol::sym; -use rustc_span::{DUMMY_SP, Symbol}; +use rustc_span::{DUMMY_SP, Symbol, sym}; use rustc_trait_selection::infer::at::ToTrace; use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt}; use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; use tracing::{debug, info}; +use {rustc_ast as ast, rustc_attr_parsing as attr}; use crate::assert_module_sources::CguReuse; use crate::back::link::are_upstream_rust_objects_already_included; @@ -873,7 +872,8 @@ impl CrateInfo { crate_types.iter().map(|&c| (c, crate::back::linker::linked_symbols(tcx, c))).collect(); let local_crate_name = tcx.crate_name(LOCAL_CRATE); let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); - let subsystem = attr::first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem); + let subsystem = + ast::attr::first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem); let windows_subsystem = subsystem.map(|subsystem| { if subsystem != sym::windows && subsystem != sym::console { tcx.dcx().emit_fatal(errors::InvalidWindowsSubsystem { subsystem }); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index a5acd8170ab..cdb72aba36f 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,13 +1,13 @@ -use rustc_ast::{MetaItemInner, MetaItemKind, ast, attr}; -use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr, list_contains_name}; +use rustc_ast::attr::list_contains_name; +use rustc_ast::{MetaItemInner, attr}; +use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err}; -use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; -use rustc_hir::{LangItem, lang_items}; +use rustc_hir::{self as hir, HirId, LangItem, lang_items}; use rustc_middle::middle::codegen_fn_attrs::{ CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, }; @@ -16,8 +16,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self as ty, TyCtxt}; use rustc_session::parse::feature_err; use rustc_session::{Session, lint}; -use rustc_span::symbol::Ident; -use rustc_span::{Span, sym}; +use rustc_span::{Ident, Span, sym}; use rustc_target::spec::{SanitizerSet, abi}; use crate::errors; @@ -78,6 +77,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let mut inline_span = None; let mut link_ordinal_span = None; let mut no_sanitize_span = None; + let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default(); for attr in attrs.iter() { // In some cases, attribute are only valid on functions, but it's the `check_attr` @@ -116,7 +116,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, sym::no_mangle => { if tcx.opt_item_name(did.to_def_id()).is_some() { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; + mixed_export_name_no_mangle_lint_state.track_no_mangle( + attr.span, + tcx.local_def_id_to_hir_id(did), + attr, + ); } else { tcx.dcx() .struct_span_err( @@ -240,12 +245,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { .emit(); } codegen_fn_attrs.export_name = Some(s); + mixed_export_name_no_mangle_lint_state.track_export_name(attr.span); } } sym::target_feature => { if !tcx.is_closure_like(did.to_def_id()) && let Some(fn_sig) = fn_sig() - && fn_sig.skip_binder().safety() == hir::Safety::Safe + && fn_sig.skip_binder().safety().is_safe() { if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { // The `#[target_feature]` attribute is allowed on @@ -419,7 +425,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { && let [item] = items.as_slice() && let Some((sym::align, literal)) = item.singleton_lit_list() { - rustc_attr::parse_alignment(&literal.kind) + rustc_attr_parsing::parse_alignment(&literal.kind) .map_err(|msg| { struct_span_code_err!( tcx.dcx(), @@ -513,61 +519,65 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } + mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx); + codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { if !attr.has_name(sym::inline) { return ia; } - match attr.meta_kind() { - Some(MetaItemKind::Word) => InlineAttr::Hint, - Some(MetaItemKind::List(ref items)) => { - inline_span = Some(attr.span); - if items.len() != 1 { - struct_span_code_err!(tcx.dcx(), attr.span, E0534, "expected one argument") - .emit(); - InlineAttr::None - } else if list_contains_name(items, sym::always) { - InlineAttr::Always - } else if list_contains_name(items, sym::never) { - InlineAttr::Never - } else { - struct_span_code_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument") - .with_help("valid inline arguments are `always` and `never`") - .emit(); + if attr.is_word() { + InlineAttr::Hint + } else if let Some(ref items) = attr.meta_item_list() { + inline_span = Some(attr.span); + if items.len() != 1 { + struct_span_code_err!(tcx.dcx(), attr.span, E0534, "expected one argument").emit(); + InlineAttr::None + } else if list_contains_name(items, sym::always) { + InlineAttr::Always + } else if list_contains_name(items, sym::never) { + InlineAttr::Never + } else { + struct_span_code_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument") + .with_help("valid inline arguments are `always` and `never`") + .emit(); - InlineAttr::None - } + InlineAttr::None } - Some(MetaItemKind::NameValue(_)) => ia, - None => ia, + } else { + ia } }); + // naked function MUST NOT be inlined! This attribute is required for the rust compiler itself, + // but not for the code generation backend because at that point the naked function will just be + // a declaration, with a definition provided in global assembly. + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { + codegen_fn_attrs.inline = InlineAttr::Never; + } + codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| { if !attr.has_name(sym::optimize) { return ia; } let err = |sp, s| struct_span_code_err!(tcx.dcx(), sp, E0722, "{}", s).emit(); - match attr.meta_kind() { - Some(MetaItemKind::Word) => { + if attr.is_word() { + err(attr.span, "expected one argument"); + ia + } else if let Some(ref items) = attr.meta_item_list() { + inline_span = Some(attr.span); + if items.len() != 1 { err(attr.span, "expected one argument"); - ia - } - Some(MetaItemKind::List(ref items)) => { - inline_span = Some(attr.span); - if items.len() != 1 { - err(attr.span, "expected one argument"); - OptimizeAttr::None - } else if list_contains_name(items, sym::size) { - OptimizeAttr::Size - } else if list_contains_name(items, sym::speed) { - OptimizeAttr::Speed - } else { - err(items[0].span(), "invalid argument"); - OptimizeAttr::None - } + OptimizeAttr::None + } else if list_contains_name(items, sym::size) { + OptimizeAttr::Size + } else if list_contains_name(items, sym::speed) { + OptimizeAttr::Speed + } else { + err(items[0].span(), "invalid argument"); + OptimizeAttr::None } - Some(MetaItemKind::NameValue(_)) => ia, - None => ia, + } else { + OptimizeAttr::None } }); @@ -626,10 +636,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { - codegen_fn_attrs.inline = InlineAttr::Never; - } - // Weak lang items have the same semantics as "std internal" symbols in the // sense that they're preserved through all our LTO passes and only // strippable by the linker. @@ -719,7 +725,7 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { false } -fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> { +fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Option<u16> { use rustc_ast::{LitIntType, LitKind, MetaItemLit}; let meta_item_list = attr.meta_item_list(); let meta_item_list = meta_item_list.as_deref(); @@ -779,6 +785,49 @@ fn check_link_name_xor_ordinal( } } +#[derive(Default)] +struct MixedExportNameAndNoMangleState<'a> { + export_name: Option<Span>, + hir_id: Option<HirId>, + no_mangle: Option<Span>, + no_mangle_attr: Option<&'a hir::Attribute>, +} + +impl<'a> MixedExportNameAndNoMangleState<'a> { + fn track_export_name(&mut self, span: Span) { + self.export_name = Some(span); + } + + fn track_no_mangle(&mut self, span: Span, hir_id: HirId, attr_name: &'a hir::Attribute) { + self.no_mangle = Some(span); + self.hir_id = Some(hir_id); + self.no_mangle_attr = Some(attr_name); + } + + /// Emit diagnostics if the lint condition is met. + fn lint_if_mixed(self, tcx: TyCtxt<'_>) { + if let Self { + export_name: Some(export_name), + no_mangle: Some(no_mangle), + hir_id: Some(hir_id), + no_mangle_attr: Some(no_mangle_attr), + } = self + { + tcx.emit_node_span_lint( + lint::builtin::UNUSED_ATTRIBUTES, + hir_id, + no_mangle, + errors::MixedExportNameAndNoMangle { + no_mangle, + no_mangle_attr: rustc_hir_pretty::attribute_to_string(&tcx, no_mangle_attr), + export_name, + removal_span: no_mangle, + }, + ); + } + } +} + pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers }; } diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs index 88d36b19da4..7c62c03d574 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs @@ -65,8 +65,8 @@ fn tag_base_type_opt<'tcx>( }); match enum_type_and_layout.layout.variants() { - // A single-variant enum has no discriminant. - Variants::Single { .. } => None, + // A single-variant or no-variant enum has no discriminant. + Variants::Single { .. } | Variants::Empty => None, Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } => { // Niche tags are always normalized to unsized integers of the correct size. diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 6c4f6d37972..869798d8be1 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -432,11 +432,9 @@ fn push_debuginfo_type_name<'tcx>( push_closure_or_coroutine_name(tcx, def_id, args, qualified, output, visited); } } - // Type parameters from polymorphized functions. - ty::Param(_) => { - write!(output, "{t:?}").unwrap(); - } - ty::Error(_) + ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binders)"), + ty::Param(_) + | ty::Error(_) | ty::Infer(_) | ty::Placeholder(..) | ty::Alias(..) diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index f93cb52ea3e..c7213bbc801 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1,6 +1,7 @@ //! Errors emitted by codegen_ssa use std::borrow::Cow; +use std::ffi::OsString; use std::io::Error; use std::num::ParseIntError; use std::path::{Path, PathBuf}; @@ -10,7 +11,7 @@ use rustc_errors::codes::*; use rustc_errors::{ Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, }; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutError; use rustc_span::{Span, Symbol}; @@ -345,21 +346,82 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ThorinErrorWrapper { } pub(crate) struct LinkingFailed<'a> { - pub linker_path: &'a PathBuf, + pub linker_path: &'a Path, pub exit_status: ExitStatus, - pub command: &'a Command, + pub command: Command, pub escaped_output: String, + pub verbose: bool, } impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> { - fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { + fn into_diag(mut self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_linking_failed); diag.arg("linker_path", format!("{}", self.linker_path.display())); diag.arg("exit_status", format!("{}", self.exit_status)); let contains_undefined_ref = self.escaped_output.contains("undefined reference to"); - diag.note(format!("{:?}", self.command)).note(self.escaped_output); + if self.verbose { + diag.note(format!("{:?}", self.command)); + } else { + enum ArgGroup { + Regular(OsString), + Objects(usize), + Rlibs(PathBuf, Vec<OsString>), + } + + // Omit rust object files and fold rlibs in the error by default to make linker errors a + // bit less verbose. + let orig_args = self.command.take_args(); + let mut args: Vec<ArgGroup> = vec![]; + for arg in orig_args { + if arg.as_encoded_bytes().ends_with(b".rcgu.o") { + if let Some(ArgGroup::Objects(n)) = args.last_mut() { + *n += 1; + } else { + args.push(ArgGroup::Objects(1)); + } + } else if arg.as_encoded_bytes().ends_with(b".rlib") { + let rlib_path = Path::new(&arg); + let dir = rlib_path.parent().unwrap(); + let filename = rlib_path.file_name().unwrap().to_owned(); + if let Some(ArgGroup::Rlibs(parent, rlibs)) = args.last_mut() { + if parent == dir { + rlibs.push(filename); + } else { + args.push(ArgGroup::Rlibs(dir.to_owned(), vec![filename])); + } + } else { + args.push(ArgGroup::Rlibs(dir.to_owned(), vec![filename])); + } + } else { + args.push(ArgGroup::Regular(arg)); + } + } + self.command.args(args.into_iter().map(|arg_group| match arg_group { + ArgGroup::Regular(arg) => arg, + ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")), + ArgGroup::Rlibs(dir, rlibs) => { + let mut arg = dir.into_os_string(); + arg.push("/{"); + let mut first = true; + for rlib in rlibs { + if !first { + arg.push(","); + } + first = false; + arg.push(rlib); + } + arg.push("}"); + arg + } + })); + + diag.note(format!("{:?}", self.command)); + diag.note("some arguments are omitted. use `--verbose` to show all linker arguments"); + } + + diag.note(self.escaped_output); // Trying to match an error from OS linkers // which by now we have no way to translate. @@ -1114,3 +1176,15 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_ #[derive(Diagnostic)] #[diag(codegen_ssa_aix_strip_not_used)] pub(crate) struct AixStripNotUsed; + +#[derive(LintDiagnostic)] +#[diag(codegen_ssa_mixed_export_name_and_no_mangle)] +pub(crate) struct MixedExportNameAndNoMangle { + #[label] + pub no_mangle: Span, + pub no_mangle_attr: String, + #[note] + pub export_name: Span, + #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] + pub removal_span: Span, +} diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 7dc8ab38a97..65c6067c740 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -42,7 +42,7 @@ use rustc_session::Session; use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT}; use rustc_session::cstore::{self, CrateSource}; use rustc_session::utils::NativeLibKind; -use rustc_span::symbol::Symbol; +use rustc_span::Symbol; pub mod assert_module_sources; pub mod back; diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index e3ed12b5ce6..b0a1dedd646 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -847,10 +847,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (instance, mut llfn) = match *callee.layout.ty.kind() { ty::FnDef(def_id, args) => ( - Some( - ty::Instance::expect_resolve(bx.tcx(), bx.typing_env(), def_id, args, fn_span) - .polymorphize(bx.tcx()), - ), + Some(ty::Instance::expect_resolve( + bx.tcx(), + bx.typing_env(), + def_id, + args, + fn_span, + )), None, ), ty::FnPtr(..) => (None, Some(callee.immediate())), diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index d4d7f16db55..843a996d2bf 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -10,8 +10,7 @@ use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{Instance, Ty}; use rustc_middle::{bug, mir, ty}; use rustc_session::config::DebugInfo; -use rustc_span::symbol::{Symbol, kw}; -use rustc_span::{BytePos, Span, hygiene}; +use rustc_span::{BytePos, Span, Symbol, hygiene, kw}; use super::operand::{OperandRef, OperandValue}; use super::place::{PlaceRef, PlaceValue}; diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 299b98c0a4f..304ac4544ee 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -75,7 +75,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // If we're swapping something that's *not* an `OperandValue::Ref`, // then we can do it directly and avoid the alloca. // Otherwise, we'll let the fallback MIR body take care of it. - if let sym::typed_swap = name { + if let sym::typed_swap_nonoverlapping = name { let pointee_ty = fn_args.type_at(0); let pointee_layout = bx.layout_of(pointee_ty); if !bx.is_backend_ref(pointee_layout) diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 0cbc5c45736..62f69af3f2f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -20,6 +20,7 @@ mod coverageinfo; pub mod debuginfo; mod intrinsic; mod locals; +mod naked_asm; pub mod operand; pub mod place; mod rvalue; @@ -176,6 +177,11 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); debug!("fn_abi: {:?}", fn_abi); + if cx.tcx().codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) { + crate::mir::naked_asm::codegen_naked_asm::<Bx>(cx, &mir, instance); + return; + } + let debug_context = cx.create_function_debug_context(instance, fn_abi, llfn, mir); let start_llbb = Bx::append_block(cx, llfn, "start"); diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs new file mode 100644 index 00000000000..cac3cc587cb --- /dev/null +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -0,0 +1,266 @@ +use rustc_attr_parsing::InstructionSetAttr; +use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility}; +use rustc_middle::mir::{Body, InlineAsmOperand}; +use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf}; +use rustc_middle::ty::{Instance, TyCtxt}; +use rustc_middle::{bug, ty}; +use rustc_span::sym; + +use crate::common; +use crate::traits::{AsmCodegenMethods, BuilderMethods, GlobalAsmOperandRef, MiscCodegenMethods}; + +pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + cx: &'a Bx::CodegenCx, + mir: &Body<'tcx>, + instance: Instance<'tcx>, +) { + let rustc_middle::mir::TerminatorKind::InlineAsm { + asm_macro: _, + template, + ref operands, + options, + line_spans, + targets: _, + unwind: _, + } = mir.basic_blocks.iter().next().unwrap().terminator().kind + else { + bug!("#[naked] functions should always terminate with an asm! block") + }; + + let operands: Vec<_> = + operands.iter().map(|op| inline_to_global_operand::<Bx>(cx, instance, op)).collect(); + + let item_data = cx.codegen_unit().items().get(&MonoItem::Fn(instance)).unwrap(); + let name = cx.mangled_name(instance); + let (begin, end) = prefix_and_suffix(cx.tcx(), instance, &name, item_data); + + let mut template_vec = Vec::new(); + template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(begin.into())); + template_vec.extend(template.iter().cloned()); + template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(end.into())); + + cx.codegen_global_asm(&template_vec, &operands, options, line_spans); +} + +fn inline_to_global_operand<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + cx: &'a Bx::CodegenCx, + instance: Instance<'tcx>, + op: &InlineAsmOperand<'tcx>, +) -> GlobalAsmOperandRef<'tcx> { + match op { + InlineAsmOperand::Const { value } => { + let const_value = instance + .instantiate_mir_and_normalize_erasing_regions( + cx.tcx(), + cx.typing_env(), + ty::EarlyBinder::bind(value.const_), + ) + .eval(cx.tcx(), cx.typing_env(), value.span) + .expect("erroneous constant missed by mono item collection"); + + let mono_type = instance.instantiate_mir_and_normalize_erasing_regions( + cx.tcx(), + cx.typing_env(), + ty::EarlyBinder::bind(value.ty()), + ); + + let string = common::asm_const_to_str( + cx.tcx(), + value.span, + const_value, + cx.layout_of(mono_type), + ); + + GlobalAsmOperandRef::Const { string } + } + InlineAsmOperand::SymFn { value } => { + let mono_type = instance.instantiate_mir_and_normalize_erasing_regions( + cx.tcx(), + cx.typing_env(), + ty::EarlyBinder::bind(value.ty()), + ); + + let instance = match mono_type.kind() { + &ty::FnDef(def_id, args) => Instance::new(def_id, args), + _ => bug!("asm sym is not a function"), + }; + + GlobalAsmOperandRef::SymFn { instance } + } + InlineAsmOperand::SymStatic { def_id } => { + GlobalAsmOperandRef::SymStatic { def_id: *def_id } + } + InlineAsmOperand::In { .. } + | InlineAsmOperand::Out { .. } + | InlineAsmOperand::InOut { .. } + | InlineAsmOperand::Label { .. } => { + bug!("invalid operand type for naked_asm!") + } + } +} + +enum AsmBinaryFormat { + Elf, + Macho, + Coff, +} + +impl AsmBinaryFormat { + fn from_target(target: &rustc_target::spec::Target) -> Self { + if target.is_like_windows { + Self::Coff + } else if target.is_like_osx { + Self::Macho + } else { + Self::Elf + } + } +} + +fn prefix_and_suffix<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + asm_name: &str, + item_data: &MonoItemData, +) -> (String, String) { + use std::fmt::Write; + + let asm_binary_format = AsmBinaryFormat::from_target(&tcx.sess.target); + + let is_arm = tcx.sess.target.arch == "arm"; + let is_thumb = tcx.sess.unstable_target_features.contains(&sym::thumb_mode); + + let attrs = tcx.codegen_fn_attrs(instance.def_id()); + let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string()); + let align = attrs.alignment.map(|a| a.bytes()).unwrap_or(4); + + // See https://sourceware.org/binutils/docs/as/ARM-Directives.html for info on these directives. + // In particular, `.arm` can also be written `.code 32` and `.thumb` as `.code 16`. + let (arch_prefix, arch_suffix) = if is_arm { + ( + match attrs.instruction_set { + None => match is_thumb { + true => ".thumb\n.thumb_func", + false => ".arm", + }, + Some(InstructionSetAttr::ArmT32) => ".thumb\n.thumb_func", + Some(InstructionSetAttr::ArmA32) => ".arm", + }, + match is_thumb { + true => ".thumb", + false => ".arm", + }, + ) + } else { + ("", "") + }; + + let emit_fatal = |msg| tcx.dcx().span_fatal(tcx.def_span(instance.def_id()), msg); + + // see https://godbolt.org/z/cPK4sxKor. + let write_linkage = |w: &mut String| -> std::fmt::Result { + match item_data.linkage { + Linkage::External => { + writeln!(w, ".globl {asm_name}")?; + } + Linkage::LinkOnceAny | Linkage::LinkOnceODR | Linkage::WeakAny | Linkage::WeakODR => { + match asm_binary_format { + AsmBinaryFormat::Elf | AsmBinaryFormat::Coff => { + writeln!(w, ".weak {asm_name}")?; + } + AsmBinaryFormat::Macho => { + writeln!(w, ".globl {asm_name}")?; + writeln!(w, ".weak_definition {asm_name}")?; + } + } + } + Linkage::Internal | Linkage::Private => { + // write nothing + } + Linkage::Appending => emit_fatal("Only global variables can have appending linkage!"), + Linkage::Common => emit_fatal("Functions may not have common linkage"), + Linkage::AvailableExternally => { + // this would make the function equal an extern definition + emit_fatal("Functions may not have available_externally linkage") + } + Linkage::ExternalWeak => { + // FIXME: actually this causes a SIGILL in LLVM + emit_fatal("Functions may not have external weak linkage") + } + } + + Ok(()) + }; + + let mut begin = String::new(); + let mut end = String::new(); + match asm_binary_format { + AsmBinaryFormat::Elf => { + let section = link_section.unwrap_or(format!(".text.{asm_name}")); + + let progbits = match is_arm { + true => "%progbits", + false => "@progbits", + }; + + let function = match is_arm { + true => "%function", + false => "@function", + }; + + writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap(); + writeln!(begin, ".balign {align}").unwrap(); + write_linkage(&mut begin).unwrap(); + if let Visibility::Hidden = item_data.visibility { + writeln!(begin, ".hidden {asm_name}").unwrap(); + } + writeln!(begin, ".type {asm_name}, {function}").unwrap(); + if !arch_prefix.is_empty() { + writeln!(begin, "{}", arch_prefix).unwrap(); + } + writeln!(begin, "{asm_name}:").unwrap(); + + writeln!(end).unwrap(); + writeln!(end, ".size {asm_name}, . - {asm_name}").unwrap(); + writeln!(end, ".popsection").unwrap(); + if !arch_suffix.is_empty() { + writeln!(end, "{}", arch_suffix).unwrap(); + } + } + AsmBinaryFormat::Macho => { + let section = link_section.unwrap_or("__TEXT,__text".to_string()); + writeln!(begin, ".pushsection {},regular,pure_instructions", section).unwrap(); + writeln!(begin, ".balign {align}").unwrap(); + write_linkage(&mut begin).unwrap(); + if let Visibility::Hidden = item_data.visibility { + writeln!(begin, ".private_extern {asm_name}").unwrap(); + } + writeln!(begin, "{asm_name}:").unwrap(); + + writeln!(end).unwrap(); + writeln!(end, ".popsection").unwrap(); + if !arch_suffix.is_empty() { + writeln!(end, "{}", arch_suffix).unwrap(); + } + } + AsmBinaryFormat::Coff => { + let section = link_section.unwrap_or(format!(".text.{asm_name}")); + writeln!(begin, ".pushsection {},\"xr\"", section).unwrap(); + writeln!(begin, ".balign {align}").unwrap(); + write_linkage(&mut begin).unwrap(); + writeln!(begin, ".def {asm_name}").unwrap(); + writeln!(begin, ".scl 2").unwrap(); + writeln!(begin, ".type 32").unwrap(); + writeln!(begin, ".endef {asm_name}").unwrap(); + writeln!(begin, "{asm_name}:").unwrap(); + + writeln!(end).unwrap(); + writeln!(end, ".popsection").unwrap(); + if !arch_suffix.is_empty() { + writeln!(end, "{}", arch_suffix).unwrap(); + } + } + } + + (begin, end) +} diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index c38484109d2..c634f864ffb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -243,6 +243,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { return bx.cx().const_poison(cast_to); } let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants { + Variants::Empty => unreachable!("we already handled uninhabited types"), Variants::Single { index } => { let discr_val = self .layout @@ -365,9 +366,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { return; } match self.layout.variants { - Variants::Single { index } => { - assert_eq!(index, variant_index); - } + Variants::Empty => unreachable!("we already handled uninhabited types"), + Variants::Single { index } => assert_eq!(index, variant_index), + Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => { let ptr = self.project_field(bx, tag_field); let to = @@ -422,10 +423,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { layout.size }; - let llval = bx.inbounds_gep(bx.cx().backend_type(self.layout), self.val.llval, &[ - bx.cx().const_usize(0), - llindex, - ]); + let llval = bx.inbounds_gep(bx.cx().backend_type(layout), self.val.llval, &[llindex]); let align = self.val.align.restrict_for_offset(offset); PlaceValue::new_sized(llval, align).with_type(layout) } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index f63b2d139c5..3b62148abb7 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -10,9 +10,9 @@ use rustc_session::config::OptLevel; use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; +use super::FunctionCx; use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; -use super::{FunctionCx, LocalRef}; use crate::common::IntPredicate; use crate::traits::*; use crate::{MemFlags, base}; @@ -478,8 +478,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { def_id, args, ) - .unwrap() - .polymorphize(bx.cx().tcx()); + .unwrap(); OperandValue::Immediate(bx.get_fn_addr(instance)) } _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty), @@ -493,8 +492,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { def_id, args, ty::ClosureKind::FnOnce, - ) - .polymorphize(bx.cx().tcx()); + ); OperandValue::Immediate(bx.cx().get_fn_addr(instance)) } _ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty), @@ -595,14 +593,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_place_to_pointer(bx, place, mk_ptr) } - mir::Rvalue::Len(place) => { - let size = self.evaluate_array_len(bx, place); - OperandRef { - val: OperandValue::Immediate(size), - layout: bx.cx().layout_of(bx.tcx().types.usize), - } - } - mir::Rvalue::BinaryOp(op_with_overflow, box (ref lhs, ref rhs)) if let Some(op) = op_with_overflow.overflowing_to_wrapping() => { @@ -802,24 +792,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - fn evaluate_array_len(&mut self, bx: &mut Bx, place: mir::Place<'tcx>) -> Bx::Value { - // ZST are passed as operands and require special handling - // because codegen_place() panics if Local is operand. - if let Some(index) = place.as_local() { - if let LocalRef::Operand(op) = self.locals[index] { - if let ty::Array(_, n) = op.layout.ty.kind() { - let n = n - .try_to_target_usize(bx.tcx()) - .expect("expected monomorphic const in codegen"); - return bx.cx().const_usize(n); - } - } - } - // use common size calculation for non zero-sized types - let cg_value = self.codegen_place(bx, place.as_ref()); - cg_value.len(bx.cx()) - } - /// Codegen an `Rvalue::RawPtr` or `Rvalue::Ref` fn codegen_place_to_pointer( &mut self, @@ -1091,7 +1063,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::Ref(..) | mir::Rvalue::CopyForDeref(..) | mir::Rvalue::RawPtr(..) | - mir::Rvalue::Len(..) | mir::Rvalue::Cast(..) | // (*) mir::Rvalue::ShallowInitBox(..) | // (*) mir::Rvalue::BinaryOp(..) | diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index 038c5857fac..6749bc63327 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -1,4 +1,5 @@ use rustc_hir as hir; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility}; use rustc_middle::ty::Instance; @@ -135,7 +136,13 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { cx.predefine_static(def_id, linkage, visibility, symbol_name); } MonoItem::Fn(instance) => { - cx.predefine_fn(instance, linkage, visibility, symbol_name); + let attrs = cx.tcx().codegen_fn_attrs(instance.def_id()); + + if attrs.flags.contains(CodegenFnAttrFlags::NAKED) { + // do not define this function; it will become a global assembly block + } else { + cx.predefine_fn(instance, linkage, visibility, symbol_name); + }; } MonoItem::GlobalAsm(..) => {} } diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index eee7cc75400..7e80d014ea2 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,17 +1,16 @@ -use rustc_ast::ast; -use rustc_attr::InstructionSetAttr; +use rustc_attr_parsing::InstructionSetAttr; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::Applicability; +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_middle::middle::codegen_fn_attrs::TargetFeature; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; -use rustc_span::Span; -use rustc_span::symbol::{Symbol, sym}; -use rustc_target::target_features::{self, Stability}; +use rustc_span::{Span, Symbol, sym}; +use rustc_target::target_features; use crate::errors; @@ -19,8 +18,8 @@ use crate::errors; /// Enabled target features are added to `target_features`. pub(crate) fn from_target_feature_attr( tcx: TyCtxt<'_>, - attr: &ast::Attribute, - rust_target_features: &UnordMap<String, target_features::Stability>, + attr: &hir::Attribute, + rust_target_features: &UnordMap<String, target_features::StabilityComputed>, target_features: &mut Vec<TargetFeature>, ) { let Some(list) = attr.meta_item_list() else { return }; @@ -63,32 +62,24 @@ pub(crate) fn from_target_feature_attr( return None; }; - // Only allow target features whose feature gates have been enabled. - let allowed = match stability { - Stability::Forbidden { .. } => false, - Stability::Stable => true, - Stability::Unstable(name) => rust_features.enabled(*name), - }; - if !allowed { - match stability { - Stability::Stable => unreachable!(), - &Stability::Unstable(lang_feature_name) => { - feature_err( - &tcx.sess, - lang_feature_name, - item.span(), - format!("the target feature `{feature}` is currently unstable"), - ) - .emit(); - } - Stability::Forbidden { reason } => { - tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { - span: item.span(), - feature, - reason, - }); - } - } + // Only allow target features whose feature gates have been enabled + // and which are permitted to be toggled. + if let Err(reason) = stability.toggle_allowed(/*enable*/ true) { + tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { + span: item.span(), + feature, + reason, + }); + } else if let Some(nightly_feature) = stability.requires_nightly() + && !rust_features.enabled(nightly_feature) + { + feature_err( + &tcx.sess, + nightly_feature, + item.span(), + format!("the target feature `{feature}` is currently unstable"), + ) + .emit(); } Some(Symbol::intern(feature)) })); @@ -156,18 +147,19 @@ pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { rust_target_features: |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); + let target = &tcx.sess.target; if tcx.sess.opts.actually_rustdoc { // rustdoc needs to be able to document functions that use all the features, so // whitelist them all rustc_target::target_features::all_rust_features() - .map(|(a, b)| (a.to_string(), b)) + .map(|(a, b)| (a.to_string(), b.compute_toggleability(target))) .collect() } else { tcx.sess .target .rust_target_features() .iter() - .map(|&(a, b, _)| (a.to_string(), b)) + .map(|(a, b, _)| (a.to_string(), b.compute_toggleability(target))) .collect() } }, diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs index f4853da1156..7767bffbfbf 100644 --- a/compiler/rustc_codegen_ssa/src/traits/asm.rs +++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs @@ -68,4 +68,11 @@ pub trait AsmCodegenMethods<'tcx> { options: InlineAsmOptions, line_spans: &[Span], ); + + /// The mangled name of this instance + /// + /// Additional mangling is used on + /// some targets to add a leading underscore (Mach-O) + /// or byte count suffixes (x86 Windows). + fn mangled_name(&self, instance: Instance<'tcx>) -> String; } diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 7eab889edf0..ebcf118b903 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -4,7 +4,6 @@ use std::hash::Hash; use rustc_ast::expand::allocator::AllocatorKind; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{DynSend, DynSync}; -use rustc_errors::ErrorGuaranteed; use rustc_metadata::EncodedMetadata; use rustc_metadata::creader::MetadataLoaderDyn; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; @@ -12,7 +11,7 @@ use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; use rustc_session::Session; use rustc_session::config::{self, OutputFilenames, PrintRequest}; -use rustc_span::symbol::Symbol; +use rustc_span::Symbol; use super::CodegenObject; use super::write::WriteBackendMethods; @@ -46,7 +45,9 @@ pub trait CodegenBackend { fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {} - fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> { + /// Returns the features that should be set in `cfg(target_features)`. + /// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen. + fn target_features_cfg(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> { vec![] } @@ -84,13 +85,8 @@ pub trait CodegenBackend { ) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>); /// This is called on the returned [`CodegenResults`] from [`join_codegen`](Self::join_codegen). - fn link( - &self, - sess: &Session, - codegen_results: CodegenResults, - outputs: &OutputFilenames, - ) -> Result<(), ErrorGuaranteed> { - link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, outputs) + fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) { + link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, outputs); } /// Returns `true` if this backend can be safely called from multiple threads. diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index b0138ac8bfe..3ee13b19f66 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -382,7 +382,7 @@ pub trait BuilderMethods<'a, 'tcx>: /// Avoids `alloca`s for Immediates and ScalarPairs. /// /// FIXME: Maybe do something smarter for Ref types too? - /// For now, the `typed_swap` intrinsic just doesn't call this for those + /// For now, the `typed_swap_nonoverlapping` intrinsic just doesn't call this for those /// cases (in non-debug), preferring the fallback body instead. fn typed_place_swap( &mut self, diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index aabe9e33c4a..51e2255efe1 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -1,5 +1,7 @@ +use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_errors::{DiagCtxtHandle, FatalError}; use rustc_middle::dep_graph::WorkProduct; +use rustc_middle::ty::TyCtxt; use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig}; @@ -61,6 +63,13 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { want_summary: bool, ) -> (String, Self::ThinBuffer); fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer); + fn autodiff( + cgcx: &CodegenContext<Self>, + tcx: TyCtxt<'_>, + module: &ModuleCodegen<Self::Module>, + diff_fncs: Vec<AutoDiffItem>, + config: &ModuleConfig, + ) -> Result<(), FatalError>; } pub trait ThinBufferMethods: Send + Sync { |
