Skip to content

Commit 9bd0b76

Browse files
committed
Auto merge of rust-lang#136226 - tgross35:builtins-is-private-dep, r=<try>
Inject `compiler_builtins` during postprocessing rather than via AST `compiler_builtins` is currently injected into the AST as `extern crate compiler_builtins as _`. This has made gating via diagnostics difficult because it appears in the crate graph as a non-private dependency, and there isn't an easy way to differentiate between the injected AST and user-specified `extern crate compiler_builtins`. Resolve this by injecting `compiler_builtins` during postprocessing rather than early in the AST. Most of the time this isn't even needed because it shows up in `std` or `core`'s crate graph, but injection is still needed to ensure `#![no_core]` works correctly. A similar change was attempted at [1] but this encountered errors building `proc_macro` and `rustc-std-workspace-std`. Similar failures showed up while working on this patch, which were traced back to `compiler_builtins` showing up in the graph twice (once via dependency and once via injection). This is resolved by not injecting if a `#![compiler_builtins]` crate already exists. This PR is a smaller subset of changes, split from rust-lang#135501. rust-lang#135501 builds on this to resolve a couple remaining privacy issues and actually do the update that has been troublesome. [1]: rust-lang#113634 try-job: aarch64-gnu try-job: dist-x86_64-linux try-job: i686-mingw try-job: x86_64-gnu-distcheck try-job: x86_64-msvc-1 try-job: x86_64-rust-for-linux try-job: test-various
2 parents e6f12c8 + 0112499 commit 9bd0b76

10 files changed

+166
-64
lines changed

compiler/rustc_builtin_macros/src/standard_library_imports.rs

