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
101struct 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#[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 krate = sess.time("macro_expand_crate", || {
159 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 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 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 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 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 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 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 #[allow(rustc::potential_query_instability)]
318 let mut macro_stats: Vec<_> = ecx
319 .macro_stats
320 .iter()
321 .map(|((name, kind), stat)| {
322 (stat.bytes, stat.lines, stat.uses, name, *kind)
324 })
325 .collect();
326 macro_stats.sort_unstable();
327 macro_stats.reverse(); 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 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 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 let mut uses_w = uses_w;
365 if name.len() + uses_with_underscores.len() >= name_w + uses_w {
366 _ = writeln!(s, "{prefix} {:<name_w$}", name);
370 name = String::new();
371 } else if name.len() >= name_w {
372 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 sess.time("complete_gated_feature_checking", || {
404 rustc_ast_passes::feature_gate::check_crate(krate, sess, tcx.features());
405 });
406
407 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 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 unsafe { OsStr::from_encoded_bytes_unchecked(encoded_bytes) }
485 });
486
487 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
500fn 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 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 }
524 OutputType::DepInfo if out_filename.is_stdout() => {
525 }
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 filename.replace(' ', "\\ ")
551}
552
553fn 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 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 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 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 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 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 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 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 for (path, _file_len, _checksum_hash_algo) in &files {
715 writeln!(file, "{path}:")?;
716 }
717
718 let env_depinfo = sess.psess.env_depinfo.borrow();
720 if !env_depinfo.is_empty() {
721 #[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 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(()); 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 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 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 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 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 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 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
1027fn 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 #[cfg(all(not(doc), debug_assertions))]
1036 rustc_passes::hir_id_validator::check_crate(tcx);
1037
1038 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 tcx.ensure_ok().limits(());
1069 }
1070 );
1071 });
1072
1073 rustc_hir_analysis::check_crate(tcx);
1074 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 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 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 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 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
1131fn analysis(tcx: TyCtxt<'_>, (): ()) {
1134 run_required_analyses(tcx);
1135
1136 let sess = tcx.sess;
1137
1138 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 sess.time("check_lint_expectations", || tcx.ensure_ok().check_expectations(None));
1188
1189 let _ = tcx.all_diagnostic_items(());
1193 });
1194}
1195
1196pub(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 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 if tcx.sess.opts.output_types.should_codegen() {
1214 rustc_symbol_mangling::test::report_symbol_names(tcx);
1215 }
1216
1217 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 if tcx.sess.opts.unstable_opts.print_type_sizes {
1235 tcx.sess.code_stats.print_type_sizes();
1236 }
1237
1238 (codegen, metadata)
1239}
1240
1241pub fn get_crate_name(sess: &Session, krate_attrs: &[ast::Attribute]) -> Symbol {
1243 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 ShouldEmit::EarlyFatal { also_emit_lints: false },
1324 );
1325 crate::limits::get_recursion_limit(attr.as_slice())
1326}