rustc_interface/
passes.rs

1use std::any::Any;
2use std::ffi::{OsStr, OsString};
3use std::io::{self, BufWriter, Write};
4use std::path::{Path, PathBuf};
5use std::sync::{Arc, LazyLock, OnceLock};
6use std::{env, fs, iter};
7
8use rustc_ast as ast;
9use rustc_attr_parsing::{AttributeParser, ShouldEmit};
10use rustc_codegen_ssa::traits::CodegenBackend;
11use rustc_data_structures::jobserver::Proxy;
12use rustc_data_structures::steal::Steal;
13use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, WorkerLocal};
14use rustc_data_structures::{parallel, thousands};
15use rustc_errors::timings::TimingSection;
16use rustc_expand::base::{ExtCtxt, LintStoreExpand};
17use rustc_feature::Features;
18use rustc_fs_util::try_canonicalize;
19use rustc_hir::attrs::AttributeKind;
20use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap};
21use rustc_hir::definitions::Definitions;
22use rustc_hir::limit::Limit;
23use rustc_incremental::setup_dep_graph;
24use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store};
25use rustc_metadata::EncodedMetadata;
26use rustc_metadata::creader::CStore;
27use rustc_middle::arena::Arena;
28use rustc_middle::dep_graph::DepsType;
29use rustc_middle::ty::{self, CurrentGcx, GlobalCtxt, RegisteredTools, TyCtxt};
30use rustc_middle::util::Providers;
31use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
32use rustc_passes::{abi_test, input_stats, layout_test};
33use rustc_resolve::{Resolver, ResolverOutputs};
34use rustc_session::Session;
35use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
36use rustc_session::cstore::Untracked;
37use rustc_session::output::{collect_crate_types, filename_for_input};
38use rustc_session::parse::feature_err;
39use rustc_session::search_paths::PathKind;
40use rustc_span::{
41    DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, SourceFileHash, SourceFileHashAlgorithm, Span,
42    Symbol, sym,
43};
44use rustc_target::spec::PanicStrategy;
45use rustc_trait_selection::{solve, traits};
46use tracing::{info, instrument};
47
48use crate::interface::Compiler;
49use crate::{errors, limits, proc_macro_decls, util};
50
51pub fn parse<'a>(sess: &'a Session) -> ast::Crate {
52    let mut krate = sess
53        .time("parse_crate", || {
54            let mut parser = unwrap_or_emit_fatal(match &sess.io.input {
55                Input::File(file) => new_parser_from_file(&sess.psess, file, None),
56                Input::Str { input, name } => {
57                    new_parser_from_source_str(&sess.psess, name.clone(), input.clone())
58                }
59            });
60            parser.parse_crate_mod()
61        })
62        .unwrap_or_else(|parse_error| {
63            let guar: ErrorGuaranteed = parse_error.emit();
64            guar.raise_fatal();
65        });
66
67    rustc_builtin_macros::cmdline_attrs::inject(
68        &mut krate,
69        &sess.psess,
70        &sess.opts.unstable_opts.crate_attr,
71    );
72
73    krate
74}
75
76fn pre_expansion_lint<'a>(
77    sess: &Session,
78    features: &Features,
79    lint_store: &LintStore,
80    registered_tools: &RegisteredTools,
81    check_node: impl EarlyCheckNode<'a>,
82    node_name: Symbol,
83) {
84    sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", node_name.as_str()).run(
85        || {
86            rustc_lint::check_ast_node(
87                sess,
88                None,
89                features,
90                true,
91                lint_store,
92                registered_tools,
93                None,
94                rustc_lint::BuiltinCombinedPreExpansionLintPass::new(),
95                check_node,
96            );
97        },
98    );
99}
100
101// Cannot implement directly for `LintStore` due to trait coherence.
102struct LintStoreExpandImpl<'a>(&'a LintStore);
103
104impl LintStoreExpand for LintStoreExpandImpl<'_> {
105    fn pre_expansion_lint(
106        &self,
107        sess: &Session,
108        features: &Features,
109        registered_tools: &RegisteredTools,
110        node_id: ast::NodeId,
111        attrs: &[ast::Attribute],
112        items: &[Box<ast::Item>],
113        name: Symbol,
114    ) {
115        pre_expansion_lint(sess, features, self.0, registered_tools, (node_id, attrs, items), name);
116    }
117}
118
119/// Runs the "early phases" of the compiler: initial `cfg` processing,
120/// syntax expansion, secondary `cfg` expansion, synthesis of a test
121/// harness if one is to be provided, injection of a dependency on the
122/// standard library and prelude, and name resolution.
123#[instrument(level = "trace", skip(krate, resolver))]
124fn configure_and_expand(
125    mut krate: ast::Crate,
126    pre_configured_attrs: &[ast::Attribute],
127    resolver: &mut Resolver<'_, '_>,
128) -> ast::Crate {
129    let tcx = resolver.tcx();
130    let sess = tcx.sess;
131    let features = tcx.features();
132    let lint_store = unerased_lint_store(tcx.sess);
133    let crate_name = tcx.crate_name(LOCAL_CRATE);
134    let lint_check_node = (&krate, pre_configured_attrs);
135    pre_expansion_lint(
136        sess,
137        features,
138        lint_store,
139        tcx.registered_tools(()),
140        lint_check_node,
141        crate_name,
142    );
143    rustc_builtin_macros::register_builtin_macros(resolver);
144
145    let num_standard_library_imports = sess.time("crate_injection", || {
146        rustc_builtin_macros::standard_library_imports::inject(
147            &mut krate,
148            pre_configured_attrs,
149            resolver,
150            sess,
151            features,
152        )
153    });
154
155    util::check_attr_crate_type(sess, pre_configured_attrs, resolver.lint_buffer());
156
157    // Expand all macros
158    krate = sess.time("macro_expand_crate", || {
159        // Windows dlls do not have rpaths, so they don't know how to find their
160        // dependencies. It's up to us to tell the system where to find all the
161        // dependent dlls. Note that this uses cfg!(windows) as opposed to
162        // targ_cfg because syntax extensions are always loaded for the host
163        // compiler, not for the target.
164        //
165        // This is somewhat of an inherently racy operation, however, as
166        // multiple threads calling this function could possibly continue
167        // extending PATH far beyond what it should. To solve this for now we
168        // just don't add any new elements to PATH which are already there
169        // within PATH. This is basically a targeted fix at #17360 for rustdoc
170        // which runs rustc in parallel but has been seen (#33844) to cause
171        // problems with PATH becoming too long.
172        let mut old_path = OsString::new();
173        if cfg!(windows) {
174            old_path = env::var_os("PATH").unwrap_or(old_path);
175            let mut new_path = Vec::from_iter(
176                sess.host_filesearch().search_paths(PathKind::All).map(|p| p.dir.clone()),
177            );
178            for path in env::split_paths(&old_path) {
179                if !new_path.contains(&path) {
180                    new_path.push(path);
181                }
182            }
183            unsafe {
184                env::set_var(
185                    "PATH",
186                    &env::join_paths(
187                        new_path.iter().filter(|p| env::join_paths(iter::once(p)).is_ok()),
188                    )
189                    .unwrap(),
190                );
191            }
192        }
193
194        // Create the config for macro expansion
195        let recursion_limit = get_recursion_limit(pre_configured_attrs, sess);
196        let cfg = rustc_expand::expand::ExpansionConfig {
197            crate_name,
198            features,
199            recursion_limit,
200            trace_mac: sess.opts.unstable_opts.trace_macros,
201            should_test: sess.is_test_crate(),
202            span_debug: sess.opts.unstable_opts.span_debug,
203            proc_macro_backtrace: sess.opts.unstable_opts.proc_macro_backtrace,
204        };
205
206        let lint_store = LintStoreExpandImpl(lint_store);
207        let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&lint_store));
208        ecx.num_standard_library_imports = num_standard_library_imports;
209        // Expand macros now!
210        let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
211
212        if ecx.nb_macro_errors > 0 {
213            sess.dcx().abort_if_errors();
214        }
215
216        // The rest is error reporting and stats
217
218        sess.psess.buffered_lints.with_lock(|buffered_lints: &mut Vec<BufferedEarlyLint>| {
219            buffered_lints.append(&mut ecx.buffered_early_lint);
220        });
221
222        sess.time("check_unused_macros", || {
223            ecx.check_unused_macros();
224        });
225
226        // If we hit a recursion limit, exit early to avoid later passes getting overwhelmed
227        // with a large AST
228        if ecx.reduced_recursion_limit.is_some() {
229            sess.dcx().abort_if_errors();
230            unreachable!();
231        }
232
233        if cfg!(windows) {
234            unsafe {
235                env::set_var("PATH", &old_path);
236            }
237        }
238
239        if ecx.sess.opts.unstable_opts.macro_stats {
240            print_macro_stats(&ecx);
241        }
242
243        krate
244    });
245
246    sess.time("maybe_building_test_harness", || {
247        rustc_builtin_macros::test_harness::inject(&mut krate, sess, features, resolver)
248    });
249
250    let has_proc_macro_decls = sess.time("AST_validation", || {
251        rustc_ast_passes::ast_validation::check_crate(
252            sess,
253            features,
254            &krate,
255            tcx.is_sdylib_interface_build(),
256            resolver.lint_buffer(),
257        )
258    });
259
260    let crate_types = tcx.crate_types();
261    let is_executable_crate = crate_types.contains(&CrateType::Executable);
262    let is_proc_macro_crate = crate_types.contains(&CrateType::ProcMacro);
263
264    if crate_types.len() > 1 {
265        if is_executable_crate {
266            sess.dcx().emit_err(errors::MixedBinCrate);
267        }
268        if is_proc_macro_crate {
269            sess.dcx().emit_err(errors::MixedProcMacroCrate);
270        }
271    }
272    if crate_types.contains(&CrateType::Sdylib) && !tcx.features().export_stable() {
273        feature_err(sess, sym::export_stable, DUMMY_SP, "`sdylib` crate type is unstable").emit();
274    }
275
276    if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort {
277        sess.dcx().emit_warn(errors::ProcMacroCratePanicAbort);
278    }
279
280    sess.time("maybe_create_a_macro_crate", || {
281        let is_test_crate = sess.is_test_crate();
282        rustc_builtin_macros::proc_macro_harness::inject(
283            &mut krate,
284            sess,
285            features,
286            resolver,
287            is_proc_macro_crate,
288            has_proc_macro_decls,
289            is_test_crate,
290            sess.dcx(),
291        )
292    });
293
294    // Done with macro expansion!
295
296    resolver.resolve_crate(&krate);
297
298    CStore::from_tcx(tcx).report_incompatible_target_modifiers(tcx, &krate);
299    CStore::from_tcx(tcx).report_incompatible_async_drop_feature(tcx, &krate);
300    krate
301}
302
303fn print_macro_stats(ecx: &ExtCtxt<'_>) {
304    use std::fmt::Write;
305
306    let crate_name = ecx.ecfg.crate_name.as_str();
307    let crate_name = if crate_name == "build_script_build" {
308        // This is a build script. Get the package name from the environment.
309        let pkg_name =
310            std::env::var("CARGO_PKG_NAME").unwrap_or_else(|_| "<unknown crate>".to_string());
311        format!("{pkg_name} build script")
312    } else {
313        crate_name.to_string()
314    };
315
316    // No instability because we immediately sort the produced vector.
317    #[allow(rustc::potential_query_instability)]
318    let mut macro_stats: Vec<_> = ecx
319        .macro_stats
320        .iter()
321        .map(|((name, kind), stat)| {
322            // This gives the desired sort order: sort by bytes, then lines, etc.
323            (stat.bytes, stat.lines, stat.uses, name, *kind)
324        })
325        .collect();
326    macro_stats.sort_unstable();
327    macro_stats.reverse(); // bigger items first
328
329    let prefix = "macro-stats";
330    let name_w = 32;
331    let uses_w = 7;
332    let lines_w = 11;
333    let avg_lines_w = 11;
334    let bytes_w = 11;
335    let avg_bytes_w = 11;
336    let banner_w = name_w + uses_w + lines_w + avg_lines_w + bytes_w + avg_bytes_w;
337
338    // We write all the text into a string and print it with a single
339    // `eprint!`. This is an attempt to minimize interleaved text if multiple
340    // rustc processes are printing macro-stats at the same time (e.g. with
341    // `RUSTFLAGS='-Zmacro-stats' cargo build`). It still doesn't guarantee
342    // non-interleaving, though.
343    let mut s = String::new();
344    _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w));
345    _ = writeln!(s, "{prefix} MACRO EXPANSION STATS: {}", crate_name);
346    _ = writeln!(
347        s,
348        "{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}",
349        "Macro Name", "Uses", "Lines", "Avg Lines", "Bytes", "Avg Bytes",
350    );
351    _ = writeln!(s, "{prefix} {}", "-".repeat(banner_w));
352    // It's helpful to print something when there are no entries, otherwise it
353    // might look like something went wrong.
354    if macro_stats.is_empty() {
355        _ = writeln!(s, "{prefix} (none)");
356    }
357    for (bytes, lines, uses, name, kind) in macro_stats {
358        let mut name = ExpnKind::Macro(kind, *name).descr();
359        let uses_with_underscores = thousands::usize_with_underscores(uses);
360        let avg_lines = lines as f64 / uses as f64;
361        let avg_bytes = bytes as f64 / uses as f64;
362
363        // Ensure the "Macro Name" and "Uses" columns are as compact as possible.
364        let mut uses_w = uses_w;
365        if name.len() + uses_with_underscores.len() >= name_w + uses_w {
366            // The name would abut or overlap the uses value. Print the name
367            // on a line by itself, then set the name to empty and print things
368            // normally, to show the stats on the next line.
369            _ = writeln!(s, "{prefix} {:<name_w$}", name);
370            name = String::new();
371        } else if name.len() >= name_w {
372            // The name won't abut or overlap with the uses value, but it does
373            // overlap with the empty part of the uses column. Shrink the width
374            // of the uses column to account for the excess name length.
375            uses_w -= name.len() - name_w;
376        };
377
378        _ = writeln!(
379            s,
380            "{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}",
381            name,
382            uses_with_underscores,
383            thousands::usize_with_underscores(lines),
384            thousands::f64p1_with_underscores(avg_lines),
385            thousands::usize_with_underscores(bytes),
386            thousands::f64p1_with_underscores(avg_bytes),
387        );
388    }
389    _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w));
390    eprint!("{s}");
391}
392
393fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
394    let sess = tcx.sess;
395    let (resolver, krate) = &*tcx.resolver_for_lowering().borrow();
396    let mut lint_buffer = resolver.lint_buffer.steal();
397
398    if sess.opts.unstable_opts.input_stats {
399        input_stats::print_ast_stats(tcx, krate);
400    }
401
402    // Needs to go *after* expansion to be able to check the results of macro expansion.
403    sess.time("complete_gated_feature_checking", || {
404        rustc_ast_passes::feature_gate::check_crate(krate, sess, tcx.features());
405    });
406
407    // Add all buffered lints from the `ParseSess` to the `Session`.
408    sess.psess.buffered_lints.with_lock(|buffered_lints| {
409        info!("{} parse sess buffered_lints", buffered_lints.len());
410        for early_lint in buffered_lints.drain(..) {
411            lint_buffer.add_early_lint(early_lint);
412        }
413    });
414
415    // Gate identifiers containing invalid Unicode codepoints that were recovered during lexing.
416    sess.psess.bad_unicode_identifiers.with_lock(|identifiers| {
417        for (ident, mut spans) in identifiers.drain(..) {
418            spans.sort();
419            if ident == sym::ferris {
420                enum FerrisFix {
421                    SnakeCase,
422                    ScreamingSnakeCase,
423                    PascalCase,
424                }
425
426                impl FerrisFix {
427                    const fn as_str(self) -> &'static str {
428                        match self {
429                            FerrisFix::SnakeCase => "ferris",
430                            FerrisFix::ScreamingSnakeCase => "FERRIS",
431                            FerrisFix::PascalCase => "Ferris",
432                        }
433                    }
434                }
435
436                let first_span = spans[0];
437                let prev_source = sess.psess.source_map().span_to_prev_source(first_span);
438                let ferris_fix = prev_source
439                    .map_or(FerrisFix::SnakeCase, |source| {
440                        let mut source_before_ferris = source.trim_end().split_whitespace().rev();
441                        match source_before_ferris.next() {
442                            Some("struct" | "trait" | "mod" | "union" | "type" | "enum") => {
443                                FerrisFix::PascalCase
444                            }
445                            Some("const" | "static") => FerrisFix::ScreamingSnakeCase,
446                            Some("mut") if source_before_ferris.next() == Some("static") => {
447                                FerrisFix::ScreamingSnakeCase
448                            }
449                            _ => FerrisFix::SnakeCase,
450                        }
451                    })
452                    .as_str();
453
454                sess.dcx().emit_err(errors::FerrisIdentifier { spans, first_span, ferris_fix });
455            } else {
456                sess.dcx().emit_err(errors::EmojiIdentifier { spans, ident });
457            }
458        }
459    });
460
461    let lint_store = unerased_lint_store(tcx.sess);
462    rustc_lint::check_ast_node(
463        sess,
464        Some(tcx),
465        tcx.features(),
466        false,
467        lint_store,
468        tcx.registered_tools(()),
469        Some(lint_buffer),
470        rustc_lint::BuiltinCombinedEarlyLintPass::new(),
471        (&**krate, &*krate.attrs),
472    )
473}
474
475fn env_var_os<'tcx>(tcx: TyCtxt<'tcx>, key: &'tcx OsStr) -> Option<&'tcx OsStr> {
476    let value = env::var_os(key);
477
478    let value_tcx = value.as_ref().map(|value| {
479        let encoded_bytes = tcx.arena.alloc_slice(value.as_encoded_bytes());
480        debug_assert_eq!(value.as_encoded_bytes(), encoded_bytes);
481        // SAFETY: The bytes came from `as_encoded_bytes`, and we assume that
482        // `alloc_slice` is implemented correctly, and passes the same bytes
483        // back (debug asserted above).
484        unsafe { OsStr::from_encoded_bytes_unchecked(encoded_bytes) }
485    });
486
487    // Also add the variable to Cargo's dependency tracking
488    //
489    // NOTE: This only works for passes run before `write_dep_info`. See that
490    // for extension points for configuring environment variables to be
491    // properly change-tracked.
492    tcx.sess.psess.env_depinfo.borrow_mut().insert((
493        Symbol::intern(&key.to_string_lossy()),
494        value.as_ref().and_then(|value| value.to_str()).map(|value| Symbol::intern(&value)),
495    ));
496
497    value_tcx
498}
499
500// Returns all the paths that correspond to generated files.
501fn generated_output_paths(
502    tcx: TyCtxt<'_>,
503    outputs: &OutputFilenames,
504    exact_name: bool,
505    crate_name: Symbol,
506) -> Vec<PathBuf> {
507    let sess = tcx.sess;
508    let mut out_filenames = Vec::new();
509    for output_type in sess.opts.output_types.keys() {
510        let out_filename = outputs.path(*output_type);
511        let file = out_filename.as_path().to_path_buf();
512        match *output_type {
513            // If the filename has been overridden using `-o`, it will not be modified
514            // by appending `.rlib`, `.exe`, etc., so we can skip this transformation.
515            OutputType::Exe if !exact_name => {
516                for crate_type in tcx.crate_types().iter() {
517                    let p = filename_for_input(sess, *crate_type, crate_name, outputs);
518                    out_filenames.push(p.as_path().to_path_buf());
519                }
520            }
521            OutputType::DepInfo if sess.opts.unstable_opts.dep_info_omit_d_target => {
522                // Don't add the dep-info output when omitting it from dep-info targets
523            }
524            OutputType::DepInfo if out_filename.is_stdout() => {
525                // Don't add the dep-info output when it goes to stdout
526            }
527            _ => {
528                out_filenames.push(file);
529            }
530        }
531    }
532    out_filenames
533}
534
535fn output_contains_path(output_paths: &[PathBuf], input_path: &Path) -> bool {
536    let input_path = try_canonicalize(input_path).ok();
537    if input_path.is_none() {
538        return false;
539    }
540    output_paths.iter().any(|output_path| try_canonicalize(output_path).ok() == input_path)
541}
542
543fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option<&PathBuf> {
544    output_paths.iter().find(|output_path| output_path.is_dir())
545}
546
547fn escape_dep_filename(filename: &str) -> String {
548    // Apparently clang and gcc *only* escape spaces:
549    // https://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
550    filename.replace(' ', "\\ ")
551}
552
553// Makefile comments only need escaping newlines and `\`.
554// The result can be unescaped by anything that can unescape `escape_default` and friends.
555fn escape_dep_env(symbol: Symbol) -> String {
556    let s = symbol.as_str();
557    let mut escaped = String::with_capacity(s.len());
558    for c in s.chars() {
559        match c {
560            '\n' => escaped.push_str(r"\n"),
561            '\r' => escaped.push_str(r"\r"),
562            '\\' => escaped.push_str(r"\\"),
563            _ => escaped.push(c),
564        }
565    }
566    escaped
567}
568
569fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[PathBuf]) {
570    // Write out dependency rules to the dep-info file if requested
571    let sess = tcx.sess;
572    if !sess.opts.output_types.contains_key(&OutputType::DepInfo) {
573        return;
574    }
575    let deps_output = outputs.path(OutputType::DepInfo);
576    let deps_filename = deps_output.as_path();
577
578    let result: io::Result<()> = try {
579        // Build a list of files used to compile the output and
580        // write Makefile-compatible dependency rules
581        let mut files: Vec<(String, u64, Option<SourceFileHash>)> = sess
582            .source_map()
583            .files()
584            .iter()
585            .filter(|fmap| fmap.is_real_file())
586            .filter(|fmap| !fmap.is_imported())
587            .map(|fmap| {
588                (
589                    escape_dep_filename(&fmap.name.prefer_local().to_string()),
590                    fmap.source_len.0 as u64,
591                    fmap.checksum_hash,
592                )
593            })
594            .collect();
595
596        let checksum_hash_algo = sess.opts.unstable_opts.checksum_hash_algorithm;
597
598        // Account for explicitly marked-to-track files
599        // (e.g. accessed in proc macros).
600        let file_depinfo = sess.psess.file_depinfo.borrow();
601
602        let normalize_path = |path: PathBuf| {
603            let file = FileName::from(path);
604            escape_dep_filename(&file.prefer_local().to_string())
605        };
606
607        // The entries will be used to declare dependencies between files in a
608        // Makefile-like output, so the iteration order does not matter.
609        fn hash_iter_files<P: AsRef<Path>>(
610            it: impl Iterator<Item = P>,
611            checksum_hash_algo: Option<SourceFileHashAlgorithm>,
612        ) -> impl Iterator<Item = (P, u64, Option<SourceFileHash>)> {
613            it.map(move |path| {
614                match checksum_hash_algo.and_then(|algo| {
615                    fs::File::open(path.as_ref())
616                        .and_then(|mut file| {
617                            SourceFileHash::new(algo, &mut file).map(|h| (file, h))
618                        })
619                        .and_then(|(file, h)| file.metadata().map(|m| (m.len(), h)))
620                        .map_err(|e| {
621                            tracing::error!(
622                                "failed to compute checksum, omitting it from dep-info {} {e}",
623                                path.as_ref().display()
624                            )
625                        })
626                        .ok()
627                }) {
628                    Some((file_len, checksum)) => (path, file_len, Some(checksum)),
629                    None => (path, 0, None),
630                }
631            })
632        }
633
634        let extra_tracked_files = hash_iter_files(
635            file_depinfo.iter().map(|path_sym| normalize_path(PathBuf::from(path_sym.as_str()))),
636            checksum_hash_algo,
637        );
638        files.extend(extra_tracked_files);
639
640        // We also need to track used PGO profile files
641        if let Some(ref profile_instr) = sess.opts.cg.profile_use {
642            files.extend(hash_iter_files(
643                iter::once(normalize_path(profile_instr.as_path().to_path_buf())),
644                checksum_hash_algo,
645            ));
646        }
647        if let Some(ref profile_sample) = sess.opts.unstable_opts.profile_sample_use {
648            files.extend(hash_iter_files(
649                iter::once(normalize_path(profile_sample.as_path().to_path_buf())),
650                checksum_hash_algo,
651            ));
652        }
653
654        // Debugger visualizer files
655        for debugger_visualizer in tcx.debugger_visualizers(LOCAL_CRATE) {
656            files.extend(hash_iter_files(
657                iter::once(normalize_path(debugger_visualizer.path.clone().unwrap())),
658                checksum_hash_algo,
659            ));
660        }
661
662        if sess.binary_dep_depinfo() {
663            if let Some(ref backend) = sess.opts.unstable_opts.codegen_backend {
664                if backend.contains('.') {
665                    // If the backend name contain a `.`, it is the path to an external dynamic
666                    // library. If not, it is not a path.
667                    files.extend(hash_iter_files(
668                        iter::once(backend.to_string()),
669                        checksum_hash_algo,
670                    ));
671                }
672            }
673
674            for &cnum in tcx.crates(()) {
675                let source = tcx.used_crate_source(cnum);
676                if let Some((path, _)) = &source.dylib {
677                    files.extend(hash_iter_files(
678                        iter::once(escape_dep_filename(&path.display().to_string())),
679                        checksum_hash_algo,
680                    ));
681                }
682                if let Some((path, _)) = &source.rlib {
683                    files.extend(hash_iter_files(
684                        iter::once(escape_dep_filename(&path.display().to_string())),
685                        checksum_hash_algo,
686                    ));
687                }
688                if let Some((path, _)) = &source.rmeta {
689                    files.extend(hash_iter_files(
690                        iter::once(escape_dep_filename(&path.display().to_string())),
691                        checksum_hash_algo,
692                    ));
693                }
694            }
695        }
696
697        let write_deps_to_file = |file: &mut dyn Write| -> io::Result<()> {
698            for path in out_filenames {
699                writeln!(
700                    file,
701                    "{}: {}\n",
702                    path.display(),
703                    files
704                        .iter()
705                        .map(|(path, _file_len, _checksum_hash_algo)| path.as_str())
706                        .intersperse(" ")
707                        .collect::<String>()
708                )?;
709            }
710
711            // Emit a fake target for each input file to the compilation. This
712            // prevents `make` from spitting out an error if a file is later
713            // deleted. For more info see #28735
714            for (path, _file_len, _checksum_hash_algo) in &files {
715                writeln!(file, "{path}:")?;
716            }
717
718            // Emit special comments with information about accessed environment variables.
719            let env_depinfo = sess.psess.env_depinfo.borrow();
720            if !env_depinfo.is_empty() {
721                // We will soon sort, so the initial order does not matter.
722                #[allow(rustc::potential_query_instability)]
723                let mut envs: Vec<_> = env_depinfo
724                    .iter()
725                    .map(|(k, v)| (escape_dep_env(*k), v.map(escape_dep_env)))
726                    .collect();
727                envs.sort_unstable();
728                writeln!(file)?;
729                for (k, v) in envs {
730                    write!(file, "# env-dep:{k}")?;
731                    if let Some(v) = v {
732                        write!(file, "={v}")?;
733                    }
734                    writeln!(file)?;
735                }
736            }
737
738            // If caller requested this information, add special comments about source file checksums.
739            // These are not necessarily the same checksums as was used in the debug files.
740            if sess.opts.unstable_opts.checksum_hash_algorithm().is_some() {
741                files
742                    .iter()
743                    .filter_map(|(path, file_len, hash_algo)| {
744                        hash_algo.map(|hash_algo| (path, file_len, hash_algo))
745                    })
746                    .try_for_each(|(path, file_len, checksum_hash)| {
747                        writeln!(file, "# checksum:{checksum_hash} file_len:{file_len} {path}")
748                    })?;
749            }
750
751            Ok(())
752        };
753
754        match deps_output {
755            OutFileName::Stdout => {
756                let mut file = BufWriter::new(io::stdout());
757                write_deps_to_file(&mut file)?;
758            }
759            OutFileName::Real(ref path) => {
760                let mut file = fs::File::create_buffered(path)?;
761                write_deps_to_file(&mut file)?;
762            }
763        }
764    };
765
766    match result {
767        Ok(_) => {
768            if sess.opts.json_artifact_notifications {
769                sess.dcx().emit_artifact_notification(deps_filename, "dep-info");
770            }
771        }
772        Err(error) => {
773            sess.dcx().emit_fatal(errors::ErrorWritingDependencies { path: deps_filename, error });
774        }
775    }
776}
777
778fn resolver_for_lowering_raw<'tcx>(
779    tcx: TyCtxt<'tcx>,
780    (): (),
781) -> (&'tcx Steal<(ty::ResolverAstLowering, Arc<ast::Crate>)>, &'tcx ty::ResolverGlobalCtxt) {
782    let arenas = Resolver::arenas();
783    let _ = tcx.registered_tools(()); // Uses `crate_for_resolver`.
784    let (krate, pre_configured_attrs) = tcx.crate_for_resolver(()).steal();
785    let mut resolver = Resolver::new(
786        tcx,
787        &pre_configured_attrs,
788        krate.spans.inner_span,
789        krate.spans.inject_use_span,
790        &arenas,
791    );
792    let krate = configure_and_expand(krate, &pre_configured_attrs, &mut resolver);
793
794    // Make sure we don't mutate the cstore from here on.
795    tcx.untracked().cstore.freeze();
796
797    let ResolverOutputs {
798        global_ctxt: untracked_resolutions,
799        ast_lowering: untracked_resolver_for_lowering,
800    } = resolver.into_outputs();
801
802    let resolutions = tcx.arena.alloc(untracked_resolutions);
803    (tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, Arc::new(krate)))), resolutions)
804}
805
806pub fn write_dep_info(tcx: TyCtxt<'_>) {
807    // Make sure name resolution and macro expansion is run for
808    // the side-effect of providing a complete set of all
809    // accessed files and env vars.
810    let _ = tcx.resolver_for_lowering();
811
812    let sess = tcx.sess;
813    let _timer = sess.timer("write_dep_info");
814    let crate_name = tcx.crate_name(LOCAL_CRATE);
815
816    let outputs = tcx.output_filenames(());
817    let output_paths =
818        generated_output_paths(tcx, &outputs, sess.io.output_file.is_some(), crate_name);
819
820    // Ensure the source file isn't accidentally overwritten during compilation.
821    if let Some(input_path) = sess.io.input.opt_path() {
822        if sess.opts.will_create_output_file() {
823            if output_contains_path(&output_paths, input_path) {
824                sess.dcx().emit_fatal(errors::InputFileWouldBeOverWritten { path: input_path });
825            }
826            if let Some(dir_path) = output_conflicts_with_dir(&output_paths) {
827                sess.dcx().emit_fatal(errors::GeneratedFileConflictsWithDirectory {
828                    input_path,
829                    dir_path,
830                });
831            }
832        }
833    }
834
835    if let Some(ref dir) = sess.io.temps_dir {
836        if fs::create_dir_all(dir).is_err() {
837            sess.dcx().emit_fatal(errors::TempsDirError);
838        }
839    }
840
841    write_out_deps(tcx, &outputs, &output_paths);
842
843    let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo)
844        && sess.opts.output_types.len() == 1;
845
846    if !only_dep_info {
847        if let Some(ref dir) = sess.io.output_dir {
848            if fs::create_dir_all(dir).is_err() {
849                sess.dcx().emit_fatal(errors::OutDirError);
850            }
851        }
852    }
853}
854
855pub fn write_interface<'tcx>(tcx: TyCtxt<'tcx>) {
856    if !tcx.crate_types().contains(&rustc_session::config::CrateType::Sdylib) {
857        return;
858    }
859    let _timer = tcx.sess.timer("write_interface");
860    let (_, krate) = &*tcx.resolver_for_lowering().borrow();
861
862    let krate = rustc_ast_pretty::pprust::print_crate_as_interface(
863        krate,
864        tcx.sess.psess.edition,
865        &tcx.sess.psess.attr_id_generator,
866    );
867    let export_output = tcx.output_filenames(()).interface_path();
868    let mut file = fs::File::create_buffered(export_output).unwrap();
869    if let Err(err) = write!(file, "{}", krate) {
870        tcx.dcx().fatal(format!("error writing interface file: {}", err));
871    }
872}
873
874pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
875    let providers = &mut Providers::default();
876    providers.analysis = analysis;
877    providers.hir_crate = rustc_ast_lowering::lower_to_hir;
878    providers.resolver_for_lowering_raw = resolver_for_lowering_raw;
879    providers.stripped_cfg_items = |tcx, _| &tcx.resolutions(()).stripped_cfg_items[..];
880    providers.resolutions = |tcx, ()| tcx.resolver_for_lowering_raw(()).1;
881    providers.early_lint_checks = early_lint_checks;
882    providers.env_var_os = env_var_os;
883    limits::provide(providers);
884    proc_macro_decls::provide(providers);
885    rustc_const_eval::provide(providers);
886    rustc_middle::hir::provide(providers);
887    rustc_borrowck::provide(providers);
888    rustc_incremental::provide(providers);
889    rustc_mir_build::provide(providers);
890    rustc_mir_transform::provide(providers);
891    rustc_monomorphize::provide(providers);
892    rustc_privacy::provide(providers);
893    rustc_query_impl::provide(providers);
894    rustc_resolve::provide(providers);
895    rustc_hir_analysis::provide(providers);
896    rustc_hir_typeck::provide(providers);
897    ty::provide(providers);
898    traits::provide(providers);
899    solve::provide(providers);
900    rustc_passes::provide(providers);
901    rustc_traits::provide(providers);
902    rustc_ty_utils::provide(providers);
903    rustc_metadata::provide(providers);
904    rustc_lint::provide(providers);
905    rustc_symbol_mangling::provide(providers);
906    rustc_codegen_ssa::provide(providers);
907    *providers
908});
909
910pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
911    compiler: &Compiler,
912    krate: rustc_ast::Crate,
913    f: F,
914) -> T {
915    let sess = &compiler.sess;
916
917    let pre_configured_attrs = rustc_expand::config::pre_configure_attrs(sess, &krate.attrs);
918
919    let crate_name = get_crate_name(sess, &pre_configured_attrs);
920    let crate_types = collect_crate_types(sess, &pre_configured_attrs);
921    let stable_crate_id = StableCrateId::new(
922        crate_name,
923        crate_types.contains(&CrateType::Executable),
924        sess.opts.cg.metadata.clone(),
925        sess.cfg_version,
926    );
927
928    let outputs = util::build_output_filenames(&pre_configured_attrs, sess);
929
930    let dep_type = DepsType { dep_names: rustc_query_impl::dep_kind_names() };
931    let dep_graph = setup_dep_graph(sess, crate_name, &dep_type);
932
933    let cstore =
934        FreezeLock::new(Box::new(CStore::new(compiler.codegen_backend.metadata_loader())) as _);
935    let definitions = FreezeLock::new(Definitions::new(stable_crate_id));
936
937    let stable_crate_ids = FreezeLock::new(StableCrateIdMap::default());
938    let untracked =
939        Untracked { cstore, source_span: AppendOnlyIndexVec::new(), definitions, stable_crate_ids };
940
941    // We're constructing the HIR here; we don't care what we will
942    // read, since we haven't even constructed the *input* to
943    // incr. comp. yet.
944    dep_graph.assert_ignored();
945
946    let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
947
948    let codegen_backend = &compiler.codegen_backend;
949    let mut providers = *DEFAULT_QUERY_PROVIDERS;
950    codegen_backend.provide(&mut providers);
951
952    if let Some(callback) = compiler.override_queries {
953        callback(sess, &mut providers);
954    }
955
956    let incremental = dep_graph.is_fully_enabled();
957
958    let gcx_cell = OnceLock::new();
959    let arena = WorkerLocal::new(|_| Arena::default());
960    let hir_arena = WorkerLocal::new(|_| rustc_hir::Arena::default());
961
962    // This closure is necessary to force rustc to perform the correct lifetime
963    // subtyping for GlobalCtxt::enter to be allowed.
964    let inner: Box<
965        dyn for<'tcx> FnOnce(
966            &'tcx Session,
967            CurrentGcx,
968            Arc<Proxy>,
969            &'tcx OnceLock<GlobalCtxt<'tcx>>,
970            &'tcx WorkerLocal<Arena<'tcx>>,
971            &'tcx WorkerLocal<rustc_hir::Arena<'tcx>>,
972            F,
973        ) -> T,
974    > = Box::new(move |sess, current_gcx, jobserver_proxy, gcx_cell, arena, hir_arena, f| {
975        TyCtxt::create_global_ctxt(
976            gcx_cell,
977            sess,
978            crate_types,
979            stable_crate_id,
980            arena,
981            hir_arena,
982            untracked,
983            dep_graph,
984            rustc_query_impl::query_callbacks(arena),
985            rustc_query_impl::query_system(
986                providers.queries,
987                providers.extern_queries,
988                query_result_on_disk_cache,
989                incremental,
990            ),
991            providers.hooks,
992            current_gcx,
993            jobserver_proxy,
994            |tcx| {
995                let feed = tcx.create_crate_num(stable_crate_id).unwrap();
996                assert_eq!(feed.key(), LOCAL_CRATE);
997                feed.crate_name(crate_name);
998
999                let feed = tcx.feed_unit_query();
1000                feed.features_query(tcx.arena.alloc(rustc_expand::config::features(
1001                    tcx.sess,
1002                    &pre_configured_attrs,
1003                    crate_name,
1004                )));
1005                feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs))));
1006                feed.output_filenames(Arc::new(outputs));
1007
1008                let res = f(tcx);
1009                // FIXME maybe run finish even when a fatal error occurred? or at least tcx.alloc_self_profile_query_strings()?
1010                tcx.finish();
1011                res
1012            },
1013        )
1014    });
1015
1016    inner(
1017        &compiler.sess,
1018        compiler.current_gcx.clone(),
1019        Arc::clone(&compiler.jobserver_proxy),
1020        &gcx_cell,
1021        &arena,
1022        &hir_arena,
1023        f,
1024    )
1025}
1026
1027/// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses.
1028/// This function never fails.
1029fn run_required_analyses(tcx: TyCtxt<'_>) {
1030    if tcx.sess.opts.unstable_opts.input_stats {
1031        rustc_passes::input_stats::print_hir_stats(tcx);
1032    }
1033    // When using rustdoc's "jump to def" feature, it enters this code and `check_crate`
1034    // is not defined. So we need to cfg it out.
1035    #[cfg(all(not(doc), debug_assertions))]
1036    rustc_passes::hir_id_validator::check_crate(tcx);
1037
1038    // Prefetch this to prevent multiple threads from blocking on it later.
1039    // This is needed since the `hir_id_validator::check_crate` call above is not guaranteed
1040    // to use `hir_crate_items`.
1041    tcx.ensure_done().hir_crate_items(());
1042
1043    let sess = tcx.sess;
1044    sess.time("misc_checking_1", || {
1045        parallel!(
1046            {
1047                sess.time("looking_for_entry_point", || tcx.ensure_ok().entry_fn(()));
1048
1049                sess.time("looking_for_derive_registrar", || {
1050                    tcx.ensure_ok().proc_macro_decls_static(())
1051                });
1052
1053                CStore::from_tcx(tcx).report_unused_deps(tcx);
1054            },
1055            {
1056                tcx.ensure_ok().exportable_items(LOCAL_CRATE);
1057                tcx.ensure_ok().stable_order_of_exportable_impls(LOCAL_CRATE);
1058                tcx.par_hir_for_each_module(|module| {
1059                    tcx.ensure_ok().check_mod_attrs(module);
1060                    tcx.ensure_ok().check_mod_unstable_api_usage(module);
1061                });
1062            },
1063            {
1064                // We force these queries to run,
1065                // since they might not otherwise get called.
1066                // This marks the corresponding crate-level attributes
1067                // as used, and ensures that their values are valid.
1068                tcx.ensure_ok().limits(());
1069            }
1070        );
1071    });
1072
1073    rustc_hir_analysis::check_crate(tcx);
1074    // Freeze definitions as we don't add new ones at this point.
1075    // We need to wait until now since we synthesize a by-move body
1076    // for all coroutine-closures.
1077    //
1078    // This improves performance by allowing lock-free access to them.
1079    tcx.untracked().definitions.freeze();
1080
1081    sess.time("MIR_borrow_checking", || {
1082        tcx.par_hir_body_owners(|def_id| {
1083            if !tcx.is_typeck_child(def_id.to_def_id()) {
1084                // Child unsafety and borrowck happens together with the parent
1085                tcx.ensure_ok().check_unsafety(def_id);
1086                tcx.ensure_ok().mir_borrowck(def_id);
1087                tcx.ensure_ok().check_transmutes(def_id);
1088            }
1089            tcx.ensure_ok().has_ffi_unwind_calls(def_id);
1090
1091            // If we need to codegen, ensure that we emit all errors from
1092            // `mir_drops_elaborated_and_const_checked` now, to avoid discovering
1093            // them later during codegen.
1094            if tcx.sess.opts.output_types.should_codegen()
1095                || tcx.hir_body_const_context(def_id).is_some()
1096            {
1097                tcx.ensure_ok().mir_drops_elaborated_and_const_checked(def_id);
1098            }
1099            if tcx.is_coroutine(def_id.to_def_id()) {
1100                tcx.ensure_ok().mir_coroutine_witnesses(def_id);
1101                let _ = tcx.ensure_ok().check_coroutine_obligations(
1102                    tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(),
1103                );
1104                if !tcx.is_async_drop_in_place_coroutine(def_id.to_def_id()) {
1105                    // Eagerly check the unsubstituted layout for cycles.
1106                    tcx.ensure_ok().layout_of(
1107                        ty::TypingEnv::post_analysis(tcx, def_id.to_def_id())
1108                            .as_query_input(tcx.type_of(def_id).instantiate_identity()),
1109                    );
1110                }
1111            }
1112        });
1113    });
1114
1115    sess.time("layout_testing", || layout_test::test_layout(tcx));
1116    sess.time("abi_testing", || abi_test::test_abi(tcx));
1117
1118    // If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item
1119    // (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs
1120    // in MIR optimizations that may only be reachable through codegen, or other codepaths
1121    // that requires the optimized/ctfe MIR, coroutine bodies, or evaluating consts.
1122    if tcx.sess.opts.unstable_opts.validate_mir {
1123        sess.time("ensuring_final_MIR_is_computable", || {
1124            tcx.par_hir_body_owners(|def_id| {
1125                tcx.instance_mir(ty::InstanceKind::Item(def_id.into()));
1126            });
1127        });
1128    }
1129}
1130
1131/// Runs the type-checking, region checking and other miscellaneous analysis
1132/// passes on the crate.
1133fn analysis(tcx: TyCtxt<'_>, (): ()) {
1134    run_required_analyses(tcx);
1135
1136    let sess = tcx.sess;
1137
1138    // Avoid overwhelming user with errors if borrow checking failed.
1139    // I'm not sure how helpful this is, to be honest, but it avoids a
1140    // lot of annoying errors in the ui tests (basically,
1141    // lint warnings and so on -- kindck used to do this abort, but
1142    // kindck is gone now). -nmatsakis
1143    //
1144    // But we exclude lint errors from this, because lint errors are typically
1145    // less serious and we're more likely to want to continue (#87337).
1146    if let Some(guar) = sess.dcx().has_errors_excluding_lint_errors() {
1147        guar.raise_fatal();
1148    }
1149
1150    sess.time("misc_checking_3", || {
1151        parallel!(
1152            {
1153                tcx.ensure_ok().effective_visibilities(());
1154
1155                parallel!(
1156                    {
1157                        tcx.par_hir_for_each_module(|module| {
1158                            tcx.ensure_ok().check_private_in_public(module)
1159                        })
1160                    },
1161                    {
1162                        tcx.par_hir_for_each_module(|module| {
1163                            tcx.ensure_ok().check_mod_deathness(module)
1164                        });
1165                    },
1166                    {
1167                        sess.time("lint_checking", || {
1168                            rustc_lint::check_crate(tcx);
1169                        });
1170                    },
1171                    {
1172                        tcx.ensure_ok().clashing_extern_declarations(());
1173                    }
1174                );
1175            },
1176            {
1177                sess.time("privacy_checking_modules", || {
1178                    tcx.par_hir_for_each_module(|module| {
1179                        tcx.ensure_ok().check_mod_privacy(module);
1180                    });
1181                });
1182            }
1183        );
1184
1185        // This check has to be run after all lints are done processing. We don't
1186        // define a lint filter, as all lint checks should have finished at this point.
1187        sess.time("check_lint_expectations", || tcx.ensure_ok().check_expectations(None));
1188
1189        // This query is only invoked normally if a diagnostic is emitted that needs any
1190        // diagnostic item. If the crate compiles without checking any diagnostic items,
1191        // we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally.
1192        let _ = tcx.all_diagnostic_items(());
1193    });
1194}
1195
1196/// Runs the codegen backend, after which the AST and analysis can
1197/// be discarded.
1198pub(crate) fn start_codegen<'tcx>(
1199    codegen_backend: &dyn CodegenBackend,
1200    tcx: TyCtxt<'tcx>,
1201) -> (Box<dyn Any>, EncodedMetadata) {
1202    tcx.sess.timings.start_section(tcx.sess.dcx(), TimingSection::Codegen);
1203
1204    // Hook for tests.
1205    if let Some((def_id, _)) = tcx.entry_fn(())
1206        && tcx.has_attr(def_id, sym::rustc_delayed_bug_from_inside_query)
1207    {
1208        tcx.ensure_ok().trigger_delayed_bug(def_id);
1209    }
1210
1211    // Don't run this test assertions when not doing codegen. Compiletest tries to build
1212    // build-fail tests in check mode first and expects it to not give an error in that case.
1213    if tcx.sess.opts.output_types.should_codegen() {
1214        rustc_symbol_mangling::test::report_symbol_names(tcx);
1215    }
1216
1217    // Don't do code generation if there were any errors. Likewise if
1218    // there were any delayed bugs, because codegen will likely cause
1219    // more ICEs, obscuring the original problem.
1220    if let Some(guar) = tcx.sess.dcx().has_errors_or_delayed_bugs() {
1221        guar.raise_fatal();
1222    }
1223
1224    info!("Pre-codegen\n{:?}", tcx.debug_stats());
1225
1226    let metadata = rustc_metadata::fs::encode_and_write_metadata(tcx);
1227
1228    let codegen = tcx.sess.time("codegen_crate", move || codegen_backend.codegen_crate(tcx));
1229
1230    info!("Post-codegen\n{:?}", tcx.debug_stats());
1231
1232    // This must run after monomorphization so that all generic types
1233    // have been instantiated.
1234    if tcx.sess.opts.unstable_opts.print_type_sizes {
1235        tcx.sess.code_stats.print_type_sizes();
1236    }
1237
1238    (codegen, metadata)
1239}
1240
1241/// Compute and validate the crate name.
1242pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol {
1243    // We validate *all* occurrences of `#![crate_name]`, pick the first find and
1244    // if a crate name was passed on the command line via `--crate-name` we enforce
1245    // that they match.
1246    // We perform the validation step here instead of later to ensure it gets run
1247    // in all code paths that require the crate name very early on, namely before
1248    // macro expansion.
1249
1250    let attr_crate_name =
1251        parse_crate_name(sess, krate_attrs, ShouldEmit::EarlyFatal { also_emit_lints: true });
1252
1253    let validate = |name, span| {
1254        rustc_session::output::validate_crate_name(sess, name, span);
1255        name
1256    };
1257
1258    if let Some(crate_name) = &sess.opts.crate_name {
1259        let crate_name = Symbol::intern(crate_name);
1260        if let Some((attr_crate_name, span)) = attr_crate_name
1261            && attr_crate_name != crate_name
1262        {
1263            sess.dcx().emit_err(errors::CrateNameDoesNotMatch {
1264                span,
1265                crate_name,
1266                attr_crate_name,
1267            });
1268        }
1269        return validate(crate_name, None);
1270    }
1271
1272    if let Some((crate_name, span)) = attr_crate_name {
1273        return validate(crate_name, Some(span));
1274    }
1275
1276    if let Input::File(ref path) = sess.io.input
1277        && let Some(file_stem) = path.file_stem().and_then(|s| s.to_str())
1278    {
1279        if file_stem.starts_with('-') {
1280            sess.dcx().emit_err(errors::CrateNameInvalid { crate_name: file_stem });
1281        } else {
1282            return validate(Symbol::intern(&file_stem.replace('-', "_")), None);
1283        }
1284    }
1285
1286    sym::rust_out
1287}
1288
1289pub(crate) fn parse_crate_name(
1290    sess: &Session,
1291    attrs: &[ast::Attribute],
1292    emit_errors: ShouldEmit,
1293) -> Option<(Symbol, Span)> {
1294    let rustc_hir::Attribute::Parsed(AttributeKind::CrateName { name, name_span, .. }) =
1295        AttributeParser::parse_limited_should_emit(
1296            sess,
1297            &attrs,
1298            sym::crate_name,
1299            DUMMY_SP,
1300            rustc_ast::node_id::CRATE_NODE_ID,
1301            None,
1302            emit_errors,
1303        )?
1304    else {
1305        unreachable!("crate_name is the only attr we could've parsed here");
1306    };
1307
1308    Some((name, name_span))
1309}
1310
1311fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit {
1312    let attr = AttributeParser::parse_limited_should_emit(
1313        sess,
1314        &krate_attrs,
1315        sym::recursion_limit,
1316        DUMMY_SP,
1317        rustc_ast::node_id::CRATE_NODE_ID,
1318        None,
1319        // errors are fatal here, but lints aren't.
1320        // If things aren't fatal we continue, and will parse this again.
1321        // That makes the same lint trigger again.
1322        // So, no lints here to avoid duplicates.
1323        ShouldEmit::EarlyFatal { also_emit_lints: false },
1324    );
1325    crate::limits::get_recursion_limit(attr.as_slice())
1326}