Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exclude dependencies of std for diagnostics #135278

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions compiler/rustc_expand/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}

Expand All @@ -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);
}
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down
77 changes: 60 additions & 17 deletions compiler/rustc_metadata/src/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -402,7 +402,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
fn register_crate(
&mut self,
host_lib: Option<Library>,
root: Option<&CratePaths>,
dep_root: Option<&CratePaths>,
lib: Library,
dep_kind: CrateDepKind,
name: Symbol,
Expand All @@ -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();
Expand All @@ -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;
Expand Down Expand Up @@ -465,6 +469,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
dep_kind,
source,
private_dep,
stdlib_private_dep,
host_hash,
);

Expand Down Expand Up @@ -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,
Expand All @@ -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<CrateNum, CrateError> {
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[..]),
Expand Down Expand Up @@ -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())),
}
}
}
Expand All @@ -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!(),
}
Expand Down Expand Up @@ -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<CrateNumMap, CrateError> {
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());
}
Expand All @@ -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);
}

Expand Down Expand Up @@ -1116,6 +1136,29 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> {
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<Span> {
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_metadata/src/locator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ pub(crate) struct CrateLocator<'a> {

#[derive(Clone)]
pub(crate) struct CratePaths {
name: Symbol,
pub(crate) name: Symbol,
source: CrateSource,
}

Expand Down Expand Up @@ -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<CratePaths>) -> CrateError {
pub(crate) fn into_error(self, dep_root: Option<CratePaths>) -> 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(),
Expand Down Expand Up @@ -914,7 +914,7 @@ struct CrateRejections {
/// otherwise they are ignored.
pub(crate) struct CombinedLocatorError {
crate_name: Symbol,
root: Option<CratePaths>,
dep_root: Option<CratePaths>,
triple: TargetTuple,
dll_prefix: String,
dll_suffix: String,
Expand Down Expand Up @@ -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),
};
Expand All @@ -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 `{}`: {}",
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Svh>,
/// The crate was used non-speculatively.
Expand Down Expand Up @@ -1826,6 +1829,7 @@ impl CrateMetadata {
dep_kind: CrateDepKind,
source: CrateSource,
private_dep: bool,
stdlib_private_dep: bool,
host_hash: Option<Svh>,
) -> CrateMetadata {
let trait_impls = root
Expand Down Expand Up @@ -1857,6 +1861,7 @@ impl CrateMetadata {
dep_kind,
source: Lrc::new(source),
private_dep,
stdlib_private_dep,
host_hash,
used: false,
extern_crate: None,
Expand Down Expand Up @@ -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
}
Expand Down
18 changes: 17 additions & 1 deletion compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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.
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading
Loading