rustc_builtin_macros/
standard_library_imports.rs

1use rustc_ast::{self as ast, attr};
2use rustc_expand::base::{ExtCtxt, ResolverExpand};
3use rustc_expand::expand::ExpansionConfig;
4use rustc_feature::Features;
5use rustc_session::Session;
6use rustc_span::edition::Edition::*;
7use rustc_span::hygiene::AstPass;
8use rustc_span::{DUMMY_SP, Ident, Symbol, kw, sym};
9use thin_vec::thin_vec;
10
11pub fn inject(
12    krate: &mut ast::Crate,
13    pre_configured_attrs: &[ast::Attribute],
14    resolver: &mut dyn ResolverExpand,
15    sess: &Session,
16    features: &Features,
17) -> usize {
18    let orig_num_items = krate.items.len();
19    let edition = sess.psess.edition;
20
21    // 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) {
23        return 0;
24    } 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        }
30    } else {
31        &[sym::std]
32    };
33
34    let expn_id = resolver.expansion_for_ast_pass(
35        DUMMY_SP,
36        AstPass::StdImports,
37        &[sym::prelude_import],
38        None,
39    );
40    let span = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id());
41    let call_site = DUMMY_SP.with_call_site_ctxt(expn_id.to_expn_id());
42
43    let ecfg = ExpansionConfig::default("std_lib_injection".to_string(), features);
44    let cx = ExtCtxt::new(sess, ecfg, resolver, None);
45
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    }
72
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];
76
77    let root = (edition == Edition2015).then_some(kw::PathRoot);
78
79    let import_path = root
80        .iter()
81        .chain(&[name, sym::prelude])
82        .chain(&[match edition {
83            Edition2015 => sym::rust_2015,
84            Edition2018 => sym::rust_2018,
85            Edition2021 => sym::rust_2021,
86            Edition2024 => sym::rust_2024,
87        }])
88        .map(|&symbol| Ident::new(symbol, span))
89        .collect();
90
91    let use_item = cx.item(
92        span,
93        Ident::empty(),
94        thin_vec![cx.attr_word(sym::prelude_import, span)],
95        ast::ItemKind::Use(ast::UseTree {
96            prefix: cx.path(span, import_path),
97            kind: ast::UseTreeKind::Glob,
98            span,
99        }),
100    );
101
102    krate.items.insert(0, use_item);
103    krate.items.len() - orig_num_items
104}