diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 91624c7554cb0..3e3f35332e0d5 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -18,7 +18,7 @@ use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::validate_attr; use rustc_session::Session; use rustc_session::parse::feature_err; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym}; use thin_vec::ThinVec; use tracing::instrument; @@ -107,14 +107,11 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - // If the enabled feature is unstable, record it. if UNSTABLE_LANG_FEATURES.iter().find(|f| name == f.name).is_some() { - // When the ICE comes from core, alloc or std (approximation of the standard - // library), there's a chance that the person hitting the ICE may be using - // -Zbuild-std or similar with an untested target. The bug is probably in the - // standard library and not the compiler in that case, but that doesn't really - // matter - we want a bug report. - if features.internal(name) - && ![sym::core, sym::alloc, sym::std].contains(&crate_name) - { + // When the ICE comes a standard library crate, there's a chance that the person + // hitting the ICE may be using -Zbuild-std or similar with an untested target. + // The bug is probably in the standard library and not the compiler in that case, + // but that doesn't really matter - we want a bug report. + if features.internal(name) && !STDLIB_STABLE_CRATES.contains(&crate_name) { sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed); } @@ -133,7 +130,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - // Similar to above, detect internal lib features to suppress // the ICE message that asks for a report. - if features.internal(name) && ![sym::core, sym::alloc, sym::std].contains(&crate_name) { + if features.internal(name) && !STDLIB_STABLE_CRATES.contains(&crate_name) { sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed); } } diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs index 5ccfcf93f69ef..69d7a6c97cb36 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs @@ -8,7 +8,7 @@ use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER}; use rustc_middle::span_bug; use rustc_middle::ty::{self, Ty}; use rustc_session::lint::builtin::{RUST_2021_PRELUDE_COLLISIONS, RUST_2024_PRELUDE_COLLISIONS}; -use rustc_span::{Ident, Span, kw, sym}; +use rustc_span::{Ident, STDLIB_STABLE_CRATES, Span, kw, sym}; use rustc_trait_selection::infer::InferCtxtExt; use tracing::debug; @@ -76,7 +76,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // No need to lint if method came from std/core, as that will now be in the prelude - if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) { + if STDLIB_STABLE_CRATES.contains(&self.tcx.crate_name(pick.item.def_id.krate)) { return; } @@ -252,7 +252,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // No need to lint if method came from std/core, as that will now be in the prelude - if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) { + if STDLIB_STABLE_CRATES.contains(&self.tcx.crate_name(pick.item.def_id.krate)) { return; } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index c8715f94d5dd3..c05e1c3bca470 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -29,7 +29,7 @@ use rustc_session::lint::{self, BuiltinLintDiag}; use rustc_session::output::validate_crate_name; use rustc_session::search_paths::PathKind; use rustc_span::edition::Edition; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; +use rustc_span::{DUMMY_SP, Ident, STDLIB_STABLE_CRATES, Span, Symbol, sym}; use rustc_target::spec::{PanicStrategy, Target, TargetTuple}; use tracing::{debug, info, trace}; @@ -402,7 +402,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { fn register_crate( &mut self, host_lib: Option, - root: Option<&CratePaths>, + dep_root: Option<&CratePaths>, lib: Library, dep_kind: CrateDepKind, name: Symbol, @@ -416,6 +416,10 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash()); let private_dep = self.is_private_dep(name.as_str(), private_dep); + // At this point there are no other dependencies, so treat dependencies + // of `std` as stdlib-private. + let stdlib_private_dep = self.maybe_stdlib_private_dep(dep_root, name); + // Claim this crate number and cache it let feed = self.cstore.intern_stable_crate_id(&crate_root, self.tcx)?; let cnum = feed.key(); @@ -430,14 +434,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // Maintain a reference to the top most crate. // Stash paths for top-most crate locally if necessary. let crate_paths; - let root = if let Some(root) = root { - root + let dep_root = if let Some(dep_root) = dep_root { + dep_root } else { crate_paths = CratePaths::new(crate_root.name(), source.clone()); &crate_paths }; - let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, dep_kind)?; + let cnum_map = self.resolve_crate_deps(dep_root, &crate_root, &metadata, cnum, dep_kind)?; let raw_proc_macros = if crate_root.is_proc_macro_crate() { let temp_root; @@ -465,6 +469,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { dep_kind, source, private_dep, + stdlib_private_dep, host_hash, ); @@ -533,6 +538,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { })) } + /// Attempt to resolve the crate but emit an error if it fails. fn resolve_crate( &mut self, name: Symbol, @@ -559,15 +565,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { &'b mut self, name: Symbol, mut dep_kind: CrateDepKind, - dep: Option<(&'b CratePaths, &'b CrateDep)>, + dep_of: Option<(&'b CratePaths, &'b CrateDep)>, ) -> Result { info!("resolving crate `{}`", name); if !name.as_str().is_ascii() { return Err(CrateError::NonAsciiName(name)); } - let (root, hash, host_hash, extra_filename, path_kind, private_dep) = match dep { - Some((root, dep)) => ( - Some(root), + let (dep_root, hash, host_hash, extra_filename, path_kind, private_dep) = match dep_of { + Some((dep_root, dep)) => ( + Some(dep_root), Some(dep.hash), dep.host_hash, Some(&dep.extra_filename[..]), @@ -599,7 +605,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { dep_kind = CrateDepKind::MacrosOnly; match self.load_proc_macro(&mut locator, path_kind, host_hash)? { Some(res) => res, - None => return Err(locator.into_error(root.cloned())), + None => return Err(locator.into_error(dep_root.cloned())), } } } @@ -613,17 +619,24 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // `private-dependency` when `register_crate` is called for the first time. Then it must be updated to // `public-dependency` here. let private_dep = self.is_private_dep(name.as_str(), private_dep); + + // If the dependency root is something other than `std`, indicate that the crate + // should no longer be considered stdlib-private. + let maybe_stdlib_private = self.maybe_stdlib_private_dep(dep_root, name); + let data = self.cstore.get_crate_data_mut(cnum); if data.is_proc_macro_crate() { dep_kind = CrateDepKind::MacrosOnly; } data.set_dep_kind(cmp::max(data.dep_kind(), dep_kind)); data.update_and_private_dep(private_dep); + data.update_and_stdlib_private_dep(!maybe_stdlib_private); + Ok(cnum) } (LoadResult::Loaded(library), host_library) => { info!("register newly loaded library for `{}`", name); - self.register_crate(host_library, root, library, dep_kind, name, private_dep) + self.register_crate(host_library, dep_root, library, dep_kind, name, private_dep) } _ => panic!(), } @@ -663,16 +676,20 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { })) } - // Go through the crate metadata and load any crates that it references + /// Go through the crate metadata and load any crates that it references. fn resolve_crate_deps( &mut self, - root: &CratePaths, + dep_root: &CratePaths, crate_root: &CrateRoot, metadata: &MetadataBlob, krate: CrateNum, dep_kind: CrateDepKind, ) -> Result { - debug!("resolving deps of external crate"); + debug!( + "resolving deps of external crate `{}` with dep root `{}`", + crate_root.name(), + dep_root.name + ); if crate_root.is_proc_macro_crate() { return Ok(CrateNumMap::new()); } @@ -685,14 +702,17 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { crate_num_map.push(krate); for dep in deps { info!( - "resolving dep crate {} hash: `{}` extra filename: `{}`", - dep.name, dep.hash, dep.extra_filename + "resolving dep `{}`->`{}` hash: `{}` extra filename: `{}`", + crate_root.name(), + dep.name, + dep.hash, + dep.extra_filename ); let dep_kind = match dep_kind { CrateDepKind::MacrosOnly => CrateDepKind::MacrosOnly, _ => dep.kind, }; - let cnum = self.maybe_resolve_crate(dep.name, dep_kind, Some((root, &dep)))?; + let cnum = self.maybe_resolve_crate(dep.name, dep_kind, Some((dep_root, &dep)))?; crate_num_map.push(cnum); } @@ -1116,6 +1136,29 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option { self.maybe_resolve_crate(name, CrateDepKind::Explicit, None).ok() } + + /// Return `true` if this is a crate is a dependency of the standard library, `false` otherwise. + /// + /// This function's result is not absolute, if the same dependency is used by a non-std crate + /// then it should not be treated as stdlib-private (hence the "maybe"). + fn maybe_stdlib_private_dep(&self, dep_root: Option<&CratePaths>, new_crate: Symbol) -> bool { + // If there is no dependency root, this crate was passed directly. + let Some(dep_root) = dep_root else { + return false; + }; + + // If the new dependency is itself part of the stable stdlib crates (eg. `core` is a dep + // of `std`) or if the current crate is the standard library, stdlib-private is not + // relevant. + if STDLIB_STABLE_CRATES.contains(&new_crate) + || STDLIB_STABLE_CRATES.contains(&self.crate_name(LOCAL_CRATE)) + { + return false; + } + + // Otherwise, all crates that are a dependency of the standard library are private. + STDLIB_STABLE_CRATES.contains(&dep_root.name) + } } fn global_allocator_spans(krate: &ast::Crate) -> Vec { diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index b9ebf17af248f..2ddabeb49f70d 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -262,7 +262,7 @@ pub(crate) struct CrateLocator<'a> { #[derive(Clone)] pub(crate) struct CratePaths { - name: Symbol, + pub(crate) name: Symbol, source: CrateSource, } @@ -765,10 +765,10 @@ impl<'a> CrateLocator<'a> { self.extract_lib(rlibs, rmetas, dylibs).map(|opt| opt.map(|(_, lib)| lib)) } - pub(crate) fn into_error(self, root: Option) -> CrateError { + pub(crate) fn into_error(self, dep_root: Option) -> CrateError { CrateError::LocatorCombined(Box::new(CombinedLocatorError { crate_name: self.crate_name, - root, + dep_root, triple: self.tuple, dll_prefix: self.target.dll_prefix.to_string(), dll_suffix: self.target.dll_suffix.to_string(), @@ -914,7 +914,7 @@ struct CrateRejections { /// otherwise they are ignored. pub(crate) struct CombinedLocatorError { crate_name: Symbol, - root: Option, + dep_root: Option, triple: TargetTuple, dll_prefix: String, dll_suffix: String, @@ -987,7 +987,7 @@ impl CrateError { } CrateError::LocatorCombined(locator) => { let crate_name = locator.crate_name; - let add_info = match &locator.root { + let add_info = match &locator.dep_root { None => String::new(), Some(r) => format!(" which `{}` depends on", r.name), }; @@ -1012,7 +1012,7 @@ impl CrateError { path.display() )); } - if let Some(r) = locator.root { + if let Some(r) = locator.dep_root { for path in r.source.paths() { found_crates.push_str(&format!( "\ncrate `{}`: {}", diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index c2b5e318bda72..d5ebe54886181 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -118,6 +118,9 @@ pub(crate) struct CrateMetadata { /// Used by the 'exported_private_dependencies' lint, and for determining /// whether to emit suggestions that reference this crate. private_dep: bool, + /// This crate is only used as a dependency of the standard library and by default should + /// not be user-facing (i.e. not shown in diagnostics). + stdlib_private_dep: bool, /// The hash for the host proc macro. Used to support `-Z dual-proc-macro`. host_hash: Option, /// The crate was used non-speculatively. @@ -1826,6 +1829,7 @@ impl CrateMetadata { dep_kind: CrateDepKind, source: CrateSource, private_dep: bool, + stdlib_private_dep: bool, host_hash: Option, ) -> CrateMetadata { let trait_impls = root @@ -1857,6 +1861,7 @@ impl CrateMetadata { dep_kind, source: Lrc::new(source), private_dep, + stdlib_private_dep, host_hash, used: false, extern_crate: None, @@ -1908,6 +1913,10 @@ impl CrateMetadata { self.private_dep &= private_dep; } + pub(crate) fn update_and_stdlib_private_dep(&mut self, stdlib_private_dep: bool) { + self.stdlib_private_dep &= stdlib_private_dep; + } + pub(crate) fn used(&self) -> bool { self.used } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 527f2f10205a6..e99f5d6709408 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -18,7 +18,7 @@ use rustc_middle::util::Providers; use rustc_session::cstore::{CrateStore, ExternCrate}; use rustc_session::{Session, StableCrateId}; use rustc_span::hygiene::ExpnId; -use rustc_span::{Span, Symbol, kw}; +use rustc_span::{Span, Symbol, kw, sym}; use super::{Decodable, DecodeContext, DecodeIterator}; use crate::creader::{CStore, LoadedMacro}; @@ -561,6 +561,22 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { tcx.untracked().cstore.freeze(); tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).iter_crate_data().map(|(cnum, _)| cnum)) }, + visible_crates: |tcx, ()| { + // The list of loaded crates is now frozen in query cache, + // so make sure cstore is not mutably accessed from here on. + tcx.untracked().cstore.freeze(); + + // if `#![feature(rustc_private)]` is enabled in the current crate, include + if tcx.features().enabled(sym::rustc_private) { + tcx.crates(()) + } else { + tcx.arena.alloc_from_iter( + CStore::from_tcx(tcx) + .iter_crate_data() + .filter_map(|(cnum, meta)| (!meta.stdlib_private_dep).then_some(cnum)), + ) + } + }, used_crates: |tcx, ()| { // The list of loaded crates is now frozen in query cache, // so make sure cstore is not mutably accessed from here on. diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 95995b956cda5..cdbed0cdffb77 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2128,10 +2128,21 @@ rustc_queries! { eval_always desc { "calculating the stability index for the local crate" } } + /// All available crates in the graph. Use `.visible_crates(())` instead if results should only + /// include user-visible crates (such as for diagnostics). query crates(_: ()) -> &'tcx [CrateNum] { eval_always desc { "fetching all foreign CrateNum instances" } } + /// Crates that are meant to be accessible by the user. Use `.crates(())` if the entire crate + /// graph is required. + /// + /// This excludes e.g. private dependencies of the standard library, unless `rustc_private` is + /// enabled. + query visible_crates(_: ()) -> &'tcx [CrateNum] { + eval_always + desc { "fetching all user-reachable CrateNum instances" } + } // Crates that are loaded non-speculatively (not for diagnostics or doc links). // FIXME: This is currently only used for collecting lang items, but should be used instead of // `crates` in most other cases too. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index d26c007d227df..c5c84157435df 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2080,7 +2080,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn all_traits(self) -> impl Iterator + 'tcx { iter::once(LOCAL_CRATE) - .chain(self.crates(()).iter().copied()) + .chain(self.visible_crates(()).iter().copied()) .flat_map(move |cnum| self.traits(cnum).iter().copied()) } diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index 7b02aecdfae1f..090edd34de4e1 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -80,7 +80,7 @@ fn all_diagnostic_items(tcx: TyCtxt<'_>, (): ()) -> DiagnosticItems { let mut items = DiagnosticItems::default(); // Collect diagnostic items in other crates. - for &cnum in tcx.crates(()).iter().chain(std::iter::once(&LOCAL_CRATE)) { + for &cnum in tcx.visible_crates(()).iter().chain(std::iter::once(&LOCAL_CRATE)) { for (&name, &def_id) in &tcx.diagnostic_items(cnum).name_to_id { collect_item(tcx, &mut items, name, def_id); } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index d5c2a337b4c19..51cfbf594716c 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -67,7 +67,7 @@ mod span_encoding; pub use span_encoding::{DUMMY_SP, Span}; pub mod symbol; -pub use symbol::{Ident, MacroRulesNormalizedIdent, Symbol, kw, sym}; +pub use symbol::{Ident, MacroRulesNormalizedIdent, STDLIB_STABLE_CRATES, Symbol, kw, sym}; mod analyze_source_file; pub mod fatal_error; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 0dcf38e349365..ef1e2c20978c4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2240,6 +2240,10 @@ symbols! { } } +/// Symbols for crates that are part of the stable standard library: `std`, `core`, `alloc`, and +/// `proc_macro`. +pub const STDLIB_STABLE_CRATES: &[Symbol] = &[sym::std, sym::core, sym::alloc, sym::proc_macro]; + #[derive(Copy, Clone, Eq, HashStable_Generic, Encodable, Decodable)] pub struct Ident { pub name: Symbol, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 7ba87e180d0bc..405c26b5b3b58 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -27,7 +27,7 @@ use rustc_middle::ty::{ self, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast, }; use rustc_middle::{bug, span_bug}; -use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, sym}; +use rustc_span::{BytePos, DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym}; use tracing::{debug, instrument}; use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote}; @@ -520,7 +520,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { match obligation.cause.span.ctxt().outer_expn_data().macro_def_id { Some(macro_def_id) => { let crate_name = tcx.crate_name(macro_def_id.krate); - crate_name == sym::std || crate_name == sym::core + STDLIB_STABLE_CRATES.contains(&crate_name) } None => false, };