Skip to content

[experiment] inject compiler builtins #136234

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

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub fn inject(
for &name in names.iter().rev() {
let ident_span = if edition >= Edition2018 { span } else { call_site };
let item = if name == sym::compiler_builtins {
eprintln!("INJECTING BUILTINS");
// compiler_builtins is a private implementation detail. We only
// need to insert it into the crate graph for linking and should not
// expose any of its public API.
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_metadata/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ metadata_crate_dep_rustc_driver =
metadata_crate_location_unknown_type =
extern location for {$crate_name} is of an unknown type: {$path}

metadata_crate_not_compiler_builtins =
the crate `{$crate_name}` resolved as `compiler_builtins` but is not `#![compiler_builtins]`

metadata_crate_not_panic_runtime =
the crate `{$crate_name}` is not a panic runtime

Expand Down
144 changes: 123 additions & 21 deletions compiler/rustc_metadata/src/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,43 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
}
}

/// Reason that a crate is being sourced as a dependency.
#[derive(Clone, Copy)]
enum CrateOrigin<'a> {
/// This crate was a dependency of another crate.
Dependency {
dep_root: &'a CratePaths,
/// Dependency info about this crate.
dep: &'a CrateDep,
},
/// Injected by `rustc`.
Injected,
/// An extern that has been provided with the `force` option.
ForcedExtern,
/// Part of the extern prelude.
ExternPrelude,
/// Provided by `extern crate foo`.
AstExtern,
}

impl<'a> CrateOrigin<'a> {
/// Return the dependency root, if any.
fn dep_root(&self) -> Option<&'a CratePaths> {
match self {
CrateOrigin::Dependency { dep_root, .. } => Some(dep_root),
_ => None,
}
}

/// Return dependency information, if any.
fn dep(&self) -> Option<&'a CrateDep> {
match self {
CrateOrigin::Dependency { dep, .. } => Some(dep),
_ => None,
}
}
}

