diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 2f8ff159ceb0a..fe10ab9fe2466 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3843,8 +3843,11 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { location: Location, ) -> impl Iterator { if location.statement_index == 0 { - let predecessors = body.basic_blocks.predecessors()[location.block].to_vec(); - Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb))) + Either::Left( + body.basic_blocks.predecessors()[location.block] + .iter() + .map(|&bb| body.terminator_loc(bb)), + ) } else { Either::Right(std::iter::once(Location { statement_index: location.statement_index - 1, diff --git a/compiler/rustc_borrowck/src/implied_bounds.rs b/compiler/rustc_borrowck/src/implied_bounds.rs index d5f765edfdb5d..f787e011944f2 100644 --- a/compiler/rustc_borrowck/src/implied_bounds.rs +++ b/compiler/rustc_borrowck/src/implied_bounds.rs @@ -40,7 +40,7 @@ pub(super) fn mir_borrowck_implied_outlives_bounds<'tcx>( // parent body, so for these we do want to define opaque types. Not doing so can result // in incorrect errors when normalizing implied bounds. let typing_env = if tcx.is_typeck_child(body_def_id.to_def_id()) { - TypingEnv::post_typeck_until_borrowck(tcx, body_def_id) + TypingEnv::post_typeck_through_borrowck(tcx, body_def_id) } else { TypingEnv::non_body_analysis(tcx, body_def_id) }; diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 96fc9b2e37651..7e1ba1fad72c4 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -657,7 +657,7 @@ pub(crate) struct BorrowckInferCtxt<'tcx> { impl<'tcx> BorrowckInferCtxt<'tcx> { pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, root_def_id: LocalDefId) -> Self { - let typing_mode = if tcx.use_typing_mode_post_typeck_until_borrowck() { + let typing_mode = if tcx.use_typing_mode_post_typeck_through_borrowck() { TypingMode::borrowck(tcx, def_id) } else { TypingMode::analysis_in_body(tcx, def_id) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs index e3240c2add95c..7892e6ed72f96 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types/mod.rs @@ -261,8 +261,8 @@ fn collect_defining_uses<'tcx>( DefiningScopeKind::MirBorrowck, ) { // A non-defining use. This is a hard error on stable and gets ignored - // with `TypingMode::PostTypeckUntilBorrowck`. - if infcx.tcx.use_typing_mode_post_typeck_until_borrowck() { + // with `TypingMode::PostTypeckThroughBorrowck`. + if infcx.tcx.use_typing_mode_post_typeck_through_borrowck() { match err { NonDefiningUseReason::Tainted(guar) => add_hidden_type( infcx.tcx, @@ -327,7 +327,7 @@ fn compute_definition_site_hidden_types_from_defining_uses<'tcx>( // If we're using the next solver, the unconstrained region may be resolved by a // fully defining use from another body. // So we don't generate error eagerly here. - if rcx.infcx.tcx.use_typing_mode_post_typeck_until_borrowck() { + if rcx.infcx.tcx.use_typing_mode_post_typeck_through_borrowck() { unconstrained_hidden_type_errors.push(UnexpectedHiddenRegion { def_id, hidden_type, @@ -362,7 +362,7 @@ fn compute_definition_site_hidden_types_from_defining_uses<'tcx>( DefinitionSiteHiddenType::new_error(tcx, guar) }); - if !rcx.infcx.tcx.use_typing_mode_post_typeck_until_borrowck() { + if !rcx.infcx.tcx.use_typing_mode_post_typeck_through_borrowck() { // Sometimes, when the hidden type is an inference variable, it can happen that // the hidden type becomes the opaque type itself. In this case, this was an opaque // usage of the opaque type and we can ignore it. This check is mirrored in typeck's @@ -539,7 +539,7 @@ pub(crate) fn apply_definition_site_hidden_types<'tcx>( let mut errors = Vec::new(); for &(key, hidden_type) in opaque_types { let Some(expected) = hidden_types.get(&key.def_id) else { - if !tcx.use_typing_mode_post_typeck_until_borrowck() { + if !tcx.use_typing_mode_post_typeck_through_borrowck() { if let &ty::Alias(_, ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) = hidden_type.ty.kind() && def_id == key.def_id.to_def_id() diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 00874bdd64097..3d1d0a12a6242 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -110,7 +110,7 @@ impl Qualif for HasMutInterior { let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, cx.body.span); let did = cx.body.source.def_id().expect_local(); - let typing_env = if cx.tcx.use_typing_mode_post_typeck_until_borrowck() { + let typing_env = if cx.tcx.use_typing_mode_post_typeck_through_borrowck() { cx.typing_env } else { ty::TypingEnv::new(cx.typing_env.param_env, TypingMode::analysis_in_body(cx.tcx, did)) diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 6ad79541bdbea..20e4c1c6085be 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -42,7 +42,7 @@ fn retry_codegen_mode_with_postanalysis<'tcx, K: TypeVisitable>, V> } ty::TypingMode::Coherence | ty::TypingMode::Typeck { .. } - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::Reflection | ty::TypingMode::PostAnalysis => {} diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 981813f13c97f..091f0f71cc50d 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -34,7 +34,7 @@ fn assert_typing_mode(typing_mode: ty::TypingMode<'_>) { ty::TypingMode::Coherence | ty::TypingMode::Typeck { .. } | ty::TypingMode::Reflection - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } => bug!( "Const eval should always happens in PostAnalysis or Codegen mode. See the comment on `assert_typing_mode` for more details." ), diff --git a/compiler/rustc_data_structures/src/stable_hash.rs b/compiler/rustc_data_structures/src/stable_hash.rs index 8e7ca5a75d861..91578b9fd4308 100644 --- a/compiler/rustc_data_structures/src/stable_hash.rs +++ b/compiler/rustc_data_structures/src/stable_hash.rs @@ -5,6 +5,7 @@ use std::num::NonZero; use rustc_index::bit_set::{self, DenseBitSet}; use rustc_index::{Idx, IndexSlice, IndexVec}; +use rustc_macros::StableHash; use smallvec::SmallVec; use thin_vec::ThinVec; @@ -37,6 +38,25 @@ pub trait StableHashCtxt { fn assert_default_stable_hash_controls(&self, msg: &str); } +/// Dummy impl of [`StableHashCtxt`], for code that can't provide a real context, +/// and only wants to compute stable hashes for types that don't rely on the context. +pub struct DummyStableHashCtxt; + +impl StableHashCtxt for DummyStableHashCtxt { + fn stable_hash_span(&mut self, _span: RawSpan, _hasher: &mut StableHasher) { + panic!("method on dummy stable-hash context was unexpectedly called"); + } + fn def_path_hash(&self, _def_id: RawDefId) -> Fingerprint { + panic!("method on dummy stable-hash context was unexpectedly called"); + } + fn stable_hash_controls(&self) -> StableHashControls { + panic!("method on dummy stable-hash context was unexpectedly called"); + } + fn assert_default_stable_hash_controls(&self, _msg: &str) { + panic!("method on dummy stable-hash context was unexpectedly called"); + } +} + // A type used to work around `Span` not being visible in this crate. It is the same size as // `Span` but has a different alignment. pub struct RawSpan(pub u64); @@ -71,6 +91,18 @@ pub struct RawDefId(pub u32, pub u32); /// - `stable_hash()` must be independent of the host architecture. The /// `StableHasher` takes care of endianness and `isize`/`usize` platform /// differences. +/// +/// # Consistency across compiler stages +/// +/// Because the stage1 compiler is built against the bootstrap stdlib, but the stage2 +/// compiler uses in-tree stdlib, implementations of `StableHash` must not rely on `Hash` +/// impls that were provided or derived by the standard library. Doing so leads to weird +/// bugs and CI failures that can block changes to those stdlib hash impls. +/// +/// (Unfortunately, as of late 2026 we have many stable-hash impls that _do_ +/// leak details of stdlib hash impls.) +/// +/// See for more context. pub trait StableHash { fn stable_hash(&self, hcx: &mut Hcx, hasher: &mut StableHasher); } @@ -575,8 +607,97 @@ impl StableHash for bit_set::BitMatrix { impl_stable_traits_for_trivial_type!(::std::ffi::OsStr); -impl_stable_traits_for_trivial_type!(::std::path::Path); -impl_stable_traits_for_trivial_type!(::std::path::PathBuf); +impl StableHash for std::path::Path { + fn stable_hash(&self, hcx: &mut Hcx, hasher: &mut StableHasher) { + use std::path::{Component, Prefix}; + + /// Tag value to be mixed in with each kind of component/prefix. + #[derive(StableHash)] + enum Tag { + StartOfPath, + PrefixVerbatim, + PrefixVerbatimUNC, + PrefixVerbatimDisk, + PrefixDeviceNS, + PrefixUNC, + PrefixDisk, + RootDir, + CurDir, + ParentDir, + Normal, + EndOfPath, + } + + // Explicitly tag the start of each path, so that empty paths always hash something. + Tag::StartOfPath.stable_hash(hcx, hasher); + + for (i, component) in self.components().enumerate() { + // Mix in the index of each component, to avoid potentially trivial collisions + // between inputs like `("foo/bar", "baz")` and `("foo", "bar/baz")`. + i.stable_hash(hcx, hasher); + match component { + Component::Prefix(prefix) => match prefix.kind() { + Prefix::Verbatim(os_str) => { + Tag::PrefixVerbatim.stable_hash(hcx, hasher); + os_str.stable_hash(hcx, hasher); + } + Prefix::VerbatimUNC(host, share) => { + Tag::PrefixVerbatimUNC.stable_hash(hcx, hasher); + host.stable_hash(hcx, hasher); + share.stable_hash(hcx, hasher); + } + Prefix::VerbatimDisk(letter) => { + Tag::PrefixVerbatimDisk.stable_hash(hcx, hasher); + letter.stable_hash(hcx, hasher); + } + Prefix::DeviceNS(os_str) => { + Tag::PrefixDeviceNS.stable_hash(hcx, hasher); + os_str.stable_hash(hcx, hasher); + } + Prefix::UNC(host, share) => { + Tag::PrefixUNC.stable_hash(hcx, hasher); + host.stable_hash(hcx, hasher); + share.stable_hash(hcx, hasher); + } + Prefix::Disk(letter) => { + Tag::PrefixDisk.stable_hash(hcx, hasher); + letter.stable_hash(hcx, hasher); + } + }, + Component::RootDir => Tag::RootDir.stable_hash(hcx, hasher), + Component::CurDir => Tag::CurDir.stable_hash(hcx, hasher), + Component::ParentDir => Tag::ParentDir.stable_hash(hcx, hasher), + Component::Normal(os_str) => { + Tag::Normal.stable_hash(hcx, hasher); + os_str.stable_hash(hcx, hasher); + } + } + } + + // Explicitly tag the end of each path, so that empty paths always hash something. + // (Tagging the start and the end and the component-index is potentially overkill.) + Tag::EndOfPath.stable_hash(hcx, hasher); + } +} + +impl StableOrd for std::path::Path { + /// FIXME(Zalathar): Unstably sorting paths is pre-existing behavior, but potentially wrong. + const CAN_USE_UNSTABLE_SORT: bool = true; + /// Stdlib path sorting should (hopefully) not change. + const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = (); +} + +impl StableHash for std::path::PathBuf { + fn stable_hash(&self, hcx: &mut Hcx, hasher: &mut StableHasher) { + self.as_path().stable_hash(hcx, hasher); + } +} + +impl StableOrd for std::path::PathBuf { + const CAN_USE_UNSTABLE_SORT: bool = ::CAN_USE_UNSTABLE_SORT; + /// Stdlib path sorting should (hopefully) not change. + const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = (); +} // It is not safe to implement StableHash for HashSet, HashMap or any other collection type // with unstable but observable iteration order. diff --git a/compiler/rustc_data_structures/src/stable_hash/tests.rs b/compiler/rustc_data_structures/src/stable_hash/tests.rs index 163e441d5a47d..fa73b2ce16331 100644 --- a/compiler/rustc_data_structures/src/stable_hash/tests.rs +++ b/compiler/rustc_data_structures/src/stable_hash/tests.rs @@ -1,3 +1,5 @@ +use std::path::Path; + use super::*; // The tests below compare the computed hashes to particular expected values @@ -29,6 +31,19 @@ fn hash(t: &T) -> Hash128 { h.finish() } +/// Computes the stable hash of two values in sequence. +/// +/// This is similar to computing the stable hash of `(a, b)`, except that it +/// avoids relying on the actual impl of StableHash for tuples. +fn hash_two(a: &impl StableHash, b: &impl StableHash) -> Hash128 { + let hcx = &mut DummyStableHashCtxt; + let mut hasher = StableHasher::new(); + + a.stable_hash(hcx, &mut hasher); + b.stable_hash(hcx, &mut hasher); + hasher.finish() +} + // Check that bit set hash includes the domain size. #[test] fn test_hash_bit_set() { @@ -115,3 +130,22 @@ fn test_isize_compression() { check_hash(0xFF, 0xFFFFFFFFFFFFFFFF); check_hash(u64::MAX /* -1 */, 1); } + +#[test] +fn path_component_rebracketing() { + let hash_a = hash_two(&Path::new("alfa/bravo"), &Path::new("charlie")); + let hash_b = hash_two(&Path::new("alfa"), &Path::new("bravo/charlie")); + + assert_ne!(hash_a, hash_b); +} + +#[test] +fn empty_path_rebracketing() { + let nonempty_path = &Path::new("foo"); + let empty_path = &Path::new(""); + + let hash_a = hash_two(nonempty_path, empty_path); + let hash_b = hash_two(empty_path, nonempty_path); + + assert_ne!(hash_a, hash_b); +} diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 0a7686a2876bb..4f753f02ed9fd 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -2355,7 +2355,7 @@ pub(super) fn check_coroutine_obligations( } } else { // We're not checking region constraints here, so we can simply drop the - // added opaque type uses in `TypingMode::PostTypeckUntilBorrowck`. + // added opaque type uses in `TypingMode::PostTypeckThroughBorrowck`. let _ = infcx.take_opaque_types(); } @@ -2372,7 +2372,7 @@ pub(super) fn check_potentially_region_dependent_goals<'tcx>( let typeck_results = tcx.typeck(def_id); let param_env = tcx.param_env(def_id); - // We use `TypingMode::PostTypeckUntilBorrowck` as we want to use the opaque types computed by HIR typeck. + // We use `TypingMode::PostTypeckThroughBorrowck` as we want to use the opaque types computed by HIR typeck. let typing_mode = TypingMode::borrowck(tcx, def_id); let infcx = tcx.infer_ctxt().ignoring_regions().build(typing_mode); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 9e3e3d810345e..4d76887698ad9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -719,7 +719,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ty::TypingMode::Coherence | ty::TypingMode::Reflection - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen => { diff --git a/compiler/rustc_hir_typeck/src/opaque_types.rs b/compiler/rustc_hir_typeck/src/opaque_types.rs index da9162629ec80..6d1e1bc67f8e7 100644 --- a/compiler/rustc_hir_typeck/src/opaque_types.rs +++ b/compiler/rustc_hir_typeck/src/opaque_types.rs @@ -104,7 +104,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } ty::TypingMode::Coherence | ty::TypingMode::Reflection - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen => { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 76234c7459f84..d3ed447e5201f 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -360,10 +360,10 @@ impl<'tcx> Drop for InferCtxt<'tcx> { let mut inner = self.inner.borrow_mut(); let opaque_type_storage = &mut inner.opaque_type_storage; - // No need for the drop bomb when we're in `TypingMode::PostTypeckUntilBorrowck`, and the `InferCtxt` + // No need for the drop bomb when we're in `TypingMode::PostTypeckThroughBorrowck`, and the `InferCtxt` // doesn't consider regions. This is okay since after typeck, the only reason we care about opaques is // in relation to regions. In some places *after* typeck that aren't borrowck, we use - // `TypingMode::PostTypeckUntilBorrowck` to prevent defining opaque types and we simply don't care about regions. + // `TypingMode::PostTypeckThroughBorrowck` to prevent defining opaque types and we simply don't care about regions. match self.typing_mode_raw() { TypingMode::Coherence | TypingMode::Typeck { .. } @@ -373,7 +373,7 @@ impl<'tcx> Drop for InferCtxt<'tcx> { | TypingMode::Codegen => {} // In erased mode, the opaque type storage is always empty TypingMode::ErasedNotCoherence(..) => {} - TypingMode::PostTypeckUntilBorrowck { .. } => { + TypingMode::PostTypeckThroughBorrowck { .. } => { if !self.considering_regions { return; } @@ -1193,7 +1193,7 @@ impl<'tcx> InferCtxt<'tcx> { debug_assert!(!self.next_trait_solver()); match self.typing_mode_raw().assert_not_erased() { TypingMode::Typeck { defining_opaque_types_and_generators: defining_opaque_types } - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types } => { + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types } => { id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id)) } // FIXME(#132279): This function is quite weird in post-analysis @@ -1683,7 +1683,7 @@ impl<'tcx> InferCtxt<'tcx> { // errors and fail to reveal opaques while inside of bodies. We should rename this // function and require explicit comments on all use-sites in the future. ty::TypingMode::Typeck { defining_opaque_types_and_generators: _ } - | ty::TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: _ } => { + | ty::TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: _ } => { TypingMode::non_body_analysis() } mode @ (ty::TypingMode::Coherence diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 3cca843157b8f..6a922f75dbe9b 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -253,7 +253,7 @@ impl<'tcx> InferCtxt<'tcx> { ); } } - ty::TypingMode::PostTypeckUntilBorrowck { .. } => { + ty::TypingMode::PostTypeckThroughBorrowck { .. } => { let prev = self .inner .borrow_mut() diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 0278f564bd34d..9678ed65d2891 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -627,7 +627,7 @@ impl<'tcx> LateContext<'tcx> { /// building a new `InferCtxt`. pub fn typing_mode(&self) -> TypingMode<'tcx> { if let Some(body_id) = self.enclosing_body - && self.tcx.use_typing_mode_post_typeck_until_borrowck() + && self.tcx.use_typing_mode_post_typeck_through_borrowck() { let def_id = self.tcx.hir_enclosing_body_owner(body_id.hir_id); TypingMode::post_borrowck_analysis(self.tcx, def_id) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index fbb810d5423b2..ffcef6df06e4f 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -732,7 +732,11 @@ extern "C" LLVMRustResult LLVMRustOptimize( PGOOptions::ColdFuncOpt::Default, DebugInfoForProfiling); } +#if LLVM_VERSION_GE(24, 0) + auto PB = PassBuilder(TheModule->getContext(), TM, PTO, PGOOpt, &PIC); +#else auto PB = PassBuilder(TM, PTO, PGOOpt, &PIC); +#endif LoopAnalysisManager LAM; FunctionAnalysisManager FAM; CGSCCAnalysisManager CGAM; @@ -1201,7 +1205,13 @@ extern "C" LLVMRustResult LLVMRustPrintModule(LLVMModuleRef M, const char *Path, } extern "C" void LLVMRustPrintPasses() { +#if LLVM_VERSION_GE(24, 0) + LLVMContext C; + PassBuilder PB(C); +#else PassBuilder PB; +#endif + PB.printPassNames(outs()); } @@ -1554,7 +1564,11 @@ extern "C" LLVMRustBuffer *LLVMRustModuleSerialize(LLVMModuleRef M, { auto OS = raw_string_ostream(Ret->data); { +#if LLVM_VERSION_GE(24, 0) + PassBuilder PB(unwrap(M)->getContext()); +#else PassBuilder PB; +#endif LoopAnalysisManager LAM; FunctionAnalysisManager FAM; CGSCCAnalysisManager CGAM; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index f68cfcc0d388b..8ac88f0c9bd63 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -467,15 +467,21 @@ impl<'a, 'tcx> SpanDecoder for MetadataDecodeContext<'a, 'tcx> { let tcx = self.tcx; let cname = cdata.root.name(); - rustc_span::hygiene::decode_syntax_context(self, &cdata.hygiene_context, |_, id| { - debug!("SpecializedDecoder: decoding {}", id); - cdata - .root - .syntax_contexts - .get(cdata, id) - .unwrap_or_else(|| panic!("Missing SyntaxContext {id:?} for crate {cname:?}")) - .decode((cdata, tcx)) - }) + rustc_span::hygiene::decode_syntax_context( + self, + &cdata.hygiene_context, + |_, external_ctxt| { + debug!("SpecializedDecoder: decoding {:?}", external_ctxt); + cdata + .root + .syntax_contexts + .get(cdata, external_ctxt) + .unwrap_or_else(|| { + panic!("Missing SyntaxContext {external_ctxt:?} for crate {cname:?}") + }) + .decode((cdata, tcx)) + }, + ) } fn decode_expn_id(&mut self) -> ExpnId { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index dc8a117704ca4..cbc6851d8d719 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -83,8 +83,8 @@ pub(super) struct EncodeContext<'a, 'tcx> { // Used for both `Symbol`s and `ByteSymbol`s. symbol_index_table: FxHashMap, local_defs_remapping: LocalDefsRemapping, - syntax_context_remapping: HygieneRemappingResults, - local_expn_id_remapping: HygieneRemappingResults, + syntax_context_remapping: HygieneRemappingResults, + local_expn_id_remapping: HygieneRemappingResults, } /// If the current crate is a proc-macro, returns early with `LazyArray::default()`. @@ -198,12 +198,12 @@ impl<'a, 'tcx> SpanEncoder for EncodeContext<'a, 'tcx> { } expn_id.krate.encode(self); - let expn_index = match expn_id.as_local() { - Some(local_expn) => self.local_expn_id_remapping.map_id(local_expn).as_raw(), - None => expn_id.local_id, + let raw_expn_index = match expn_id.as_local() { + Some(local_expn) => self.local_expn_id_remapping.map_id(local_expn).as_u32(), + None => expn_id.local_id.as_u32(), }; - expn_index.encode(self); + raw_expn_index.encode(self); } fn encode_span(&mut self, span: Span) { @@ -2087,12 +2087,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { &Rc::clone(&self.hygiene_ctxt), &mut (&mut *self, &mut syntax_contexts, &mut expn_data_table, &mut expn_hash_table), |(this, syntax_contexts, _, _), ctxt, ctxt_data| { - let context = this.syntax_context_remapping.map_id(ctxt); - syntax_contexts.set_some(context.as_u32(), this.lazy(ctxt_data)); + let ctxt = this.syntax_context_remapping.map_id(ctxt); + syntax_contexts.set_some(ctxt, this.lazy(ctxt_data)); }, |(this, _, expn_data_table, expn_hash_table), expn_id, expn_data, hash| { if let Some(expn_id) = expn_id.as_local() { - let expn_index = this.local_expn_id_remapping.map_id(expn_id).as_raw(); + let expn_index = this.local_expn_id_remapping.map_id(expn_id); expn_data_table.set_some(expn_index, this.lazy(expn_data.expect("local expn"))); expn_hash_table.set_some(expn_index, this.lazy(hash)); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 0410874c122a6..4d3c49497a6c2 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -48,7 +48,7 @@ use rustc_serialize::opaque::FileEncoder; use rustc_session::config::mitigation_coverage::DeniedPartialMitigation; use rustc_session::config::{SymbolManglingVersion, TargetModifier}; use rustc_span::edition::Edition; -use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextKey}; +use rustc_span::hygiene::{DecodedSyntaxContext, ExpnIndex, MacroKind, SyntaxContextKey}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Ident, Span, Symbol}; use rustc_target::spec::{PanicStrategy, TargetTuple}; use table::TableBuilder; @@ -209,9 +209,10 @@ enum LazyState { Previous(NonZero), } -type SyntaxContextTable = LazyTable>>; -type ExpnDataTable = LazyTable>>; -type ExpnHashTable = LazyTable>>; +type SyntaxContextTable = + LazyTable>>; +type ExpnDataTable = LazyTable>>; +type ExpnHashTable = LazyTable>>; #[derive(MetadataEncodable, LazyDecodable)] pub(crate) struct ProcMacroData { @@ -343,6 +344,17 @@ pub(crate) struct CrateRootUnhashed { dep_extra_filenames: IndexVec, } +rustc_index::newtype_index! { + #[max = 0x1FFF_FFFF] // `u32::MAX` >> 3, as `SyntaxContext` should be fit in 29 bits (see `span_encoding`). + #[default] + pub(super) struct RemappedSyntaxContext {} +} + +rustc_index::newtype_index! { + #[default] + pub(super) struct RemappedLocalExpnIndex {} +} + #[derive(Default)] pub(crate) struct LocalDefsRemapping { /// See `Definitions::first_non_det_index`, it is just cached version of it. diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 41e21749f3920..ab843950a71d4 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -15,44 +15,71 @@ use crate::mir::{BasicBlock, BasicBlockData, START_BLOCK}; pub struct BasicBlocks<'tcx> { basic_blocks: IndexVec>, /// Use an `Arc` so we can share the cache when we clone the MIR body, as borrowck does. - cache: Arc, + cache: Arc, } // Typically 95%+ of basic blocks have 4 or fewer predecessors. -type Predecessors = IndexVec>; +pub type Predecessors = IndexVec>; #[derive(Clone, Default, Debug)] -struct Cache { +pub struct CfgCache { predecessors: OnceLock, reverse_postorder: OnceLock>, dominators: OnceLock>, } +impl CfgCache { + #[inline] + pub fn dominators(self: &Arc, bbs: &BasicBlocks<'_>) -> &Dominators { + debug_assert!(Arc::ptr_eq(self, &bbs.cache)); + self.dominators.get_or_init(|| dominators(bbs)) + } + + #[inline] + pub fn reverse_postorder(self: &Arc, bbs: &BasicBlocks<'_>) -> &[BasicBlock] { + debug_assert!(Arc::ptr_eq(self, &bbs.cache)); + self.reverse_postorder.get_or_init(|| { + let mut rpo: Vec<_> = Postorder::new(&bbs.basic_blocks, START_BLOCK, None).collect(); + rpo.reverse(); + rpo + }) + } + + #[inline] + pub fn predecessors(self: &Arc, bbs: &BasicBlocks<'_>) -> &Predecessors { + debug_assert!(Arc::ptr_eq(self, &bbs.cache)); + self.predecessors.get_or_init(|| { + let mut preds = IndexVec::from_elem(SmallVec::new(), &bbs.basic_blocks); + for (bb, data) in bbs.basic_blocks.iter_enumerated() { + for succ in data.terminator().successors() { + preds[succ].push(bb); + } + } + preds + }) + } +} + impl<'tcx> BasicBlocks<'tcx> { #[inline] pub fn new(basic_blocks: IndexVec>) -> Self { - BasicBlocks { basic_blocks, cache: Arc::new(Cache::default()) } + BasicBlocks { basic_blocks, cache: Arc::new(CfgCache::default()) } + } + + #[inline] + pub fn cfg_cache(&self) -> Arc { + Arc::clone(&self.cache) } #[inline] pub fn dominators(&self) -> &Dominators { - self.cache.dominators.get_or_init(|| dominators(self)) + self.cache.dominators(self) } /// Returns predecessors for each basic block. #[inline] pub fn predecessors(&self) -> &Predecessors { - self.cache.predecessors.get_or_init(|| { - let mut preds = IndexVec::from_elem(SmallVec::new(), &self.basic_blocks); - for (bb, data) in self.basic_blocks.iter_enumerated() { - if let Some(term) = &data.terminator { - for succ in term.successors() { - preds[succ].push(bb); - } - } - } - preds - }) + self.cache.predecessors(self) } /// Returns basic blocks in a reverse postorder. @@ -62,11 +89,7 @@ impl<'tcx> BasicBlocks<'tcx> { /// [`traversal::reverse_postorder`]: crate::mir::traversal::reverse_postorder #[inline] pub fn reverse_postorder(&self) -> &[BasicBlock] { - self.cache.reverse_postorder.get_or_init(|| { - let mut rpo: Vec<_> = Postorder::new(&self.basic_blocks, START_BLOCK, None).collect(); - rpo.reverse(); - rpo - }) + self.cache.reverse_postorder(self) } /// Returns mutable reference to basic blocks. Invalidates CFG cache. @@ -100,11 +123,11 @@ impl<'tcx> BasicBlocks<'tcx> { pub fn invalidate_cfg_cache(&mut self) { if let Some(cache) = Arc::get_mut(&mut self.cache) { // If we only have a single reference to this cache, clear it. - *cache = Cache::default(); + *cache = CfgCache::default(); } else { // If we have several references to this cache, overwrite the pointer itself so other // users can continue to use their (valid) cache. - self.cache = Arc::new(Cache::default()); + self.cache = Arc::new(CfgCache::default()); } } } @@ -149,21 +172,21 @@ impl<'tcx> graph::Predecessors for BasicBlocks<'tcx> { } // Done here instead of in `structural_impls.rs` because `Cache` is private, as is `basic_blocks`. -TrivialTypeTraversalImpls! { Cache } +TrivialTypeTraversalImpls! { CfgCache } -impl Encodable for Cache { +impl Encodable for CfgCache { #[inline] fn encode(&self, _s: &mut S) {} } -impl Decodable for Cache { +impl Decodable for CfgCache { #[inline] fn decode(_: &mut D) -> Self { Default::default() } } -impl StableHash for Cache { +impl StableHash for CfgCache { #[inline] fn stable_hash(&self, _: &mut Hcx, _: &mut StableHasher) {} } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 29ca694b6431b..ebcc2da09551e 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -36,7 +36,7 @@ use crate::ty::{ TypeVisitableExt, TypingEnv, UserTypeAnnotationIndex, }; -mod basic_blocks; +pub mod basic_blocks; mod consts; pub mod coverage; mod generic_graph; @@ -413,7 +413,7 @@ impl<'tcx> Body<'tcx> { } pub fn typing_env(&self, tcx: TyCtxt<'tcx>) -> TypingEnv<'tcx> { - if tcx.use_typing_mode_post_typeck_until_borrowck() { + if tcx.use_typing_mode_post_typeck_through_borrowck() { match self.phase { MirPhase::Built | MirPhase::Analysis(AnalysisPhase::Initial) if let Some(def_id) = self.source.def_id().as_local() => diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 14794b5cb73c7..3c7d73b4a1226 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -552,15 +552,19 @@ impl<'a, 'tcx> Decodable> for Vec { impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { fn decode_syntax_context(&mut self) -> SyntaxContext { let syntax_contexts = self.syntax_contexts; - rustc_span::hygiene::decode_syntax_context(self, self.hygiene_context, |this, id| { - // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing. - // We look up the position of the associated `SyntaxData` and decode it. - let pos = syntax_contexts.get(&id).unwrap(); - this.with_position(pos.to_usize(), |decoder| { - let data: SyntaxContextKey = decode_tagged(decoder, TAG_SYNTAX_CONTEXT); - data - }) - }) + rustc_span::hygiene::decode_syntax_context( + self, + self.hygiene_context, + |this, external_ctxt| { + // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing. + // We look up the position of the associated `SyntaxData` and decode it. + let pos = syntax_contexts.get(&external_ctxt.as_u32()).unwrap(); + this.with_position(pos.to_usize(), |decoder| { + let data: SyntaxContextKey = decode_tagged(decoder, TAG_SYNTAX_CONTEXT); + data + }) + }, + ) } fn decode_expn_id(&mut self) -> ExpnId { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 20a2cc4dadaa7..2e71a7c72603d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2871,9 +2871,8 @@ impl<'tcx> TyCtxt<'tcx> { } #[allow(rustc::bad_opt_access)] - pub fn use_typing_mode_post_typeck_until_borrowck(self) -> bool { + pub fn use_typing_mode_post_typeck_through_borrowck(self) -> bool { self.next_trait_solver_globally() - || self.sess.opts.unstable_opts.typing_mode_post_typeck_until_borrowck } pub fn assumptions_on_binders(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a4d22ea9923f2..2fe1b98402391 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1156,20 +1156,20 @@ impl<'tcx> TypingEnv<'tcx> { /// The `TypingEnv` which should be for everything happens after HIR typeck /// up-to and including borrowck itself. - pub fn post_typeck_until_borrowck(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> TypingEnv<'tcx> { + pub fn post_typeck_through_borrowck(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> TypingEnv<'tcx> { let param_env = tcx.param_env(def_id.to_def_id()); TypingEnv::new(param_env, ty::TypingMode::borrowck(tcx, def_id)) } - /// Ideally we just use `TypingMode::post_typeck_until_borrowck`. + /// Ideally we just use `TypingMode::post_typeck_through_borrowck`. /// But that's not compatible with the old solver yet. /// /// FIXME: this should not be needed in the long term. - pub fn post_typeck_until_borrowck_for_mir_build( + pub fn post_typeck_through_borrowck_for_mir_build( tcx: TyCtxt<'tcx>, def_id: LocalDefId, ) -> TypingEnv<'tcx> { - if tcx.use_typing_mode_post_typeck_until_borrowck() { + if tcx.use_typing_mode_post_typeck_through_borrowck() { TypingEnv::new(tcx.param_env(def_id.to_def_id()), ty::TypingMode::borrowck(tcx, def_id)) } else { // FIXME(#132279): We're in a body, we should use a typing @@ -1210,7 +1210,7 @@ impl<'tcx> TypingEnv<'tcx> { TypingMode::Coherence | TypingMode::Reflection | TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } => {} TypingMode::PostAnalysis | TypingMode::Codegen => return self.as_query_input(value), } @@ -1235,7 +1235,7 @@ impl<'tcx> TypingEnv<'tcx> { TypingMode::Coherence | TypingMode::Reflection | TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis => {} TypingMode::Codegen => return self.as_query_input(value), diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 3c4888a05d6e9..7e6c9f9ac6565 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -496,7 +496,7 @@ fn construct_fn<'tcx>( ); } - let typing_mode = if tcx.use_typing_mode_post_typeck_until_borrowck() { + let typing_mode = if tcx.use_typing_mode_post_typeck_through_borrowck() { TypingMode::borrowck(tcx, fn_def) } else { // FIXME(#132279): This should be able to reveal opaque @@ -606,7 +606,7 @@ fn construct_const<'a, 'tcx>( _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def), }; - let typing_mode = if tcx.use_typing_mode_post_typeck_until_borrowck() { + let typing_mode = if tcx.use_typing_mode_post_typeck_through_borrowck() { TypingMode::borrowck(tcx, def) } else { // FIXME(#132279): This should be able to reveal opaque diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 06f48e3ccebe2..fd1215cfdad9b 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -960,7 +960,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { tcx: self.tcx, typeck_results, module: self.tcx.parent_module(self.hir_id), - typing_env: ty::TypingEnv::post_typeck_until_borrowck_for_mir_build( + typing_env: ty::TypingEnv::post_typeck_through_borrowck_for_mir_build( self.tcx, self.def_id, ), diff --git a/compiler/rustc_mir_build/src/check_tail_calls.rs b/compiler/rustc_mir_build/src/check_tail_calls.rs index 5d421f6c3c885..881b50de017f8 100644 --- a/compiler/rustc_mir_build/src/check_tail_calls.rs +++ b/compiler/rustc_mir_build/src/check_tail_calls.rs @@ -25,7 +25,7 @@ pub(crate) fn check_tail_calls(tcx: TyCtxt<'_>, def: LocalDefId) -> Result<(), E tcx, thir, found_errors: Ok(()), - typing_env: ty::TypingEnv::post_typeck_until_borrowck_for_mir_build(tcx, def), + typing_env: ty::TypingEnv::post_typeck_through_borrowck_for_mir_build(tcx, def), is_closure, caller_def_id: def, }; diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index e83c3560a1ee9..f1423c2c4b152 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -1091,7 +1091,7 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { body_target_features, assignment_info: None, in_union_destructure: false, - typing_env: ty::TypingEnv::post_typeck_until_borrowck_for_mir_build(tcx, def), + typing_env: ty::TypingEnv::post_typeck_through_borrowck_for_mir_build(tcx, def), inside_adt: false, warnings: &mut warnings, suggest_unsafe_block: true, diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index ad1227bb51df0..c2a8fa9c31cea 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -107,7 +107,7 @@ impl<'tcx> ThirBuildCx<'tcx> { Self { tcx, thir: Thir::new(body_type), - typing_env: ty::TypingEnv::post_typeck_until_borrowck_for_mir_build(tcx, def), + typing_env: ty::TypingEnv::post_typeck_through_borrowck_for_mir_build(tcx, def), typeck_results, body_owner: def.to_def_id(), apply_adjustments: !find_attr!(tcx, hir_id, CustomMir(..)), diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index b434bd17e2d8e..72c2ffbe957e7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -37,7 +37,7 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err tcx, thir: &*thir, typeck_results, - typing_env: ty::TypingEnv::post_typeck_until_borrowck_for_mir_build(tcx, def_id), + typing_env: ty::TypingEnv::post_typeck_through_borrowck_for_mir_build(tcx, def_id), hir_source: tcx.local_def_id_to_hir_id(def_id), let_source: LetSource::None, pattern_arena: &pattern_arena, diff --git a/compiler/rustc_mir_transform/src/coverage/expansion.rs b/compiler/rustc_mir_transform/src/coverage/expansion.rs index 5e8d261ae1f41..237392c583803 100644 --- a/compiler/rustc_mir_transform/src/coverage/expansion.rs +++ b/compiler/rustc_mir_transform/src/coverage/expansion.rs @@ -106,14 +106,14 @@ pub(crate) fn build_expn_tree( let raw_spans = from_mir::extract_raw_spans_from_mir(mir_body, hir_info, graph); let mut nodes = FxIndexMap::default(); - let new_node = |&context: &SyntaxContext| ExpnNode::for_context(context); + let new_node = |context: SyntaxContext| ExpnNode::for_context(context); for from_mir::RawSpanFromMir { raw_span, bcb } in raw_spans { let span_with_bcb = SpanWithBcb { span: raw_span, bcb }; // Create a node for this span's enclosing expansion, and add the span to it. let context = span_with_bcb.span.ctxt(); - let node = nodes.entry(context).or_insert_with_key(new_node); + let node = nodes.entry(context).or_insert_with_key(|&c| new_node(c)); node.spans.push(span_with_bcb); // Now walk up the expansion call-site chain, creating nodes and registering children. @@ -123,7 +123,7 @@ pub(crate) fn build_expn_tree( let entry = nodes.entry(context); let node_existed = matches!(entry, IndexEntry::Occupied(_)); - let node = entry.or_insert_with_key(new_node); + let node = entry.or_insert_with_key(|&c| new_node(c)); node.child_contexts.insert(prev); if node_existed { diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index 53739284f8c0f..6f4a98b1765e8 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -770,7 +770,7 @@ where ty::TypingMode::Coherence | ty::TypingMode::Reflection | ty::TypingMode::Typeck { .. } - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } => { bug!() } diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index d74581b00980d..07215976ef9f3 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -137,8 +137,8 @@ impl<'tcx> crate::MirPass<'tcx> for GVN { let typing_env = body.typing_env(tcx); let ssa = SsaLocals::new(tcx, body, typing_env); - // Clone dominators because we need them while mutating the body. - let dominators = body.basic_blocks.dominators().clone(); + let cfg_cache = body.basic_blocks.cfg_cache(); + let dominators = cfg_cache.dominators(&body.basic_blocks); let arena = DroplessArena::default(); let mut state = @@ -149,8 +149,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN { state.assign(local, opaque); } - let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec(); - for bb in reverse_postorder { + for &bb in cfg_cache.reverse_postorder(&body.basic_blocks) { let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb]; state.visit_basic_block_data(bb, data); } @@ -395,7 +394,7 @@ struct VnState<'body, 'a, 'tcx> { /// - `Some(Some(op))` are successful computations. evaluated: IndexVec>>>, ssa: &'body SsaLocals, - dominators: Dominators, + dominators: &'a Dominators, reused_locals: DenseBitSet, arena: &'a DroplessArena, } @@ -406,7 +405,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { body: &Body<'tcx>, typing_env: ty::TypingEnv<'tcx>, ssa: &'body SsaLocals, - dominators: Dominators, + dominators: &'a Dominators, local_decls: &'body LocalDecls<'tcx>, arena: &'a DroplessArena, ) -> Self { diff --git a/compiler/rustc_mir_transform/src/ssa_range_prop.rs b/compiler/rustc_mir_transform/src/ssa_range_prop.rs index e6df6bbd9fb4e..f854e4c5a8d3c 100644 --- a/compiler/rustc_mir_transform/src/ssa_range_prop.rs +++ b/compiler/rustc_mir_transform/src/ssa_range_prop.rs @@ -13,7 +13,7 @@ use rustc_abi::WrappingRange; use rustc_const_eval::interpret::Scalar; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::dominators::Dominators; -use rustc_index::bit_set::DenseBitSet; +use rustc_middle::mir::basic_blocks::Predecessors; use rustc_middle::mir::visit::MutVisitor; use rustc_middle::mir::{BasicBlock, Body, Location, Operand, Place, TerminatorKind, *}; use rustc_middle::ty::{TyCtxt, TypingEnv}; @@ -32,13 +32,13 @@ impl<'tcx> crate::MirPass<'tcx> for SsaRangePropagation { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let typing_env = body.typing_env(tcx); let ssa = SsaLocals::new(tcx, body, typing_env); - // Clone dominators because we need them while mutating the body. - let dominators = body.basic_blocks.dominators().clone(); + let cfg_cache = body.basic_blocks.cfg_cache(); + let dominators = cfg_cache.dominators(&body.basic_blocks); + let predecessors = cfg_cache.predecessors(&body.basic_blocks); let mut range_set = - RangeSet::new(tcx, typing_env, body, &ssa, &body.local_decls, dominators); + RangeSet::new(tcx, typing_env, &ssa, &body.local_decls, dominators, predecessors); - let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec(); - for bb in reverse_postorder { + for &bb in cfg_cache.reverse_postorder(&body.basic_blocks) { let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb]; range_set.visit_basic_block_data(bb, data); } @@ -50,29 +50,21 @@ struct RangeSet<'tcx, 'body, 'a> { typing_env: TypingEnv<'tcx>, ssa: &'a SsaLocals, local_decls: &'body LocalDecls<'tcx>, - dominators: Dominators, + dominators: &'a Dominators, /// Known ranges at each locations. ranges: FxHashMap, Vec<(Location, WrappingRange)>>, - /// Determines if the basic block has a single unique predecessor. - unique_predecessors: DenseBitSet, + predecessors: &'a Predecessors, } impl<'tcx, 'body, 'a> RangeSet<'tcx, 'body, 'a> { fn new( tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>, - body: &Body<'tcx>, ssa: &'a SsaLocals, local_decls: &'body LocalDecls<'tcx>, - dominators: Dominators, + dominators: &'a Dominators, + predecessors: &'a Predecessors, ) -> Self { - let predecessors = body.basic_blocks.predecessors(); - let mut unique_predecessors = DenseBitSet::new_empty(body.basic_blocks.len()); - for bb in body.basic_blocks.indices() { - if predecessors[bb].len() == 1 { - unique_predecessors.insert(bb); - } - } RangeSet { tcx, typing_env, @@ -80,10 +72,14 @@ impl<'tcx, 'body, 'a> RangeSet<'tcx, 'body, 'a> { local_decls, dominators, ranges: FxHashMap::default(), - unique_predecessors, + predecessors, } } + fn has_unique_predecessor(&self, bb: BasicBlock) -> bool { + self.predecessors[bb].len() == 1 + } + /// Create a new known range at the location. fn insert_range(&mut self, place: Place<'tcx>, location: Location, range: WrappingRange) { assert!(self.is_ssa(place)); @@ -187,7 +183,7 @@ impl<'tcx> MutVisitor<'tcx> for RangeSet<'tcx, '_, '_> { continue; } let successor = target.start_location(); - if self.unique_predecessors.contains(successor.block) { + if self.has_unique_predecessor(successor.block) { assert_ne!(location.block, successor.block); let range = WrappingRange { start: val, end: val }; self.insert_range(place, successor, range); @@ -199,7 +195,7 @@ impl<'tcx> MutVisitor<'tcx> for RangeSet<'tcx, '_, '_> { let otherwise = targets.otherwise().start_location(); if place.ty(self.local_decls, self.tcx).ty.is_bool() && let [val] = targets.all_values() - && self.unique_predecessors.contains(otherwise.block) + && self.has_unique_predecessor(otherwise.block) { assert_ne!(location.block, otherwise.block); let range = if val.get() == 0 { diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 5262f849bf764..dcab703546a7e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -529,7 +529,7 @@ where let assemble_impls = match self.typing_mode() { TypingMode::Coherence => true, TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::Reflection | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis @@ -1136,7 +1136,7 @@ where let opaque_types = match self.typing_mode() { TypingMode::Typeck { .. } => self.opaques_with_sub_unified_hidden_type(self_ty), TypingMode::Coherence - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis | TypingMode::Reflection diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 3b372876f574b..54f5a196b4154 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -774,7 +774,7 @@ where let skip_erased_attempt = match typing_mode { TypingMode::Reflection | TypingMode::Coherence => true, TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } | TypingMode::Codegen | TypingMode::PostAnalysis @@ -1963,7 +1963,7 @@ fn should_rerun_after_erased_canonicalization( RerunCondition::OpaqueInStorage(defids), TypingMode::PostBorrowck { defined_opaque_types: opaques } | TypingMode::Typeck { defining_opaque_types_and_generators: opaques } - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: opaques }, + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: opaques }, ) => opaque_in_storage(opaques, defids), // ============================= (RerunCondition::AnyOpaqueHasInferAsHidden, TypingMode::Typeck { .. }) => { @@ -1975,7 +1975,7 @@ fn should_rerun_after_erased_canonicalization( | TypingMode::PostAnalysis | TypingMode::Codegen | TypingMode::Reflection - | TypingMode::PostTypeckUntilBorrowck { .. }, + | TypingMode::PostTypeckThroughBorrowck { .. }, ) => RerunDecision::No, // ============================= ( @@ -1997,7 +1997,7 @@ fn should_rerun_after_erased_canonicalization( ( RerunCondition::OpaqueInStorageOrAnyOpaqueHasInferAsHidden(defids), TypingMode::PostBorrowck { defined_opaque_types: opaques } - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: opaques }, + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: opaques }, ) => opaque_in_storage(opaques, defids), } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs index f8c4597dce654..49e5744cfe46c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs @@ -350,7 +350,7 @@ where } // Outside of coherence, we treat the associated item as rigid instead. ty::TypingMode::Typeck { .. } - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::PostAnalysis | ty::TypingMode::Reflection diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs index 675477ca7180a..08a602d78f354 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals/opaque_types.rs @@ -41,7 +41,7 @@ where self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } TypingMode::Typeck { defining_opaque_types_and_generators: defining_opaque_types } - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types } => { + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types } => { let Some(def_id) = def_id .as_local() .filter(|&def_id| defining_opaque_types.contains(&def_id.into())) @@ -86,7 +86,7 @@ where // computed in HIR typeck as the initial value. match self.typing_mode().assert_not_erased() { TypingMode::Typeck { .. } => {} - TypingMode::PostTypeckUntilBorrowck { .. } => { + TypingMode::PostTypeckThroughBorrowck { .. } => { let actual = cx .type_of_opaque_hir_typeck(def_id) .instantiate(cx, opaque_ty.args); diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 1d3008da399dc..22e68c99d2cb6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -1354,7 +1354,7 @@ where // We're inferring regions of opaque types, but // the type itself is already fully known, no way // to leak the hidden type. - TypingMode::PostTypeckUntilBorrowck { .. } => {} + TypingMode::PostTypeckThroughBorrowck { .. } => {} // We're inferring the hidden type of opaques, could // leak types through it. TypingMode::Typeck { .. } => { @@ -1799,7 +1799,7 @@ where | TypingMode::PostAnalysis | TypingMode::Reflection | TypingMode::Codegen - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: _ } + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: _ } | TypingMode::PostBorrowck { defined_opaque_types: _ } => {} } } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 5a96c0524c093..96d4e4ad82468 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -3406,7 +3406,7 @@ pub(crate) mod dep_tracking { use rustc_abi::Align; use rustc_ast::attr::version::RustcVersion; use rustc_data_structures::fx::FxIndexMap; - use rustc_data_structures::stable_hash::StableHasher; + use rustc_data_structures::stable_hash::{DummyStableHashCtxt, StableHash, StableHasher}; use rustc_errors::LanguageIdentifier; use rustc_feature::UnstableFeatures; use rustc_hashes::Hash64; @@ -3469,73 +3469,73 @@ pub(crate) mod dep_tracking { } impl_dep_tracking_hash_via_hash!( + // tidy-alphabetical-start (), + Align, AnnotateMoves, AutoDiff, - Offload, - bool, - usize, - NonZero, - u64, - Hash64, - String, - PathBuf, - lint::Level, - WasiExecModel, - u32, - FramePointer, - RelocModel, + BranchProtection, + CFGuard, + CFProtection, CodeModel, - TlsModel, - InstrumentCoverage, + CodegenRetagOptions, + CollapseMacroDebuginfo, CoverageOptions, + CrateType, + DebugInfo, + DebugInfoCompression, + Edition, + FmtDebug, + FramePointer, + FunctionReturn, + Hash64, + InliningThreshold, + InstrumentCoverage, InstrumentMcount, InstrumentMcountOpts, InstrumentXRay, - CrateType, + LanguageIdentifier, + LinkerPluginLto, + LocationDetail, + LtoCli, MergeFunctions, + MirStripDebugInfo, + NativeLib, + NextSolverConfig, + NonZero, + Offload, OnBrokenPipe, + OptLevel, + OutFileName, + OutputType, PanicStrategy, + PatchableFunctionEntry, + PointerAuthOption, + Polonius, + RelocModel, RelroLevel, - OptLevel, - LtoCli, - DebugInfo, - DebugInfoCompression, - MirStripDebugInfo, - CollapseMacroDebuginfo, - UnstableFeatures, - NativeLib, - SanitizerSet, - CFGuard, - CFProtection, - TargetTuple, - Edition, - LinkerPluginLto, + RemapPathScopeComponents, ResolveDocLinks, + RustcVersion, + SanitizerSet, + SourceFileHashAlgorithm, SplitDebuginfo, SplitDwarfKind, StackProtector, + String, SwitchWithOptPath, SymbolManglingVersion, SymbolVisibility, - RemapPathScopeComponents, - SourceFileHashAlgorithm, - OutFileName, - OutputType, - RealFileName, - LocationDetail, - FmtDebug, - BranchProtection, - LanguageIdentifier, - NextSolverConfig, - PatchableFunctionEntry, - Polonius, - InliningThreshold, - FunctionReturn, - Align, - CodegenRetagOptions, - RustcVersion, - PointerAuthOption, + TargetTuple, + TlsModel, + UnstableFeatures, + WasiExecModel, + bool, + lint::Level, + u32, + u64, + usize, + // tidy-alphabetical-end ); impl DepTrackingHash for (T1, T2) @@ -3624,6 +3624,28 @@ pub(crate) mod dep_tracking { } } + impl DepTrackingHash for PathBuf { + fn hash( + &self, + hasher: &mut StableHasher, + _error_format: ErrorOutputType, + _for_crate_hash: bool, + ) { + self.stable_hash(&mut DummyStableHashCtxt, hasher); + } + } + + impl DepTrackingHash for RealFileName { + fn hash( + &self, + hasher: &mut StableHasher, + _error_format: ErrorOutputType, + _for_crate_hash: bool, + ) { + self.stable_hash(&mut DummyStableHashCtxt, hasher); + } + } + // This is a stable hash because BTreeMap is a sorted container pub(crate) fn stable_hash( sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index a2127ee0eae78..9ac479e8abe51 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2966,9 +2966,6 @@ written to standard error output)"), "in diagnostics, use heuristics to shorten paths referring to items"), tune_cpu: Option = (None, parse_opt_string, [TRACKED], "select processor to schedule for (`rustc --print target-cpus` for details)"), - #[rustc_lint_opt_deny_field_access("use `TyCtxt::use_typing_mode_post_typeck` instead of this field")] - typing_mode_post_typeck_until_borrowck: bool = (false, parse_bool, [TRACKED], - "enable `TypingMode::PostTypeckUntilBorrowck`, changing the way opaque types are handled during MIR borrowck"), #[rustc_lint_opt_deny_field_access("use `Session::ub_checks` instead of this field")] ub_checks: Option = (None, parse_opt_bool, [TRACKED], "emit runtime checks for Undefined Behavior (default: -Cdebug-assertions)"), diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index c107f6ce4f64c..180dd9061aba2 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -26,6 +26,7 @@ use std::cell::RefCell; use std::hash::{Hash, Hasher}; +use std::marker::PhantomData; use std::sync::Arc; use std::{fmt, iter, mem}; @@ -48,24 +49,14 @@ use crate::source_map::SourceMap; use crate::symbol::{Symbol, kw, sym}; use crate::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, with_session_globals}; -/// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks". -/// -/// See for more explanation. -#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)] -pub struct SyntaxContext(u32); - -impl From for SyntaxContext { - #[inline(always)] - fn from(value: u32) -> SyntaxContext { - SyntaxContext(value) - } -} - -impl Into for SyntaxContext { - #[inline(always)] - fn into(self) -> u32 { - self.0 - } +rustc_index::newtype_index! { + /// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks". + /// + /// See for more explanation. + #[max = 0x1FFF_FFFF] // `u32::MAX` >> 3, as `SyntaxContext` should be fit in 29 bits (see `span_encoding`). + #[debug_format = "#{}"] + #[default] + pub struct SyntaxContext {} } // To ensure correctness of incremental compilation, @@ -363,19 +354,26 @@ impl ExpnId { } #[derive(Default)] -pub struct HygieneRemappingResults { - pub remapping: FxHashMap, - pub first_non_det_index: T, +pub struct HygieneRemappingResults { + remapping: FxHashMap, + first_non_det_index: u32, + data: PhantomData<(TKey, TRemappedKey)>, } -impl + Copy> HygieneRemappingResults { +pub trait RemappableIdx = Hash + Eq + Copy; +impl, TRemappedKey: RemappableIdx + From> + HygieneRemappingResults +{ #[inline] - pub fn map_id(&self, idx: T) -> T { - if idx.into() < self.first_non_det_index.into() { - idx + pub fn map_id(&self, idx: TKey) -> TRemappedKey { + let raw_idx: u32 = idx.into(); + let remapped_idx = if raw_idx < self.first_non_det_index { + raw_idx } else { - self.remapping.get(&idx).copied().unwrap_or(idx) - } + self.remapping.get(&raw_idx).copied().unwrap_or(raw_idx) + }; + + TRemappedKey::from(remapped_idx) } } @@ -399,33 +397,36 @@ pub trait HygieneRemapper { assert!(prev.is_none(), "this function can be called only once") } - fn remapping_results(&self, hcx: &mut impl StableHashCtxt) -> HygieneRemappingResults + fn remapping_results( + &self, + hcx: &mut impl StableHashCtxt, + ) -> HygieneRemappingResults where - T: From + Hash + Eq + Copy, + T: RemappableIdx + From, { let start = self.first_non_det_index(); let range = start..self.len() as u32; - let mut indices_to_remap = range.map(|raw_id| T::from(raw_id)).collect::>(); + let mut indices_to_remap = range.collect::>(); indices_to_remap.sort_by_cached_key(|&key| { let hasher = &mut StableHasher::new(); - self.stable_hash(key, hcx, hasher); + self.stable_hash(T::from(key), hcx, hasher); hasher.finish() }); - let mut remapping = FxHashMap::::default(); + let mut remapping = FxHashMap::default(); for (idx, key) in indices_to_remap.into_iter().enumerate() { let from = key; - let to = T::from(start + idx as u32); + let to = start + idx as u32; if from != to { remapping.insert(from, to); } } - HygieneRemappingResults { remapping, first_non_det_index: T::from(start) } + HygieneRemappingResults { remapping, first_non_det_index: start, data: PhantomData } } } @@ -509,7 +510,7 @@ pub(crate) struct HygieneData { foreign_expn_data: FxHashMap, foreign_expn_hashes: FxHashMap, expn_hash_to_expn_id: UnhashMap, - syntax_context_data: Vec, + syntax_context_data: IndexVec, first_non_det_syntax_context: Option, first_non_det_local_expn_id: Option, syntax_context_map: FxHashMap, @@ -541,8 +542,8 @@ impl HygieneData { foreign_expn_hashes: FxHashMap::default(), expn_hash_to_expn_id: iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root())) .collect(), - syntax_context_data: vec![root_ctxt_data], - syntax_context_map: iter::once((root_ctxt_data.key(), SyntaxContext(0))).collect(), + syntax_context_data: IndexVec::from_elem_n(root_ctxt_data, 1), + syntax_context_map: iter::once((root_ctxt_data.key(), SyntaxContext::root())).collect(), expn_data_disambiguators: UnhashMap::default(), first_non_det_syntax_context: None, first_non_det_local_expn_id: None, @@ -596,30 +597,30 @@ impl HygieneData { #[inline] fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext { - self.syntax_context_data[ctxt.0 as usize].opaque + self.syntax_context_data[ctxt].opaque } #[inline] fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext { - self.syntax_context_data[ctxt.0 as usize].opaque_and_semiopaque + self.syntax_context_data[ctxt].opaque_and_semiopaque } /// See [`SyntaxContextData::outer_expn`] #[inline] fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId { - self.syntax_context_data[ctxt.0 as usize].outer_expn + self.syntax_context_data[ctxt].outer_expn } /// The last macro expansion and its Transparency #[inline] fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) { - let data = &self.syntax_context_data[ctxt.0 as usize]; + let data = &self.syntax_context_data[ctxt]; (data.outer_expn, data.outer_transparency) } #[inline] fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext { - self.syntax_context_data[ctxt.0 as usize].parent + self.syntax_context_data[ctxt].parent } fn remove_mark(&self, ctxt: &mut SyntaxContext) -> (ExpnId, Transparency) { @@ -738,15 +739,16 @@ impl HygieneData { // Reserve a new syntax context. // The inserted dummy data can only be potentially accessed by nested `alloc_ctxt` calls, // the assert below ensures that it doesn't happen. - let ctxt = SyntaxContext::from_usize(self.syntax_context_data.len()); - self.syntax_context_data + let ctxt = self + .syntax_context_data .push(SyntaxContextData { dollar_crate_name: sym::dummy, ..SyntaxContextData::root() }); + self.syntax_context_map.insert(key, ctxt); // Opaque and semi-opaque versions of the parent. Note that they may be equal to the // parent itself. E.g. `parent_opaque` == `parent` if the expn chain contains only opaques, // and `parent_opaque_and_semiopaque` == `parent` if the expn contains only (semi-)opaques. - let parent_data = &self.syntax_context_data[parent.0 as usize]; + let parent_data = &self.syntax_context_data[parent]; assert_ne!(parent_data.dollar_crate_name, sym::dummy); let parent_opaque = parent_data.opaque; let parent_opaque_and_semiopaque = parent_data.opaque_and_semiopaque; @@ -768,7 +770,7 @@ impl HygieneData { }; // Fill the full data, now that we have it. - self.syntax_context_data[ctxt.as_u32() as usize] = SyntaxContextData { + self.syntax_context_data[ctxt] = SyntaxContextData { outer_expn: expn_id, outer_transparency: transparency, parent, @@ -797,7 +799,7 @@ pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symb // The new contexts that need updating are at the end of the list and have `$crate` as a name. let mut to_update = vec![]; HygieneData::with(|data| { - for (idx, scdata) in data.syntax_context_data.iter().enumerate().rev() { + for (idx, scdata) in data.syntax_context_data.iter_enumerated().rev() { if scdata.dollar_crate_name == kw::DollarCrate { to_update.push((idx, kw::DollarCrate)); } else { @@ -807,12 +809,12 @@ pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symb }); // The callback must be called from outside of the `HygieneData` lock, // since it will try to acquire it too. - for (idx, name) in &mut to_update { - *name = get_name(SyntaxContext::from_usize(*idx)); + for (ctxt, name) in &mut to_update { + *name = get_name(*ctxt); } HygieneData::with(|data| { - for (idx, name) in to_update { - data.syntax_context_data[idx].dollar_crate_name = name; + for (ctxt, name) in to_update { + data.syntax_context_data[ctxt].dollar_crate_name = name; } }) } @@ -857,29 +859,14 @@ pub fn debug_hygiene_data(verbose: bool) -> String { } impl SyntaxContext { - #[inline] - pub const fn root() -> Self { - SyntaxContext(0) + #[inline(always)] + pub const fn root() -> SyntaxContext { + SyntaxContext::from_u32(0) } #[inline] pub const fn is_root(self) -> bool { - self.0 == SyntaxContext::root().as_u32() - } - - #[inline] - pub const fn as_u32(self) -> u32 { - self.0 - } - - #[inline] - pub(crate) const fn from_u32(raw: u32) -> SyntaxContext { - SyntaxContext(raw) - } - - #[inline] - fn from_usize(raw: usize) -> SyntaxContext { - SyntaxContext(u32::try_from(raw).unwrap()) + self.as_u32() == SyntaxContext::root().as_u32() } /// Extend a syntax context with a given expansion and transparency. @@ -1070,7 +1057,7 @@ impl SyntaxContext { #[inline] pub(crate) fn dollar_crate_name(self) -> Symbol { - HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name) + HygieneData::with(|data| data.syntax_context_data[self].dollar_crate_name) } #[inline] @@ -1107,12 +1094,6 @@ impl SyntaxContext { } } -impl fmt::Debug for SyntaxContext { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "#{}", self.0) - } -} - impl Span { /// Reuses the span but adds information like the kind of the desugaring and features that are /// allowed inside this span. @@ -1495,7 +1476,7 @@ impl HygieneEncodeContext { let latest_contexts = { mem::take(&mut h_ctxt.borrow_mut().latest_ctxts) }.into_iter(); for ctxt in latest_contexts { - let key = HygieneData::with(|data| data.syntax_context_data[ctxt.0 as usize].key()); + let key = HygieneData::with(|data| data.syntax_context_data[ctxt].key()); encode_ctxt(encoder, ctxt, &key); } @@ -1532,7 +1513,7 @@ impl HygieneEncodeContext { pub struct HygieneDecodeContext { // A cache mapping raw serialized per-crate syntax context ids to corresponding decoded // `SyntaxContext`s in the current global `HygieneData`. - remapped_ctxts: Lock>>, + remapped_ctxts: Lock>>, } /// Register an expansion which has been decoded from the on-disk-cache for the local crate. @@ -1599,6 +1580,22 @@ pub fn decode_expn_id( register_expn_id(krate, index, expn_data, hash) } +rustc_index::newtype_index! { + /// A syntax context that is obtained from metadata of an external crate and + /// was not yet remapped to local `SyntaxContext`. + #[encodable] + #[max = 0x1FFF_FFFF] // `u32::MAX` >> 3, as `SyntaxContext` should be fit in 29 bits (see `span_encoding`). + #[debug_format = "#decoded{}"] + pub struct DecodedSyntaxContext {} +} + +impl DecodedSyntaxContext { + #[inline(always)] + fn is_root(self) -> bool { + self.as_u32() == 0 + } +} + // Decodes `SyntaxContext`, using the provided `HygieneDecodeContext` // to track which `SyntaxContext`s we have already decoded. // The provided closure will be invoked to deserialize a `SyntaxContextData` @@ -1606,10 +1603,10 @@ pub fn decode_expn_id( pub fn decode_syntax_context( d: &mut D, context: &HygieneDecodeContext, - decode_data: impl FnOnce(&mut D, u32) -> SyntaxContextKey, + decode_data: impl FnOnce(&mut D, DecodedSyntaxContext) -> SyntaxContextKey, ) -> SyntaxContext { - let raw_id: u32 = Decodable::decode(d); - if raw_id == 0 { + let decoded_ctxt: DecodedSyntaxContext = Decodable::decode(d); + if decoded_ctxt.is_root() { trace!("decode_syntax_context: deserialized root"); // The root is special return SyntaxContext::root(); @@ -1618,19 +1615,19 @@ pub fn decode_syntax_context( // Look into the cache first. // Reminder: `HygieneDecodeContext` is per-crate, so there are no collisions between // raw ids from different crate metadatas. - if let Some(Some(ctxt)) = context.remapped_ctxts.lock().get(raw_id) { + if let Some(Some(ctxt)) = context.remapped_ctxts.lock().get(decoded_ctxt) { return *ctxt; } // Don't try to decode data while holding the lock, since we need to // be able to recursively decode a SyntaxContext - let (parent, expn_id, transparency) = decode_data(d, raw_id); - let ctxt = + let (parent, expn_id, transparency) = decode_data(d, decoded_ctxt); + let remapped_ctxt = HygieneData::with(|hygiene_data| hygiene_data.alloc_ctxt(parent, expn_id, transparency)); - context.remapped_ctxts.lock().insert(raw_id, ctxt); + context.remapped_ctxts.lock().insert(decoded_ctxt, remapped_ctxt); - ctxt + remapped_ctxt } impl Encodable for LocalExpnId { diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f0b53eac061ea..914cb6f02b577 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -25,6 +25,7 @@ #![feature(negative_impls)] #![feature(read_buf)] #![feature(rustc_attrs)] +#![feature(trait_alias)] // tidy-alphabetical-end // The code produced by the `Encodable`/`Decodable` derive macros refer to @@ -32,7 +33,7 @@ // this crate without this line making `rustc_span` available. extern crate self as rustc_span; -use rustc_data_structures::stable_hash::StableHashCtxt; +use rustc_data_structures::stable_hash::{DummyStableHashCtxt, StableHashCtxt}; use rustc_data_structures::{AtomicRef, outline}; use rustc_macros::{Decodable, Encodable, StableHash}; use rustc_serialize::opaque::mem_encoder::MemEncoder; @@ -317,7 +318,7 @@ pub struct RealFileName { /// The inner workings of `RealFileName`. /// /// It contains the `name`, `working_directory` and `embeddable_name` components. -#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable, Encodable, Hash)] +#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, StableHash, Decodable, Encodable)] struct InnerRealFileName { /// The name. name: PathBuf, @@ -327,18 +328,18 @@ struct InnerRealFileName { embeddable_name: PathBuf, } -impl Hash for RealFileName { - #[inline] - fn hash(&self, state: &mut H) { +impl StableHash for RealFileName { + fn stable_hash(&self, hcx: &mut Hcx, hasher: &mut StableHasher) { + let RealFileName { local, maybe_remapped, scopes } = self; // To prevent #70924 from happening again we should only hash the // remapped path if that exists. This is because remapped paths to // sysroot crates (/rust/$hash or /rust/$version) remain stable even // if the corresponding local path changes. if !self.was_fully_remapped() { - self.local.hash(state); + local.stable_hash(hcx, hasher); } - self.maybe_remapped.hash(state); - self.scopes.bits().hash(state); + maybe_remapped.stable_hash(hcx, hasher); + scopes.bits().stable_hash(hcx, hasher); } } @@ -507,7 +508,7 @@ impl RealFileName { } /// Differentiates between real files and common virtual files. -#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, Decodable, Encodable)] +#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, StableHash, Decodable, Encodable)] pub enum FileName { Real(RealFileName), /// Strings provided as `--cfg [cfgspec]`. @@ -2207,8 +2208,8 @@ impl StableSourceFileId { stable_crate_id: Option, ) -> Self { let mut hasher = StableHasher::new(); - filename.hash(&mut hasher); - stable_crate_id.hash(&mut hasher); + filename.stable_hash(&mut DummyStableHashCtxt, &mut hasher); + stable_crate_id.stable_hash(&mut DummyStableHashCtxt, &mut hasher); StableSourceFileId(hasher.finish()) } } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 29563c0262621..d1064ba03948d 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -463,7 +463,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< match typing_mode { TypingMode::Coherence | TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::Reflection | TypingMode::PostBorrowck { .. } => false, TypingMode::PostAnalysis | TypingMode::Codegen => { diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 5e834c8c4059d..7b09baf7fe03e 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -328,7 +328,7 @@ where defining_opaque_types_and_generators } TypingMode::Coherence - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: _ } + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: _ } | TypingMode::PostBorrowck { defined_opaque_types: _ } | TypingMode::Reflection | TypingMode::PostAnalysis diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index ba480654bd84a..cf77d061d2baa 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -175,7 +175,7 @@ where TypingMode::Typeck { defining_opaque_types_and_generators } => { defining_opaque_types_and_generators } - TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: _ } + TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: _ } | TypingMode::PostBorrowck { defined_opaque_types: _ } | TypingMode::Reflection | TypingMode::PostAnalysis diff --git a/compiler/rustc_trait_selection/src/traits/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/implied_outlives_bounds.rs index d234f95fe7602..cc98a9ba6a935 100644 --- a/compiler/rustc_trait_selection/src/traits/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/implied_outlives_bounds.rs @@ -165,7 +165,7 @@ pub fn query_compute_implied_outlives_bounds<'tcx>( /* if cfg!(debug_assertions) { match ocx.infcx.typing_mode_raw() { TypingMode::Typeck { defining_opaque_types_and_generators: opaque_types } - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: opaque_types } + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: opaque_types } | TypingMode::PostBorrowck { defined_opaque_types: opaque_types } => { assert!(opaque_types.is_empty()) } diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 63f7c6dfc94fc..0eeb9f9ed976e 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -140,7 +140,7 @@ pub(super) fn needs_normalization<'tcx, T: TypeVisitable>>( match infcx.typing_mode_raw().assert_not_erased() { // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } => flags.remove(ty::TypeFlags::HAS_TY_OPAQUE), TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => {} TypingMode::Coherence => { @@ -429,7 +429,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx match self.selcx.typing_mode() { // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } => ty.super_fold_with(self), TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => { let recursion_limit = self.cx().recursion_limit(); diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 6cea4a9300824..5d7be99f7907a 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1035,7 +1035,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // get a result which isn't correct for all monomorphizations. match selcx.typing_mode() { TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::Reflection | TypingMode::PostBorrowck { .. } => { debug!( diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index b4dffab26d1e4..aee900937f4cc 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -232,7 +232,7 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { // Only normalize `impl Trait` outside of type inference, usually in codegen. match self.infcx.typing_mode_raw().assert_not_erased() { TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } => ty.try_super_fold_with(self)?, TypingMode::Reflection | TypingMode::PostAnalysis | TypingMode::Codegen => { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 05b4ba6a7180c..432fa2e142d88 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1389,7 +1389,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // This is likely fixed by better caching in general in the new solver. // See: . TypingMode::Typeck { defining_opaque_types_and_generators: defining_opaque_types } - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types } => { + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types } => { defining_opaque_types.is_empty() || (!pred.has_opaque_types() && !pred.has_coroutines()) } @@ -2435,7 +2435,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } | TypingMode::Codegen | TypingMode::ErasedNotCoherence(_) @@ -2787,7 +2787,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { TypingMode::PostAnalysis | TypingMode::Reflection | TypingMode::Codegen - | TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: _ } + | TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: _ } | TypingMode::PostBorrowck { defined_opaque_types: _ } => false, TypingMode::Coherence => { unreachable!("old solver coherence") diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 1a868ba4b8cee..0ded7482bb6c4 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -163,7 +163,7 @@ fn resolve_associated_item<'tcx>( match typing_env.typing_mode().assert_not_erased() { ty::TypingMode::Coherence | ty::TypingMode::Typeck { .. } - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::Reflection | ty::TypingMode::PostBorrowck { .. } => false, ty::TypingMode::PostAnalysis | ty::TypingMode::Codegen => { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index bcae974daab7e..83f9f6d2f87f0 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -85,7 +85,7 @@ fn layout_of<'tcx>( } ty::TypingMode::Coherence | ty::TypingMode::Typeck { .. } - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::Reflection | ty::TypingMode::ErasedNotCoherence(_) @@ -551,7 +551,7 @@ fn layout_of_uncached<'tcx>( ty::TypingMode::Codegen => {} ty::TypingMode::Coherence | ty::TypingMode::Typeck { .. } - | ty::TypingMode::PostTypeckUntilBorrowck { .. } + | ty::TypingMode::PostTypeckThroughBorrowck { .. } | ty::TypingMode::PostBorrowck { .. } | ty::TypingMode::Reflection | ty::TypingMode::ErasedNotCoherence(_) diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index d50f6521441d5..d6d4d27764c46 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -111,16 +111,16 @@ pub enum TypingMode { /// } /// ``` Typeck { defining_opaque_types_and_generators: I::LocalDefIds }, - /// `PostTypeckUntilBorrowck` is used after `Typeck` has finished, up to and including borrowck, + /// `PostTypeckThroughBorrowck` is used after `Typeck` has finished, up to and including borrowck, /// for anything that accesses typeck results. This is the behavior that's used mainly in borrowck, /// but, for example, also in late lints and other analyses while building MIR. The behavior of - /// `PostTypeckUntilBorrowck` is identical to `TypingMode::Typeck` except that the initial value for + /// `PostTypeckThroughBorrowck` is identical to `TypingMode::Typeck` except that the initial value for /// opaque types is the type computed during HIR typeck with unique unconstrained region inference variables. /// /// This is currently only used by the new solver as it results in new /// non-universal defining uses of opaque types, which is a breaking change. /// See tests/ui/impl-trait/non-defining-use/as-projection-term.rs. - PostTypeckUntilBorrowck { defining_opaque_types: I::LocalDefIds }, + PostTypeckThroughBorrowck { defining_opaque_types: I::LocalDefIds }, /// Any analysis after borrowck for a given body should be able to use all the /// hidden types defined by borrowck, without being able to define any new ones. /// @@ -191,8 +191,8 @@ impl PartialEq for TypingModeEqWrapper { TypingMode::Typeck { defining_opaque_types_and_generators: r }, ) => l == r, ( - TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: l }, - TypingMode::PostTypeckUntilBorrowck { defining_opaque_types: r }, + TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: l }, + TypingMode::PostTypeckThroughBorrowck { defining_opaque_types: r }, ) => l == r, ( TypingMode::PostBorrowck { defined_opaque_types: l }, @@ -208,7 +208,7 @@ impl PartialEq for TypingModeEqWrapper { TypingMode::Coherence | TypingMode::Reflection | TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis | TypingMode::Codegen @@ -231,7 +231,7 @@ impl TypingMode { match self { TypingMode::Coherence => true, TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::Reflection | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis @@ -249,7 +249,7 @@ impl TypingMode { match self { TypingMode::Reflection => true, TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::Coherence | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis @@ -268,7 +268,7 @@ impl TypingMode { TypingMode::ErasedNotCoherence(_) => true, TypingMode::Coherence | TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::Reflection | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis @@ -288,8 +288,8 @@ impl TypingMode { TypingMode::Typeck { defining_opaque_types_and_generators } => { TypingMode::Typeck { defining_opaque_types_and_generators } } - TypingMode::PostTypeckUntilBorrowck { defining_opaque_types } => { - TypingMode::PostTypeckUntilBorrowck { defining_opaque_types } + TypingMode::PostTypeckThroughBorrowck { defining_opaque_types } => { + TypingMode::PostTypeckThroughBorrowck { defining_opaque_types } } TypingMode::PostBorrowck { defined_opaque_types } => { TypingMode::PostBorrowck { defined_opaque_types } @@ -333,7 +333,7 @@ impl TypingMode { if defining_opaque_types.is_empty() { TypingMode::non_body_analysis() } else { - TypingMode::PostTypeckUntilBorrowck { defining_opaque_types } + TypingMode::PostTypeckThroughBorrowck { defining_opaque_types } } } @@ -354,8 +354,8 @@ impl From> for TypingMode { TypingMode::Typeck { defining_opaque_types_and_generators } } - TypingMode::PostTypeckUntilBorrowck { defining_opaque_types } => { - TypingMode::PostTypeckUntilBorrowck { defining_opaque_types } + TypingMode::PostTypeckThroughBorrowck { defining_opaque_types } => { + TypingMode::PostTypeckThroughBorrowck { defining_opaque_types } } TypingMode::PostBorrowck { defined_opaque_types } => { TypingMode::PostBorrowck { defined_opaque_types } @@ -627,7 +627,7 @@ where match infcx.typing_mode_raw().assert_not_erased() { TypingMode::Coherence | TypingMode::Typeck { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::Reflection | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis => infcx.cx().features().feature_bound_holds_in_crate(symbol), diff --git a/compiler/rustc_type_ir/src/region_constraint.rs b/compiler/rustc_type_ir/src/region_constraint.rs index 257d0a776403e..445d9b09ba04d 100644 --- a/compiler/rustc_type_ir/src/region_constraint.rs +++ b/compiler/rustc_type_ir/src/region_constraint.rs @@ -1080,7 +1080,7 @@ fn rewrite_alias_ty_outlives_constraints_in_universe_for_eager_placeholder_handl TypingMode::Typeck { .. } | TypingMode::Reflection | TypingMode::ErasedNotCoherence { .. } - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis | TypingMode::Codegen => (), diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs index 054dff869e650..56d3c81734072 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -129,7 +129,7 @@ where } TypingMode::Typeck { .. } | TypingMode::Reflection - | TypingMode::PostTypeckUntilBorrowck { .. } + | TypingMode::PostTypeckThroughBorrowck { .. } | TypingMode::PostBorrowck { .. } | TypingMode::PostAnalysis | TypingMode::Codegen => structurally_relate_tys(relation, a, b), diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 35f8897afd4c4..e996f6684515a 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -115,7 +115,7 @@ impl AliasTyKind { /// Rigidness becomes outdated when the surrounding typing mode or param env changes, /// because further normalization might be possible. /// We should also note that rigidness can be shared within some typing mode groups -/// if the param env is the same, e.g., `Typeck/PostTypeckUntilBorrowck` and +/// if the param env is the same, e.g., `Typeck/PostTypeckThroughBorrowck` and /// `PostAnalysis/Codegen`. /// /// We always reveal auto traits for rigid aliases and this can cause query cycle in diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index c7dbc815b3434..0585ea5348c78 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -871,6 +871,7 @@ impl File { /// `restart` is set to `true`. /// /// The returned bool indicates if there are more entries or not. + /// You must only iterate the buffer if this returned `true`! /// It is an error if `self` is not a directory. /// /// # Symlinks and other reparse points @@ -892,6 +893,8 @@ impl File { buffer.capacity() as _, ); if result == 0 { + // Apparently ERROR_NO_MORE_FILES also means that the buffer is empty / was left + // unchanged. FIXME: find docs that say this. let err = api::get_last_error(); if err.code == c::ERROR_NO_MORE_FILES { Ok(false) } else { Err(err) } } else { @@ -961,8 +964,8 @@ impl<'a> Iterator for DirBuffIter<'a> { // While this is guaranteed to be aligned in documentation for // https://docs.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_id_both_dir_info // it does not seem that reality is so kind, and assuming this - // caused crashes in some cases (https://github.com/rust-lang/rust/issues/104530) - // presumably, this can be blamed on buggy filesystem drivers, but who knows. + // caused crashes in some cases (https://github.com/rust-lang/rust/issues/104530). + // Presumably, this can be blamed on buggy filesystem drivers, but who knows. let next_entry = (&raw const (*info).NextEntryOffset).read_unaligned() as usize; let length = (&raw const (*info).FileNameLength).read_unaligned() as usize; let attrs = (&raw const (*info).FileAttributes).read_unaligned(); diff --git a/library/std/src/sys/fs/windows/remove_dir_all.rs b/library/std/src/sys/fs/windows/remove_dir_all.rs index 8f89dbf1be16d..f701a22f7d6dd 100644 --- a/library/std/src/sys/fs/windows/remove_dir_all.rs +++ b/library/std/src/sys/fs/windows/remove_dir_all.rs @@ -174,33 +174,41 @@ pub fn remove_dir_all_iterative(dir: File) -> Result<(), WinError> { let mut buffer = DirBuff::new(); let mut dirlist = vec![dir]; - let mut restart = true; - 'outer: while let Some(dir) = dirlist.pop() { + while let Some(dir) = dirlist.pop() { + let restart = false; // we never have to restart, we iterate every directory only once let more_data = dir.fill_dir_buff(&mut buffer, restart)?; + if !more_data { + // This directory is done! + // Attempt to delete, retrying on not empty errors because we may + // need to wait some time for files to be removed from the filesystem. + let name = unicode_str!(""); + retry(|| delete(&dir, name), WinError::DIR_NOT_EMPTY)?; + continue; + } + + // There is more data, so we have to re-insert `dir` so it gets visited again. We need to + // push it first so that it gets visited after any subdirs that we push below. We also need + // to still access it during the `for` loop so remember where we put it. + let dir_idx = dirlist.len(); + dirlist.push(dir); + // To avoid indexing `dirlist` each time through the loop, we use a reference that we + // re-compute whenever the borrow got invalidated. + let mut dir = &dirlist[dir_idx]; + for (name, is_directory) in buffer.iter() { let name = unicode_str!(&name); if is_directory { - let Some(subdir) = open_dir(&dir, name)? else { continue }; - dirlist.push(dir); + let Some(subdir) = open_dir(dir, name)? else { continue }; dirlist.push(subdir); - continue 'outer; + // We need to re-create the borrow. + dir = &dirlist[dir_idx] } else { // Attempt to delete, retrying on sharing violation errors as these // can often be very temporary. E.g. if something takes just a // bit longer than expected to release a file handle. - retry(|| delete(&dir, name), WinError::SHARING_VIOLATION)?; + retry(|| delete(dir, name), WinError::SHARING_VIOLATION)?; } } - if more_data { - dirlist.push(dir); - restart = false; - } else { - // Attempt to delete, retrying on not empty errors because we may - // need to wait some time for files to be removed from the filesystem. - let name = unicode_str!(""); - retry(|| delete(&dir, name), WinError::DIR_NOT_EMPTY)?; - restart = true; - } } Ok(()) } diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index f43395ce8fd80..f2dbea7176ae1 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -51,21 +51,7 @@ impl Socket { Ok(()) } - pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { - self.set_nonblocking(true)?; - let r = unsafe { - let (addr, len) = socket_addr_to_c(addr); - cvt(netc::connect(self.as_raw_fd(), addr.as_ptr(), len)) - }; - self.set_nonblocking(false)?; - - match r { - Ok(_) => return Ok(()), - // there's no ErrorKind for EINPROGRESS :( - Err(ref e) if e.raw_os_error() == Some(netc::errno::EINPROGRESS) => {} - Err(e) => return Err(e), - } - + pub fn poll_connected(&self, timeout: Duration) -> io::Result<()> { let mut pollfd = netc::pollfd { fd: self.as_raw_fd(), events: netc::POLLOUT, revents: 0 }; if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { diff --git a/library/std/src/sys/net/connection/socket/mod.rs b/library/std/src/sys/net/connection/socket/mod.rs index 08375078b44ef..0f45bb9526827 100644 --- a/library/std/src/sys/net/connection/socket/mod.rs +++ b/library/std/src/sys/net/connection/socket/mod.rs @@ -57,6 +57,21 @@ const MAX_SEND_LEN: usize = _ => libc::ssize_t::MAX as usize, }; +/// Some systems support setting the nonblocking mode upon socket creation, which +/// saves a syscall. +const SOCK_NONBLOCK: i32 = cfg_select! { + any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "hermit", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + ) => c::SOCK_NONBLOCK, + _ => 0, +}; + cfg_select! { any( target_os = "dragonfly", @@ -407,8 +422,26 @@ impl TcpStream { pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result { init(); - let sock = Socket::new(addr_family(addr), c::SOCK_STREAM)?; - sock.connect_timeout(addr, timeout)?; + let sock = Socket::new(addr_family(addr), c::SOCK_STREAM | SOCK_NONBLOCK)?; + if SOCK_NONBLOCK == 0 { + // The `SOCK_NONBLOCK` option is unsupported... + sock.set_nonblocking(true)?; + } + + match sock.connect(addr) { + Ok(()) => { + sock.set_nonblocking(false)?; + return Ok(TcpStream { inner: sock }); + } + #[cfg(not(target_os = "windows"))] + Err(ref e) if e.raw_os_error() == Some(c::EINPROGRESS) => {} + #[cfg(target_os = "windows")] + Err(ref e) if e.raw_os_error() == Some(crate::sys::pal::c::WSAEWOULDBLOCK) => {} + Err(e) => return Err(e), + } + + sock.set_nonblocking(false)?; + sock.poll_connected(timeout)?; Ok(TcpStream { inner: sock }) } diff --git a/library/std/src/sys/net/connection/socket/solid.rs b/library/std/src/sys/net/connection/socket/solid.rs index 9fe08ec951e75..ccb2c218b95c6 100644 --- a/library/std/src/sys/net/connection/socket/solid.rs +++ b/library/std/src/sys/net/connection/socket/solid.rs @@ -126,18 +126,7 @@ impl Socket { Ok(()) } - pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { - self.set_nonblocking(true)?; - let r = self.connect(addr); - self.set_nonblocking(false)?; - - match r { - Ok(_) => return Ok(()), - // there's no ErrorKind for EINPROGRESS - Err(ref e) if e.raw_os_error() == Some(netc::EINPROGRESS) => {} - Err(e) => return Err(e), - } - + pub fn poll_connected(&self, timeout: Duration) -> io::Result<()> { if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { return Err(io::Error::ZERO_TIMEOUT); } diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index 15e9dc2c7cc9d..a240850ec087e 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -171,21 +171,7 @@ impl Socket { } } - pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { - self.set_nonblocking(true)?; - let r = unsafe { - let (addr, len) = socket_addr_to_c(addr); - cvt(libc::connect(self.as_raw_fd(), addr.as_ptr(), len)) - }; - self.set_nonblocking(false)?; - - match r { - Ok(_) => return Ok(()), - // there's no ErrorKind for EINPROGRESS :( - Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {} - Err(e) => return Err(e), - } - + pub fn poll_connected(&self, timeout: Duration) -> io::Result<()> { let mut pollfd = libc::pollfd { fd: self.as_raw_fd(), events: libc::POLLOUT, revents: 0 }; if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 1249ac2808195..32159ab1abb8d 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -159,57 +159,47 @@ impl Socket { cvt(result).map(drop) } - pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { - self.set_nonblocking(true)?; - let result = self.connect(addr); - self.set_nonblocking(false)?; + pub fn poll_connected(&self, timeout: Duration) -> io::Result<()> { + if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { + return Err(io::Error::ZERO_TIMEOUT); + } - match result { - Err(ref error) if error.kind() == io::ErrorKind::WouldBlock => { - if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { - return Err(io::Error::ZERO_TIMEOUT); - } + let mut timeout = c::TIMEVAL { + tv_sec: cmp::min(timeout.as_secs(), c_long::MAX as u64) as c_long, + tv_usec: timeout.subsec_micros() as c_long, + }; - let mut timeout = c::TIMEVAL { - tv_sec: cmp::min(timeout.as_secs(), c_long::MAX as u64) as c_long, - tv_usec: timeout.subsec_micros() as c_long, - }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } - if timeout.tv_sec == 0 && timeout.tv_usec == 0 { - timeout.tv_usec = 1; - } + let fds = { + let mut fds = unsafe { mem::zeroed::() }; + fds.fd_count = 1; + fds.fd_array[0] = self.as_raw(); + fds + }; + + let mut writefds = fds; + let mut errorfds = fds; + + let count = { + let result = + unsafe { c::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout) }; + cvt(result)? + }; - let fds = { - let mut fds = unsafe { mem::zeroed::() }; - fds.fd_count = 1; - fds.fd_array[0] = self.as_raw(); - fds - }; - - let mut writefds = fds; - let mut errorfds = fds; - - let count = { - let result = unsafe { - c::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout) - }; - cvt(result)? - }; - - match count { - 0 => Err(io::const_error!(io::ErrorKind::TimedOut, "connection timed out")), - _ => { - if writefds.fd_count != 1 { - if let Some(e) = self.take_error()? { - return Err(e); - } - } - - Ok(()) + match count { + 0 => Err(io::const_error!(io::ErrorKind::TimedOut, "connection timed out")), + _ => { + if writefds.fd_count != 1 { + if let Some(e) = self.take_error()? { + return Err(e); } } + + Ok(()) } - _ => result, } } diff --git a/src/ci/docker/scripts/illumos-toolchain.sh b/src/ci/docker/scripts/illumos-toolchain.sh index 7a3ca875554ae..b284fca65f282 100644 --- a/src/ci/docker/scripts/illumos-toolchain.sh +++ b/src/ci/docker/scripts/illumos-toolchain.sh @@ -47,11 +47,12 @@ GCC_BASE="gcc-$GCC_VERSION" GCC_TAR="gcc-$GCC_VERSION.tar.xz" GCC_URL="https://ftp.gnu.org/gnu/gcc/$GCC_BASE/$GCC_TAR" -SYSROOT_VER='20181213-de6af22ae73b-v1' -SYSROOT_SUM='ee792d956dfa6967453cebe9286a149143290d296a8ce4b8a91d36bea89f8112' +# Originally downloaded from: +# https://github.com/illumos/sysroot/releases/download/$SYSROOT_VER/$SYSROOT_TAR" +SYSROOT_VER='20210501-e0b4275f34-v0' +SYSROOT_SUM='28d8f4f6d84331ff1e99ac3d68b917cf8174897a5c00171c5e493253eb1587f6' SYSROOT_TAR="illumos-sysroot-$SYSROOT_MACH-$SYSROOT_VER.tar.gz" -SYSROOT_URL='https://github.com/illumos/sysroot/releases/download/' -SYSROOT_URL+="$SYSROOT_VER/$SYSROOT_TAR" +SYSROOT_URL="https://ci-mirrors.rust-lang.org/rustc/$SYSROOT_TAR" SYSROOT_DIR="$PREFIX/sysroot" BINUTILS_VERSION='2.40' diff --git a/src/doc/rustc/src/platform-support/illumos.md b/src/doc/rustc/src/platform-support/illumos.md index c03238269d37a..f45c9b8421c30 100644 --- a/src/doc/rustc/src/platform-support/illumos.md +++ b/src/doc/rustc/src/platform-support/illumos.md @@ -40,3 +40,12 @@ The target supports C code. The illumos project makes available [prebuilt sysroot artefacts](https://github.com/illumos/sysroot) which can be used for cross compilation. The official Rust binaries are cross-compiled using these artefacts. + +## Target version requirements + +The host tools cross-compiled for this target should work on any +illumos distribution based on illumos sources later than the +date shown in the sysroot version tag. + +For details on illumos sysroot versions see: +[sysroot versions](https://github.com/illumos/sysroot/releases) diff --git a/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md index cc21da11f4de1..32253fe4ab123 100644 --- a/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md +++ b/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md @@ -30,16 +30,8 @@ is 8-bytes large as well as pointers. The tradeoff, though, is that the maximum memory size is now the full 64-bit address space instead of the 4GB as limited by the 32-bit address space for `wasm32-unknown-unknown`. -This target is not a stable target. The [memory64] WebAssembly proposal is still -in-progress and not standardized. This means that there are not many engines -which implement the `memory64` feature and if they do they're likely behind a -flag, for example: - -* Nodejs - `--experimental-wasm-memory64` -* Wasmtime - `--wasm memory64` - -Also note that at this time the `wasm64-unknown-unknown` target assumes the -presence of other merged wasm proposals such as (with their LLVM feature flags): +Note that at this time the `wasm64-unknown-unknown` target assumes the presence +of other merged wasm proposals such as (with their LLVM feature flags): * [Bulk memory] - `+bulk-memory` * Mutable imported globals - `+mutable-globals` @@ -54,11 +46,6 @@ The `wasm64-unknown-unknown` target intends to match the default Clang targets for its `"C"` ABI, which is likely to be the same as Clang's `wasm32-unknown-unknown` largely. -> **Note**: due to the relatively early-days nature of this target when working -> with this target you may encounter LLVM bugs. If an assertion hit or a bug is -> found it's recommended to open an issue either with rust-lang/rust or ideally -> with LLVM itself. - This target does not support `panic=unwind` at this time. ## Building the target diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index 5790c3cce2606..db0f046d72811 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::{LocalDefId, LocalModId}; use rustc_hir::{Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass, impl_lint_pass}; -use rustc_span::{FileName, Span}; +use rustc_span::{Span, StableSourceFileId}; use std::collections::hash_map::Entry; declare_clippy_lint! { @@ -63,7 +63,7 @@ impl MultipleInherentImpl { #[derive(Hash, Eq, PartialEq, Clone)] enum Criterion { Module(LocalModId), - File(FileName), + File(StableSourceFileId), Crate, } @@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { InherentImplLintScope::Module => Criterion::Module(cx.tcx.parent_module(hir_id)), InherentImplLintScope::File => { let span = cx.tcx.hir_span(hir_id); - Criterion::File(cx.tcx.sess.source_map().lookup_source_file(span.lo()).name.clone()) + Criterion::File(cx.tcx.sess.source_map().lookup_source_file(span.lo()).stable_id) }, InherentImplLintScope::Crate => Criterion::Crate, }; diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index f800dd61e47d6..661c3518f64ee 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -16,11 +16,11 @@ pub mod diff; pub mod env; pub mod external_deps; pub mod linker; +pub mod obj; pub mod path_helpers; pub mod run; pub mod scoped_run; pub mod string; -pub mod symbols; pub mod targets; pub mod wasm; @@ -34,6 +34,16 @@ pub mod rfs { pub use crate::fs::*; } +/// Older version of the [`obj`] module. Prefer importing from there instead. +pub mod symbols { + pub use crate::obj::{ + ContainsAllSymbolSubstringsOutcome, ContainsAllSymbolsOutcome, + exported_dynamic_symbol_names, object_contains_all_symbol_substring, + object_contains_all_symbols, object_contains_any_symbol, + object_contains_any_symbol_substring, + }; +} + // Re-exports of third-party library crates. pub use bstr; pub use gimli; diff --git a/src/tools/run-make-support/src/symbols.rs b/src/tools/run-make-support/src/obj.rs similarity index 68% rename from src/tools/run-make-support/src/symbols.rs rename to src/tools/run-make-support/src/obj.rs index 0e11360bd5a02..1acf85e7eb650 100644 --- a/src/tools/run-make-support/src/symbols.rs +++ b/src/tools/run-make-support/src/obj.rs @@ -1,7 +1,95 @@ +//! Helpers for working with types from the [`object`] crate. + use std::collections::BTreeSet; -use std::path::Path; +#[cfg(unix)] +use std::os::unix::ffi::OsStrExt; +use std::path::{Path, PathBuf}; + +use bstr::BStr; +pub use object::read::archive::ArchiveFile; +use object::{self, Object, ObjectSymbol, Symbol}; +pub use object::{File as ObjFile, Result as ObjResult}; + +use crate::rfs; + +/// Thin wrapper for owning data used by `object`, which may be either an archive or a single +/// object file. +pub struct BinFile { + path: PathBuf, + data: Vec, +} + +impl BinFile { + /// Read an archive or object file at `path`. + pub fn read_path>(path: P) -> Self { + let path = path.into(); + Self { data: rfs::read(&path), path } + } + + /// Access the owned buffer as an archive file. + pub fn parse_as_archive_file(&self) -> ObjResult> { + ArchiveFile::parse(self.data.as_slice()) + } + + /// Access the owned buffer as an archive file. + pub fn parse_as_obj_file(&self) -> ObjResult> { + ObjFile::parse(self.data.as_slice()) + } -use object::{self, Object, ObjectSymbol}; + /// If the file is an archive, run the callback for each object file. If it is an object + /// file, the callback will run once. + /// + /// The callback receives the parsed object file and its name in the archive or on disk. + pub fn for_each_object(&self, mut f: impl FnMut(ObjFile<'_>, &BStr)) { + // Try as an archive first. + let as_archive = self.parse_as_archive_file(); + if let Ok(archive) = as_archive { + for member in archive.members() { + let member = member.expect("failed to access member"); + let obj_data = member.data(self.data.as_slice()).expect("failed to access object"); + let obj = ObjFile::parse(obj_data).expect("failed to parse object"); + f(obj, BStr::new(member.name())); + } + + return; + } + + // Fall back to parsing as an object file. + let as_obj = self.parse_as_obj_file(); + if let Ok(obj) = as_obj { + let path_os = self.path.as_os_str(); + let path = cfg_select! { + unix => path_os.as_bytes(), + _ => path_os + .to_str() + .unwrap_or_else(|| panic!("non-utf-8 path on non-unix: {:?}", self.path)) + .as_bytes(), + }; + f(obj, BStr::new(path)); + return; + } + + panic!( + "failed to parse {:?} as either an archive or a object file: {:?}, {:?}", + self.path, + as_archive.unwrap_err(), + as_obj.unwrap_err(), + ); + } + + /// Do something with each symbol in an archive or object file. + /// + /// The callback receives: + /// + /// * The symbol. + /// * The parsed object file that contains the symbol. + /// * The name of the object file in its archive or on disk. + pub fn for_each_symbol(&self, mut f: impl FnMut(Symbol<'_, '_>, &ObjFile<'_>, &BStr)) { + self.for_each_object(|obj, obj_path| { + obj.symbols().for_each(|sym| f(sym, &obj, obj_path)); + }); + } +} /// Given an [`object::File`], find the exported dynamic symbol names via /// [`object::Object::exports`]. This does not distinguish between which section the symbols appear diff --git a/tests/run-make/libstd-no-protected/rmake.rs b/tests/run-make/libstd-no-protected/rmake.rs index 75a1dcc4a7d0f..f907618966d3d 100644 --- a/tests/run-make/libstd-no-protected/rmake.rs +++ b/tests/run-make/libstd-no-protected/rmake.rs @@ -4,11 +4,9 @@ //@ only-x86_64-unknown-linux-gnu -use run_make_support::object::Endianness; -use run_make_support::object::read::archive::ArchiveFile; -use run_make_support::object::read::elf::{FileHeader as _, SectionHeader as _}; -use run_make_support::rfs::read; -use run_make_support::{has_prefix, has_suffix, object, path, rustc, shallow_find_files, target}; +use run_make_support::obj::BinFile; +use run_make_support::object::{Endianness, ObjectSymbol, SymbolFlags}; +use run_make_support::{has_prefix, has_suffix, object, rustc, shallow_find_files, target}; type FileHeader = run_make_support::object::elf::FileHeader64; type SymbolTable<'data> = run_make_support::object::read::elf::SymbolTable<'data, FileHeader>; @@ -21,41 +19,25 @@ fn main() { }); assert_eq!(libs.len(), 1); let libstd_path = libs.pop().unwrap(); - let archive_data = read(libstd_path); + let archive = BinFile::read_path(libstd_path); // Parse all the object files within the libstd archive, checking defined symbols. - let mut num_protected = 0; + let mut protected = Vec::new(); let mut num_symbols = 0; - let archive = ArchiveFile::parse(&*archive_data).unwrap(); - for member in archive.members() { - let member = member.unwrap(); - if member.name() == b"lib.rmeta" { - continue; + archive.for_each_symbol(|symbol, _obj, obj_name| { + if obj_name == "lib.rmeta" { + return; } - let data = member.data(&*archive_data).unwrap(); - - let header = FileHeader::parse(data).unwrap(); - let endian = header.endian().unwrap(); - let sections = header.sections(endian, data).unwrap(); - - for (section_index, section) in sections.enumerate() { - if section.sh_type(endian) == object::elf::SHT_SYMTAB { - let symbols = - SymbolTable::parse(endian, data, §ions, section_index, section).unwrap(); - for symbol in symbols.symbols() { - if symbol.st_visibility() == object::elf::STV_PROTECTED { - num_protected += 1; - } - num_symbols += 1; - } - } + if symbol.flags().elf_visibility().expect("non-elf file") == object::elf::STV_PROTECTED { + protected.push(String::from_utf8_lossy(symbol.name_bytes().unwrap()).into_owned()); } - } + num_symbols += 1; + }); // If there were no symbols at all, then something is wrong with the test. assert_ne!(num_symbols, 0); // The purpose of this test - check that no symbols have protected visibility. - assert_eq!(num_protected, 0); + assert!(protected.is_empty(), "found protected symbols {protected:#?}"); } diff --git a/tests/ui/borrowck/borrowck-union-borrow-nested.rs b/tests/ui/borrowck/borrowck-union-borrow-nested.rs index b3a6670fa4881..faf59a292c22a 100644 --- a/tests/ui/borrowck/borrowck-union-borrow-nested.rs +++ b/tests/ui/borrowck/borrowck-union-borrow-nested.rs @@ -29,3 +29,5 @@ fn main() { trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { } } impl Fake for T { } + +//@ reference: items.union.ref.borrow diff --git a/tests/ui/borrowck/borrowck-union-borrow.rs b/tests/ui/borrowck/borrowck-union-borrow.rs index f01915398a412..3564defd3ea32 100644 --- a/tests/ui/borrowck/borrowck-union-borrow.rs +++ b/tests/ui/borrowck/borrowck-union-borrow.rs @@ -94,3 +94,5 @@ fn main() { } } } + +//@ reference: items.union.ref.borrow diff --git a/tests/ui/consts/const-eval/union-const-eval-field.rs b/tests/ui/consts/const-eval/union-const-eval-field.rs index 2c9061a7a50f8..6ae8e8188dcfe 100644 --- a/tests/ui/consts/const-eval/union-const-eval-field.rs +++ b/tests/ui/consts/const-eval/union-const-eval-field.rs @@ -37,3 +37,6 @@ fn main() { assert_eq!(read_field2(), 1.0); assert_eq!(read_field3(), unsafe { UNION.field3 }); } + +//@ reference: items.union.fields.read +//@ reference: items.union.fields.validity diff --git a/tests/ui/consts/const-eval/union-ub.rs b/tests/ui/consts/const-eval/union-ub.rs index 0fa5d31285604..33bf5cc316735 100644 --- a/tests/ui/consts/const-eval/union-ub.rs +++ b/tests/ui/consts/const-eval/union-ub.rs @@ -40,3 +40,6 @@ const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool }; const BAD_UNION: Foo = unsafe { Bar { u8: 42 }.foo }; fn main() {} + +//@ reference: items.union.fields.intro +//@ reference: items.union.fields.validity diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index 242a91cab7e77..304b568408c62 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -1001,3 +1001,5 @@ fn test_punct() { p!([ ,; ;, ** @@ $+$ >< <> ?? +== ], ",; ;, ** @@ $+$ >< <> ?? +=="); p!([ :#!@|$=&*,+;*~? ], ":#!@|$=&*,+;*~?"); } + +//@ reference: items.union.fieldless diff --git a/tests/ui/nll/issue-45157.rs b/tests/ui/nll/issue-45157.rs index 8d2bf22a03c9a..9c59bde7cb310 100644 --- a/tests/ui/nll/issue-45157.rs +++ b/tests/ui/nll/issue-45157.rs @@ -29,3 +29,5 @@ fn main() { println!("{} {}", mref, nref) } } + +//@ reference: items.union.ref.borrow diff --git a/tests/ui/nll/issue-57100.rs b/tests/ui/nll/issue-57100.rs index f15929334bb40..bd31fd230fbf0 100644 --- a/tests/ui/nll/issue-57100.rs +++ b/tests/ui/nll/issue-57100.rs @@ -65,3 +65,5 @@ fn first_union() { } fn main() {} + +//@ reference: items.union.ref.borrow diff --git a/tests/ui/parser/recover/recover-field-semi.rs b/tests/ui/parser/recover/recover-field-semi.rs index b6f235f8ad1c9..8ea8adff145b5 100644 --- a/tests/ui/parser/recover/recover-field-semi.rs +++ b/tests/ui/parser/recover/recover-field-semi.rs @@ -16,3 +16,5 @@ enum Baz { fn main() { let _ = Foo { foo: "" }; //~ ERROR mismatched types } + +//@ reference: items.union.syntax diff --git a/tests/ui/privacy/union-field-privacy-1.rs b/tests/ui/privacy/union-field-privacy-1.rs index 8a84bd86ae559..e64286146fd82 100644 --- a/tests/ui/privacy/union-field-privacy-1.rs +++ b/tests/ui/privacy/union-field-privacy-1.rs @@ -15,3 +15,5 @@ fn main() { unsafe { let m::U { b } = u; // OK let m::U { c } = u; //~ ERROR field `c` of union `U` is private }} + +//@ reference: items.union.ref.use diff --git a/tests/ui/privacy/union-field-privacy-2.rs b/tests/ui/privacy/union-field-privacy-2.rs index f02e0f8a9b95e..3c62efb8f7c4d 100644 --- a/tests/ui/privacy/union-field-privacy-2.rs +++ b/tests/ui/privacy/union-field-privacy-2.rs @@ -13,3 +13,5 @@ fn main() { let b = u.b; // OK let c = u.c; //~ ERROR field `c` of union `U` is private } + +//@ reference: items.union.ref.use diff --git a/tests/ui/union/union-basic.rs b/tests/ui/union/union-basic.rs index 027f994ab4c94..ec8a523faedb3 100644 --- a/tests/ui/union/union-basic.rs +++ b/tests/ui/union/union-basic.rs @@ -58,3 +58,6 @@ fn main() { local(); xcrate(); } + +//@ reference: items.union.common-storage +//@ reference: items.union.init.result diff --git a/tests/ui/union/union-inherent-method.rs b/tests/ui/union/union-inherent-method.rs index b3b0fec8c1f37..35f724fdb2f78 100644 --- a/tests/ui/union/union-inherent-method.rs +++ b/tests/ui/union/union-inherent-method.rs @@ -1,5 +1,4 @@ //@ run-pass -//@ reference: items.impl.inherent.allowed-items union U { a: u8, @@ -13,3 +12,6 @@ fn main() { let u = U { a: 10 }; assert_eq!(u.method(), 10); } + +//@ reference: items.impl.inherent.allowed-items +//@ reference: items.union.ref.use diff --git a/tests/ui/union/union-modification.rs b/tests/ui/union/union-modification.rs index 0f123395680b5..66ffe0e2e24e0 100644 --- a/tests/ui/union/union-modification.rs +++ b/tests/ui/union/union-modification.rs @@ -32,3 +32,5 @@ pub fn main() { assert_eq!(unsafe { foo_holder.inner_foo.bar }, 4); drop(foo_holder); } + +//@ reference: items.union.fields.write-safety diff --git a/tests/ui/union/union-nodrop.rs b/tests/ui/union/union-nodrop.rs index 401ed42f73bff..310f3b5e11e7d 100644 --- a/tests/ui/union/union-nodrop.rs +++ b/tests/ui/union/union-nodrop.rs @@ -64,3 +64,5 @@ fn main() { assert!(needs_drop::>()); assert!(needs_drop::>>()); } + +//@ reference: items.union.drop diff --git a/tests/ui/union/union-repr-c.rs b/tests/ui/union/union-repr-c.rs index 1367835e67781..84d633cc11b78 100644 --- a/tests/ui/union/union-repr-c.rs +++ b/tests/ui/union/union-repr-c.rs @@ -16,3 +16,5 @@ extern "C" { } fn main() {} + +//@ reference: type.union.layout diff --git a/tests/ui/union/union-transmute.rs b/tests/ui/union/union-transmute.rs index 879ee7a23dbd8..b578512fe07a3 100644 --- a/tests/ui/union/union-transmute.rs +++ b/tests/ui/union/union-transmute.rs @@ -1,6 +1,4 @@ //@ run-pass -//@ reference: items.union.common-storage -//@ reference: type.union.access union U { a: (u8, u8), @@ -25,3 +23,7 @@ fn main() { assert_eq!(w.a, 0b1_11111111_00000000000000000000000); } } + +//@ reference: items.union.common-storage +//@ reference: items.union.fields.intro +//@ reference: type.union.access diff --git a/tests/ui/union/union.rs b/tests/ui/union/union.rs index ae81708aa191c..751041343eb4a 100644 --- a/tests/ui/union/union.rs +++ b/tests/ui/union/union.rs @@ -47,3 +47,5 @@ pub fn main() { } let Foo { bar: _ } = foo; } + +//@ reference: items.union.pattern.safety diff --git a/triagebot.toml b/triagebot.toml index 676ab4df6448a..528e6e2cc9462 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -26,6 +26,7 @@ allow-unauthenticated = [ "beta-nominated", "CI-spurious-*", "const-hack", + "llm-assisted", "llvm-*", "needs-fcp", "relnotes",