+13-36
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,12 @@ pub fn inject(
1919
let edition = sess.psess.edition;
2020

2121
// the first name in this list is the crate name of the crate with the prelude
22-
let names: &[Symbol] = if attr::contains_name(pre_configured_attrs, sym::no_core) {
22+
let name: Symbol = if attr::contains_name(pre_configured_attrs, sym::no_core) {
2323
return 0;
2424
} else if attr::contains_name(pre_configured_attrs, sym::no_std) {
25-
if attr::contains_name(pre_configured_attrs, sym::compiler_builtins) {
26-
&[sym::core]
27-
} else {
28-
&[sym::core, sym::compiler_builtins]
29-
}
25+
sym::core
3026
} else {
31-
&[sym::std]
27+
sym::std
3228
};
3329

3430
let expn_id = resolver.expansion_for_ast_pass(
@@ -43,36 +39,16 @@ pub fn inject(
4339
let ecfg = ExpansionConfig::default("std_lib_injection".to_string(), features);
4440
let cx = ExtCtxt::new(sess, ecfg, resolver, None);
4541

46-
// .rev() to preserve ordering above in combination with insert(0, ...)
47-
for &name in names.iter().rev() {
48-
let ident_span = if edition >= Edition2018 { span } else { call_site };
49-
let item = if name == sym::compiler_builtins {
50-
// compiler_builtins is a private implementation detail. We only
51-
// need to insert it into the crate graph for linking and should not
52-
// expose any of its public API.
53-
//
54-
// FIXME(#113634) We should inject this during post-processing like
55-
// we do for the panic runtime, profiler runtime, etc.
56-
cx.item(
57-
span,
58-
Ident::new(kw::Underscore, ident_span),
59-
thin_vec![],
60-
ast::ItemKind::ExternCrate(Some(name)),
61-
)
62-
} else {
63-
cx.item(
64-
span,
65-
Ident::new(name, ident_span),
66-
thin_vec![cx.attr_word(sym::macro_use, span)],
67-
ast::ItemKind::ExternCrate(None),
68-
)
69-
};
70-
krate.items.insert(0, item);
71-
}
42+
let ident_span = if edition >= Edition2018 { span } else { call_site };
7243

73-
// The crates have been injected, the assumption is that the first one is
74-
// the one with the prelude.
75-
let name = names[0];
44+
let item = cx.item(
45+
span,
46+
Ident::new(name, ident_span),
47+
thin_vec![cx.attr_word(sym::macro_use, span)],
48+
ast::ItemKind::ExternCrate(None),
49+
);
50+
51+
krate.items.insert(0, item);
7652

7753
let root = (edition == Edition2015).then_some(kw::PathRoot);
7854

@@ -88,6 +64,7 @@ pub fn inject(
8864
.map(|&symbol| Ident::new(symbol, span))
8965
.collect();
9066

67+
// Inject the relevant crate's prelude.
9168
let use_item = cx.item(
9269
span,
9370
Ident::empty(),

compiler/rustc_metadata/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ metadata_crate_dep_rustc_driver =
4747
metadata_crate_location_unknown_type =
4848
extern location for {$crate_name} is of an unknown type: {$path}
4949
50+
metadata_crate_not_compiler_builtins =
51+
the crate `{$crate_name}` resolved as `compiler_builtins` but is not `#![compiler_builtins]`
52+
5053
metadata_crate_not_panic_runtime =
5154
the crate `{$crate_name}` is not a panic runtime
5255

compiler/rustc_metadata/src/creader.rs

+121-21
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
142142
writeln!(fmt, " cnum: {cnum}")?;
143143
writeln!(fmt, " hash: {}", data.hash())?;
144144
writeln!(fmt, " reqd: {:?}", data.dep_kind())?;
145+
writeln!(fmt, " priv: {:?}", data.is_private_dep())?;
145146
let CrateSource { dylib, rlib, rmeta } = data.source();
146147
if let Some(dylib) = dylib {
147148
writeln!(fmt, " dylib: {}", dylib.0.display())?;
@@ -157,6 +158,43 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
157158
}
158159
}
159160

161+
/// Reason that a crate is being sourced as a dependency.
162+
#[derive(Clone, Copy)]
163+
enum CrateOrigin<'a> {
164+
/// This crate was a dependency of another crate.
165+
Dependency {
166+
dep_root: &'a CratePaths,
167+
/// Dependency info about this crate.
168+
dep: &'a CrateDep,
169+
},
170+
/// Injected by `rustc`.
171+
Injected,
172+
/// An extern that has been provided with the `force` option.
173+
ForcedExtern,
174+
/// Part of the extern prelude.
175+
ExternPrelude,
176+
/// Provided by `extern crate foo`.
177+
AstExtern,
178+
}
179+
180+
impl<'a> CrateOrigin<'a> {
181+
/// Return the dependency root, if any.
182+
fn dep_root(&self) -> Option<&'a CratePaths> {
183+
match self {
184+
CrateOrigin::Dependency { dep_root, .. } => Some(dep_root),
185+
_ => None,
186+
}
187+
}
188+
189+
/// Return dependency information, if any.
190+
fn dep(&self) -> Option<&'a CrateDep> {
191+
match self {
192+
CrateOrigin::Dependency { dep, .. } => Some(dep),
193+
_ => None,
194+
}
195+
}
196+
}
197+
160198
impl CStore {
161199
pub fn from_tcx(tcx: TyCtxt<'_>) -> FreezeReadGuard<'_, CStore> {
162200
FreezeReadGuard::map(tcx.untracked().cstore.read(), |cstore| {
@@ -404,7 +442,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
404442
&self,
405443
name: Symbol,
406444
private_dep: Option<bool>,
407-
dep_root: Option<&CratePaths>,
445+
origin: CrateOrigin<'_>,
408446
) -> bool {
409447
// Standard library crates are never private.
410448
if STDLIB_STABLE_CRATES.contains(&name) {
@@ -414,10 +452,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
414452

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

455+
if matches!(origin, CrateOrigin::Injected) {
456+
return true;
457+
}
458+
417459
// Any descendants of `std` should be private. These crates are usually not marked
418460
// private in metadata, so we ignore that field.
419461
if extern_private.is_none()
420-
&& let Some(dep) = dep_root
462+
&& let Some(dep) = origin.dep_root()
421463
&& STDLIB_STABLE_CRATES.contains(&dep.name)
422464
{
423465
return true;
@@ -435,7 +477,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
435477
fn register_crate(
436478
&mut self,
437479
host_lib: Option<Library>,
438-
dep_root: Option<&CratePaths>,
480+
origin: CrateOrigin<'_>,
439481
lib: Library,
440482
dep_kind: CrateDepKind,
441483
name: Symbol,
@@ -447,7 +489,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
447489
let Library { source, metadata } = lib;
448490
let crate_root = metadata.get_root();
449491
let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
450-
let private_dep = self.is_private_dep(name, private_dep, dep_root);
492+
let private_dep = self.is_private_dep(name, private_dep, origin);
451493

452494
// Claim this crate number and cache it
453495
let feed = self.cstore.intern_stable_crate_id(&crate_root, self.tcx)?;
@@ -463,7 +505,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
463505
// Maintain a reference to the top most crate.
464506
// Stash paths for top-most crate locally if necessary.
465507
let crate_paths;
466-
let dep_root = if let Some(dep_root) = dep_root {
508+
let dep_root = if let Some(dep_root) = origin.dep_root() {
467509
dep_root
468510
} else {
469511
crate_paths = CratePaths::new(crate_root.name(), source.clone());
@@ -571,17 +613,23 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
571613
name: Symbol,
572614
span: Span,
573615
dep_kind: CrateDepKind,
616+
origin: CrateOrigin<'_>,
574617
) -> Option<CrateNum> {
575618
self.used_extern_options.insert(name);
576-
match self.maybe_resolve_crate(name, dep_kind, None) {
619+
match self.maybe_resolve_crate(name, dep_kind, origin) {
577620
Ok(cnum) => {
578621
self.cstore.set_used_recursively(cnum);
579622
Some(cnum)
580623
}
581624
Err(err) => {
582625
debug!("failed to resolve crate {} {:?}", name, dep_kind);
583-
let missing_core =
584-
self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err();
626+
let missing_core = self
627+
.maybe_resolve_crate(
628+
sym::core,
629+
CrateDepKind::Explicit,
630+
CrateOrigin::ExternPrelude,
631+
)
632+
.is_err();
585633
err.report(self.sess, span, missing_core);
586634
None
587635
}
@@ -592,15 +640,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
592640
&'b mut self,
593641
name: Symbol,
594642
mut dep_kind: CrateDepKind,
595-
dep_of: Option<(&'b CratePaths, &'b CrateDep)>,
643+
origin: CrateOrigin<'b>,
596644
) -> Result<CrateNum, CrateError> {
597645
info!("resolving crate `{}`", name);
598646
if !name.as_str().is_ascii() {
599647
return Err(CrateError::NonAsciiName(name));
600648
}
601649

602-
let dep_root = dep_of.map(|d| d.0);
603-
let dep = dep_of.map(|d| d.1);
650+
let dep_root = origin.dep_root();
651+
let dep = origin.dep();
604652
let hash = dep.map(|d| d.hash);
605653
let host_hash = dep.map(|d| d.host_hash).flatten();
606654
let extra_filename = dep.map(|d| &d.extra_filename[..]);
@@ -638,12 +686,12 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
638686

639687
match result {
640688
(LoadResult::Previous(cnum), None) => {
641-
info!("library for `{}` was loaded previously", name);
689+
info!("library for `{}` was loaded previously, cnum {cnum}", name);
642690
// When `private_dep` is none, it indicates the directly dependent crate. If it is
643691
// not specified by `--extern` on command line parameters, it may be
644692
// `private-dependency` when `register_crate` is called for the first time. Then it must be updated to
645693
// `public-dependency` here.
646-
let private_dep = self.is_private_dep(name, private_dep, dep_root);
694+
let private_dep = self.is_private_dep(name, private_dep, origin);
647695
let data = self.cstore.get_crate_data_mut(cnum);
648696
if data.is_proc_macro_crate() {
649697
dep_kind = CrateDepKind::MacrosOnly;
@@ -654,7 +702,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
654702
}
655703
(LoadResult::Loaded(library), host_library) => {
656704
info!("register newly loaded library for `{}`", name);
657-
self.register_crate(host_library, dep_root, library, dep_kind, name, private_dep)
705+
self.register_crate(host_library, origin, library, dep_kind, name, private_dep)
658706
}
659707
_ => panic!(),
660708
}
@@ -730,7 +778,10 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
730778
CrateDepKind::MacrosOnly => CrateDepKind::MacrosOnly,
731779
_ => dep.kind,
732780
};
733-
let cnum = self.maybe_resolve_crate(dep.name, dep_kind, Some((dep_root, &dep)))?;
781+
let cnum = self.maybe_resolve_crate(dep.name, dep_kind, CrateOrigin::Dependency {
782+
dep_root,
783+
dep: &dep,
784+
})?;
734785
crate_num_map.push(cnum);
735786
}
736787

@@ -824,7 +875,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
824875
};
825876
info!("panic runtime not found -- loading {}", name);
826877

827-
let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else {
878+
let Some(cnum) =
879+
self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
880+
else {
828881
return;
829882
};
830883
let data = self.cstore.get_crate_data(cnum);
@@ -853,7 +906,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
853906
info!("loading profiler");
854907

855908
let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
856-
let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else {
909+
let Some(cnum) =
910+
self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
911+
else {
857912
return;
858913
};
859914
let data = self.cstore.get_crate_data(cnum);
@@ -966,12 +1021,54 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
9661021
if entry.force {
9671022
let name_interned = Symbol::intern(name);
9681023
if !self.used_extern_options.contains(&name_interned) {
969-
self.resolve_crate(name_interned, DUMMY_SP, CrateDepKind::Explicit);
1024+
self.resolve_crate(
1025+
name_interned,
1026+
DUMMY_SP,
1027+
CrateDepKind::Explicit,
1028+
CrateOrigin::ForcedExtern,
1029+
);
9701030
}
9711031
}
9721032
}
9731033
}
9741034

1035+
/// Inject the `compiler_builtins` crate if it is not already in the graph.
1036+
fn inject_compiler_builtins(&mut self, krate: &ast::Crate) {
1037+
// `compiler_builtins` does not get extern builtins, nor do `#![no_core]` crates
1038+
if attr::contains_name(&krate.attrs, sym::compiler_builtins)
1039+
|| attr::contains_name(&krate.attrs, sym::no_core)
1040+
{
1041+
info!("`compiler_builtins` unneeded");
1042+
return;
1043+
}
1044+
1045+
// If a `#![compiler_builtins]` crate already exists, avoid injecting it twice. This is
1046+
// the common case since usually it appears as a dependency of `std` or `core`.
1047+
for (cnum, cmeta) in self.cstore.iter_crate_data() {
1048+
if cmeta.is_compiler_builtins() {
1049+
info!("`compiler_builtins` already exists (cnum = {cnum}); skipping injection");
1050+
return;
1051+
}
1052+
}
1053+
1054+
// Allow builtins to remain unresolved, which will just mean linker errors if the
1055+
// relevant symbols aren't otherwise provided.
1056+
let Ok(cnum) = self.maybe_resolve_crate(
1057+
sym::compiler_builtins,
1058+
CrateDepKind::Explicit,
1059+
CrateOrigin::Injected,
1060+
) else {
1061+
info!("`compiler_builtins` not resolved");
1062+
return;
1063+
};
1064+
1065+
// Sanity check that the loaded crate is `#![compiler_builtins]`
1066+
let cmeta = self.cstore.get_crate_data(cnum);
1067+
if !cmeta.is_compiler_builtins() {
1068+
self.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cmeta.name() });
1069+
}
1070+
}
1071+
9751072
fn inject_dependency_if(
9761073
&mut self,
9771074
krate: CrateNum,
@@ -1081,6 +1178,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
10811178
}
10821179

10831180
pub fn postprocess(&mut self, krate: &ast::Crate) {
1181+
self.inject_compiler_builtins(krate);
10841182
self.inject_forced_externs();
10851183
self.inject_profiler_runtime();
10861184
self.inject_allocator_crate(krate);
@@ -1092,6 +1190,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
10921190
info!("{:?}", CrateDump(self.cstore));
10931191
}
10941192

1193+
/// Process an `extern crate foo` AST node.
10951194
pub fn process_extern_crate(
10961195
&mut self,
10971196
item: &ast::Item,
@@ -1117,7 +1216,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
11171216
CrateDepKind::Explicit
11181217
};
11191218

1120-
let cnum = self.resolve_crate(name, item.span, dep_kind)?;
1219+
let cnum = self.resolve_crate(name, item.span, dep_kind, CrateOrigin::AstExtern)?;
11211220

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

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

11381238
self.cstore.update_extern_crate(cnum, ExternCrate {
11391239
src: ExternCrateSource::Path,
@@ -1147,7 +1247,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
11471247
}
11481248

11491249
pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> {
1150-
self.maybe_resolve_crate(name, CrateDepKind::Explicit, None).ok()
1250+
self.maybe_resolve_crate(name, CrateDepKind::Explicit, CrateOrigin::ExternPrelude).ok()
11511251
}
11521252
}
11531253

0 commit comments

Comments
 (0)