diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 37ee9a5140a06..03ad75ca8b4a4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -427,7 +427,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { tcx.ensure_with_value().early_lint_checks(()); tcx.ensure_with_value().debugger_visualizers(LOCAL_CRATE); tcx.ensure_with_value().get_lang_items(()); - let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal(); + let (mut resolver, krate) = tcx.resolver_for_lowering().steal(); let ast_index = index_crate(&resolver.node_id_to_def_id, &krate); let mut owners = IndexVec::from_fn_n( diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 3b6bf0005a3b1..6869c14e81a4c 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -37,7 +37,7 @@ use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS}; use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType}; use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; -use rustc_session::{config, EarlyDiagCtxt, Session}; +use rustc_session::{config, filesearch, EarlyDiagCtxt, Session}; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::source_map::FileLoader; use rustc_span::symbol::sym; @@ -418,7 +418,7 @@ fn run_compiler( } // Make sure name resolution and macro expansion is run. - queries.global_ctxt()?.enter(|tcx| tcx.resolver_for_lowering(())); + queries.global_ctxt()?.enter(|tcx| tcx.resolver_for_lowering()); if callbacks.after_expansion(compiler, queries) == Compilation::Stop { return early_exit(); @@ -886,7 +886,11 @@ pub fn version_at_macro_invocation( let debug_flags = matches.opt_strs("Z"); let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); - get_codegen_backend(early_dcx, &None, backend_name).print_version(); + let opts = config::Options::default(); + let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone()); + let target = config::build_target_config(early_dcx, &opts, None, &sysroot); + + get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_version(); } } @@ -1091,7 +1095,12 @@ pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, matches: &Matches) -> if cg_flags.iter().any(|x| *x == "passes=list") { let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); - get_codegen_backend(early_dcx, &None, backend_name).print_passes(); + + let opts = config::Options::default(); + let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone()); + let target = config::build_target_config(early_dcx, &opts, None, &sysroot); + + get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_passes(); return true; } diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 768d98ce01efe..c9bbe45b21276 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -229,7 +229,7 @@ impl<'tcx> PrintExtra<'tcx> { { match self { PrintExtra::AfterParsing { krate, .. } => f(krate), - PrintExtra::NeedsAstMap { tcx } => f(&tcx.resolver_for_lowering(()).borrow().1), + PrintExtra::NeedsAstMap { tcx } => f(&tcx.resolver_for_lowering().borrow().1), } } @@ -281,7 +281,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { } AstTreeExpanded => { debug!("pretty-printing expanded AST"); - format!("{:#?}", ex.tcx().resolver_for_lowering(()).borrow().1) + format!("{:#?}", ex.tcx().resolver_for_lowering().borrow().1) } Hir(s) => { debug!("pretty printing HIR {:?}", s); diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 284d965979ece..1a82e6c6910ae 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -16,7 +16,7 @@ use rustc_parse::maybe_new_parser_from_source_str; use rustc_query_impl::QueryCtxt; use rustc_query_system::query::print_query_stack; use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName}; -use rustc_session::filesearch::sysroot_candidates; +use rustc_session::filesearch::{self, sysroot_candidates}; use rustc_session::parse::ParseSess; use rustc_session::{lint, CompilerIO, EarlyDiagCtxt, Session}; use rustc_span::source_map::FileLoader; @@ -339,16 +339,53 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se let early_dcx = EarlyDiagCtxt::new(config.opts.error_format); - let codegen_backend = if let Some(make_codegen_backend) = config.make_codegen_backend { - make_codegen_backend(&config.opts) - } else { - util::get_codegen_backend( - &early_dcx, - &config.opts.maybe_sysroot, - config.opts.unstable_opts.codegen_backend.as_deref(), - ) + let sysroot = filesearch::materialize_sysroot(config.opts.maybe_sysroot.clone()); + + let (codegen_backend, target_override) = match config.make_codegen_backend { + None => { + // Build a target without override, so that it can override the backend if needed + let target = + config::build_target_config(&early_dcx, &config.opts, None, &sysroot); + + let backend = util::get_codegen_backend( + &early_dcx, + &sysroot, + config.opts.unstable_opts.codegen_backend.as_deref(), + &target, + ); + + // target_override is documented to be called before init(), so this is okay + let target_override = backend.target_override(&config.opts); + + // Assert that we don't use target's override of the backend and + // backend's override of the target at the same time + if config.opts.unstable_opts.codegen_backend.is_none() + && target.default_codegen_backend.is_some() + && target_override.is_some() + { + rustc_middle::bug!( + "Codegen backend requested target override even though the target requested the backend" + ); + } + + (backend, target_override) + } + Some(make_codegen_backend) => { + // N.B. `make_codegen_backend` takes precedence over `target.default_codegen_backend`, + // which is ignored in this case. + let backend = make_codegen_backend(&config.opts); + + // target_override is documented to be called before init(), so this is okay + let target_override = backend.target_override(&config.opts); + + (backend, target_override) + } }; + // Re-build target with the (potential) override + let target_cfg = + config::build_target_config(&early_dcx, &config.opts, target_override, &sysroot); + let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from); let bundle = match rustc_errors::fluent_bundle( @@ -367,9 +404,6 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se let mut locale_resources = Vec::from(config.locale_resources); locale_resources.push(codegen_backend.locale_resource()); - // target_override is documented to be called before init(), so this is okay - let target_override = codegen_backend.target_override(&config.opts); - let mut sess = rustc_session::build_session( early_dcx, config.opts, @@ -384,7 +418,8 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se locale_resources, config.lint_caps, config.file_loader, - target_override, + target_cfg, + sysroot, util::rustc_version_str().unwrap_or("unknown"), config.ice_file, config.using_internal_features, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 085e90260515b..b571226860069 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -280,7 +280,7 @@ fn configure_and_expand( fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { let sess = tcx.sess; - let (resolver, krate) = &*tcx.resolver_for_lowering(()).borrow(); + let (resolver, krate) = &*tcx.resolver_for_lowering().borrow(); let mut lint_buffer = resolver.lint_buffer.steal(); if sess.opts.unstable_opts.input_stats { @@ -531,10 +531,10 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P } } -fn resolver_for_lowering<'tcx>( +fn resolver_for_lowering_raw<'tcx>( tcx: TyCtxt<'tcx>, (): (), -) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc)> { +) -> (&'tcx Steal<(ty::ResolverAstLowering, Lrc)>, &'tcx ty::ResolverGlobalCtxt) { let arenas = Resolver::arenas(); let _ = tcx.registered_tools(()); // Uses `crate_for_resolver`. let (krate, pre_configured_attrs) = tcx.crate_for_resolver(()).steal(); @@ -549,16 +549,15 @@ fn resolver_for_lowering<'tcx>( ast_lowering: untracked_resolver_for_lowering, } = resolver.into_outputs(); - let feed = tcx.feed_unit_query(); - feed.resolutions(tcx.arena.alloc(untracked_resolutions)); - tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, Lrc::new(krate)))) + let resolutions = tcx.arena.alloc(untracked_resolutions); + (tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, Lrc::new(krate)))), resolutions) } pub(crate) fn write_dep_info(tcx: TyCtxt<'_>) { // Make sure name resolution and macro expansion is run for // the side-effect of providing a complete set of all // accessed files and env vars. - let _ = tcx.resolver_for_lowering(()); + let _ = tcx.resolver_for_lowering(); let sess = tcx.sess; let _timer = sess.timer("write_dep_info"); @@ -607,7 +606,10 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { let providers = &mut Providers::default(); providers.analysis = analysis; providers.hir_crate = rustc_ast_lowering::lower_to_hir; - providers.resolver_for_lowering = resolver_for_lowering; + providers.resolver_for_lowering_raw = resolver_for_lowering_raw; + providers.stripped_cfg_items = + |tcx, _| tcx.arena.alloc_from_iter(tcx.resolutions(()).stripped_cfg_items.steal()); + providers.resolutions = |tcx, ()| tcx.resolver_for_lowering_raw(()).1; providers.early_lint_checks = early_lint_checks; proc_macro_decls::provide(providers); rustc_const_eval::provide(providers); diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 7cdf7cd25b1c1..da11d090b7497 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -8,8 +8,7 @@ use rustc_codegen_ssa::CodegenResults; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, OnceLock, WorkerLocal}; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::{StableCrateId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_incremental::setup_dep_graph; use rustc_metadata::creader::CStore; @@ -144,10 +143,8 @@ impl<'tcx> Queries<'tcx> { stable_crate_id, )) as _); let definitions = FreezeLock::new(Definitions::new(stable_crate_id)); - let source_span = AppendOnlyIndexVec::new(); - let _id = source_span.push(krate.spans.inner_span); - debug_assert_eq!(_id, CRATE_DEF_ID); - let untracked = Untracked { cstore, source_span, definitions }; + let untracked = + Untracked { cstore, source_span: AppendOnlyIndexVec::new(), definitions }; let qcx = passes::create_global_ctxt( self.compiler, @@ -172,9 +169,6 @@ impl<'tcx> Queries<'tcx> { ))); feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); feed.output_filenames(Arc::new(outputs)); - - let feed = tcx.feed_local_def_id(CRATE_DEF_ID); - feed.def_kind(DefKind::Mod); }); Ok(qcx) }) diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 4f15d1c1d3a0b..80ca77c8f73b0 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -13,7 +13,7 @@ use rustc_session::config::{ use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; -use rustc_session::{build_session, getopts, CompilerIO, EarlyDiagCtxt, Session}; +use rustc_session::{build_session, filesearch, getopts, CompilerIO, EarlyDiagCtxt, Session}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use rustc_span::symbol::sym; use rustc_span::{FileName, SourceFileHashAlgorithm}; @@ -37,6 +37,12 @@ fn mk_session(matches: getopts::Matches) -> (Session, Cfg) { output_file: None, temps_dir, }; + + let sysroot = filesearch::materialize_sysroot(sessopts.maybe_sysroot.clone()); + + let target_cfg = + rustc_session::config::build_target_config(&early_dcx, &sessopts, None, &sysroot); + let sess = build_session( early_dcx, sessopts, @@ -46,7 +52,8 @@ fn mk_session(matches: getopts::Matches) -> (Session, Cfg) { vec![], Default::default(), None, - None, + target_cfg, + sysroot, "", None, Arc::default(), diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 0d50200133cb2..8699187acf262 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -14,13 +14,14 @@ use rustc_session::{filesearch, output, Session}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::symbol::{sym, Symbol}; +use rustc_target::spec::Target; use session::EarlyDiagCtxt; -use std::env; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::OnceLock; use std::thread; +use std::{env, iter}; /// Function pointer type that constructs a new CodegenBackend. pub type MakeBackendFn = fn() -> Box; @@ -182,21 +183,25 @@ fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBacken /// A name of `None` indicates that the default backend should be used. pub fn get_codegen_backend( early_dcx: &EarlyDiagCtxt, - maybe_sysroot: &Option, + sysroot: &Path, backend_name: Option<&str>, + target: &Target, ) -> Box { static LOAD: OnceLock Box> = OnceLock::new(); let load = LOAD.get_or_init(|| { - let default_codegen_backend = option_env!("CFG_DEFAULT_CODEGEN_BACKEND").unwrap_or("llvm"); + let backend = backend_name + .or(target.default_codegen_backend.as_deref()) + .or(option_env!("CFG_DEFAULT_CODEGEN_BACKEND")) + .unwrap_or("llvm"); - match backend_name.unwrap_or(default_codegen_backend) { + match backend { filename if filename.contains('.') => { load_backend_from_dylib(early_dcx, filename.as_ref()) } #[cfg(feature = "llvm")] "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new, - backend_name => get_codegen_sysroot(early_dcx, maybe_sysroot, backend_name), + backend_name => get_codegen_sysroot(early_dcx, sysroot, backend_name), } }); @@ -231,7 +236,7 @@ fn get_rustc_path_inner(bin_path: &str) -> Option { #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable fn get_codegen_sysroot( early_dcx: &EarlyDiagCtxt, - maybe_sysroot: &Option, + sysroot: &Path, backend_name: &str, ) -> MakeBackendFn { // For now we only allow this function to be called once as it'll dlopen a @@ -248,28 +253,28 @@ fn get_codegen_sysroot( let target = session::config::host_triple(); let sysroot_candidates = sysroot_candidates(); - let sysroot = maybe_sysroot - .iter() - .chain(sysroot_candidates.iter()) + let sysroot = iter::once(sysroot) + .chain(sysroot_candidates.iter().map(<_>::as_ref)) .map(|sysroot| { filesearch::make_target_lib_path(sysroot, target).with_file_name("codegen-backends") }) .find(|f| { info!("codegen backend candidate: {}", f.display()); f.exists() - }); - let sysroot = sysroot.unwrap_or_else(|| { - let candidates = sysroot_candidates - .iter() - .map(|p| p.display().to_string()) - .collect::>() - .join("\n* "); - let err = format!( - "failed to find a `codegen-backends` folder \ + }) + .unwrap_or_else(|| { + let candidates = sysroot_candidates + .iter() + .map(|p| p.display().to_string()) + .collect::>() + .join("\n* "); + let err = format!( + "failed to find a `codegen-backends` folder \ in the sysroot candidates:\n* {candidates}" - ); - early_dcx.early_fatal(err); - }); + ); + early_dcx.early_fatal(err); + }); + info!("probing {} for a codegen backend", sysroot.display()); let d = sysroot.read_dir().unwrap_or_else(|e| { diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 90e68a6b5b916..dcccace12b00a 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -1077,7 +1077,7 @@ impl CrateError { crate_rejections, }); } else { - dcx.emit_err(errors::CannotFindCrate { + let error = errors::CannotFindCrate { span, crate_name, add_info, @@ -1091,11 +1091,18 @@ impl CrateError { profiler_runtime: Symbol::intern(&sess.opts.unstable_opts.profiler_runtime), locator_triple: locator.triple, is_ui_testing: sess.opts.unstable_opts.ui_testing, - }); + }; + // The diagnostic for missing core is very good, but it is followed by a lot of + // other diagnostics that do not add information. + if missing_core { + dcx.emit_fatal(error); + } else { + dcx.emit_err(error); + } } } CrateError::NotFound(crate_name) => { - dcx.emit_err(errors::CannotFindCrate { + let error = errors::CannotFindCrate { span, crate_name, add_info: String::new(), @@ -1105,7 +1112,14 @@ impl CrateError { profiler_runtime: Symbol::intern(&sess.opts.unstable_opts.profiler_runtime), locator_triple: sess.opts.target_triple.clone(), is_ui_testing: sess.opts.unstable_opts.ui_testing, - }); + }; + // The diagnostic for missing core is very good, but it is followed by a lot of + // other diagnostics that do not add information. + if missing_core { + dcx.emit_fatal(error); + } else { + dcx.emit_err(error); + } } } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index ebfdf8aa197fb..be8c05923207b 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -125,12 +125,11 @@ rustc_queries! { } query resolutions(_: ()) -> &'tcx ty::ResolverGlobalCtxt { - feedable no_hash desc { "getting the resolver outputs" } } - query resolver_for_lowering(_: ()) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc)> { + query resolver_for_lowering_raw(_: ()) -> (&'tcx Steal<(ty::ResolverAstLowering, Lrc)>, &'tcx ty::ResolverGlobalCtxt) { eval_always no_hash desc { "getting the resolver for lowering" } @@ -2221,7 +2220,6 @@ rustc_queries! { /// Should not be called for the local crate before the resolver outputs are created, as it /// is only fed there. query stripped_cfg_items(cnum: CrateNum) -> &'tcx [StrippedCfgItem] { - feedable desc { "getting cfg-ed out item names" } separate_provide_extern } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4eec93532a246..34cc5fb4096bd 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -39,7 +39,7 @@ use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::{self, FreezeReadGuard, Lock, WorkerLocal}; +use rustc_data_structures::sync::{self, FreezeReadGuard, Lock, Lrc, WorkerLocal}; #[cfg(parallel_compiler)] use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_data_structures::unord::UnordSet; @@ -60,7 +60,7 @@ use rustc_session::config::CrateType; use rustc_session::cstore::{CrateStoreDyn, Untracked}; use rustc_session::lint::Lint; use rustc_session::{Limit, MetadataKind, Session}; -use rustc_span::def_id::{DefPathHash, StableCrateId}; +use rustc_span::def_id::{DefPathHash, StableCrateId, CRATE_DEF_ID}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}; @@ -74,6 +74,7 @@ use std::cmp::Ordering; use std::fmt; use std::hash::{Hash, Hasher}; use std::iter; +use std::marker::PhantomData; use std::mem; use std::ops::{Bound, Deref}; @@ -498,14 +499,55 @@ pub struct TyCtxtFeed<'tcx, KEY: Copy> { key: KEY, } +/// Never return a `Feed` from a query. Only queries that create a `DefId` are +/// allowed to feed queries for that `DefId`. +impl !HashStable for TyCtxtFeed<'_, KEY> {} + +/// The same as `TyCtxtFeed`, but does not contain a `TyCtxt`. +/// Use this to pass around when you have a `TyCtxt` elsewhere. +/// Just an optimization to save space and not store hundreds of +/// `TyCtxtFeed` in the resolver. +#[derive(Copy, Clone)] +pub struct Feed<'tcx, KEY: Copy> { + _tcx: PhantomData>, + // Do not allow direct access, as downstream code must not mutate this field. + key: KEY, +} + +/// Never return a `Feed` from a query. Only queries that create a `DefId` are +/// allowed to feed queries for that `DefId`. +impl !HashStable for Feed<'_, KEY> {} + +impl fmt::Debug for Feed<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.key.fmt(f) + } +} + +/// Some workarounds to use cases that cannot use `create_def`. +/// Do not add new ways to create `TyCtxtFeed` without consulting +/// with T-compiler and making an analysis about why your addition +/// does not cause incremental compilation issues. impl<'tcx> TyCtxt<'tcx> { + /// Can only be fed before queries are run, and is thus exempt from any + /// incremental issues. Do not use except for the initial query feeding. pub fn feed_unit_query(self) -> TyCtxtFeed<'tcx, ()> { + self.dep_graph.assert_ignored(); TyCtxtFeed { tcx: self, key: () } } + + /// Can only be fed before queries are run, and is thus exempt from any + /// incremental issues. Do not use except for the initial query feeding. pub fn feed_local_crate(self) -> TyCtxtFeed<'tcx, CrateNum> { + self.dep_graph.assert_ignored(); TyCtxtFeed { tcx: self, key: LOCAL_CRATE } } - pub fn feed_local_def_id(self, key: LocalDefId) -> TyCtxtFeed<'tcx, LocalDefId> { + + /// Only used in the resolver to register the `CRATE_DEF_ID` `DefId` and feed + /// some queries for it. It will panic if used twice. + pub fn create_local_crate_def_id(self, span: Span) -> TyCtxtFeed<'tcx, LocalDefId> { + let key = self.untracked().source_span.push(span); + assert_eq!(key, CRATE_DEF_ID); TyCtxtFeed { tcx: self, key } } @@ -523,6 +565,23 @@ impl<'tcx, KEY: Copy> TyCtxtFeed<'tcx, KEY> { pub fn key(&self) -> KEY { self.key } + + #[inline(always)] + pub fn downgrade(self) -> Feed<'tcx, KEY> { + Feed { _tcx: PhantomData, key: self.key } + } +} + +impl<'tcx, KEY: Copy> Feed<'tcx, KEY> { + #[inline(always)] + pub fn key(&self) -> KEY { + self.key + } + + #[inline(always)] + pub fn upgrade(self, tcx: TyCtxt<'tcx>) -> TyCtxtFeed<'tcx, KEY> { + TyCtxtFeed { tcx, key: self.key } + } } impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> { @@ -1067,7 +1126,7 @@ impl<'tcx> TyCtxt<'tcx> { // needs to be re-evaluated. self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE); - let feed = self.feed_local_def_id(def_id); + let feed = TyCtxtFeed { tcx: self, key: def_id }; feed.def_kind(def_kind); // Unique types created for closures participate in type privacy checking. // They have visibilities inherited from the module they are defined in. @@ -2304,6 +2363,10 @@ impl<'tcx> TyCtxt<'tcx> { self.resolutions(()).module_children.get(&def_id).map_or(&[], |v| &v[..]) } + pub fn resolver_for_lowering(self) -> &'tcx Steal<(ty::ResolverAstLowering, Lrc)> { + self.resolver_for_lowering_raw(()).0 + } + /// Given an `impl_id`, return the trait it implements. /// Return `None` if this is an inherent impl. pub fn impl_trait_ref( diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index b1bfd2f1105a8..4862df440e1e1 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -345,11 +345,16 @@ impl<'tcx> SizeSkeleton<'tcx> { ty::Array(inner, len) if len.ty() == tcx.types.usize && tcx.features().transmute_generic_consts => { + let len_eval = len.try_eval_target_usize(tcx, param_env); + if len_eval == Some(0) { + return Ok(SizeSkeleton::Known(Size::from_bytes(0))); + } + match SizeSkeleton::compute(inner, tcx, param_env)? { // This may succeed because the multiplication of two types may overflow // but a single size of a nested array will not. SizeSkeleton::Known(s) => { - if let Some(c) = len.try_eval_target_usize(tcx, param_env) { + if let Some(c) = len_eval { let size = s .bytes() .checked_mul(c) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0a38d379a5216..f9314e1da1c7b 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -32,6 +32,7 @@ pub use generic_args::*; pub use generics::*; pub use intrinsic::IntrinsicDef; use rustc_ast as ast; +use rustc_ast::expand::StrippedCfgItem; use rustc_ast::node_id::NodeMap; pub use rustc_ast_ir::{try_visit, Movability, Mutability}; use rustc_attr as attr; @@ -85,7 +86,8 @@ pub use self::consts::{ Const, ConstData, ConstInt, ConstKind, Expr, ScalarInt, UnevaluatedConst, ValTree, }; pub use self::context::{ - tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, + tls, CtxtInterners, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, + TyCtxtFeed, }; pub use self::instance::{Instance, InstanceDef, ShortInstance, UnusedGenericParams}; pub use self::list::List; @@ -189,6 +191,7 @@ pub struct ResolverGlobalCtxt { pub doc_link_resolutions: FxHashMap, pub doc_link_traits_in_scope: FxHashMap>, pub all_macro_rules: FxHashMap>, + pub stripped_cfg_items: Steal>, } /// Resolutions that should only be used for lowering. diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 54854cd2da995..ea9c78ca34c08 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -787,13 +787,17 @@ impl<'a> Parser<'a> { let suggest_eq = if self.token.kind == token::Dot && let _ = self.bump() && let mut snapshot = self.create_snapshot_for_diagnostic() - && let Ok(_) = snapshot.parse_dot_suffix_expr( - colon_sp, - self.mk_expr_err( + && let Ok(_) = snapshot + .parse_dot_suffix_expr( colon_sp, - self.dcx().delayed_bug("error during `:` -> `=` recovery"), - ), - ) { + self.mk_expr_err( + colon_sp, + self.dcx() + .delayed_bug("error during `:` -> `=` recovery"), + ), + ) + .map_err(Diag::cancel) + { true } else if let Some(op) = self.check_assoc_op() && op.node.can_continue_expr_unambiguously() diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index 4bfe6be549377..96893e585491f 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -87,7 +87,7 @@ impl<'ast> rustc_ast::visit::Visitor<'ast> for DebuggerVisualizerCollector<'_> { /// Traverses and collects the debugger visualizers for a specific crate. fn debugger_visualizers(tcx: TyCtxt<'_>, _: LocalCrate) -> Vec { - let resolver_and_krate = tcx.resolver_for_lowering(()).borrow(); + let resolver_and_krate = tcx.resolver_for_lowering().borrow(); let krate = &*resolver_and_krate.1; let mut visitor = DebuggerVisualizerCollector { sess: tcx.sess, visualizers: Vec::new() }; diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index d3e3e183845ee..d1368267224a7 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -243,7 +243,7 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { /// Traverses and collects all the lang items in all crates. fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems { - let resolver = tcx.resolver_for_lowering(()).borrow(); + let resolver = tcx.resolver_for_lowering().borrow(); let (resolver, krate) = &*resolver; // Initialize the collector. diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 1c4aeefcbcfd0..dd18ab7d9d23e 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -25,6 +25,7 @@ use rustc_hir::def::{self, *}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_metadata::creader::LoadedMacro; use rustc_middle::metadata::ModChild; +use rustc_middle::ty::Feed; use rustc_middle::{bug, ty}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -407,7 +408,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { // Top level use tree reuses the item's id and list stems reuse their parent // use tree's ids, so in both cases their visibilities are already filled. if nested && !list_stem { - self.r.feed_visibility(self.r.local_def_id(id), vis); + self.r.feed_visibility(self.r.feed(id), vis); } let mut prefix_iter = parent_prefix @@ -632,7 +633,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { &mut self, fields: &[ast::FieldDef], ident: Ident, - def_id: LocalDefId, + feed: Feed<'tcx, LocalDefId>, adt_res: Res, adt_vis: ty::Visibility, adt_span: Span, @@ -643,7 +644,8 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { // Define a name in the type namespace if it is not anonymous. self.r.define(parent, ident, TypeNS, (adt_res, adt_vis, adt_span, expansion)); - self.r.feed_visibility(def_id, adt_vis); + self.r.feed_visibility(feed, adt_vis); + let def_id = feed.key(); // Record field names for error reporting. self.insert_field_def_ids(def_id, fields); @@ -653,14 +655,15 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { match &field.ty.kind { ast::TyKind::AnonStruct(id, nested_fields) | ast::TyKind::AnonUnion(id, nested_fields) => { - let local_def_id = self.r.local_def_id(*id); + let feed = self.r.feed(*id); + let local_def_id = feed.key(); let def_id = local_def_id.to_def_id(); let def_kind = self.r.tcx.def_kind(local_def_id); let res = Res::Def(def_kind, def_id); self.build_reduced_graph_for_struct_variant( &nested_fields, Ident::empty(), - local_def_id, + feed, res, // Anonymous adts inherit visibility from their parent adts. adt_vis, @@ -680,12 +683,13 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let ident = item.ident; let sp = item.span; let vis = self.resolve_visibility(&item.vis); - let local_def_id = self.r.local_def_id(item.id); + let feed = self.r.feed(item.id); + let local_def_id = feed.key(); let def_id = local_def_id.to_def_id(); let def_kind = self.r.tcx.def_kind(def_id); let res = Res::Def(def_kind, def_id); - self.r.feed_visibility(local_def_id, vis); + self.r.feed_visibility(feed, vis); match item.kind { ItemKind::Use(ref use_tree) => { @@ -762,7 +766,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.build_reduced_graph_for_struct_variant( vdata.fields(), ident, - local_def_id, + feed, res, vis, sp, @@ -795,10 +799,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } ret_fields.push(field_vis.to_def_id()); } - let ctor_def_id = self.r.local_def_id(ctor_node_id); + let feed = self.r.feed(ctor_node_id); + let ctor_def_id = feed.key(); let ctor_res = self.res(ctor_def_id); self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); - self.r.feed_visibility(ctor_def_id, ctor_vis); + self.r.feed_visibility(feed, ctor_vis); // We need the field visibility spans also for the constructor for E0603. self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata.fields()); @@ -812,7 +817,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.build_reduced_graph_for_struct_variant( vdata.fields(), ident, - local_def_id, + feed, res, vis, sp, @@ -919,7 +924,8 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { /// Constructs the reduced graph for one foreign item. fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem) { - let local_def_id = self.r.local_def_id(item.id); + let feed = self.r.feed(item.id); + let local_def_id = feed.key(); let def_id = local_def_id.to_def_id(); let ns = match item.kind { ForeignItemKind::Fn(..) => ValueNS, @@ -931,7 +937,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let expansion = self.parent_scope.expansion; let vis = self.resolve_visibility(&item.vis); self.r.define(parent, item.ident, ns, (self.res(def_id), vis, item.span, expansion)); - self.r.feed_visibility(local_def_id, vis); + self.r.feed_visibility(feed, vis); } fn build_reduced_graph_for_block(&mut self, block: &Block) { @@ -1218,7 +1224,8 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'a> { let parent_scope = self.parent_scope; let expansion = parent_scope.expansion; - let def_id = self.r.local_def_id(item.id); + let feed = self.r.feed(item.id); + let def_id = feed.key(); let (res, ident, span, macro_rules) = match &item.kind { ItemKind::MacroDef(def) => (self.res(def_id), item.ident, item.span, def.macro_rules), ItemKind::Fn(..) => match self.proc_macro_stub(item) { @@ -1269,7 +1276,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.check_reserved_macro_name(ident, res); self.insert_unused_macro(ident, def_id, item.id); } - self.r.feed_visibility(def_id, vis); + self.r.feed_visibility(feed, vis); let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding( self.r.arenas.alloc_macro_rules_binding(MacroRulesBinding { parent_macro_rules_scope: parent_scope.macro_rules, @@ -1293,7 +1300,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.insert_unused_macro(ident, def_id, item.id); } self.r.define(module, ident, MacroNS, (res, vis, span, expansion)); - self.r.feed_visibility(def_id, vis); + self.r.feed_visibility(feed, vis); self.parent_scope.macro_rules } } @@ -1385,7 +1392,8 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { } let vis = self.resolve_visibility(&item.vis); - let local_def_id = self.r.local_def_id(item.id); + let feed = self.r.feed(item.id); + let local_def_id = feed.key(); let def_id = local_def_id.to_def_id(); if !(ctxt == AssocCtxt::Impl @@ -1395,7 +1403,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { // Trait impl item visibility is inherited from its trait when not specified // explicitly. In that case we cannot determine it here in early resolve, // so we leave a hole in the visibility table to be filled later. - self.r.feed_visibility(local_def_id, vis); + self.r.feed_visibility(feed, vis); } if ctxt == AssocCtxt::Trait { @@ -1469,7 +1477,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.visit_invoc(sf.id); } else { let vis = self.resolve_visibility(&sf.vis); - self.r.feed_visibility(self.r.local_def_id(sf.id), vis); + self.r.feed_visibility(self.r.feed(sf.id), vis); visit::walk_field_def(self, sf); } } @@ -1487,10 +1495,11 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { let ident = variant.ident; // Define a name in the type namespace. - let def_id = self.r.local_def_id(variant.id); + let feed = self.r.feed(variant.id); + let def_id = feed.key(); let vis = self.resolve_visibility(&variant.vis); self.r.define(parent, ident, TypeNS, (self.res(def_id), vis, variant.span, expn_id)); - self.r.feed_visibility(def_id, vis); + self.r.feed_visibility(feed, vis); // If the variant is marked as non_exhaustive then lower the visibility to within the crate. let ctor_vis = @@ -1502,10 +1511,11 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { // Define a constructor name in the value namespace. if let Some(ctor_node_id) = variant.data.ctor_node_id() { - let ctor_def_id = self.r.local_def_id(ctor_node_id); + let feed = self.r.feed(ctor_node_id); + let ctor_def_id = feed.key(); let ctor_res = self.res(ctor_def_id); self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, variant.span, expn_id)); - self.r.feed_visibility(ctor_def_id, ctor_vis); + self.r.feed_visibility(feed, ctor_vis); } // Record field names for error reporting. diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 12bf462a6fdfd..bb3b902c0de64 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -38,14 +38,16 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> { "create_def(node_id={:?}, def_kind={:?}, parent_def={:?})", node_id, def_kind, parent_def ); - self.resolver.create_def( - parent_def, - node_id, - name, - def_kind, - self.expansion.to_expn_id(), - span.with_parent(None), - ) + self.resolver + .create_def( + parent_def, + node_id, + name, + def_kind, + self.expansion.to_expn_id(), + span.with_parent(None), + ) + .def_id() } fn with_parent(&mut self, parent_def: LocalDefId, f: F) { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 83ee1d8bdcb10..377d1252d5909 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3112,7 +3112,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ); rustc_middle::ty::Visibility::Public }; - this.r.feed_visibility(this.r.local_def_id(id), vis); + this.r.feed_visibility(this.r.feed(id), vis); }; let Some(binding) = binding else { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5de147c2b2444..ccb67ea78cfdb 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -52,8 +52,8 @@ use rustc_middle::metadata::ModChild; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::query::Providers; use rustc_middle::span_bug; -use rustc_middle::ty::{self, MainDefinition, RegisteredTools, TyCtxt}; -use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs}; +use rustc_middle::ty::{self, MainDefinition, RegisteredTools, TyCtxt, TyCtxtFeed}; +use rustc_middle::ty::{Feed, ResolverGlobalCtxt, ResolverOutputs}; use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_session::lint::LintBuffer; @@ -1117,7 +1117,7 @@ pub struct Resolver<'a, 'tcx> { next_node_id: NodeId, - node_id_to_def_id: NodeMap, + node_id_to_def_id: NodeMap>, def_id_to_node_id: IndexVec, /// Indices of unnamed struct or variant fields with unresolved attributes. @@ -1233,11 +1233,19 @@ impl<'a, 'tcx> AsMut> for Resolver<'a, 'tcx> { impl<'tcx> Resolver<'_, 'tcx> { fn opt_local_def_id(&self, node: NodeId) -> Option { - self.node_id_to_def_id.get(&node).copied() + self.opt_feed(node).map(|f| f.key()) } fn local_def_id(&self, node: NodeId) -> LocalDefId { - self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) + self.feed(node).key() + } + + fn opt_feed(&self, node: NodeId) -> Option> { + self.node_id_to_def_id.get(&node).copied() + } + + fn feed(&self, node: NodeId) -> Feed<'tcx, LocalDefId> { + self.opt_feed(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) } fn local_def_kind(&self, node: NodeId) -> DefKind { @@ -1253,18 +1261,19 @@ impl<'tcx> Resolver<'_, 'tcx> { def_kind: DefKind, expn_id: ExpnId, span: Span, - ) -> LocalDefId { + ) -> TyCtxtFeed<'tcx, LocalDefId> { let data = def_kind.def_path_data(name); assert!( !self.node_id_to_def_id.contains_key(&node_id), "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}", node_id, data, - self.tcx.definitions_untracked().def_key(self.node_id_to_def_id[&node_id]), + self.tcx.definitions_untracked().def_key(self.node_id_to_def_id[&node_id].key()), ); // FIXME: remove `def_span` body, pass in the right spans here and call `tcx.at().create_def()` - let def_id = self.tcx.create_def(parent, name, def_kind).def_id(); + let feed = self.tcx.create_def(parent, name, def_kind); + let def_id = feed.def_id(); // Create the definition. if expn_id != ExpnId::root() { @@ -1281,11 +1290,11 @@ impl<'tcx> Resolver<'_, 'tcx> { // we don't need a mapping from `NodeId` to `LocalDefId`. if node_id != ast::DUMMY_NODE_ID { debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id); - self.node_id_to_def_id.insert(node_id, def_id); + self.node_id_to_def_id.insert(node_id, feed.downgrade()); } assert_eq!(self.def_id_to_node_id.push(node_id), def_id); - def_id + feed } fn item_generics_num_lifetimes(&self, def_id: DefId) -> usize { @@ -1333,7 +1342,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut def_id_to_node_id = IndexVec::default(); assert_eq!(def_id_to_node_id.push(CRATE_NODE_ID), CRATE_DEF_ID); let mut node_id_to_def_id = NodeMap::default(); - node_id_to_def_id.insert(CRATE_NODE_ID, CRATE_DEF_ID); + let crate_feed = tcx.create_local_crate_def_id(crate_span); + + crate_feed.def_kind(DefKind::Mod); + let crate_feed = crate_feed.downgrade(); + node_id_to_def_id.insert(CRATE_NODE_ID, crate_feed); let mut invocation_parents = FxHashMap::default(); invocation_parents.insert(LocalExpnId::ROOT, (CRATE_DEF_ID, ImplTraitContext::Existential)); @@ -1484,7 +1497,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let root_parent_scope = ParentScope::module(graph_root, &resolver); resolver.invocation_parent_scopes.insert(LocalExpnId::ROOT, root_parent_scope); - resolver.feed_visibility(CRATE_DEF_ID, ty::Visibility::Public); + resolver.feed_visibility(crate_feed, ty::Visibility::Public); resolver } @@ -1532,9 +1545,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Default::default() } - fn feed_visibility(&mut self, def_id: LocalDefId, vis: ty::Visibility) { - self.tcx.feed_local_def_id(def_id).visibility(vis.to_def_id()); - self.visibilities_for_hashing.push((def_id, vis)); + fn feed_visibility(&mut self, feed: Feed<'tcx, LocalDefId>, vis: ty::Visibility) { + let feed = feed.upgrade(self.tcx); + feed.visibility(vis.to_def_id()); + self.visibilities_for_hashing.push((feed.def_id(), vis)); } pub fn into_outputs(self) -> ResolverOutputs { @@ -1547,12 +1561,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let confused_type_with_std_module = self.confused_type_with_std_module; let effective_visibilities = self.effective_visibilities; - self.tcx.feed_local_crate().stripped_cfg_items(self.tcx.arena.alloc_from_iter( - self.stripped_cfg_items.into_iter().filter_map(|item| { - let parent_module = self.node_id_to_def_id.get(&item.parent_module)?.to_def_id(); - Some(StrippedCfgItem { parent_module, name: item.name, cfg: item.cfg }) - }), - )); + let stripped_cfg_items = Steal::new( + self.stripped_cfg_items + .into_iter() + .filter_map(|item| { + let parent_module = + self.node_id_to_def_id.get(&item.parent_module)?.key().to_def_id(); + Some(StrippedCfgItem { parent_module, name: item.name, cfg: item.cfg }) + }) + .collect(), + ); let global_ctxt = ResolverGlobalCtxt { expn_that_defined, @@ -1569,6 +1587,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { doc_link_resolutions: self.doc_link_resolutions, doc_link_traits_in_scope: self.doc_link_traits_in_scope, all_macro_rules: self.all_macro_rules, + stripped_cfg_items, }; let ast_lowering = ty::ResolverAstLowering { legacy_const_generic_args: self.legacy_const_generic_args, @@ -1578,7 +1597,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { lifetimes_res_map: self.lifetimes_res_map, extra_lifetime_params_map: self.extra_lifetime_params_map, next_node_id: self.next_node_id, - node_id_to_def_id: self.node_id_to_def_id, + node_id_to_def_id: self + .node_id_to_def_id + .into_items() + .map(|(k, f)| (k, f.key())) + .collect(), def_id_to_node_id: self.def_id_to_node_id, trait_map: self.trait_map, lifetime_elision_allowed: self.lifetime_elision_allowed, diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 61a220428b03b..471d828ad7c45 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -8,7 +8,7 @@ pub use crate::options::*; use crate::errors::FileWriteFail; use crate::search_paths::SearchPath; use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; -use crate::{lint, HashStableContext}; +use crate::{filesearch, lint, HashStableContext}; use crate::{EarlyDiagCtxt, Session}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey}; @@ -1564,7 +1564,7 @@ pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg { user_cfg } -pub(super) fn build_target_config( +pub fn build_target_config( early_dcx: &EarlyDiagCtxt, opts: &Options, target_override: Option, @@ -2863,16 +2863,8 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let logical_env = parse_logical_env(early_dcx, matches); - // Try to find a directory containing the Rust `src`, for more details see - // the doc comment on the `real_rust_source_base_dir` field. - let tmp_buf; - let sysroot = match &sysroot_opt { - Some(s) => s, - None => { - tmp_buf = crate::filesearch::get_or_default_sysroot().expect("Failed finding sysroot"); - &tmp_buf - } - }; + let sysroot = filesearch::materialize_sysroot(sysroot_opt); + let real_rust_source_base_dir = { // This is the location used by the `rust-src` `rustup` component. let mut candidate = sysroot.join("lib/rustlib/src/rust"); @@ -2916,7 +2908,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M describe_lints, output_types, search_paths, - maybe_sysroot: sysroot_opt, + maybe_sysroot: Some(sysroot), target_triple, test, incremental, diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 2456b4b3a15c2..4f0e3354680ac 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -193,6 +193,12 @@ pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> { return sysroot_candidates; } +/// Returns the provided sysroot or calls [`get_or_default_sysroot`] if it's none. +/// Panics if [`get_or_default_sysroot`] returns an error. +pub fn materialize_sysroot(maybe_sysroot: Option) -> PathBuf { + maybe_sysroot.unwrap_or_else(|| get_or_default_sysroot().expect("Failed finding sysroot")) +} + /// This function checks if sysroot is found using env::args().next(), and if it /// is not found, finds sysroot from current rustc_driver dll. pub fn get_or_default_sysroot() -> Result { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index ae1dbd13204b0..193bc8e89a48f 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1020,7 +1020,8 @@ pub fn build_session( fluent_resources: Vec<&'static str>, driver_lint_caps: FxHashMap, file_loader: Option>, - target_override: Option, + target_cfg: Target, + sysroot: PathBuf, cfg_version: &'static str, ice_file: Option, using_internal_features: Arc, @@ -1037,12 +1038,6 @@ pub fn build_session( let cap_lints_allow = sopts.lint_cap.is_some_and(|cap| cap == lint::Allow); let can_emit_warnings = !(warnings_allow || cap_lints_allow); - let sysroot = match &sopts.maybe_sysroot { - Some(sysroot) => sysroot.clone(), - None => filesearch::get_or_default_sysroot().expect("Failed finding sysroot"), - }; - - let target_cfg = config::build_target_config(&early_dcx, &sopts, target_override, &sysroot); let host_triple = TargetTriple::from_triple(config::host_triple()); let (host, target_warnings) = Target::search(&host_triple, &sysroot).unwrap_or_else(|e| { early_dcx.early_fatal(format!("Error loading host specification: {e}")) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 3fda1e1833c12..bf6015c3a46de 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2053,6 +2053,14 @@ pub struct TargetOptions { /// Default number of codegen units to use in debug mode pub default_codegen_units: Option, + /// Default codegen backend used for this target. Defaults to `None`. + /// + /// If `None`, then `CFG_DEFAULT_CODEGEN_BACKEND` environmental variable captured when + /// compiling `rustc` will be used instead (or llvm if it is not set). + /// + /// N.B. when *using* the compiler, backend can always be overriden with `-Zcodegen-backend`. + pub default_codegen_backend: Option>, + /// Whether to generate trap instructions in places where optimization would /// otherwise produce control flow that falls through into unrelated memory. pub trap_unreachable: bool, @@ -2359,6 +2367,7 @@ impl Default for TargetOptions { stack_probes: StackProbeType::None, min_global_align: None, default_codegen_units: None, + default_codegen_backend: None, trap_unreachable: true, requires_lto: false, singlethread: false, diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index c35bab5ef6657..41adc2e79dc74 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -559,6 +559,30 @@ impl VecDeque { pub fn with_capacity(capacity: usize) -> VecDeque { Self::with_capacity_in(capacity, Global) } + + /// Creates an empty deque with space for at least `capacity` elements. + /// + /// # Errors + /// + /// Returns an error if the capacity exceeds `isize::MAX` _bytes_, + /// or if the allocator reports allocation failure. + /// + /// # Examples + /// + /// ``` + /// # #![feature(try_with_capacity)] + /// # #[allow(unused)] + /// # fn example() -> Result<(), std::collections::TryReserveError> { + /// use std::collections::VecDeque; + /// + /// let deque: VecDeque = VecDeque::try_with_capacity(10)?; + /// # Ok(()) } + /// ``` + #[inline] + #[unstable(feature = "try_with_capacity", issue = "91913")] + pub fn try_with_capacity(capacity: usize) -> Result, TryReserveError> { + Ok(VecDeque { head: 0, len: 0, buf: RawVec::try_with_capacity_in(capacity, Global)? }) + } } impl VecDeque { diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 28695ade5bf55..ca504b05a9689 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -163,6 +163,7 @@ #![feature(trusted_len)] #![feature(trusted_random_access)] #![feature(try_trait_v2)] +#![feature(try_with_capacity)] #![feature(tuple_trait)] #![feature(unchecked_math)] #![feature(unicode_internals)] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index dd8d6f6c7e634..ace73c0fdaa5e 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -17,10 +17,19 @@ use crate::collections::TryReserveErrorKind::*; #[cfg(test)] mod tests; +// One central function responsible for reporting capacity overflows. This'll +// ensure that the code generation related to these panics is minimal as there's +// only one location which panics rather than a bunch throughout the module. #[cfg(not(no_global_oom_handling))] +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +fn capacity_overflow() -> ! { + panic!("capacity overflow"); +} + enum AllocInit { /// The contents of the new memory are uninitialized. Uninitialized, + #[cfg(not(no_global_oom_handling))] /// The new memory is guaranteed to be zeroed. Zeroed, } @@ -93,6 +102,8 @@ impl RawVec { /// zero-sized. Note that if `T` is zero-sized this means you will /// *not* get a `RawVec` with the requested capacity. /// + /// Non-fallible version of `try_with_capacity` + /// /// # Panics /// /// Panics if the requested capacity exceeds `isize::MAX` bytes. @@ -104,7 +115,7 @@ impl RawVec { #[must_use] #[inline] pub fn with_capacity(capacity: usize) -> Self { - Self::with_capacity_in(capacity, Global) + handle_reserve(Self::try_allocate_in(capacity, AllocInit::Uninitialized, Global)) } /// Like `with_capacity`, but guarantees the buffer is zeroed. @@ -142,7 +153,14 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[inline] pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { - Self::allocate_in(capacity, AllocInit::Uninitialized, alloc) + handle_reserve(Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc)) + } + + /// Like `try_with_capacity`, but parameterized over the choice of + /// allocator for the returned `RawVec`. + #[inline] + pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { + Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc) } /// Like `with_capacity_zeroed`, but parameterized over the choice @@ -150,7 +168,7 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] #[inline] pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self { - Self::allocate_in(capacity, AllocInit::Zeroed, alloc) + handle_reserve(Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc)) } /// Converts the entire buffer into `Box<[MaybeUninit]>` with the specified `len`. @@ -179,35 +197,41 @@ impl RawVec { } } - #[cfg(not(no_global_oom_handling))] - fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self { + fn try_allocate_in( + capacity: usize, + init: AllocInit, + alloc: A, + ) -> Result { // Don't allocate here because `Drop` will not deallocate when `capacity` is 0. + if T::IS_ZST || capacity == 0 { - Self::new_in(alloc) + Ok(Self::new_in(alloc)) } else { // We avoid `unwrap_or_else` here because it bloats the amount of // LLVM IR generated. let layout = match Layout::array::(capacity) { Ok(layout) => layout, - Err(_) => capacity_overflow(), + Err(_) => return Err(CapacityOverflow.into()), }; - match alloc_guard(layout.size()) { - Ok(_) => {} - Err(_) => capacity_overflow(), + + if let Err(err) = alloc_guard(layout.size()) { + return Err(err); } + let result = match init { AllocInit::Uninitialized => alloc.allocate(layout), + #[cfg(not(no_global_oom_handling))] AllocInit::Zeroed => alloc.allocate_zeroed(layout), }; let ptr = match result { Ok(ptr) => ptr, - Err(_) => handle_alloc_error(layout), + Err(_) => return Err(AllocError { layout, non_exhaustive: () }.into()), }; // Allocators currently return a `NonNull<[u8]>` whose length // matches the size requested. If that ever changes, the capacity // here should change to `ptr.len() / mem::size_of::()`. - Self { ptr: Unique::from(ptr.cast()), cap: unsafe { Cap(capacity) }, alloc } + Ok(Self { ptr: Unique::from(ptr.cast()), cap: unsafe { Cap(capacity) }, alloc }) } } @@ -259,7 +283,7 @@ impl RawVec { } else { // We could use Layout::array here which ensures the absence of isize and usize overflows // and could hypothetically handle differences between stride and size, but this memory - // has already been allocated so we know it can't overflow and currently rust does not + // has already been allocated so we know it can't overflow and currently Rust does not // support such types. So we can do better by skipping some checks and avoid an unwrap. const { assert!(mem::size_of::() % mem::align_of::() == 0) }; unsafe { @@ -537,11 +561,11 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for RawVec { // Central function for reserve error handling. #[cfg(not(no_global_oom_handling))] #[inline] -fn handle_reserve(result: Result<(), TryReserveError>) { +fn handle_reserve(result: Result) -> T { match result.map_err(|e| e.kind()) { + Ok(res) => res, Err(CapacityOverflow) => capacity_overflow(), Err(AllocError { layout, .. }) => handle_alloc_error(layout), - Ok(()) => { /* yay */ } } } @@ -561,12 +585,3 @@ fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { Ok(()) } } - -// One central function responsible for reporting capacity overflows. This'll -// ensure that the code generation related to these panics is minimal as there's -// only one location which panics rather than a bunch throughout the module. -#[cfg(not(no_global_oom_handling))] -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] -fn capacity_overflow() -> ! { - panic!("capacity overflow"); -} diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs index f8cada01c0309..4194be530612d 100644 --- a/library/alloc/src/raw_vec/tests.rs +++ b/library/alloc/src/raw_vec/tests.rs @@ -105,13 +105,14 @@ fn zst() { let v: RawVec = RawVec::with_capacity_in(100, Global); zst_sanity(&v); - let v: RawVec = RawVec::allocate_in(0, AllocInit::Uninitialized, Global); + let v: RawVec = RawVec::try_allocate_in(0, AllocInit::Uninitialized, Global).unwrap(); zst_sanity(&v); - let v: RawVec = RawVec::allocate_in(100, AllocInit::Uninitialized, Global); + let v: RawVec = RawVec::try_allocate_in(100, AllocInit::Uninitialized, Global).unwrap(); zst_sanity(&v); - let mut v: RawVec = RawVec::allocate_in(usize::MAX, AllocInit::Uninitialized, Global); + let mut v: RawVec = + RawVec::try_allocate_in(usize::MAX, AllocInit::Uninitialized, Global).unwrap(); zst_sanity(&v); // Check all these operations work as expected with zero-sized elements. diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 98ded7f6cdf5b..c4dcff1b1c49c 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -492,6 +492,19 @@ impl String { String { vec: Vec::with_capacity(capacity) } } + /// Creates a new empty `String` with at least the specified capacity. + /// + /// # Errors + /// + /// Returns [`Err`] if the capacity exceeds `isize::MAX` bytes, + /// or if the memory allocator reports failure. + /// + #[inline] + #[unstable(feature = "try_with_capacity", issue = "91913")] + pub fn try_with_capacity(capacity: usize) -> Result { + Ok(String { vec: Vec::try_with_capacity(capacity)? }) + } + // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is // required for this method definition, is not available. Since we don't // require this method for testing purposes, I'll just stub it diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index c0e934b3b1fcb..f2f42e63d6b0b 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -481,6 +481,22 @@ impl Vec { Self::with_capacity_in(capacity, Global) } + /// Constructs a new, empty `Vec` with at least the specified capacity. + /// + /// The vector will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is 0, the vector will not allocate. + /// + /// # Errors + /// + /// Returns an error if the capacity exceeds `isize::MAX` _bytes_, + /// or if the allocator reports allocation failure. + #[inline] + #[unstable(feature = "try_with_capacity", issue = "91913")] + pub fn try_with_capacity(capacity: usize) -> Result { + Self::try_with_capacity_in(capacity, Global) + } + /// Creates a `Vec` directly from a pointer, a length, and a capacity. /// /// # Safety @@ -672,6 +688,24 @@ impl Vec { Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 } } + /// Constructs a new, empty `Vec` with at least the specified capacity + /// with the provided allocator. + /// + /// The vector will be able to hold at least `capacity` elements without + /// reallocating. This method is allowed to allocate for more elements than + /// `capacity`. If `capacity` is 0, the vector will not allocate. + /// + /// # Errors + /// + /// Returns an error if the capacity exceeds `isize::MAX` _bytes_, + /// or if the allocator reports allocation failure. + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "try_with_capacity", issue = "91913")] + pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { + Ok(Vec { buf: RawVec::try_with_capacity_in(capacity, alloc)?, len: 0 }) + } + /// Creates a `Vec` directly from a pointer, a length, a capacity, /// and an allocator. /// diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index ed928994ad697..e8496989bcf12 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(pattern)] #![feature(trusted_len)] #![feature(try_reserve_kind)] +#![feature(try_with_capacity)] #![feature(unboxed_closures)] #![feature(associated_type_bounds)] #![feature(binary_heap_into_iter_sorted)] diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index 711e4eef2e724..e20ceae87b0d5 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -723,6 +723,17 @@ fn test_reserve_exact() { assert!(s.capacity() >= 33) } +#[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM +#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc +fn test_try_with_capacity() { + let string = String::try_with_capacity(1000).unwrap(); + assert_eq!(0, string.len()); + assert!(string.capacity() >= 1000 && string.capacity() <= isize::MAX as usize); + + assert!(String::try_with_capacity(usize::MAX).is_err()); +} + #[test] #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM #[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 15ee4d6520523..aa95b4e977081 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1694,6 +1694,18 @@ fn test_reserve_exact() { assert!(v.capacity() >= 33) } +#[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM +#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc +fn test_try_with_capacity() { + let mut vec: Vec = Vec::try_with_capacity(5).unwrap(); + assert_eq!(0, vec.len()); + assert!(vec.capacity() >= 5 && vec.capacity() <= isize::MAX as usize / 4); + assert!(vec.spare_capacity_mut().len() >= 5); + + assert!(Vec::::try_with_capacity(isize::MAX as usize + 1).is_err()); +} + #[test] #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM #[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index eda2f8bb812b5..cea5de4dd5984 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -1182,6 +1182,17 @@ fn test_reserve_exact_2() { assert!(v.capacity() >= 33) } +#[test] +#[cfg_attr(miri, ignore)] // Miri does not support signalling OOM +#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc +fn test_try_with_capacity() { + let vec: VecDeque = VecDeque::try_with_capacity(5).unwrap(); + assert_eq!(0, vec.len()); + assert!(vec.capacity() >= 5 && vec.capacity() <= isize::MAX as usize / 4); + + assert!(VecDeque::::try_with_capacity(isize::MAX as usize + 1).is_err()); +} + #[test] #[cfg_attr(miri, ignore)] // Miri does not support signalling OOM #[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc diff --git a/library/core/src/arch.rs b/library/core/src/arch.rs index 8817ec0777b64..31d6bc36fc8b9 100644 --- a/library/core/src/arch.rs +++ b/library/core/src/arch.rs @@ -6,10 +6,10 @@ pub use crate::core_arch::arch::*; /// Inline assembly. /// -/// Refer to [rust by example] for a usage guide and the [reference] for +/// Refer to [Rust By Example] for a usage guide and the [reference] for /// detailed information about the syntax and available options. /// -/// [rust by example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html +/// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html /// [reference]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html #[stable(feature = "asm", since = "1.59.0")] #[rustc_builtin_macro] @@ -19,10 +19,10 @@ pub macro asm("assembly template", $(operands,)* $(options($(option),*))?) { /// Module-level inline assembly. /// -/// Refer to [rust by example] for a usage guide and the [reference] for +/// Refer to [Rust By Example] for a usage guide and the [reference] for /// detailed information about the syntax and available options. /// -/// [rust by example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html +/// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html /// [reference]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html #[stable(feature = "global_asm", since = "1.59.0")] #[rustc_builtin_macro] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 643968c35e849..0ee7e190e3d45 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1481,7 +1481,7 @@ pub(crate) mod builtin { /// script](https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script). /// /// When using the `include` macro to include stretches of documentation, remember that the - /// included file still needs to be a valid rust syntax. It is also possible to + /// included file still needs to be a valid Rust syntax. It is also possible to /// use the [`include_str`] macro as `#![doc = include_str!("...")]` (at the module level) or /// `#[doc = include_str!("...")]` (at the item level) to include documentation from a plain /// text or markdown file. diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index c19b5791562ce..026e21586d403 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -1125,22 +1125,6 @@ impl MaybeUninit { // unlike copy_from_slice this does not call clone_from_slice on the slice // this is because `MaybeUninit` does not implement Clone. - struct Guard<'a, T> { - slice: &'a mut [MaybeUninit], - initialized: usize, - } - - impl<'a, T> Drop for Guard<'a, T> { - fn drop(&mut self) { - let initialized_part = &mut self.slice[..self.initialized]; - // SAFETY: this raw slice will contain only initialized objects - // that's why, it is allowed to drop it. - unsafe { - crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part)); - } - } - } - assert_eq!(this.len(), src.len(), "destination and source slices have different lengths"); // NOTE: We need to explicitly slice them to the same length // for bounds checking to be elided, and the optimizer will @@ -1162,6 +1146,151 @@ impl MaybeUninit { unsafe { MaybeUninit::slice_assume_init_mut(this) } } + /// Fills `this` with elements by cloning `value`, returning a mutable reference to the now + /// initialized contents of `this`. + /// Any previously initialized elements will not be dropped. + /// + /// This is similar to [`slice::fill`]. + /// + /// # Panics + /// + /// This function will panic if any call to `Clone` panics. + /// + /// If such a panic occurs, any elements previously initialized during this operation will be + /// dropped. + /// + /// # Examples + /// + /// Fill an uninit vec with 1. + /// ``` + /// #![feature(maybe_uninit_fill)] + /// use std::mem::MaybeUninit; + /// + /// let mut buf = vec![MaybeUninit::uninit(); 10]; + /// let initialized = MaybeUninit::fill(buf.as_mut_slice(), 1); + /// assert_eq!(initialized, &mut [1; 10]); + /// ``` + #[doc(alias = "memset")] + #[unstable(feature = "maybe_uninit_fill", issue = "117428")] + pub fn fill<'a>(this: &'a mut [MaybeUninit], value: T) -> &'a mut [T] + where + T: Clone, + { + SpecFill::spec_fill(this, value); + // SAFETY: Valid elements have just been filled into `this` so it is initialized + unsafe { MaybeUninit::slice_assume_init_mut(this) } + } + + /// Fills `this` with elements returned by calling a closure repeatedly. + /// + /// This method uses a closure to create new values. If you'd rather `Clone` a given value, use + /// [`MaybeUninit::fill`]. If you want to use the `Default` trait to generate values, you can + /// pass [`Default::default`] as the argument. + /// + /// # Panics + /// + /// This function will panic if any call to the provided closure panics. + /// + /// If such a panic occurs, any elements previously initialized during this operation will be + /// dropped. + /// + /// # Examples + /// + /// Fill an uninit vec with the default value. + /// ``` + /// #![feature(maybe_uninit_fill)] + /// use std::mem::MaybeUninit; + /// + /// let mut buf = vec![MaybeUninit::::uninit(); 10]; + /// let initialized = MaybeUninit::fill_with(buf.as_mut_slice(), Default::default); + /// assert_eq!(initialized, &mut [0; 10]); + /// ``` + #[unstable(feature = "maybe_uninit_fill", issue = "117428")] + pub fn fill_with<'a, F>(this: &'a mut [MaybeUninit], mut f: F) -> &'a mut [T] + where + F: FnMut() -> T, + { + let mut guard = Guard { slice: this, initialized: 0 }; + + for element in guard.slice.iter_mut() { + element.write(f()); + guard.initialized += 1; + } + + super::forget(guard); + + // SAFETY: Valid elements have just been written into `this` so it is initialized + unsafe { MaybeUninit::slice_assume_init_mut(this) } + } + + /// Fills `this` with elements yielded by an iterator until either all elements have been + /// initialized or the iterator is empty. + /// + /// Returns two slices. The first slice contains the initialized portion of the original slice. + /// The second slice is the still-uninitialized remainder of the original slice. + /// + /// # Panics + /// + /// This function panics if the iterator's `next` function panics. + /// + /// If such a panic occurs, any elements previously initialized during this operation will be + /// dropped. + /// + /// # Examples + /// + /// Fill an uninit vec with a cycling iterator. + /// ``` + /// #![feature(maybe_uninit_fill)] + /// use std::mem::MaybeUninit; + /// + /// let mut buf = vec![MaybeUninit::uninit(); 5]; + /// + /// let iter = [1, 2, 3].into_iter().cycle(); + /// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter); + /// + /// assert_eq!(initialized, &mut [1, 2, 3, 1, 2]); + /// assert_eq!(0, remainder.len()); + /// ``` + /// + /// Fill an uninit vec, but not completely. + /// ``` + /// #![feature(maybe_uninit_fill)] + /// use std::mem::MaybeUninit; + /// + /// let mut buf = vec![MaybeUninit::uninit(); 5]; + /// let iter = [1, 2]; + /// let (initialized, remainder) = MaybeUninit::fill_from(&mut buf, iter); + /// + /// assert_eq!(initialized, &mut [1, 2]); + /// assert_eq!(remainder.len(), 3); + /// ``` + #[unstable(feature = "maybe_uninit_fill", issue = "117428")] + pub fn fill_from<'a, I>( + this: &'a mut [MaybeUninit], + it: I, + ) -> (&'a mut [T], &'a mut [MaybeUninit]) + where + I: IntoIterator, + { + let iter = it.into_iter(); + let mut guard = Guard { slice: this, initialized: 0 }; + + for (element, val) in guard.slice.iter_mut().zip(iter) { + element.write(val); + guard.initialized += 1; + } + + let initialized_len = guard.initialized; + super::forget(guard); + + // SAFETY: guard.initialized <= this.len() + let (initted, remainder) = unsafe { this.split_at_mut_unchecked(initialized_len) }; + + // SAFETY: Valid elements have just been written into `init`, so that portion + // of `this` is initialized. + (unsafe { MaybeUninit::slice_assume_init_mut(initted) }, remainder) + } + /// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes. /// /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still @@ -1315,3 +1444,44 @@ impl [MaybeUninit; N] { unsafe { intrinsics::transmute_unchecked(self) } } } + +struct Guard<'a, T> { + slice: &'a mut [MaybeUninit], + initialized: usize, +} + +impl<'a, T> Drop for Guard<'a, T> { + fn drop(&mut self) { + let initialized_part = &mut self.slice[..self.initialized]; + // SAFETY: this raw sub-slice will contain only initialized objects. + unsafe { + crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(initialized_part)); + } + } +} + +trait SpecFill { + fn spec_fill(&mut self, value: T); +} + +impl SpecFill for [MaybeUninit] { + default fn spec_fill(&mut self, value: T) { + let mut guard = Guard { slice: self, initialized: 0 }; + + if let Some((last, elems)) = guard.slice.split_last_mut() { + for el in elems { + el.write(value.clone()); + guard.initialized += 1; + } + + last.write(value); + } + super::forget(guard); + } +} + +impl SpecFill for [MaybeUninit] { + fn spec_fill(&mut self, value: T) { + self.fill(MaybeUninit::new(value)); + } +} diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index 3eea065eef64e..3508b0c7f238d 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -3,7 +3,7 @@ use crate::num::NonZero; use crate::{cmp, fmt, hash, mem, num}; /// A type storing a `usize` which is a power of two, and thus -/// represents a possible alignment in the rust abstract machine. +/// represents a possible alignment in the Rust abstract machine. /// /// Note that particularly large alignments, while representable in this type, /// are likely not to be supported by actual allocators and linkers. diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index aaedbed0d550c..643b7971a662d 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -23,7 +23,7 @@ use crate::slice; issue = "none", reason = "exposed from core to be reused in std; use the memchr crate" )] -/// Pure rust memchr implementation, taken from rust-memchr +/// Pure Rust memchr implementation, taken from rust-memchr pub mod memchr; #[unstable( diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/exclusive.rs index fa02dd52e0027..e8170c13ed263 100644 --- a/library/core/src/sync/exclusive.rs +++ b/library/core/src/sync/exclusive.rs @@ -19,7 +19,7 @@ use core::task::{Context, Poll}; /// /// Certain constructs like [`Future`]s can only be used with _exclusive_ access, /// and are often `Send` but not `Sync`, so `Exclusive` can be used as hint to the -/// rust compiler that something is `Sync` in practice. +/// Rust compiler that something is `Sync` in practice. /// /// ## Examples /// Using a non-`Sync` future prevents the wrapping struct from being `Sync` diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index fa0e9a979d060..c5a7e87c4aa4f 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -54,6 +54,7 @@ #![feature(slice_from_ptr_range)] #![feature(slice_split_once)] #![feature(split_as_slice)] +#![feature(maybe_uninit_fill)] #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_write_slice)] #![feature(maybe_uninit_uninit_array_transpose)] diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 0f7fde747690a..e388800f400df 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -308,21 +308,226 @@ fn uninit_write_slice_cloned_mid_panic() { } } +#[derive(Clone)] +struct Bomb; + +impl Drop for Bomb { + fn drop(&mut self) { + panic!("dropped a bomb! kaboom!") + } +} + #[test] fn uninit_write_slice_cloned_no_drop() { - #[derive(Clone)] - struct Bomb; + let mut dst = [MaybeUninit::uninit()]; + let src = [Bomb]; + + MaybeUninit::clone_from_slice(&mut dst, &src); + + forget(src); +} + +#[test] +fn uninit_fill() { + let mut dst = [MaybeUninit::new(255); 64]; + let expect = [0; 64]; + + assert_eq!(MaybeUninit::fill(&mut dst, 0), &expect); +} + +#[cfg(panic = "unwind")] +struct CloneUntilPanic { + limit: usize, + rc: Rc<()>, +} - impl Drop for Bomb { - fn drop(&mut self) { - panic!("dropped a bomb! kaboom") +#[cfg(panic = "unwind")] +impl Clone for CloneUntilPanic { + fn clone(&self) -> Self { + if Rc::strong_count(&self.rc) >= self.limit { + panic!("expected panic on clone"); } + Self { limit: self.limit, rc: self.rc.clone() } } +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_clone_panic_drop() { + use std::panic; + + let rc = Rc::new(()); + + let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; + + let src = CloneUntilPanic { limit: 3, rc: rc.clone() }; + let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { + MaybeUninit::fill(&mut dst, src); + })); + + match err { + Ok(_) => unreachable!(), + Err(payload) => { + payload + .downcast::<&'static str>() + .and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) }) + .unwrap_or_else(|p| panic::resume_unwind(p)); + assert_eq!(Rc::strong_count(&rc), 1) + } + } +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_clone_no_drop_clones() { + let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; + + MaybeUninit::fill(&mut dst, Bomb); +} + +#[test] +fn uninit_fill_with() { + let mut dst = [MaybeUninit::new(255); 64]; + let expect = [0; 64]; + + assert_eq!(MaybeUninit::fill_with(&mut dst, || 0), &expect); +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_with_mid_panic() { + use std::panic; + + let rc = Rc::new(()); + + let mut dst = [MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit()]; + + let src = CloneUntilPanic { limit: 3, rc: rc.clone() }; + let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { + MaybeUninit::fill_with(&mut dst, || src.clone()); + })); + + drop(src); + + match err { + Ok(_) => unreachable!(), + Err(payload) => { + payload + .downcast::<&'static str>() + .and_then(|s| if *s == "expected panic on clone" { Ok(s) } else { Err(s) }) + .unwrap_or_else(|p| panic::resume_unwind(p)); + assert_eq!(Rc::strong_count(&rc), 1) + } + } +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_with_no_drop() { + let mut dst = [MaybeUninit::uninit()]; + let src = Bomb; + + MaybeUninit::fill_with(&mut dst, || src.clone()); + + forget(src); +} + +#[test] +fn uninit_fill_from() { + let mut dst = [MaybeUninit::new(255); 64]; + let src = [0; 64]; + + let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); + assert_eq!(initted, &src); + assert_eq!(remainder.len(), 0); +} + +#[test] +fn uninit_fill_from_partial() { + let mut dst = [MaybeUninit::new(255); 64]; + let src = [0; 48]; + + let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); + assert_eq!(initted, &src); + assert_eq!(remainder.len(), 16); +} + +#[test] +fn uninit_over_fill() { + let mut dst = [MaybeUninit::new(255); 64]; + let src = [0; 72]; + + let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); + assert_eq!(initted, &src[0..64]); + assert_eq!(remainder.len(), 0); +} + +#[test] +fn uninit_empty_fill() { + let mut dst = [MaybeUninit::new(255); 64]; + let src = [0; 0]; + + let (initted, remainder) = MaybeUninit::fill_from(&mut dst, src.into_iter()); + assert_eq!(initted, &src[0..0]); + assert_eq!(remainder.len(), 64); +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_from_mid_panic() { + use std::panic; + + struct IterUntilPanic { + limit: usize, + rc: Rc<()>, + } + + impl Iterator for IterUntilPanic { + type Item = Rc<()>; + fn next(&mut self) -> Option { + if Rc::strong_count(&self.rc) >= self.limit { + panic!("expected panic on next"); + } + Some(self.rc.clone()) + } + } + + let rc = Rc::new(()); + + let mut dst = [ + MaybeUninit::uninit(), + MaybeUninit::uninit(), + MaybeUninit::uninit(), + MaybeUninit::uninit(), + ]; + + let src = IterUntilPanic { limit: 3, rc: rc.clone() }; + + let err = panic::catch_unwind(panic::AssertUnwindSafe(|| { + MaybeUninit::fill_from(&mut dst, src); + })); + + match err { + Ok(_) => unreachable!(), + Err(payload) => { + payload + .downcast::<&'static str>() + .and_then(|s| if *s == "expected panic on next" { Ok(s) } else { Err(s) }) + .unwrap_or_else(|p| panic::resume_unwind(p)); + + assert_eq!(Rc::strong_count(&rc), 1) + } + } +} + +#[test] +#[cfg(panic = "unwind")] +fn uninit_fill_from_no_drop() { let mut dst = [MaybeUninit::uninit()]; let src = [Bomb]; - MaybeUninit::clone_from_slice(&mut dst, &src); + MaybeUninit::fill_from(&mut dst, src.iter()); forget(src); } diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index e44da8e637e98..8927e9a47fa83 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -157,7 +157,7 @@ impl OsString { /// # Safety /// /// As the encoding is unspecified, callers must pass in bytes that originated as a mixture of - /// validated UTF-8 and bytes from [`OsStr::as_encoded_bytes`] from within the same rust version + /// validated UTF-8 and bytes from [`OsStr::as_encoded_bytes`] from within the same Rust version /// built for the same target platform. For example, reconstructing an `OsString` from bytes sent /// over the network or stored in a file will likely violate these safety rules. /// @@ -213,7 +213,7 @@ impl OsString { /// ASCII. /// /// Note: As the encoding is unspecified, any sub-slice of bytes that is not valid UTF-8 should - /// be treated as opaque and only comparable within the same rust version built for the same + /// be treated as opaque and only comparable within the same Rust version built for the same /// target platform. For example, sending the bytes over the network or storing it in a file /// will likely result in incompatible data. See [`OsString`] for more encoding details /// and [`std::ffi`] for platform-specific, specified conversions. @@ -747,7 +747,7 @@ impl OsStr { /// # Safety /// /// As the encoding is unspecified, callers must pass in bytes that originated as a mixture of - /// validated UTF-8 and bytes from [`OsStr::as_encoded_bytes`] from within the same rust version + /// validated UTF-8 and bytes from [`OsStr::as_encoded_bytes`] from within the same Rust version /// built for the same target platform. For example, reconstructing an `OsStr` from bytes sent /// over the network or stored in a file will likely violate these safety rules. /// @@ -955,7 +955,7 @@ impl OsStr { /// ASCII. /// /// Note: As the encoding is unspecified, any sub-slice of bytes that is not valid UTF-8 should - /// be treated as opaque and only comparable within the same rust version built for the same + /// be treated as opaque and only comparable within the same Rust version built for the same /// target platform. For example, sending the slice over the network or storing it in a file /// will likely result in incompatible byte slices. See [`OsString`] for more encoding details /// and [`std::ffi`] for platform-specific, specified conversions. diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 694cc34cdc171..4373a1721e18e 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -248,10 +248,10 @@ pub struct DirBuilder { /// /// ```no_run /// use std::fs; -/// use std::net::SocketAddr; /// /// fn main() -> Result<(), Box> { -/// let foo: SocketAddr = String::from_utf8_lossy(&fs::read("address.txt")?).parse()?; +/// let data: Vec = fs::read("image.jpg")?; +/// assert_eq!(data[0..3], [0xFF, 0xD8, 0xFF]); /// Ok(()) /// } /// ``` @@ -290,11 +290,11 @@ pub fn read>(path: P) -> io::Result> { /// /// ```no_run /// use std::fs; -/// use std::net::SocketAddr; /// use std::error::Error; /// /// fn main() -> Result<(), Box> { -/// let foo: SocketAddr = fs::read_to_string("address.txt")?.parse()?; +/// let message: String = fs::read_to_string("message.txt")?; +/// println!("{}", message); /// Ok(()) /// } /// ``` diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 288cce3aa085e..55a5292a4a41b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -84,7 +84,7 @@ //! //! # Contributing changes to the documentation //! -//! Check out the rust contribution guidelines [here]( +//! Check out the Rust contribution guidelines [here]( //! https://rustc-dev-guide.rust-lang.org/contributing.html#writing-documentation). //! The source for this documentation can be found on //! [GitHub](https://github.com/rust-lang/rust). diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index f289dafd8bc56..319b835a76879 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -179,7 +179,7 @@ impl Sub for Instant { /// /// # Panics /// - /// Previous rust versions panicked when `other` was later than `self`. Currently this + /// Previous Rust versions panicked when `other` was later than `self`. Currently this /// method saturates. Future versions may reintroduce the panic in some circumstances. /// See [Monotonicity]. /// diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 923637cbaf260..78a599077c758 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -51,7 +51,7 @@ mod imp { #[cfg(all(target_os = "linux", target_env = "gnu"))] use libc::{mmap64, munmap}; use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL}; - use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE}; + use libc::{sigaltstack, SS_DISABLE}; use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV}; use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering}; @@ -130,7 +130,7 @@ mod imp { drop_handler(MAIN_ALTSTACK.load(Ordering::Relaxed)); } - unsafe fn get_stackp() -> *mut libc::c_void { + unsafe fn get_stack() -> libc::stack_t { // OpenBSD requires this flag for stack mapping // otherwise the said mapping will fail as a no-op on most systems // and has a different meaning on FreeBSD @@ -148,20 +148,28 @@ mod imp { target_os = "dragonfly", )))] let flags = MAP_PRIVATE | MAP_ANON; - let stackp = - mmap64(ptr::null_mut(), SIGSTKSZ + page_size(), PROT_READ | PROT_WRITE, flags, -1, 0); + + let sigstack_size = sigstack_size(); + let page_size = page_size(); + + let stackp = mmap64( + ptr::null_mut(), + sigstack_size + page_size, + PROT_READ | PROT_WRITE, + flags, + -1, + 0, + ); if stackp == MAP_FAILED { panic!("failed to allocate an alternative stack: {}", io::Error::last_os_error()); } - let guard_result = libc::mprotect(stackp, page_size(), PROT_NONE); + let guard_result = libc::mprotect(stackp, page_size, PROT_NONE); if guard_result != 0 { panic!("failed to set up alternative stack guard page: {}", io::Error::last_os_error()); } - stackp.add(page_size()) - } + let stackp = stackp.add(page_size); - unsafe fn get_stack() -> libc::stack_t { - libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ } + libc::stack_t { ss_sp: stackp, ss_flags: 0, ss_size: sigstack_size } } pub unsafe fn make_handler() -> Handler { @@ -182,6 +190,8 @@ mod imp { pub unsafe fn drop_handler(data: *mut libc::c_void) { if !data.is_null() { + let sigstack_size = sigstack_size(); + let page_size = page_size(); let stack = libc::stack_t { ss_sp: ptr::null_mut(), ss_flags: SS_DISABLE, @@ -189,14 +199,32 @@ mod imp { // UNIX2003 which returns ENOMEM when disabling a stack while // passing ss_size smaller than MINSIGSTKSZ. According to POSIX // both ss_sp and ss_size should be ignored in this case. - ss_size: SIGSTKSZ, + ss_size: sigstack_size, }; sigaltstack(&stack, ptr::null_mut()); // We know from `get_stackp` that the alternate stack we installed is part of a mapping // that started one page earlier, so walk back a page and unmap from there. - munmap(data.sub(page_size()), SIGSTKSZ + page_size()); + munmap(data.sub(page_size), sigstack_size + page_size); } } + + /// Modern kernels on modern hardware can have dynamic signal stack sizes. + #[cfg(any(target_os = "linux", target_os = "android"))] + fn sigstack_size() -> usize { + // FIXME: reuse const from libc when available? + const AT_MINSIGSTKSZ: crate::ffi::c_ulong = 51; + let dynamic_sigstksz = unsafe { libc::getauxval(AT_MINSIGSTKSZ) }; + // If getauxval couldn't find the entry, it returns 0, + // so take the higher of the "constant" and auxval. + // This transparently supports older kernels which don't provide AT_MINSIGSTKSZ + libc::SIGSTKSZ.max(dynamic_sigstksz as _) + } + + /// Not all OS support hardware where this is needed. + #[cfg(not(any(target_os = "linux", target_os = "android")))] + fn sigstack_size() -> usize { + libc::SIGSTKSZ + } } #[cfg(not(any( diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 91c010ef2b5e4..6f1a354d28a85 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -59,7 +59,7 @@ pub use core::time::TryFromFloatSecsError; /// experience time dilation (slow down or speed up), but it will never go /// backwards. /// As part of this non-guarantee it is also not specified whether system suspends count as -/// elapsed time or not. The behavior varies across platforms and rust versions. +/// elapsed time or not. The behavior varies across platforms and Rust versions. /// /// Instants are opaque types that can only be compared to one another. There is /// no method to get "the number of seconds" from an instant. Instead, it only @@ -142,7 +142,7 @@ pub use core::time::TryFromFloatSecsError; /// where monotonicity is violated, or `Instant`s are subtracted in the wrong order. /// /// This workaround obscures programming errors where earlier and later instants are accidentally -/// swapped. For this reason future rust versions may reintroduce panics. +/// swapped. For this reason future Rust versions may reintroduce panics. /// /// [tier 1]: https://doc.rust-lang.org/rustc/platform-support.html /// [`duration_since`]: Instant::duration_since @@ -290,7 +290,7 @@ impl Instant { /// /// # Panics /// - /// Previous rust versions panicked when `earlier` was later than `self`. Currently this + /// Previous Rust versions panicked when `earlier` was later than `self`. Currently this /// method saturates. Future versions may reintroduce the panic in some circumstances. /// See [Monotonicity]. /// @@ -365,7 +365,7 @@ impl Instant { /// /// # Panics /// - /// Previous rust versions panicked when the current time was earlier than self. Currently this + /// Previous Rust versions panicked when the current time was earlier than self. Currently this /// method returns a Duration of zero in that case. Future versions may reintroduce the panic. /// See [Monotonicity]. /// @@ -450,7 +450,7 @@ impl Sub for Instant { /// /// # Panics /// - /// Previous rust versions panicked when `other` was later than `self`. Currently this + /// Previous Rust versions panicked when `other` was later than `self`. Currently this /// method saturates. Future versions may reintroduce the panic in some circumstances. /// See [Monotonicity]. /// diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs index 22c28e4954eff..875c66e5fa32c 100644 --- a/library/test/src/formatters/terse.rs +++ b/library/test/src/formatters/terse.rs @@ -84,7 +84,7 @@ impl TerseFormatter { if self.test_column % QUIET_MODE_MAX_COLUMN == QUIET_MODE_MAX_COLUMN - 1 { // We insert a new line regularly in order to flush the // screen when dealing with line-buffered output (e.g., piping to - // `stamp` in the rust CI). + // `stamp` in the Rust CI). self.write_progress()?; } diff --git a/library/test/src/types.rs b/library/test/src/types.rs index 1a8ae889c8c1b..6a7035a8e2918 100644 --- a/library/test/src/types.rs +++ b/library/test/src/types.rs @@ -13,7 +13,7 @@ pub use NamePadding::*; pub use TestFn::*; pub use TestName::*; -/// Type of the test according to the [rust book](https://doc.rust-lang.org/cargo/guide/tests.html) +/// Type of the test according to the [Rust book](https://doc.rust-lang.org/cargo/guide/tests.html) /// conventions. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum TestType { diff --git a/src/doc/rust.css b/src/doc/rust.css index e0bf64c33bcf0..bd2e0b9451870 100644 --- a/src/doc/rust.css +++ b/src/doc/rust.css @@ -5,12 +5,13 @@ body { margin: 0 auto; padding: 0 15px; font-size: 18px; - color: #333; + color: #000; line-height: 1.428571429; -webkit-box-sizing: unset; -moz-box-sizing: unset; box-sizing: unset; + background: #fff; } @media (min-width: 768px) { body { @@ -39,7 +40,6 @@ h4, h5, h6 { padding: 5px 10px; } h5, h6 { - color: black; text-decoration: underline; } diff --git a/src/tools/miri/tests/compiletest.rs b/src/tools/miri/tests/compiletest.rs index 9f46772456518..db0768848fd37 100644 --- a/src/tools/miri/tests/compiletest.rs +++ b/src/tools/miri/tests/compiletest.rs @@ -81,8 +81,10 @@ fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> // Add a test env var to do environment communication tests. program.envs.push(("MIRI_ENV_VAR_TEST".into(), Some("0".into()))); + // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find). - program.envs.push(("MIRI_TEMP".into(), Some(env::temp_dir().into()))); + let miri_temp = env::var_os("MIRI_TEMP").unwrap_or_else(|| env::temp_dir().into()); + program.envs.push(("MIRI_TEMP".into(), Some(miri_temp))); let mut config = Config { target: Some(target.to_owned()), diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 6ba39c1f563f9..304a178dc3404 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -1,6 +1,10 @@ //@ignore-target-windows: File handling is not implemented yet //@compile-flags: -Zmiri-disable-isolation +// If this test is failing for you locally, you can try +// 1. Deleting the files `/tmp/miri_*` +// 2. Setting `MIRI_TEMP` or `TMPDIR` to a different directory, without the `miri_*` files + #![feature(io_error_more)] #![feature(io_error_uncategorized)] diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index a9c5be913ba1e..1a53637ad42f9 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -190,7 +190,11 @@ pub fn check(path: &Path, bless: bool, bad: &mut bool) { let blessed_issues_path = tidy_src.join("issues_blessed.txt"); let mut blessed_issues_txt = fs::File::create(&blessed_issues_path).unwrap(); blessed_issues_txt.write(issues_txt_header.as_bytes()).unwrap(); - for filename in allowed_issue_names.difference(&remaining_issue_names) { + // If we changed paths to use the OS separator, reassert Unix chauvinism for blessing. + for filename in allowed_issue_names + .difference(&remaining_issue_names) + .map(|s| s.replace(std::path::MAIN_SEPARATOR_STR, "/")) + { write!(blessed_issues_txt, "\"{filename}\",\n").unwrap(); } write!(blessed_issues_txt, "]\n").unwrap(); diff --git a/tests/codegen/vec-with-capacity.rs b/tests/codegen/vec-with-capacity.rs new file mode 100644 index 0000000000000..47051f2eef891 --- /dev/null +++ b/tests/codegen/vec-with-capacity.rs @@ -0,0 +1,35 @@ +//@ compile-flags: -O +//@ ignore-debug +// (with debug assertions turned on, `assert_unchecked` generates a real assertion) + +#![crate_type = "lib"] +#![feature(try_with_capacity)] + +// CHECK-LABEL: @with_capacity_does_not_grow1 +#[no_mangle] +pub fn with_capacity_does_not_grow1() -> Vec { + let v = Vec::with_capacity(1234); + // CHECK: call {{.*}}__rust_alloc( + // CHECK-NOT: call {{.*}}__rust_realloc + // CHECK-NOT: call {{.*}}capacity_overflow + // CHECK-NOT: call {{.*}}finish_grow + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: memcpy + // CHECK-NOT: memset + v +} + +// CHECK-LABEL: @try_with_capacity_does_not_grow2 +#[no_mangle] +pub fn try_with_capacity_does_not_grow2() -> Option>> { + let v = Vec::try_with_capacity(1234).ok()?; + // CHECK: call {{.*}}__rust_alloc( + // CHECK-NOT: call {{.*}}__rust_realloc + // CHECK-NOT: call {{.*}}capacity_overflow + // CHECK-NOT: call {{.*}}finish_grow + // CHECK-NOT: call {{.*}}handle_alloc_error + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: memcpy + // CHECK-NOT: memset + Some(v) +} diff --git a/tests/ui/crate-loading/missing-std.stderr b/tests/ui/crate-loading/missing-std.stderr index 70bcae1e0edd0..3eb6c2946d354 100644 --- a/tests/ui/crate-loading/missing-std.stderr +++ b/tests/ui/crate-loading/missing-std.stderr @@ -8,8 +8,6 @@ LL | extern crate core; = help: consider downloading the target with `rustup target add x86_64-unknown-uefi` = help: consider building the standard library from source with `cargo build -Zbuild-std` -error: requires `sized` lang_item - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0463`. diff --git a/tests/ui/hygiene/panic-location.run.stderr b/tests/ui/hygiene/panic-location.run.stderr index 5c552411da7f3..ec0ce18c3dfa7 100644 --- a/tests/ui/hygiene/panic-location.run.stderr +++ b/tests/ui/hygiene/panic-location.run.stderr @@ -1,3 +1,3 @@ -thread 'main' panicked at library/alloc/src/raw_vec.rs:571:5: +thread 'main' panicked at library/alloc/src/raw_vec.rs:26:5: capacity overflow note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/ui/issues/issue-37131.stderr b/tests/ui/issues/issue-37131.stderr index 9ecae3e7a2b24..588696f354184 100644 --- a/tests/ui/issues/issue-37131.stderr +++ b/tests/ui/issues/issue-37131.stderr @@ -4,8 +4,6 @@ error[E0463]: can't find crate for `std` = help: consider downloading the target with `rustup target add thumbv6m-none-eabi` = help: consider building the standard library from source with `cargo build -Zbuild-std` -error: requires `sized` lang_item - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0463`. diff --git a/tests/ui/issues/issue-49851/compiler-builtins-error.rs b/tests/ui/issues/issue-49851/compiler-builtins-error.rs index 3b62cc73f93d6..db45d040f7914 100644 --- a/tests/ui/issues/issue-49851/compiler-builtins-error.rs +++ b/tests/ui/issues/issue-49851/compiler-builtins-error.rs @@ -1,5 +1,4 @@ //~ ERROR can't find crate for `core` -//~^ ERROR can't find crate for `compiler_builtins` //@ compile-flags: --target thumbv7em-none-eabihf //@ needs-llvm-components: arm @@ -8,6 +7,5 @@ #![no_std] extern crate cortex_m; -//~^ ERROR can't find crate for `cortex_m` fn main() {} diff --git a/tests/ui/issues/issue-49851/compiler-builtins-error.stderr b/tests/ui/issues/issue-49851/compiler-builtins-error.stderr index fcfa2bf119cff..1cd65a1b68c88 100644 --- a/tests/ui/issues/issue-49851/compiler-builtins-error.stderr +++ b/tests/ui/issues/issue-49851/compiler-builtins-error.stderr @@ -4,16 +4,6 @@ error[E0463]: can't find crate for `core` = help: consider downloading the target with `rustup target add thumbv7em-none-eabihf` = help: consider building the standard library from source with `cargo build -Zbuild-std` -error[E0463]: can't find crate for `compiler_builtins` - -error[E0463]: can't find crate for `cortex_m` - --> $DIR/compiler-builtins-error.rs:10:1 - | -LL | extern crate cortex_m; - | ^^^^^^^^^^^^^^^^^^^^^^ can't find crate - -error: requires `sized` lang_item - -error: aborting due to 4 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0463`. diff --git a/tests/ui/panics/default-backtrace-ice.stderr b/tests/ui/panics/default-backtrace-ice.stderr index 9d27cb22ae942..82b61e43f4494 100644 --- a/tests/ui/panics/default-backtrace-ice.stderr +++ b/tests/ui/panics/default-backtrace-ice.stderr @@ -21,5 +21,5 @@ error: the compiler unexpectedly panicked. this is a bug. query stack during panic: -#0 [resolver_for_lowering] getting the resolver for lowering +#0 [resolver_for_lowering_raw] getting the resolver for lowering end of query stack diff --git a/tests/ui/parser/recover/recover-colon-instead-of-eq-in-local.rs b/tests/ui/parser/recover/recover-colon-instead-of-eq-in-local.rs index ed4de58cd23ce..521eb6a818b0c 100644 --- a/tests/ui/parser/recover/recover-colon-instead-of-eq-in-local.rs +++ b/tests/ui/parser/recover/recover-colon-instead-of-eq-in-local.rs @@ -1,3 +1,10 @@ +#![allow(unused)] + +fn test_122112() { + // Make sure we don't ICE if parsing in recovery fails + let _: std::env::temp_dir().join(&self, push: Box); //~ ERROR expected one of +} + fn main() { let _: std::env::temp_dir().join("foo"); //~ ERROR expected one of } diff --git a/tests/ui/parser/recover/recover-colon-instead-of-eq-in-local.stderr b/tests/ui/parser/recover/recover-colon-instead-of-eq-in-local.stderr index d03f3ae02830b..15c27bb9451b6 100644 --- a/tests/ui/parser/recover/recover-colon-instead-of-eq-in-local.stderr +++ b/tests/ui/parser/recover/recover-colon-instead-of-eq-in-local.stderr @@ -1,5 +1,13 @@ error: expected one of `!`, `+`, `->`, `::`, `;`, or `=`, found `.` - --> $DIR/recover-colon-instead-of-eq-in-local.rs:2:32 + --> $DIR/recover-colon-instead-of-eq-in-local.rs:5:32 + | +LL | let _: std::env::temp_dir().join(&self, push: Box); + | - ^ expected one of `!`, `+`, `->`, `::`, `;`, or `=` + | | + | while parsing the type for `_` + +error: expected one of `!`, `+`, `->`, `::`, `;`, or `=`, found `.` + --> $DIR/recover-colon-instead-of-eq-in-local.rs:9:32 | LL | let _: std::env::temp_dir().join("foo"); | - ^ expected one of `!`, `+`, `->`, `::`, `;`, or `=` @@ -7,5 +15,5 @@ LL | let _: std::env::temp_dir().join("foo"); | while parsing the type for `_` | help: use `=` if you meant to assign -error: aborting due to 1 previous error +error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/deref-path-method.stderr b/tests/ui/suggestions/deref-path-method.stderr index a2b68fa966fcb..b27d9aef06614 100644 --- a/tests/ui/suggestions/deref-path-method.stderr +++ b/tests/ui/suggestions/deref-path-method.stderr @@ -7,9 +7,9 @@ LL | Vec::contains(&vec, &0); note: if you're trying to build a new `Vec<_, _>` consider using one of the following associated functions: Vec::::new Vec::::with_capacity + Vec::::try_with_capacity Vec::::from_raw_parts - Vec::::new_in - and 2 others + and 4 others --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL help: the function `contains` is implemented on `[_]` | diff --git a/tests/ui/transmute/transmute-zst-generics.rs b/tests/ui/transmute/transmute-zst-generics.rs new file mode 100644 index 0000000000000..469ad632d4260 --- /dev/null +++ b/tests/ui/transmute/transmute-zst-generics.rs @@ -0,0 +1,14 @@ +// run-pass +// Transmuting to/from ZSTs that contain generics. + +#![feature(transmute_generic_consts)] + +unsafe fn cast_zst(from: ()) -> [T; 0] { + ::std::mem::transmute::<(), [T; 0]>(from) +} + +pub fn main() { + unsafe { + let _: [u32; 0] = cast_zst(()); + }; +} diff --git a/tests/ui/ufcs/bad-builder.stderr b/tests/ui/ufcs/bad-builder.stderr index e1c5e45b3ebb7..9cfeb7a5d09d6 100644 --- a/tests/ui/ufcs/bad-builder.stderr +++ b/tests/ui/ufcs/bad-builder.stderr @@ -7,9 +7,9 @@ LL | Vec::::mew() note: if you're trying to build a new `Vec` consider using one of the following associated functions: Vec::::new Vec::::with_capacity + Vec::::try_with_capacity Vec::::from_raw_parts - Vec::::new_in - and 2 others + and 4 others --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL help: there is an associated function `new` with a similar name |