diff options
| author | bors <bors@rust-lang.org> | 2025-07-13 15:32:13 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2025-07-13 15:32:13 +0000 |
| commit | 56835d7ac14da9f966e1ff39fd9ffd2e29b764d1 (patch) | |
| tree | 74bf7603a760a610352e6f0fa88668b71cb6d8a2 /compiler | |
| parent | 7e310f4b9a3f166d833ed09cf1d1ff96ab84b72c (diff) | |
| parent | 3ff549f6d33ac15df8307025ee068cada8b1e021 (diff) | |
Auto merge of #143888 - matthiaskrgr:rollup-fv9x7kf, r=matthiaskrgr
Rollup of 11 pull requests Successful merges: - rust-lang/rust#143301 (`tests/ui`: A New Order [26/N]) - rust-lang/rust#143519 (Check assoc consts and tys later like assoc fns) - rust-lang/rust#143554 (slice: Mark `rotate_left`, `rotate_right` unstably const) - rust-lang/rust#143634 (interpret/allocation: expose init + write_wildcards on a range) - rust-lang/rust#143685 (Resolve: merge `source_bindings` and `target_bindings` into `bindings`) - rust-lang/rust#143734 (Refactor resolve resolution bindings) - rust-lang/rust#143774 (constify `From` and `Into`) - rust-lang/rust#143785 (Add --compile-time-deps argument for x check) - rust-lang/rust#143786 (Fix fallback for CI_JOB_NAME) - rust-lang/rust#143825 (clippy: fix test filtering when TESTNAME is empty) - rust-lang/rust#143826 (Fix command trace) r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc/Cargo.toml | 1 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/Cargo.toml | 3 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/memory.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_driver_impl/Cargo.toml | 1 | ||||
| -rw-r--r-- | compiler/rustc_interface/Cargo.toml | 1 | ||||
| -rw-r--r-- | compiler/rustc_llvm/Cargo.toml | 4 | ||||
| -rw-r--r-- | compiler/rustc_llvm/build.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/interpret/allocation.rs | 33 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs | 28 | ||||
| -rw-r--r-- | compiler/rustc_passes/src/dead.rs | 70 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/build_reduced_graph.rs | 18 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/check_unused.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/diagnostics.rs | 4 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/ident.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/imports.rs | 312 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/late/diagnostics.rs | 29 | ||||
| -rw-r--r-- | compiler/rustc_resolve/src/lib.rs | 9 |
18 files changed, 298 insertions, 240 deletions
diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index f4caa3ef769..99414d6264e 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -27,6 +27,7 @@ features = ['unprefixed_malloc_on_supported_platforms'] [features] # tidy-alphabetical-start +check_only = ['rustc_driver_impl/check_only'] jemalloc = ['dep:tikv-jemalloc-sys'] llvm = ['rustc_driver_impl/llvm'] max_level_info = ['rustc_driver_impl/max_level_info'] diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 88efc8ac96b..5ab22f8fc4d 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -43,3 +43,6 @@ serde_json = "1" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end + +[features] +check_only = ["rustc_llvm/check_only"] diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index bb301600135..6414821e21d 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1498,7 +1498,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { dest_alloc .write_uninit(&tcx, dest_range) .map_err(|e| e.to_interp_error(dest_alloc_id))?; - // We can forget about the provenance, this is all not initialized anyway. + // `write_uninit` also resets the provenance, so we are done. return interp_ok(()); } diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 1971d06aad6..ce26aa449d9 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -72,6 +72,7 @@ ctrlc = "3.4.4" [features] # tidy-alphabetical-start +check_only = ['rustc_interface/check_only'] llvm = ['rustc_interface/llvm'] max_level_info = ['rustc_log/max_level_info'] rustc_randomized_layouts = [ diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index a72a7958787..473ac5e0cea 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -56,5 +56,6 @@ rustc_abi = { path = "../rustc_abi" } [features] # tidy-alphabetical-start +check_only = ['rustc_codegen_llvm?/check_only'] llvm = ['dep:rustc_codegen_llvm'] # tidy-alphabetical-end diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index 061562b2ec5..39de4783238 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -14,3 +14,7 @@ libc = "0.2.73" # pinned `cc` in `rustc_codegen_ssa` if you update `cc` here. cc = "=1.2.16" # tidy-alphabetical-end + +[features] +# Used by ./x.py check --compile-time-deps to skip building C++ code +check_only = [] diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 9a6549379d3..069b684ad09 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -106,6 +106,10 @@ fn output(cmd: &mut Command) -> String { } fn main() { + if cfg!(feature = "check_only") { + return; + } + for component in REQUIRED_COMPONENTS.iter().chain(OPTIONAL_COMPONENTS.iter()) { println!("cargo:rustc-check-cfg=cfg(llvm_component,values(\"{component}\"))"); } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index f039849d1bb..133111ff15d 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -101,6 +101,8 @@ pub struct Allocation<Prov: Provenance = CtfeProvenance, Extra = (), Bytes = Box /// at the given offset. provenance: ProvenanceMap<Prov>, /// Denotes which part of this allocation is initialized. + /// + /// Invariant: the uninitialized parts have no provenance. init_mask: InitMask, /// The alignment of the allocation to detect unaligned reads. /// (`Align` guarantees that this is a power of two.) @@ -796,24 +798,19 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> Ok(()) } - /// Initialize all previously uninitialized bytes in the entire allocation, and set - /// provenance of everything to `Wildcard`. Before calling this, make sure all - /// provenance in this allocation is exposed! - pub fn prepare_for_native_access(&mut self) { - let full_range = AllocRange { start: Size::ZERO, size: Size::from_bytes(self.len()) }; - // Overwrite uninitialized bytes with 0, to ensure we don't leak whatever their value happens to be. - for chunk in self.init_mask.range_as_init_chunks(full_range) { - if !chunk.is_init() { - let uninit_bytes = &mut self.bytes - [chunk.range().start.bytes_usize()..chunk.range().end.bytes_usize()]; - uninit_bytes.fill(0); - } - } - // Mark everything as initialized now. - self.mark_init(full_range, true); - - // Set provenance of all bytes to wildcard. - self.provenance.write_wildcards(self.len()); + /// Mark all bytes in the given range as initialised and reset the provenance + /// to wildcards. This entirely breaks the normal mechanisms for tracking + /// initialisation and is only provided for Miri operating in native-lib + /// mode. UB will be missed if the underlying bytes were not actually written to. + /// + /// If `range` is `None`, defaults to performing this on the whole allocation. + pub fn process_native_write(&mut self, cx: &impl HasDataLayout, range: Option<AllocRange>) { + let range = range.unwrap_or_else(|| AllocRange { + start: Size::ZERO, + size: Size::from_bytes(self.len()), + }); + self.mark_init(range, true); + self.provenance.write_wildcards(cx, range); } /// Remove all provenance in the given memory range. diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index 9c6e1664386..119d4be64e6 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -212,21 +212,37 @@ impl<Prov: Provenance> ProvenanceMap<Prov> { Ok(()) } - /// Overwrites all provenance in the allocation with wildcard provenance. + /// Overwrites all provenance in the given range with wildcard provenance. + /// Pointers partially overwritten will have their provenances preserved + /// bytewise on their remaining bytes. /// /// Provided for usage in Miri and panics otherwise. - pub fn write_wildcards(&mut self, alloc_size: usize) { + pub fn write_wildcards(&mut self, cx: &impl HasDataLayout, range: AllocRange) { assert!( Prov::OFFSET_IS_ADDR, "writing wildcard provenance is not supported when `OFFSET_IS_ADDR` is false" ); let wildcard = Prov::WILDCARD.unwrap(); - // Remove all pointer provenances, then write wildcards into the whole byte range. - self.ptrs.clear(); - let last = Size::from_bytes(alloc_size); let bytes = self.bytes.get_or_insert_with(Box::default); - for offset in Size::ZERO..last { + + // Remove pointer provenances that overlap with the range, then readd the edge ones bytewise. + let ptr_range = Self::adjusted_range_ptrs(range, cx); + let ptrs = self.ptrs.range(ptr_range.clone()); + if let Some((offset, prov)) = ptrs.first() { + for byte_ofs in *offset..range.start { + bytes.insert(byte_ofs, *prov); + } + } + if let Some((offset, prov)) = ptrs.last() { + for byte_ofs in range.end()..*offset + cx.data_layout().pointer_size() { + bytes.insert(byte_ofs, *prov); + } + } + self.ptrs.remove_range(ptr_range); + + // Overwrite bytewise provenance. + for offset in range.start..range.end() { bytes.insert(offset, wildcard); } } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index cdfd1a2b07e..35d6f22fd3b 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -18,7 +18,7 @@ use rustc_hir::{self as hir, ImplItem, ImplItemKind, Node, PatKind, QPath, TyKin use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::Level; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, AssocTag, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::DEAD_CODE; use rustc_session::lint::{self, LintExpectationId}; @@ -115,7 +115,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { fn handle_res(&mut self, res: Res) { match res { - Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::TyAlias, def_id) => { + Res::Def( + DefKind::Const | DefKind::AssocConst | DefKind::AssocTy | DefKind::TyAlias, + def_id, + ) => { self.check_def_id(def_id); } _ if self.in_pat => {} @@ -482,7 +485,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { ) -> bool { let trait_def_id = match self.tcx.def_kind(local_def_id) { // assoc impl items of traits are live if the corresponding trait items are live - DefKind::AssocFn => self + DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => self .tcx .associated_item(local_def_id) .trait_item_def_id @@ -647,6 +650,31 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { self.in_pat = in_pat; } + + fn visit_trait_ref(&mut self, t: &'tcx hir::TraitRef<'tcx>) { + if let Some(trait_def_id) = t.path.res.opt_def_id() + && let Some(segment) = t.path.segments.last() + && let Some(args) = segment.args + { + for constraint in args.constraints { + if let Some(local_def_id) = self + .tcx + .associated_items(trait_def_id) + .find_by_ident_and_kind( + self.tcx, + constraint.ident, + AssocTag::Const, + trait_def_id, + ) + .and_then(|item| item.def_id.as_local()) + { + self.worklist.push((local_def_id, ComesFromAllowExpect::No)); + } + } + } + + intravisit::walk_trait_ref(self, t); + } } fn has_allow_dead_code_or_lang_attr( @@ -744,18 +772,12 @@ fn check_item<'tcx>( { worklist.push((local_def_id, comes_from_allow)); } else if of_trait { - // FIXME: This condition can be removed - // if we support dead check for assoc consts and tys. - if !matches!(tcx.def_kind(local_def_id), DefKind::AssocFn) { - worklist.push((local_def_id, ComesFromAllowExpect::No)); - } else { - // We only care about associated items of traits, - // because they cannot be visited directly, - // so we later mark them as live if their corresponding traits - // or trait items and self types are both live, - // but inherent associated items can be visited and marked directly. - unsolved_items.push((id, local_def_id)); - } + // We only care about associated items of traits, + // because they cannot be visited directly, + // so we later mark them as live if their corresponding traits + // or trait items and self types are both live, + // but inherent associated items can be visited and marked directly. + unsolved_items.push((id, local_def_id)); } } } @@ -791,15 +813,14 @@ fn check_trait_item( worklist: &mut Vec<(LocalDefId, ComesFromAllowExpect)>, id: hir::TraitItemId, ) { - use hir::TraitItemKind::{Const, Fn}; - if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) { - let trait_item = tcx.hir_trait_item(id); - if matches!(trait_item.kind, Const(_, Some(_)) | Fn(..)) - && let Some(comes_from_allow) = - has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id) - { - worklist.push((trait_item.owner_id.def_id, comes_from_allow)); - } + use hir::TraitItemKind::{Const, Fn, Type}; + + let trait_item = tcx.hir_trait_item(id); + if matches!(trait_item.kind, Const(_, Some(_)) | Type(_, Some(_)) | Fn(..)) + && let Some(comes_from_allow) = + has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id) + { + worklist.push((trait_item.owner_id.def_id, comes_from_allow)); } } @@ -1163,6 +1184,7 @@ impl<'tcx> DeadVisitor<'tcx> { } match self.tcx.def_kind(def_id) { DefKind::AssocConst + | DefKind::AssocTy | DefKind::AssocFn | DefKind::Fn | DefKind::Static { .. } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index ef122deba4e..6979d89a8e7 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -32,10 +32,9 @@ use crate::def_collector::collect_definitions; use crate::imports::{ImportData, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::{ - BindingKey, Determinacy, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, - ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, - ResolutionError, Resolver, ResolverArenas, Segment, ToNameBinding, Used, VisResolutionError, - errors, + BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot, + NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, ResolutionError, + Resolver, ResolverArenas, Segment, ToNameBinding, Used, VisResolutionError, errors, }; type Res = def::Res<NodeId>; @@ -620,16 +619,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let kind = ImportKind::Single { source: source.ident, target: ident, - source_bindings: PerNS { - type_ns: Cell::new(Err(Determinacy::Undetermined)), - value_ns: Cell::new(Err(Determinacy::Undetermined)), - macro_ns: Cell::new(Err(Determinacy::Undetermined)), - }, - target_bindings: PerNS { - type_ns: Cell::new(None), - value_ns: Cell::new(None), - macro_ns: Cell::new(None), - }, + bindings: Default::default(), type_ns_only, nested, id, diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 2e870c47f8e..81ee02ac3c7 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -511,7 +511,7 @@ impl Resolver<'_, '_> { for (_key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); - if let Some(binding) = resolution.binding + if let Some(binding) = resolution.best_binding() && let NameBindingKind::Import { import, .. } = binding.kind && let ImportKind::Single { id, .. } = import.kind { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index c4ff5770e76..b2f16fb1dfb 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1440,7 +1440,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |(key, name_resolution)| { if key.ns == TypeNS && key.ident == ident - && let Some(binding) = name_resolution.borrow().binding + && let Some(binding) = name_resolution.borrow().best_binding() { match binding.res() { // No disambiguation needed if the identically named item we @@ -1494,7 +1494,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return None; }; for (_, resolution) in this.resolutions(m).borrow().iter() { - let Some(binding) = resolution.borrow().binding else { + let Some(binding) = resolution.borrow().best_binding() else { continue; }; let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) = diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 558cbef0014..99297de40d5 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -875,7 +875,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // binding if it exists. What we really want here is having two separate scopes in // a module - one for non-globs and one for globs, but until that's done use this // hack to avoid inconsistent resolution ICEs during import validation. - let binding = [resolution.binding, resolution.shadowed_glob] + let binding = [resolution.non_glob_binding, resolution.glob_binding] .into_iter() .find_map(|binding| if binding == ignore_binding { None } else { binding }); @@ -883,7 +883,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return self.finalize_module_binding( ident, binding, - resolution.shadowed_glob, + if resolution.non_glob_binding.is_some() { resolution.glob_binding } else { None }, parent_scope, finalize, shadowing, @@ -1090,14 +1090,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let Some(module) = single_import.imported_module.get() else { return true; }; - let ImportKind::Single { source, target, target_bindings, .. } = &single_import.kind - else { + let ImportKind::Single { source, target, bindings, .. } = &single_import.kind else { unreachable!(); }; if source != target { - if target_bindings.iter().all(|binding| binding.get().is_none()) { + if bindings.iter().all(|binding| binding.get().binding().is_none()) { return true; - } else if target_bindings[ns].get().is_none() && binding.is_some() { + } else if bindings[ns].get().binding().is_none() && binding.is_some() { return true; } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 2e81b54b136..40c63a3edf3 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -24,7 +24,6 @@ use rustc_span::{Ident, Span, Symbol, kw, sym}; use smallvec::SmallVec; use tracing::debug; -use crate::Determinacy::{self, *}; use crate::Namespace::*; use crate::diagnostics::{DiagMode, Suggestion, import_candidates}; use crate::errors::{ @@ -33,13 +32,30 @@ use crate::errors::{ ConsiderAddingMacroExport, ConsiderMarkingAsPub, }; use crate::{ - AmbiguityError, AmbiguityKind, BindingKey, Finalize, ImportSuggestion, Module, + AmbiguityError, AmbiguityKind, BindingKey, Determinacy, Finalize, ImportSuggestion, Module, ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, names_to_string, }; type Res = def::Res<NodeId>; +/// A [`NameBinding`] in the process of being resolved. +#[derive(Clone, Copy, Default, PartialEq)] +pub(crate) enum PendingBinding<'ra> { + Ready(Option<NameBinding<'ra>>), + #[default] + Pending, +} + +impl<'ra> PendingBinding<'ra> { + pub(crate) fn binding(self) -> Option<NameBinding<'ra>> { + match self { + PendingBinding::Ready(binding) => binding, + PendingBinding::Pending => None, + } + } +} + /// Contains data for specific kinds of imports. #[derive(Clone)] pub(crate) enum ImportKind<'ra> { @@ -49,10 +65,8 @@ pub(crate) enum ImportKind<'ra> { /// `target` in `use prefix::source as target`. /// It will directly use `source` when the format is `use prefix::source`. target: Ident, - /// Bindings to which `source` refers to. - source_bindings: PerNS<Cell<Result<NameBinding<'ra>, Determinacy>>>, - /// Bindings introduced by `target`. - target_bindings: PerNS<Cell<Option<NameBinding<'ra>>>>, + /// Bindings introduced by the import. + bindings: PerNS<Cell<PendingBinding<'ra>>>, /// `true` for `...::{self [as target]}` imports, `false` otherwise. type_ns_only: bool, /// Did this import result from a nested import? ie. `use foo::{bar, baz};` @@ -96,26 +110,14 @@ impl<'ra> std::fmt::Debug for ImportKind<'ra> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use ImportKind::*; match self { - Single { - source, - target, - source_bindings, - target_bindings, - type_ns_only, - nested, - id, - } => f + Single { source, target, bindings, type_ns_only, nested, id, .. } => f .debug_struct("Single") .field("source", source) .field("target", target) // Ignore the nested bindings to avoid an infinite loop while printing. .field( - "source_bindings", - &source_bindings.clone().map(|b| b.into_inner().map(|_| format_args!(".."))), - ) - .field( - "target_bindings", - &target_bindings.clone().map(|b| b.into_inner().map(|_| format_args!(".."))), + "bindings", + &bindings.clone().map(|b| b.into_inner().binding().map(|_| format_args!(".."))), ) .field("type_ns_only", type_ns_only) .field("nested", nested) @@ -242,15 +244,16 @@ pub(crate) struct NameResolution<'ra> { /// Single imports that may define the name in the namespace. /// Imports are arena-allocated, so it's ok to use pointers as keys. pub single_imports: FxIndexSet<Import<'ra>>, - /// The least shadowable known binding for this name, or None if there are no known bindings. - pub binding: Option<NameBinding<'ra>>, - pub shadowed_glob: Option<NameBinding<'ra>>, + /// The non-glob binding for this name, if it is known to exist. + pub non_glob_binding: Option<NameBinding<'ra>>, + /// The glob binding for this name, if it is known to exist. + pub glob_binding: Option<NameBinding<'ra>>, } impl<'ra> NameResolution<'ra> { /// Returns the binding for the name if it is known or None if it not known. pub(crate) fn binding(&self) -> Option<NameBinding<'ra>> { - self.binding.and_then(|binding| { + self.best_binding().and_then(|binding| { if !binding.is_glob_import() || self.single_imports.is_empty() { Some(binding) } else { @@ -258,6 +261,10 @@ impl<'ra> NameResolution<'ra> { } }) } + + pub(crate) fn best_binding(&self) -> Option<NameBinding<'ra>> { + self.non_glob_binding.or(self.glob_binding) + } } /// An error that may be transformed into a diagnostic later. Used to combine multiple unresolved @@ -338,69 +345,71 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.check_reserved_macro_name(key.ident, res); self.set_binding_parent_module(binding, module); self.update_resolution(module, key, warn_ambiguity, |this, resolution| { - if let Some(old_binding) = resolution.binding { + if let Some(old_binding) = resolution.best_binding() { if res == Res::Err && old_binding.res() != Res::Err { // Do not override real bindings with `Res::Err`s from error recovery. return Ok(()); } match (old_binding.is_glob_import(), binding.is_glob_import()) { (true, true) => { + let (glob_binding, old_glob_binding) = (binding, old_binding); // FIXME: remove `!binding.is_ambiguity_recursive()` after delete the warning ambiguity. if !binding.is_ambiguity_recursive() && let NameBindingKind::Import { import: old_import, .. } = - old_binding.kind - && let NameBindingKind::Import { import, .. } = binding.kind + old_glob_binding.kind + && let NameBindingKind::Import { import, .. } = glob_binding.kind && old_import == import { - // We should replace the `old_binding` with `binding` regardless - // of whether they has same resolution or not when they are - // imported from the same glob-import statement. - resolution.binding = Some(binding); - } else if res != old_binding.res() { - resolution.binding = Some(this.new_ambiguity_binding( + // When imported from the same glob-import statement, we should replace + // `old_glob_binding` with `glob_binding`, regardless of whether + // they have the same resolution or not. + resolution.glob_binding = Some(glob_binding); + } else if res != old_glob_binding.res() { + resolution.glob_binding = Some(this.new_ambiguity_binding( AmbiguityKind::GlobVsGlob, - old_binding, - binding, + old_glob_binding, + glob_binding, warn_ambiguity, )); } else if !old_binding.vis.is_at_least(binding.vis, this.tcx) { // We are glob-importing the same item but with greater visibility. - resolution.binding = Some(binding); + resolution.glob_binding = Some(glob_binding); } else if binding.is_ambiguity_recursive() { - resolution.binding = Some(this.new_warn_ambiguity_binding(binding)); + resolution.glob_binding = + Some(this.new_warn_ambiguity_binding(glob_binding)); } } (old_glob @ true, false) | (old_glob @ false, true) => { - let (glob_binding, nonglob_binding) = + let (glob_binding, non_glob_binding) = if old_glob { (old_binding, binding) } else { (binding, old_binding) }; if key.ns == MacroNS - && nonglob_binding.expansion != LocalExpnId::ROOT - && glob_binding.res() != nonglob_binding.res() + && non_glob_binding.expansion != LocalExpnId::ROOT + && glob_binding.res() != non_glob_binding.res() { - resolution.binding = Some(this.new_ambiguity_binding( + resolution.non_glob_binding = Some(this.new_ambiguity_binding( AmbiguityKind::GlobVsExpanded, - nonglob_binding, + non_glob_binding, glob_binding, false, )); } else { - resolution.binding = Some(nonglob_binding); + resolution.non_glob_binding = Some(non_glob_binding); } - if let Some(old_shadowed_glob) = resolution.shadowed_glob { - assert!(old_shadowed_glob.is_glob_import()); - if glob_binding.res() != old_shadowed_glob.res() { - resolution.shadowed_glob = Some(this.new_ambiguity_binding( + if let Some(old_glob_binding) = resolution.glob_binding { + assert!(old_glob_binding.is_glob_import()); + if glob_binding.res() != old_glob_binding.res() { + resolution.glob_binding = Some(this.new_ambiguity_binding( AmbiguityKind::GlobVsGlob, - old_shadowed_glob, + old_glob_binding, glob_binding, false, )); - } else if !old_shadowed_glob.vis.is_at_least(binding.vis, this.tcx) { - resolution.shadowed_glob = Some(glob_binding); + } else if !old_glob_binding.vis.is_at_least(binding.vis, this.tcx) { + resolution.glob_binding = Some(glob_binding); } } else { - resolution.shadowed_glob = Some(glob_binding); + resolution.glob_binding = Some(glob_binding); } } (false, false) => { @@ -408,7 +417,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } } else { - resolution.binding = Some(binding); + if binding.is_glob_import() { + resolution.glob_binding = Some(binding); + } else { + resolution.non_glob_binding = Some(binding); + } } Ok(()) @@ -491,8 +504,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Define a dummy resolution containing a `Res::Err` as a placeholder for a failed // or indeterminate resolution, also mark such failed imports as used to avoid duplicate diagnostics. fn import_dummy_binding(&mut self, import: Import<'ra>, is_indeterminate: bool) { - if let ImportKind::Single { target, ref target_bindings, .. } = import.kind { - if !(is_indeterminate || target_bindings.iter().all(|binding| binding.get().is_none())) + if let ImportKind::Single { target, ref bindings, .. } = import.kind { + if !(is_indeterminate + || bindings.iter().all(|binding| binding.get().binding().is_none())) { return; // Has resolution, do not create the dummy binding } @@ -567,10 +581,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { glob_error |= import.is_glob(); - if let ImportKind::Single { source, ref source_bindings, .. } = import.kind + if let ImportKind::Single { source, ref bindings, .. } = import.kind && source.name == kw::SelfLower // Silence `unresolved import` error if E0429 is already emitted - && let Err(Determined) = source_bindings.value_ns.get() + && let PendingBinding::Ready(None) = bindings.value_ns.get() { continue; } @@ -628,7 +642,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for (key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); - let Some(binding) = resolution.binding else { continue }; + let Some(binding) = resolution.best_binding() else { continue }; if let NameBindingKind::Import { import, .. } = binding.kind && let Some((amb_binding, _)) = binding.ambiguity @@ -648,7 +662,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); } - if let Some(glob_binding) = resolution.shadowed_glob { + if let Some(glob_binding) = resolution.glob_binding + && resolution.non_glob_binding.is_some() + { if binding.res() != Res::Err && glob_binding.res() != Res::Err && let NameBindingKind::Import { import: glob_import, .. } = @@ -819,15 +835,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; import.imported_module.set(Some(module)); - let (source, target, source_bindings, target_bindings, type_ns_only) = match import.kind { - ImportKind::Single { - source, - target, - ref source_bindings, - ref target_bindings, - type_ns_only, - .. - } => (source, target, source_bindings, target_bindings, type_ns_only), + let (source, target, bindings, type_ns_only) = match import.kind { + ImportKind::Single { source, target, ref bindings, type_ns_only, .. } => { + (source, target, bindings, type_ns_only) + } ImportKind::Glob { .. } => { self.resolve_glob_import(import); return 0; @@ -838,21 +849,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut indeterminate_count = 0; self.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - if let Err(Undetermined) = source_bindings[ns].get() { - let binding = this.maybe_resolve_ident_in_module( - module, - source, - ns, - &import.parent_scope, - Some(import), - ); - source_bindings[ns].set(binding); - } else { + if bindings[ns].get() != PendingBinding::Pending { return; }; - + let binding_result = this.maybe_resolve_ident_in_module( + module, + source, + ns, + &import.parent_scope, + Some(import), + ); let parent = import.parent_scope.module; - match source_bindings[ns].get() { + let binding = match binding_result { Ok(binding) => { if binding.is_assoc_item() && !this.tcx.features().import_trait_associated_functions() @@ -865,12 +873,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) .emit(); } - + // We need the `target`, `source` can be extracted. let imported_binding = this.import(binding, import); - target_bindings[ns].set(Some(imported_binding)); this.define(parent, target, ns, imported_binding); + PendingBinding::Ready(Some(imported_binding)) } - Err(Determined) => { + Err(Determinacy::Determined) => { // Don't update the resolution for underscores, because it was never added. if target.name != kw::Underscore { let key = BindingKey::new(target, ns); @@ -878,9 +886,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { resolution.single_imports.swap_remove(&import); }); } + PendingBinding::Ready(None) } - Err(Undetermined) => indeterminate_count += 1, - } + Err(Determinacy::Undetermined) => { + indeterminate_count += 1; + PendingBinding::Pending + } + }; + bindings[ns].set(binding); } }); @@ -893,7 +906,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// consolidate multiple unresolved import errors into a single diagnostic. fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportError> { let ignore_binding = match &import.kind { - ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(), + ImportKind::Single { bindings, .. } => bindings[TypeNS].get().binding(), _ => None, }; let ambiguity_errors_len = @@ -1011,60 +1024,53 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { PathResult::Indeterminate => unreachable!(), }; - let (ident, target, source_bindings, target_bindings, type_ns_only, import_id) = - match import.kind { - ImportKind::Single { - source, - target, - ref source_bindings, - ref target_bindings, - type_ns_only, - id, - .. - } => (source, target, source_bindings, target_bindings, type_ns_only, id), - ImportKind::Glob { is_prelude, ref max_vis, id } => { - if import.module_path.len() <= 1 { - // HACK(eddyb) `lint_if_path_starts_with_module` needs at least - // 2 segments, so the `resolve_path` above won't trigger it. - let mut full_path = import.module_path.clone(); - full_path.push(Segment::from_ident(Ident::dummy())); - self.lint_if_path_starts_with_module(Some(finalize), &full_path, None); - } + let (ident, target, bindings, type_ns_only, import_id) = match import.kind { + ImportKind::Single { source, target, ref bindings, type_ns_only, id, .. } => { + (source, target, bindings, type_ns_only, id) + } + ImportKind::Glob { is_prelude, ref max_vis, id } => { + if import.module_path.len() <= 1 { + // HACK(eddyb) `lint_if_path_starts_with_module` needs at least + // 2 segments, so the `resolve_path` above won't trigger it. + let mut full_path = import.module_path.clone(); + full_path.push(Segment::from_ident(Ident::dummy())); + self.lint_if_path_starts_with_module(Some(finalize), &full_path, None); + } - if let ModuleOrUniformRoot::Module(module) = module - && module == import.parent_scope.module - { - // Importing a module into itself is not allowed. - return Some(UnresolvedImportError { + if let ModuleOrUniformRoot::Module(module) = module + && module == import.parent_scope.module + { + // Importing a module into itself is not allowed. + return Some(UnresolvedImportError { + span: import.span, + label: Some(String::from("cannot glob-import a module into itself")), + note: None, + suggestion: None, + candidates: None, + segment: None, + module: None, + }); + } + if !is_prelude + && let Some(max_vis) = max_vis.get() + && !max_vis.is_at_least(import.vis, self.tcx) + { + let def_id = self.local_def_id(id); + self.lint_buffer.buffer_lint( + UNUSED_IMPORTS, + id, + import.span, + BuiltinLintDiag::RedundantImportVisibility { + max_vis: max_vis.to_string(def_id, self.tcx), + import_vis: import.vis.to_string(def_id, self.tcx), span: import.span, - label: Some(String::from("cannot glob-import a module into itself")), - note: None, - suggestion: None, - candidates: None, - segment: None, - module: None, - }); - } - if !is_prelude - && let Some(max_vis) = max_vis.get() - && !max_vis.is_at_least(import.vis, self.tcx) - { - let def_id = self.local_def_id(id); - self.lint_buffer.buffer_lint( - UNUSED_IMPORTS, - id, - import.span, - BuiltinLintDiag::RedundantImportVisibility { - max_vis: max_vis.to_string(def_id, self.tcx), - import_vis: import.vis.to_string(def_id, self.tcx), - span: import.span, - }, - ); - } - return None; + }, + ); } - _ => unreachable!(), - }; + return None; + } + _ => unreachable!(), + }; if self.privacy_errors.len() != privacy_errors_len { // Get the Res for the last element, so that we can point to alternative ways of @@ -1095,17 +1101,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ns, &import.parent_scope, Some(Finalize { report_private: false, ..finalize }), - target_bindings[ns].get(), + bindings[ns].get().binding(), Some(import), ); match binding { Ok(binding) => { // Consistency checks, analogous to `finalize_macro_resolutions`. - let initial_res = source_bindings[ns].get().map(|initial_binding| { + let initial_res = bindings[ns].get().binding().map(|binding| { + let initial_binding = binding.import_source(); all_ns_err = false; - if let Some(target_binding) = target_bindings[ns].get() - && target.name == kw::Underscore + if target.name == kw::Underscore && initial_binding.is_extern_crate() && !initial_binding.is_import() { @@ -1114,7 +1120,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { Used::Other }; - this.record_use(ident, target_binding, used); + this.record_use(ident, binding, used); } initial_binding.res() }); @@ -1126,7 +1132,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .span_delayed_bug(import.span, "some error happened for an import"); return; } - if let Ok(initial_res) = initial_res { + if let Some(initial_res) = initial_res { if res != initial_res { span_bug!(import.span, "inconsistent resolution for an import"); } @@ -1179,7 +1185,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return None; } // Never suggest the same name match *resolution.borrow() { - NameResolution { binding: Some(name_binding), .. } => { + ref resolution + if let Some(name_binding) = resolution.best_binding() => + { match name_binding.kind { NameBindingKind::Import { binding, .. } => { match binding.kind { @@ -1269,7 +1277,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut any_successful_reexport = false; let mut crate_private_reexport = false; self.per_ns(|this, ns| { - let Ok(binding) = source_bindings[ns].get() else { + let Some(binding) = bindings[ns].get().binding().map(|b| b.import_source()) else { return; }; @@ -1340,7 +1348,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut full_path = import.module_path.clone(); full_path.push(Segment::from_ident(ident)); self.per_ns(|this, ns| { - if let Ok(binding) = source_bindings[ns].get() { + if let Some(binding) = bindings[ns].get().binding().map(|b| b.import_source()) { this.lint_if_path_starts_with_module(Some(finalize), &full_path, Some(binding)); } }); @@ -1350,7 +1358,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. self.per_ns(|this, ns| { - if let Ok(binding) = source_bindings[ns].get() { + if let Some(binding) = bindings[ns].get().binding().map(|b| b.import_source()) { this.import_res_map.entry(import_id).or_default()[ns] = Some(binding.res()); } }); @@ -1361,10 +1369,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'ra>) -> bool { // This function is only called for single imports. - let ImportKind::Single { - source, target, ref source_bindings, ref target_bindings, id, .. - } = import.kind - else { + let ImportKind::Single { source, target, ref bindings, id, .. } = import.kind else { unreachable!() }; @@ -1391,7 +1396,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut is_redundant = true; let mut redundant_span = PerNS { value_ns: None, type_ns: None, macro_ns: None }; self.per_ns(|this, ns| { - if is_redundant && let Ok(binding) = source_bindings[ns].get() { + let binding = bindings[ns].get().binding().map(|b| b.import_source()); + if is_redundant && let Some(binding) = binding { if binding.res() == Res::Err { return; } @@ -1402,7 +1408,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &import.parent_scope, None, false, - target_bindings[ns].get(), + bindings[ns].get().binding(), None, ) { Ok(other_binding) => { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 08629090bb1..44a567f7810 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3437,7 +3437,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }; ident.span.normalize_to_macros_2_0_and_adjust(module.expansion); let key = BindingKey::new(ident, ns); - let mut binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding); + let mut binding = + self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.best_binding()); debug!(?binding); if binding.is_none() { // We could not find the trait item in the correct namespace. @@ -3448,7 +3449,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { _ => ns, }; let key = BindingKey::new(ident, ns); - binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding); + binding = + self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.best_binding()); debug!(?binding); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 8114021510e..b669796bb02 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -880,8 +880,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn lookup_doc_alias_name(&mut self, path: &[Segment], ns: Namespace) -> Option<(DefId, Ident)> { let find_doc_alias_name = |r: &mut Resolver<'ra, '_>, m: Module<'ra>, item_name: Symbol| { for resolution in r.resolutions(m).borrow().values() { - let Some(did) = - resolution.borrow().binding.and_then(|binding| binding.res().opt_def_id()) + let Some(did) = resolution + .borrow() + .best_binding() + .and_then(|binding| binding.res().opt_def_id()) else { continue; }; @@ -1464,15 +1466,16 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { self.resolve_path(mod_path, None, None) { let resolutions = self.r.resolutions(module).borrow(); - let targets: Vec<_> = - resolutions - .iter() - .filter_map(|(key, resolution)| { - resolution.borrow().binding.map(|binding| binding.res()).and_then( - |res| if filter_fn(res) { Some((key, res)) } else { None }, - ) - }) - .collect(); + let targets: Vec<_> = resolutions + .iter() + .filter_map(|(key, resolution)| { + resolution + .borrow() + .best_binding() + .map(|binding| binding.res()) + .and_then(|res| if filter_fn(res) { Some((key, res)) } else { None }) + }) + .collect(); if let [target] = targets.as_slice() { return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1)); } @@ -2305,7 +2308,9 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let targets = resolutions .borrow() .iter() - .filter_map(|(key, res)| res.borrow().binding.map(|binding| (key, binding.res()))) + .filter_map(|(key, res)| { + res.borrow().best_binding().map(|binding| (key, binding.res())) + }) .filter(|(_, res)| match (kind, res) { (AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true, (AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 6e4c5ef1909..f8d1b6783e3 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -641,7 +641,7 @@ impl<'ra> Module<'ra> { F: FnMut(&mut R, Ident, Namespace, NameBinding<'ra>), { for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { - if let Some(binding) = name_resolution.borrow().binding { + if let Some(binding) = name_resolution.borrow().best_binding() { f(resolver, key.ident, key.ns, binding); } } @@ -891,6 +891,13 @@ impl<'ra> NameBindingData<'ra> { } } + fn import_source(&self) -> NameBinding<'ra> { + match self.kind { + NameBindingKind::Import { binding, .. } => binding, + _ => unreachable!(), + } + } + fn is_ambiguity_recursive(&self) -> bool { self.ambiguity.is_some() || match self.kind { |
