2 CantEmitMIR
, EmojiIdentifier
, ErrorWritingDependencies
, FerrisIdentifier
,
3 GeneratedFileConflictsWithDirectory
, InputFileWouldBeOverWritten
, MixedBinCrate
,
4 MixedProcMacroCrate
, OutDirError
, ProcMacroDocWithoutArg
, TempsDirError
,
6 use crate::interface
::{Compiler, Result}
;
7 use crate::proc_macro_decls
;
10 use ast
::CRATE_NODE_ID
;
11 use rustc_ast
::{self as ast, visit}
;
12 use rustc_borrowck
as mir_borrowck
;
13 use rustc_codegen_ssa
::traits
::CodegenBackend
;
14 use rustc_data_structures
::parallel
;
15 use rustc_data_structures
::sync
::{Lrc, OnceCell, WorkerLocal}
;
16 use rustc_errors
::{ErrorGuaranteed, PResult}
;
17 use rustc_expand
::base
::{ExtCtxt, LintStoreExpand, ResolverExpand}
;
18 use rustc_hir
::def_id
::StableCrateId
;
19 use rustc_hir
::definitions
::Definitions
;
20 use rustc_lint
::{BufferedEarlyLint, EarlyCheckNode, LintStore}
;
21 use rustc_metadata
::creader
::CStore
;
22 use rustc_middle
::arena
::Arena
;
23 use rustc_middle
::dep_graph
::DepGraph
;
24 use rustc_middle
::ty
::query
::{ExternProviders, Providers}
;
25 use rustc_middle
::ty
::{self, GlobalCtxt, RegisteredTools, TyCtxt}
;
26 use rustc_mir_build
as mir_build
;
27 use rustc_parse
::{parse_crate_from_file, parse_crate_from_source_str, validate_attr}
;
28 use rustc_passes
::{self, hir_stats, layout_test}
;
29 use rustc_plugin_impl
as plugin
;
30 use rustc_query_impl
::{OnDiskCache, Queries as TcxQueries}
;
31 use rustc_resolve
::{Resolver, ResolverArenas}
;
32 use rustc_session
::config
::{CrateType, Input, OutputFilenames, OutputType}
;
33 use rustc_session
::cstore
::{CrateStoreDyn, MetadataLoader, MetadataLoaderDyn}
;
34 use rustc_session
::output
::filename_for_input
;
35 use rustc_session
::search_paths
::PathKind
;
36 use rustc_session
::{Limit, Session}
;
37 use rustc_span
::symbol
::{sym, Symbol}
;
38 use rustc_span
::FileName
;
39 use rustc_trait_selection
::traits
;
40 use rustc_typeck
as typeck
;
43 use std
::cell
::RefCell
;
44 use std
::ffi
::OsString
;
45 use std
::io
::{self, BufWriter, Write}
;
46 use std
::marker
::PhantomPinned
;
47 use std
::path
::{Path, PathBuf}
;
50 use std
::sync
::LazyLock
;
51 use std
::{env, fs, iter}
;
53 pub fn parse
<'a
>(sess
: &'a Session
, input
: &Input
) -> PResult
<'a
, ast
::Crate
> {
54 let krate
= sess
.time("parse_crate", || match input
{
55 Input
::File(file
) => parse_crate_from_file(file
, &sess
.parse_sess
),
56 Input
::Str { input, name }
=> {
57 parse_crate_from_source_str(name
.clone(), input
.clone(), &sess
.parse_sess
)
61 if sess
.opts
.unstable_opts
.input_stats
{
62 eprintln
!("Lines of code: {}", sess
.source_map().count_lines());
63 eprintln
!("Pre-expansion node count: {}", count_nodes(&krate
));
66 if let Some(ref s
) = sess
.opts
.unstable_opts
.show_span
{
67 rustc_ast_passes
::show_span
::run(sess
.diagnostic(), s
, &krate
);
70 if sess
.opts
.unstable_opts
.hir_stats
{
71 hir_stats
::print_ast_stats(&krate
, "PRE EXPANSION AST STATS", "ast-stats-1");
77 fn count_nodes(krate
: &ast
::Crate
) -> usize {
78 let mut counter
= rustc_ast_passes
::node_count
::NodeCounter
::new();
79 visit
::walk_crate(&mut counter
, krate
);
83 pub use boxed_resolver
::BoxedResolver
;
87 pub struct BoxedResolver(Pin
<Box
<BoxedResolverInner
>>);
89 struct BoxedResolverInner
{
90 session
: Lrc
<Session
>,
91 resolver_arenas
: Option
<ResolverArenas
<'
static>>,
92 resolver
: Option
<Resolver
<'
static>>,
96 // Note: Drop order is important to prevent dangling references. Resolver must be dropped first,
97 // then resolver_arenas and session.
98 impl Drop
for BoxedResolverInner
{
100 self.resolver
.take();
101 self.resolver_arenas
.take();
107 session
: Lrc
<Session
>,
108 make_resolver
: impl for<'a
> FnOnce(&'a Session
, &'a ResolverArenas
<'a
>) -> Resolver
<'a
>,
110 let mut boxed_resolver
= Box
::new(BoxedResolverInner
{
112 resolver_arenas
: Some(Resolver
::arenas()),
116 // SAFETY: `make_resolver` takes a resolver arena with an arbitrary lifetime and
117 // returns a resolver with the same lifetime as the arena. We ensure that the arena
118 // outlives the resolver in the drop impl and elsewhere so these transmutes are sound.
120 let resolver
= make_resolver(
121 std
::mem
::transmute
::<&Session
, &Session
>(&boxed_resolver
.session
),
122 std
::mem
::transmute
::<&ResolverArenas
<'_
>, &ResolverArenas
<'_
>>(
123 boxed_resolver
.resolver_arenas
.as_ref().unwrap(),
126 boxed_resolver
.resolver
= Some(resolver
);
127 BoxedResolver(Pin
::new_unchecked(boxed_resolver
))
131 pub fn access
<F
: for<'a
> FnOnce(&mut Resolver
<'a
>) -> R
, R
>(&mut self, f
: F
) -> R
{
132 // SAFETY: The resolver doesn't need to be pinned.
133 let mut resolver
= unsafe {
134 self.0.as_mut().map_unchecked_mut(|boxed_resolver
| &mut boxed_resolver
.resolver
)
136 f((&mut *resolver
).as_mut().unwrap())
139 pub fn to_resolver_outputs(
140 resolver
: Rc
<RefCell
<BoxedResolver
>>,
141 ) -> (Definitions
, Box
<CrateStoreDyn
>, ty
::ResolverOutputs
, ty
::ResolverAstLowering
)
143 match Rc
::try_unwrap(resolver
) {
145 let mut resolver
= resolver
.into_inner();
146 // SAFETY: The resolver doesn't need to be pinned.
147 let mut resolver
= unsafe {
151 .map_unchecked_mut(|boxed_resolver
| &mut boxed_resolver
.resolver
)
153 resolver
.take().unwrap().into_outputs()
155 Err(resolver
) => resolver
.borrow_mut().access(|resolver
| resolver
.clone_outputs()),
161 pub fn create_resolver(
163 metadata_loader
: Box
<MetadataLoaderDyn
>,
167 trace
!("create_resolver");
168 BoxedResolver
::new(sess
, move |sess
, resolver_arenas
| {
169 Resolver
::new(sess
, krate
, crate_name
, metadata_loader
, resolver_arenas
)
173 pub fn register_plugins
<'a
>(
175 metadata_loader
: &'a
dyn MetadataLoader
,
176 register_lints
: impl Fn(&Session
, &mut LintStore
),
177 mut krate
: ast
::Crate
,
179 ) -> Result
<(ast
::Crate
, LintStore
)> {
180 krate
= sess
.time("attributes_injection", || {
181 rustc_builtin_macros
::cmdline_attrs
::inject(
184 &sess
.opts
.unstable_opts
.crate_attr
,
188 let (krate
, features
) = rustc_expand
::config
::features(sess
, krate
, CRATE_NODE_ID
);
189 // these need to be set "early" so that expansion sees `quote` if enabled.
190 sess
.init_features(features
);
192 let crate_types
= util
::collect_crate_types(sess
, &krate
.attrs
);
193 sess
.init_crate_types(crate_types
);
195 let stable_crate_id
= StableCrateId
::new(
197 sess
.crate_types().contains(&CrateType
::Executable
),
198 sess
.opts
.cg
.metadata
.clone(),
200 sess
.stable_crate_id
.set(stable_crate_id
).expect("not yet initialized");
201 rustc_incremental
::prepare_session_directory(sess
, crate_name
, stable_crate_id
)?
;
203 if sess
.opts
.incremental
.is_some() {
204 sess
.time("incr_comp_garbage_collect_session_directories", || {
205 if let Err(e
) = rustc_incremental
::garbage_collect_session_directories(sess
) {
207 "Error while trying to garbage collect incremental \
208 compilation cache directory: {}",
215 let mut lint_store
= rustc_lint
::new_lint_store(
216 sess
.opts
.unstable_opts
.no_interleave_lints
,
217 sess
.enable_internal_lints(),
219 register_lints(sess
, &mut lint_store
);
222 sess
.time("plugin_loading", || plugin
::load
::load_plugins(sess
, metadata_loader
, &krate
));
223 sess
.time("plugin_registration", || {
224 let mut registry
= plugin
::Registry { lint_store: &mut lint_store }
;
225 for registrar
in registrars
{
226 registrar(&mut registry
);
230 Ok((krate
, lint_store
))
233 fn pre_expansion_lint
<'a
>(
235 lint_store
: &LintStore
,
236 registered_tools
: &RegisteredTools
,
237 check_node
: impl EarlyCheckNode
<'a
>,
240 sess
.prof
.generic_activity_with_arg("pre_AST_expansion_lint_checks", node_name
).run(|| {
241 rustc_lint
::check_ast_node(
247 rustc_lint
::BuiltinCombinedPreExpansionLintPass
::new(),
253 // Cannot implement directly for `LintStore` due to trait coherence.
254 struct LintStoreExpandImpl
<'a
>(&'a LintStore
);
256 impl LintStoreExpand
for LintStoreExpandImpl
<'_
> {
257 fn pre_expansion_lint(
260 registered_tools
: &RegisteredTools
,
261 node_id
: ast
::NodeId
,
262 attrs
: &[ast
::Attribute
],
263 items
: &[rustc_ast
::ptr
::P
<ast
::Item
>],
266 pre_expansion_lint(sess
, self.0, registered_tools
, (node_id
, attrs
, items
), name
);
270 /// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins,
271 /// syntax expansion, secondary `cfg` expansion, synthesis of a test
272 /// harness if one is to be provided, injection of a dependency on the
273 /// standard library and prelude, and name resolution.
274 pub fn configure_and_expand(
276 lint_store
: &LintStore
,
277 mut krate
: ast
::Crate
,
279 resolver
: &mut Resolver
<'_
>,
280 ) -> Result
<ast
::Crate
> {
281 trace
!("configure_and_expand");
282 pre_expansion_lint(sess
, lint_store
, resolver
.registered_tools(), &krate
, crate_name
);
283 rustc_builtin_macros
::register_builtin_macros(resolver
);
285 krate
= sess
.time("crate_injection", || {
286 rustc_builtin_macros
::standard_library_imports
::inject(krate
, resolver
, sess
)
289 util
::check_attr_crate_type(sess
, &krate
.attrs
, &mut resolver
.lint_buffer());
292 krate
= sess
.time("macro_expand_crate", || {
293 // Windows dlls do not have rpaths, so they don't know how to find their
294 // dependencies. It's up to us to tell the system where to find all the
295 // dependent dlls. Note that this uses cfg!(windows) as opposed to
296 // targ_cfg because syntax extensions are always loaded for the host
297 // compiler, not for the target.
299 // This is somewhat of an inherently racy operation, however, as
300 // multiple threads calling this function could possibly continue
301 // extending PATH far beyond what it should. To solve this for now we
302 // just don't add any new elements to PATH which are already there
303 // within PATH. This is basically a targeted fix at #17360 for rustdoc
304 // which runs rustc in parallel but has been seen (#33844) to cause
305 // problems with PATH becoming too long.
306 let mut old_path
= OsString
::new();
308 old_path
= env
::var_os("PATH").unwrap_or(old_path
);
309 let mut new_path
= sess
.host_filesearch(PathKind
::All
).search_path_dirs();
310 for path
in env
::split_paths(&old_path
) {
311 if !new_path
.contains(&path
) {
318 new_path
.iter().filter(|p
| env
::join_paths(iter
::once(p
)).is_ok()),
324 // Create the config for macro expansion
325 let features
= sess
.features_untracked();
326 let recursion_limit
= get_recursion_limit(&krate
.attrs
, sess
);
327 let cfg
= rustc_expand
::expand
::ExpansionConfig
{
328 features
: Some(features
),
330 trace_mac
: sess
.opts
.unstable_opts
.trace_macros
,
331 should_test
: sess
.opts
.test
,
332 span_debug
: sess
.opts
.unstable_opts
.span_debug
,
333 proc_macro_backtrace
: sess
.opts
.unstable_opts
.proc_macro_backtrace
,
334 ..rustc_expand
::expand
::ExpansionConfig
::default(crate_name
.to_string())
337 let lint_store
= LintStoreExpandImpl(lint_store
);
338 let mut ecx
= ExtCtxt
::new(sess
, cfg
, resolver
, Some(&lint_store
));
339 // Expand macros now!
340 let krate
= sess
.time("expand_crate", || ecx
.monotonic_expander().expand_crate(krate
));
342 // The rest is error reporting
344 sess
.parse_sess
.buffered_lints
.with_lock(|buffered_lints
: &mut Vec
<BufferedEarlyLint
>| {
345 buffered_lints
.append(&mut ecx
.buffered_early_lint
);
348 sess
.time("check_unused_macros", || {
349 ecx
.check_unused_macros();
352 let recursion_limit_hit
= ecx
.reduced_recursion_limit
.is_some();
355 env
::set_var("PATH", &old_path
);
358 if recursion_limit_hit
{
359 // If we hit a recursion limit, exit early to avoid later passes getting overwhelmed
361 Err(ErrorGuaranteed
::unchecked_claim_error_was_emitted())
367 sess
.time("maybe_building_test_harness", || {
368 rustc_builtin_macros
::test_harness
::inject(sess
, resolver
, &mut krate
)
371 let has_proc_macro_decls
= sess
.time("AST_validation", || {
372 rustc_ast_passes
::ast_validation
::check_crate(sess
, &krate
, resolver
.lint_buffer())
375 let crate_types
= sess
.crate_types();
376 let is_executable_crate
= crate_types
.contains(&CrateType
::Executable
);
377 let is_proc_macro_crate
= crate_types
.contains(&CrateType
::ProcMacro
);
379 if crate_types
.len() > 1 {
380 if is_executable_crate
{
381 sess
.emit_err(MixedBinCrate
);
383 if is_proc_macro_crate
{
384 sess
.emit_err(MixedProcMacroCrate
);
388 // For backwards compatibility, we don't try to run proc macro injection
389 // if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being
390 // specified. This should only affect users who manually invoke 'rustdoc', as
391 // 'cargo doc' will automatically pass the proper '--crate-type' flags.
392 // However, we do emit a warning, to let such users know that they should
393 // start passing '--crate-type proc-macro'
394 if has_proc_macro_decls
&& sess
.opts
.actually_rustdoc
&& !is_proc_macro_crate
{
395 sess
.emit_warning(ProcMacroDocWithoutArg
);
397 krate
= sess
.time("maybe_create_a_macro_crate", || {
398 let is_test_crate
= sess
.opts
.test
;
399 rustc_builtin_macros
::proc_macro_harness
::inject(
404 has_proc_macro_decls
,
411 // Done with macro expansion!
413 if sess
.opts
.unstable_opts
.input_stats
{
414 eprintln
!("Post-expansion node count: {}", count_nodes(&krate
));
417 if sess
.opts
.unstable_opts
.hir_stats
{
418 hir_stats
::print_ast_stats(&krate
, "POST EXPANSION AST STATS", "ast-stats-2");
421 resolver
.resolve_crate(&krate
);
423 // Needs to go *after* expansion to be able to check the results of macro expansion.
424 sess
.time("complete_gated_feature_checking", || {
425 rustc_ast_passes
::feature_gate
::check_crate(&krate
, sess
);
428 // Add all buffered lints from the `ParseSess` to the `Session`.
429 sess
.parse_sess
.buffered_lints
.with_lock(|buffered_lints
| {
430 info
!("{} parse sess buffered_lints", buffered_lints
.len());
431 for early_lint
in buffered_lints
.drain(..) {
432 resolver
.lint_buffer().add_early_lint(early_lint
);
436 // Gate identifiers containing invalid Unicode codepoints that were recovered during lexing.
437 sess
.parse_sess
.bad_unicode_identifiers
.with_lock(|identifiers
| {
438 let mut identifiers
: Vec
<_
> = identifiers
.drain().collect();
439 identifiers
.sort_by_key(|&(key
, _
)| key
);
440 for (ident
, mut spans
) in identifiers
.into_iter() {
442 if ident
== sym
::ferris
{
443 let first_span
= spans
[0];
444 sess
.emit_err(FerrisIdentifier { spans, first_span }
);
446 sess
.emit_err(EmojiIdentifier { spans, ident }
);
451 sess
.time("early_lint_checks", || {
452 let lint_buffer
= Some(std
::mem
::take(resolver
.lint_buffer()));
453 rustc_lint
::check_ast_node(
457 resolver
.registered_tools(),
459 rustc_lint
::BuiltinCombinedEarlyLintPass
::new(),
467 // Returns all the paths that correspond to generated files.
468 fn generated_output_paths(
470 outputs
: &OutputFilenames
,
474 let mut out_filenames
= Vec
::new();
475 for output_type
in sess
.opts
.output_types
.keys() {
476 let file
= outputs
.path(*output_type
);
478 // If the filename has been overridden using `-o`, it will not be modified
479 // by appending `.rlib`, `.exe`, etc., so we can skip this transformation.
480 OutputType
::Exe
if !exact_name
=> {
481 for crate_type
in sess
.crate_types().iter() {
482 let p
= filename_for_input(sess
, *crate_type
, crate_name
, outputs
);
483 out_filenames
.push(p
);
486 OutputType
::DepInfo
if sess
.opts
.unstable_opts
.dep_info_omit_d_target
=> {
487 // Don't add the dep-info output when omitting it from dep-info targets
490 out_filenames
.push(file
);
497 // Runs `f` on every output file path and returns the first non-None result, or None if `f`
498 // returns None for every file path.
499 fn check_output
<F
, T
>(output_paths
: &[PathBuf
], f
: F
) -> Option
<T
>
501 F
: Fn(&PathBuf
) -> Option
<T
>,
503 for output_path
in output_paths
{
504 if let Some(result
) = f(output_path
) {
511 fn output_contains_path(output_paths
: &[PathBuf
], input_path
: &Path
) -> bool
{
512 let input_path
= input_path
.canonicalize().ok();
513 if input_path
.is_none() {
516 let check
= |output_path
: &PathBuf
| {
517 if output_path
.canonicalize().ok() == input_path { Some(()) }
else { None }
519 check_output(output_paths
, check
).is_some()
522 fn output_conflicts_with_dir(output_paths
: &[PathBuf
]) -> Option
<PathBuf
> {
523 let check
= |output_path
: &PathBuf
| output_path
.is_dir().then(|| output_path
.clone());
524 check_output(output_paths
, check
)
527 fn escape_dep_filename(filename
: &str) -> String
{
528 // Apparently clang and gcc *only* escape spaces:
529 // https://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
530 filename
.replace(' '
, "\\ ")
533 // Makefile comments only need escaping newlines and `\`.
534 // The result can be unescaped by anything that can unescape `escape_default` and friends.
535 fn escape_dep_env(symbol
: Symbol
) -> String
{
536 let s
= symbol
.as_str();
537 let mut escaped
= String
::with_capacity(s
.len());
540 '
\n'
=> escaped
.push_str(r
"\n"),
541 '
\r'
=> escaped
.push_str(r
"\r"),
542 '
\\'
=> escaped
.push_str(r
"\\"),
543 _
=> escaped
.push(c
),
551 boxed_resolver
: &RefCell
<BoxedResolver
>,
552 outputs
: &OutputFilenames
,
553 out_filenames
: &[PathBuf
],
555 // Write out dependency rules to the dep-info file if requested
556 if !sess
.opts
.output_types
.contains_key(&OutputType
::DepInfo
) {
559 let deps_filename
= outputs
.path(OutputType
::DepInfo
);
561 let result
= (|| -> io
::Result
<()> {
562 // Build a list of files used to compile the output and
563 // write Makefile-compatible dependency rules
564 let mut files
: Vec
<String
> = sess
568 .filter(|fmap
| fmap
.is_real_file())
569 .filter(|fmap
| !fmap
.is_imported())
570 .map(|fmap
| escape_dep_filename(&fmap
.name
.prefer_local().to_string()))
573 // Account for explicitly marked-to-track files
574 // (e.g. accessed in proc macros).
575 let file_depinfo
= sess
.parse_sess
.file_depinfo
.borrow();
577 let normalize_path
= |path
: PathBuf
| {
578 let file
= FileName
::from(path
);
579 escape_dep_filename(&file
.prefer_local().to_string())
582 let extra_tracked_files
=
583 file_depinfo
.iter().map(|path_sym
| normalize_path(PathBuf
::from(path_sym
.as_str())));
584 files
.extend(extra_tracked_files
);
586 // We also need to track used PGO profile files
587 if let Some(ref profile_instr
) = sess
.opts
.cg
.profile_use
{
588 files
.push(normalize_path(profile_instr
.as_path().to_path_buf()));
590 if let Some(ref profile_sample
) = sess
.opts
.unstable_opts
.profile_sample_use
{
591 files
.push(normalize_path(profile_sample
.as_path().to_path_buf()));
594 if sess
.binary_dep_depinfo() {
595 if let Some(ref backend
) = sess
.opts
.unstable_opts
.codegen_backend
{
596 if backend
.contains('
.'
) {
597 // If the backend name contain a `.`, it is the path to an external dynamic
598 // library. If not, it is not a path.
599 files
.push(backend
.to_string());
603 boxed_resolver
.borrow_mut().access(|resolver
| {
604 for cnum
in resolver
.cstore().crates_untracked() {
605 let source
= resolver
.cstore().crate_source_untracked(cnum
);
606 if let Some((path
, _
)) = &source
.dylib
{
607 files
.push(escape_dep_filename(&path
.display().to_string()));
609 if let Some((path
, _
)) = &source
.rlib
{
610 files
.push(escape_dep_filename(&path
.display().to_string()));
612 if let Some((path
, _
)) = &source
.rmeta
{
613 files
.push(escape_dep_filename(&path
.display().to_string()));
619 let mut file
= BufWriter
::new(fs
::File
::create(&deps_filename
)?
);
620 for path
in out_filenames
{
621 writeln
!(file
, "{}: {}\n", path
.display(), files
.join(" "))?
;
624 // Emit a fake target for each input file to the compilation. This
625 // prevents `make` from spitting out an error if a file is later
626 // deleted. For more info see #28735
628 writeln
!(file
, "{}:", path
)?
;
631 // Emit special comments with information about accessed environment variables.
632 let env_depinfo
= sess
.parse_sess
.env_depinfo
.borrow();
633 if !env_depinfo
.is_empty() {
634 let mut envs
: Vec
<_
> = env_depinfo
636 .map(|(k
, v
)| (escape_dep_env(*k
), v
.map(escape_dep_env
)))
638 envs
.sort_unstable();
641 write
!(file
, "# env-dep:{}", k
)?
;
643 write
!(file
, "={}", v
)?
;
654 if sess
.opts
.json_artifact_notifications
{
657 .emit_artifact_notification(&deps_filename
, "dep-info");
661 sess
.emit_fatal(ErrorWritingDependencies { path: &deps_filename, error }
);
666 pub fn prepare_outputs(
670 boxed_resolver
: &RefCell
<BoxedResolver
>,
672 ) -> Result
<OutputFilenames
> {
673 let _timer
= sess
.timer("prepare_outputs");
675 // FIXME: rustdoc passes &[] instead of &krate.attrs here
676 let outputs
= util
::build_output_filenames(
678 &compiler
.output_dir
,
679 &compiler
.output_file
,
686 generated_output_paths(sess
, &outputs
, compiler
.output_file
.is_some(), crate_name
);
688 // Ensure the source file isn't accidentally overwritten during compilation.
689 if let Some(ref input_path
) = compiler
.input_path
{
690 if sess
.opts
.will_create_output_file() {
691 if output_contains_path(&output_paths
, input_path
) {
692 let reported
= sess
.emit_err(InputFileWouldBeOverWritten { path: input_path }
);
693 return Err(reported
);
695 if let Some(ref dir_path
) = output_conflicts_with_dir(&output_paths
) {
697 sess
.emit_err(GeneratedFileConflictsWithDirectory { input_path, dir_path }
);
698 return Err(reported
);
703 if let Some(ref dir
) = compiler
.temps_dir
{
704 if fs
::create_dir_all(dir
).is_err() {
705 let reported
= sess
.emit_err(TempsDirError
);
706 return Err(reported
);
710 write_out_deps(sess
, boxed_resolver
, &outputs
, &output_paths
);
712 let only_dep_info
= sess
.opts
.output_types
.contains_key(&OutputType
::DepInfo
)
713 && sess
.opts
.output_types
.len() == 1;
716 if let Some(ref dir
) = compiler
.output_dir
{
717 if fs
::create_dir_all(dir
).is_err() {
718 let reported
= sess
.emit_err(OutDirError
);
719 return Err(reported
);
727 pub static DEFAULT_QUERY_PROVIDERS
: LazyLock
<Providers
> = LazyLock
::new(|| {
728 let providers
= &mut Providers
::default();
729 providers
.analysis
= analysis
;
730 providers
.hir_crate
= rustc_ast_lowering
::lower_to_hir
;
731 proc_macro_decls
::provide(providers
);
732 rustc_const_eval
::provide(providers
);
733 rustc_middle
::hir
::provide(providers
);
734 mir_borrowck
::provide(providers
);
735 mir_build
::provide(providers
);
736 rustc_mir_transform
::provide(providers
);
737 rustc_monomorphize
::provide(providers
);
738 rustc_privacy
::provide(providers
);
739 typeck
::provide(providers
);
740 ty
::provide(providers
);
741 traits
::provide(providers
);
742 rustc_passes
::provide(providers
);
743 rustc_resolve
::provide(providers
);
744 rustc_traits
::provide(providers
);
745 rustc_ty_utils
::provide(providers
);
746 rustc_metadata
::provide(providers
);
747 rustc_lint
::provide(providers
);
748 rustc_symbol_mangling
::provide(providers
);
749 rustc_codegen_ssa
::provide(providers
);
753 pub static DEFAULT_EXTERN_QUERY_PROVIDERS
: LazyLock
<ExternProviders
> = LazyLock
::new(|| {
754 let mut extern_providers
= ExternProviders
::default();
755 rustc_metadata
::provide_extern(&mut extern_providers
);
756 rustc_codegen_ssa
::provide_extern(&mut extern_providers
);
760 pub struct QueryContext
<'tcx
> {
761 gcx
: &'tcx GlobalCtxt
<'tcx
>,
764 impl<'tcx
> QueryContext
<'tcx
> {
765 pub fn enter
<F
, R
>(&mut self, f
: F
) -> R
767 F
: FnOnce(TyCtxt
<'tcx
>) -> R
,
769 let icx
= ty
::tls
::ImplicitCtxt
::new(self.gcx
);
770 ty
::tls
::enter_context(&icx
, |_
| f(icx
.tcx
))
774 pub fn create_global_ctxt
<'tcx
>(
775 compiler
: &'tcx Compiler
,
776 lint_store
: Lrc
<LintStore
>,
777 krate
: Lrc
<ast
::Crate
>,
779 resolver
: Rc
<RefCell
<BoxedResolver
>>,
780 outputs
: OutputFilenames
,
782 queries
: &'tcx OnceCell
<TcxQueries
<'tcx
>>,
783 global_ctxt
: &'tcx OnceCell
<GlobalCtxt
<'tcx
>>,
784 arena
: &'tcx WorkerLocal
<Arena
<'tcx
>>,
785 hir_arena
: &'tcx WorkerLocal
<rustc_hir
::Arena
<'tcx
>>,
786 ) -> QueryContext
<'tcx
> {
787 // We're constructing the HIR here; we don't care what we will
788 // read, since we haven't even constructed the *input* to
790 dep_graph
.assert_ignored();
792 let (definitions
, cstore
, resolver_outputs
, resolver_for_lowering
) =
793 BoxedResolver
::to_resolver_outputs(resolver
);
795 let sess
= &compiler
.session();
796 let query_result_on_disk_cache
= rustc_incremental
::load_query_result_cache(sess
);
798 let codegen_backend
= compiler
.codegen_backend();
799 let mut local_providers
= *DEFAULT_QUERY_PROVIDERS
;
800 codegen_backend
.provide(&mut local_providers
);
802 let mut extern_providers
= *DEFAULT_EXTERN_QUERY_PROVIDERS
;
803 codegen_backend
.provide_extern(&mut extern_providers
);
805 if let Some(callback
) = compiler
.override_queries
{
806 callback(sess
, &mut local_providers
, &mut extern_providers
);
809 let queries
= queries
.get_or_init(|| {
810 TcxQueries
::new(local_providers
, extern_providers
, query_result_on_disk_cache
)
813 let gcx
= sess
.time("setup_global_ctxt", || {
814 global_ctxt
.get_or_init(move || {
815 TyCtxt
::create_global_ctxt(
823 resolver_for_lowering
,
826 queries
.on_disk_cache
.as_ref().map(OnDiskCache
::as_dyn
),
828 rustc_query_impl
::query_callbacks(arena
),
838 /// Runs the resolution, type-checking, region checking and other
839 /// miscellaneous analysis passes on the crate.
840 fn analysis(tcx
: TyCtxt
<'_
>, (): ()) -> Result
<()> {
841 rustc_passes
::hir_id_validator
::check_crate(tcx
);
844 let mut entry_point
= None
;
846 sess
.time("misc_checking_1", || {
849 entry_point
= sess
.time("looking_for_entry_point", || tcx
.entry_fn(()));
851 sess
.time("looking_for_derive_registrar", || {
852 tcx
.ensure().proc_macro_decls_static(())
855 CStore
::from_tcx(tcx
).report_unused_deps(tcx
);
858 tcx
.hir().par_for_each_module(|module
| {
859 tcx
.ensure().check_mod_loops(module
);
860 tcx
.ensure().check_mod_attrs(module
);
861 tcx
.ensure().check_mod_naked_functions(module
);
862 tcx
.ensure().check_mod_unstable_api_usage(module
);
863 tcx
.ensure().check_mod_const_bodies(module
);
867 sess
.time("unused_lib_feature_checking", || {
868 rustc_passes
::stability
::check_unused_or_stable_features(tcx
)
872 // We force these queries to run,
873 // since they might not otherwise get called.
874 // This marks the corresponding crate-level attributes
875 // as used, and ensures that their values are valid.
876 tcx
.ensure().limits(());
877 tcx
.ensure().stability_index(());
882 // passes are timed inside typeck
883 typeck
::check_crate(tcx
)?
;
885 sess
.time("misc_checking_2", || {
888 sess
.time("match_checking", || {
889 tcx
.hir().par_body_owners(|def_id
| tcx
.ensure().check_match(def_id
.to_def_id()))
893 sess
.time("liveness_checking", || {
894 tcx
.hir().par_body_owners(|def_id
| {
895 // this must run before MIR dump, because
896 // "not all control paths return a value" is reported here.
898 // maybe move the check to a MIR pass?
899 tcx
.ensure().check_liveness(def_id
.to_def_id());
906 sess
.time("MIR_borrow_checking", || {
907 tcx
.hir().par_body_owners(|def_id
| tcx
.ensure().mir_borrowck(def_id
));
910 sess
.time("MIR_effect_checking", || {
911 for def_id
in tcx
.hir().body_owners() {
912 tcx
.ensure().thir_check_unsafety(def_id
);
913 if !tcx
.sess
.opts
.unstable_opts
.thir_unsafeck
{
914 rustc_mir_transform
::check_unsafety
::check_unsafety(tcx
, def_id
);
916 tcx
.ensure().has_ffi_unwind_calls(def_id
);
918 if tcx
.hir().body_const_context(def_id
).is_some() {
920 .mir_drops_elaborated_and_const_checked(ty
::WithOptConstParam
::unknown(def_id
));
925 sess
.time("layout_testing", || layout_test
::test_layout(tcx
));
927 // Avoid overwhelming user with errors if borrow checking failed.
928 // I'm not sure how helpful this is, to be honest, but it avoids a
929 // lot of annoying errors in the ui tests (basically,
930 // lint warnings and so on -- kindck used to do this abort, but
931 // kindck is gone now). -nmatsakis
932 if let Some(reported
) = sess
.has_errors() {
933 return Err(reported
);
936 sess
.time("misc_checking_3", || {
939 tcx
.ensure().privacy_access_levels(());
943 tcx
.ensure().check_private_in_public(());
947 .par_for_each_module(|module
| tcx
.ensure().check_mod_deathness(module
));
950 sess
.time("lint_checking", || {
951 rustc_lint
::check_crate(tcx
, || {
952 rustc_lint
::BuiltinCombinedLateLintPass
::new()
959 sess
.time("privacy_checking_modules", || {
960 tcx
.hir().par_for_each_module(|module
| {
961 tcx
.ensure().check_mod_privacy(module
);
967 // This check has to be run after all lints are done processing. We don't
968 // define a lint filter, as all lint checks should have finished at this point.
969 sess
.time("check_lint_expectations", || tcx
.check_expectations(None
));
975 /// Runs the codegen backend, after which the AST and analysis can
977 pub fn start_codegen
<'tcx
>(
978 codegen_backend
: &dyn CodegenBackend
,
980 outputs
: &OutputFilenames
,
982 info
!("Pre-codegen\n{:?}", tcx
.debug_stats());
984 let (metadata
, need_metadata_module
) =
985 rustc_metadata
::fs
::encode_and_write_metadata(tcx
, outputs
);
987 let codegen
= tcx
.sess
.time("codegen_crate", move || {
988 codegen_backend
.codegen_crate(tcx
, metadata
, need_metadata_module
)
991 // Don't run these test assertions when not doing codegen. Compiletest tries to build
992 // build-fail tests in check mode first and expects it to not give an error in that case.
993 if tcx
.sess
.opts
.output_types
.should_codegen() {
994 rustc_incremental
::assert_module_sources
::assert_module_sources(tcx
);
995 rustc_symbol_mangling
::test
::report_symbol_names(tcx
);
998 info
!("Post-codegen\n{:?}", tcx
.debug_stats());
1000 if tcx
.sess
.opts
.output_types
.contains_key(&OutputType
::Mir
) {
1001 if let Err(error
) = rustc_mir_transform
::dump_mir
::emit_mir(tcx
, outputs
) {
1002 tcx
.sess
.emit_err(CantEmitMIR { error }
);
1003 tcx
.sess
.abort_if_errors();
1010 fn get_recursion_limit(krate_attrs
: &[ast
::Attribute
], sess
: &Session
) -> Limit
{
1011 if let Some(attr
) = krate_attrs
1013 .find(|attr
| attr
.has_name(sym
::recursion_limit
) && attr
.value_str().is_none())
1015 // This is here mainly to check for using a macro, such as
1016 // #![recursion_limit = foo!()]. That is not supported since that
1017 // would require expanding this while in the middle of expansion,
1018 // which needs to know the limit before expanding. Otherwise,
1019 // validation would normally be caught in AstValidator (via
1020 // `check_builtin_attribute`), but by the time that runs the macro
1021 // is expanded, and it doesn't give an error.
1022 validate_attr
::emit_fatal_malformed_builtin_attribute(
1025 sym
::recursion_limit
,
1028 rustc_middle
::middle
::limits
::get_recursion_limit(krate_attrs
, sess
)