impl CStore {
pub fn from_tcx(tcx: TyCtxt<'_>) -> FreezeReadGuard<'_, CStore> {
FreezeReadGuard::map(tcx.untracked().cstore.read(), |cstore| {
Expand Down Expand Up @@ -404,7 +441,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
&self,
name: Symbol,
private_dep: Option<bool>,
dep_root: Option<&CratePaths>,
origin: CrateOrigin<'_>,
) -> bool {
// Standard library crates are never private.
if STDLIB_STABLE_CRATES.contains(&name) {
Expand All @@ -414,10 +451,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {

let extern_private = self.sess.opts.externs.get(name.as_str()).map(|e| e.is_private_dep);

if matches!(origin, CrateOrigin::Injected) {
return true;
}

// Any descendants of `std` should be private. These crates are usually not marked
// private in metadata, so we ignore that field.
if extern_private.is_none()
&& let Some(dep) = dep_root
&& let Some(dep) = origin.dep_root()
&& STDLIB_STABLE_CRATES.contains(&dep.name)
{
return true;
Expand All @@ -435,7 +476,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
fn register_crate(
&mut self,
host_lib: Option<Library>,
dep_root: Option<&CratePaths>,
origin: CrateOrigin<'_>,
lib: Library,
dep_kind: CrateDepKind,
name: Symbol,
Expand All @@ -447,7 +488,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
let Library { source, metadata } = lib;
let crate_root = metadata.get_root();
let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
let private_dep = self.is_private_dep(name, private_dep, dep_root);
let private_dep = self.is_private_dep(name, private_dep, origin);

// Claim this crate number and cache it
let feed = self.cstore.intern_stable_crate_id(&crate_root, self.tcx)?;
Expand All @@ -463,7 +504,7 @@ 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 dep_root = if let Some(dep_root) = dep_root {
let dep_root = if let Some(dep_root) = origin.dep_root() {
dep_root
} else {
crate_paths = CratePaths::new(crate_root.name(), source.clone());
Expand Down Expand Up @@ -571,17 +612,23 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
name: Symbol,
span: Span,
dep_kind: CrateDepKind,
origin: CrateOrigin<'_>,
) -> Option<CrateNum> {
self.used_extern_options.insert(name);
match self.maybe_resolve_crate(name, dep_kind, None) {
match self.maybe_resolve_crate(name, dep_kind, origin) {
Ok(cnum) => {
self.cstore.set_used_recursively(cnum);
Some(cnum)
}
Err(err) => {
debug!("failed to resolve crate {} {:?}", name, dep_kind);
let missing_core =
self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err();
let missing_core = self
.maybe_resolve_crate(
sym::core,
CrateDepKind::Explicit,
CrateOrigin::ExternPrelude,
)
.is_err();
err.report(self.sess, span, missing_core);
None
}
Expand All @@ -592,15 +639,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
&'b mut self,
name: Symbol,
mut dep_kind: CrateDepKind,
dep_of: Option<(&'b CratePaths, &'b CrateDep)>,
origin: CrateOrigin<'b>,
) -> Result<CrateNum, CrateError> {
info!("resolving crate `{}`", name);
if !name.as_str().is_ascii() {
return Err(CrateError::NonAsciiName(name));
}

let dep_root = dep_of.map(|d| d.0);
let dep = dep_of.map(|d| d.1);
let dep_root = origin.dep_root();
let dep = origin.dep();
let hash = dep.map(|d| d.hash);
let host_hash = dep.map(|d| d.host_hash).flatten();
let extra_filename = dep.map(|d| &d.extra_filename[..]);
Expand Down Expand Up @@ -638,12 +685,12 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {

match result {
(LoadResult::Previous(cnum), None) => {
info!("library for `{}` was loaded previously", name);
info!("library for `{}` was loaded previously, cnum {cnum}", name);
// When `private_dep` is none, it indicates the directly dependent crate. If it is
// not specified by `--extern` on command line parameters, it may be
// `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, private_dep, dep_root);
let private_dep = self.is_private_dep(name, private_dep, origin);
let data = self.cstore.get_crate_data_mut(cnum);
if data.is_proc_macro_crate() {
dep_kind = CrateDepKind::MacrosOnly;
Expand All @@ -654,7 +701,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}
(LoadResult::Loaded(library), host_library) => {
info!("register newly loaded library for `{}`", name);
self.register_crate(host_library, dep_root, library, dep_kind, name, private_dep)
self.register_crate(host_library, origin, library, dep_kind, name, private_dep)
}
_ => panic!(),
}
Expand Down Expand Up @@ -730,7 +777,10 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
CrateDepKind::MacrosOnly => CrateDepKind::MacrosOnly,
_ => dep.kind,
};
let cnum = self.maybe_resolve_crate(dep.name, dep_kind, Some((dep_root, &dep)))?;
let cnum = self.maybe_resolve_crate(dep.name, dep_kind, CrateOrigin::Dependency {
dep_root,
dep: &dep,
})?;
crate_num_map.push(cnum);
}

Expand Down Expand Up @@ -824,7 +874,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
};
info!("panic runtime not found -- loading {}", name);

let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else {
let Some(cnum) =
self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
else {
return;
};
let data = self.cstore.get_crate_data(cnum);
Expand Down Expand Up @@ -853,7 +905,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
info!("loading profiler");

let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else {
let Some(cnum) =
self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
else {
return;
};
let data = self.cstore.get_crate_data(cnum);
Expand Down Expand Up @@ -966,12 +1020,50 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
if entry.force {
let name_interned = Symbol::intern(name);
if !self.used_extern_options.contains(&name_interned) {
self.resolve_crate(name_interned, DUMMY_SP, CrateDepKind::Explicit);
self.resolve_crate(
name_interned,
DUMMY_SP,
CrateDepKind::Explicit,
CrateOrigin::ForcedExtern,
);
}
}
}
}

fn inject_compiler_builtins(&mut self, krate: &ast::Crate) {
if attr::contains_name(&krate.attrs, sym::compiler_builtins)
|| attr::contains_name(&krate.attrs, sym::no_core)
{
// `compiler_builtins` does not get extern builtins, nor do `#![no_core]` crates
info!("`compiler_builtins` unneeded");
return;
}

for (cnum, cmeta) in self.cstore.iter_crate_data() {
if cmeta.is_compiler_builtins() {
info!("`compiler_builtins` already exists (cnum = {cnum}); skipping injection");
return;
}
}

let Ok(cnum) = self.maybe_resolve_crate(
sym::compiler_builtins,
CrateDepKind::Implicit,
CrateOrigin::Injected,
) else {
info!("`compiler_builtins` not resolved");
return;
};

let cmeta = self.cstore.get_crate_data(cnum);

// Sanity check the loaded crate to ensure it is indeed compiler_builtins
if !cmeta.is_compiler_builtins() {
self.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cmeta.name() });
}
}

fn inject_dependency_if(
&mut self,
krate: CrateNum,
Expand Down Expand Up @@ -1081,6 +1173,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}

pub fn postprocess(&mut self, krate: &ast::Crate) {
info!("POSTPROCESS");
self.inject_compiler_builtins(krate);
self.inject_forced_externs();
self.inject_profiler_runtime();
self.inject_allocator_crate(krate);
Expand All @@ -1092,6 +1186,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
info!("{:?}", CrateDump(self.cstore));
}

/// Process an `extern crate foo` AST node.
pub fn process_extern_crate(
&mut self,
item: &ast::Item,
Expand All @@ -1111,13 +1206,19 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}
None => item.ident.name,
};

let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) {
CrateDepKind::MacrosOnly
} else {
CrateDepKind::Explicit
};

let cnum = self.resolve_crate(name, item.span, dep_kind)?;
if name == sym::compiler_builtins {
info!("BUILTINS DETECTED dep_kind {dep_kind:?}");
return None;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you ignoring explicit extern crate compiler_builtins;? I think this is the reason of the CI failure as the implicitly injected compiler_builtins dependency isn't checked for stability, yet explicit mentions should be.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, that's dumb. I did this as a more minimal step than removing it from standard_library_imports for experimentation, but you're right that this would catch the explicit extern as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, that was it. I updated #136226 with the changes here, so will close this one.

}

let cnum = self.resolve_crate(name, item.span, dep_kind, CrateOrigin::AstExtern)?;

let path_len = definitions.def_path(def_id).data.len();
self.cstore.update_extern_crate(cnum, ExternCrate {
Expand All @@ -1133,7 +1234,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}

pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum> {
let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit)?;
let cnum =
self.resolve_crate(name, span, CrateDepKind::Explicit, CrateOrigin::ExternPrelude)?;

self.cstore.update_extern_crate(cnum, ExternCrate {
src: ExternCrateSource::Path,
Expand All @@ -1147,7 +1249,7 @@ 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()
self.maybe_resolve_crate(name, CrateDepKind::Explicit, CrateOrigin::ExternPrelude).ok()
}
}

Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_metadata/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,12 @@ pub struct CrateNotPanicRuntime {
pub crate_name: Symbol,
}

#[derive(Diagnostic)]
#[diag(metadata_crate_not_compiler_builtins)]
pub struct CrateNotCompilerBuiltins {
pub crate_name: Symbol,
}

#[derive(Diagnostic)]
#[diag(metadata_no_panic_strategy)]
pub struct NoPanicStrategy {
Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_metadata/src/locator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ pub(crate) struct CrateLocator<'a> {
crate_rejections: CrateRejections,
}

#[derive(Clone)]
#[derive(Clone, Debug)]
pub(crate) struct CratePaths {
pub(crate) name: Symbol,
source: CrateSource,
Expand All @@ -272,7 +272,7 @@ impl CratePaths {
}
}

#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub(crate) enum CrateFlavor {
Rlib,
Rmeta,
Expand Down Expand Up @@ -893,13 +893,13 @@ fn get_flavor_from_path(path: &Path) -> CrateFlavor {

// ------------------------------------------ Error reporting -------------------------------------

#[derive(Clone)]
#[derive(Clone, Debug)]
struct CrateMismatch {
path: PathBuf,
got: String,
}

#[derive(Clone, Default)]
#[derive(Clone, Debug, Default)]
struct CrateRejections {
via_hash: Vec<CrateMismatch>,
via_triple: Vec<CrateMismatch>,
Expand All @@ -912,6 +912,7 @@ struct CrateRejections {
/// Candidate rejection reasons collected during crate search.
/// If no candidate is accepted, then these reasons are presented to the user,
/// otherwise they are ignored.
#[derive(Debug)]
pub(crate) struct CombinedLocatorError {
crate_name: Symbol,
dep_root: Option<CratePaths>,
Expand All @@ -921,6 +922,7 @@ pub(crate) struct CombinedLocatorError {
crate_rejections: CrateRejections,
}

#[derive(Debug)]
pub(crate) enum CrateError {
NonAsciiName(Symbol),
ExternLocationNotExist(Symbol, PathBuf),
Expand Down
Loading
Loading