Skip to content

Commit 1412cfc

Browse files
committed
Inject compiler_builtins during postprocessing rather than via AST
`compiler_builtins` is currently injected 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. [1]: #113634
1 parent 83d70c0 commit 1412cfc

10 files changed

+73
-53
lines changed

Diff for: 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(),

Diff for: 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

Diff for: compiler/rustc_metadata/src/creader.rs

+38
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,43 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
11181118
}
11191119
}
11201120

1121+
/// Inject the `compiler_builtins` crate if it is not already in the graph.
1122+
fn inject_compiler_builtins(&mut self, krate: &ast::Crate) {
1123+
// `compiler_builtins` does not get extern builtins, nor do `#![no_core]` crates
1124+
if attr::contains_name(&krate.attrs, sym::compiler_builtins)
1125+
|| attr::contains_name(&krate.attrs, sym::no_core)
1126+
{
1127+
info!("`compiler_builtins` unneeded");
1128+
return;
1129+
}
1130+
1131+
// If a `#![compiler_builtins]` crate already exists, avoid injecting it twice. This is
1132+
// the common case since usually it appears as a dependency of `std` or `alloc`.
1133+
for (cnum, cmeta) in self.cstore.iter_crate_data() {
1134+
if cmeta.is_compiler_builtins() {
1135+
info!("`compiler_builtins` already exists (cnum = {cnum}); skipping injection");
1136+
return;
1137+
}
1138+
}
1139+
1140+
// `compiler_builtins` is not yet in the graph; inject it. Error on resolution failure.
1141+
let Some(cnum) = self.resolve_crate(
1142+
sym::compiler_builtins,
1143+
krate.spans.inner_span.shrink_to_lo(),
1144+
CrateDepKind::Explicit,
1145+
CrateOrigin::Injected,
1146+
) else {
1147+
info!("`compiler_builtins` not resolved");
1148+
return;
1149+
};
1150+
1151+
// Sanity check that the loaded crate is `#![compiler_builtins]`
1152+
let cmeta = self.cstore.get_crate_data(cnum);
1153+
if !cmeta.is_compiler_builtins() {
1154+
self.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cmeta.name() });
1155+
}
1156+
}
1157+
11211158
fn inject_dependency_if(
11221159
&mut self,
11231160
krate: CrateNum,
@@ -1227,6 +1264,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
12271264
}
12281265

12291266
pub fn postprocess(&mut self, krate: &ast::Crate) {
1267+
self.inject_compiler_builtins(krate);
12301268
self.inject_forced_externs();
12311269
self.inject_profiler_runtime();
12321270
self.inject_allocator_crate(krate);

Diff for: compiler/rustc_metadata/src/errors.rs

+6
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,12 @@ pub struct CrateNotPanicRuntime {
332332
pub crate_name: Symbol,
333333
}
334334

335+
#[derive(Diagnostic)]
336+
#[diag(metadata_crate_not_compiler_builtins)]
337+
pub struct CrateNotCompilerBuiltins {
338+
pub crate_name: Symbol,
339+
}
340+
335341
#[derive(Diagnostic)]
336342
#[diag(metadata_no_panic_strategy)]
337343
pub struct NoPanicStrategy {

Diff for: compiler/rustc_metadata/src/rmeta/decoder.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1948,6 +1948,10 @@ impl CrateMetadata {
19481948
self.root.profiler_runtime
19491949
}
19501950

1951+
pub(crate) fn is_compiler_builtins(&self) -> bool {
1952+
self.root.compiler_builtins
1953+
}
1954+
19511955
pub(crate) fn needs_allocator(&self) -> bool {
19521956
self.root.needs_allocator
19531957
}

Diff for: tests/ui/extern-flag/empty-extern-arg.stderr

+1-7
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,5 @@ error: unwinding panics are not supported without std
77
= help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding
88
= note: since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem
99

10-
error: requires `sized` lang_item
11-
--> $DIR/empty-extern-arg.rs:6:11
12-
|
13-
LL | fn main() {}
14-
| ^^
15-
16-
error: aborting due to 4 previous errors
10+
error: aborting due to 3 previous errors
1711

Diff for: tests/ui/proc-macro/issue-59191-replace-root-with-fn.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33

44
//@ edition:2018
55
//@ proc-macro: issue-59191.rs
6-
//@ error-pattern: requires `sized` lang_item
6+
//@ needs-unwind (affects error output)
7+
//@ error-pattern: error: `#[panic_handler]` function required
78

89
#![feature(custom_inner_attributes)]
910
#![issue_59191::no_main]
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
error: requires `sized` lang_item
2-
--> $DIR/issue-59191-replace-root-with-fn.rs:9:1
3-
|
4-
LL | #![issue_59191::no_main]
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^
1+
error: `#[panic_handler]` function required, but not found
2+
3+
error: unwinding panics are not supported without std
64
|
7-
= note: this error originates in the attribute macro `issue_59191::no_main` (in Nightly builds, run with -Z macro-backtrace for more info)
5+
= help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding
6+
= note: since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem
87

9-
error: aborting due to 1 previous error
8+
error: aborting due to 2 previous errors
109

Diff for: tests/ui/proc-macro/meta-macro-hygiene.stdout

-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro
2020
use core /* 0#1 */::prelude /* 0#1 */::rust_2018 /* 0#1 */::*;
2121
#[macro_use /* 0#1 */]
2222
extern crate core /* 0#1 */;
23-
extern crate compiler_builtins /* NNN */ as _ /* 0#1 */;
2423
// Don't load unnecessary hygiene information from std
2524
extern crate std /* 0#0 */;
2625

Diff for: tests/ui/proc-macro/nonterminal-token-hygiene.stdout

-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
3939
use ::core /* 0#1 */::prelude /* 0#1 */::rust_2015 /* 0#1 */::*;
4040
#[macro_use /* 0#1 */]
4141
extern crate core /* 0#2 */;
42-
extern crate compiler_builtins /* NNN */ as _ /* 0#2 */;
4342
// Don't load unnecessary hygiene information from std
4443
extern crate std /* 0#0 */;
4544

0 commit comments

Comments
 (0)