1 use crate::interface
::{Compiler, Result}
;
2 use crate::proc_macro_decls
;
5 use rustc_ast
::mut_visit
::MutVisitor
;
6 use rustc_ast
::{self as ast, visit}
;
7 use rustc_codegen_ssa
::back
::link
::emit_metadata
;
8 use rustc_codegen_ssa
::traits
::CodegenBackend
;
9 use rustc_data_structures
::parallel
;
10 use rustc_data_structures
::sync
::{par_iter, Lrc, OnceCell, ParallelIterator, WorkerLocal}
;
11 use rustc_data_structures
::temp_dir
::MaybeTempDir
;
12 use rustc_errors
::{ErrorReported, PResult}
;
13 use rustc_expand
::base
::ExtCtxt
;
14 use rustc_hir
::def_id
::{StableCrateId, LOCAL_CRATE}
;
16 use rustc_lint
::LintStore
;
17 use rustc_metadata
::creader
::CStore
;
18 use rustc_middle
::arena
::Arena
;
19 use rustc_middle
::dep_graph
::DepGraph
;
20 use rustc_middle
::middle
;
21 use rustc_middle
::middle
::cstore
::{MetadataLoader, MetadataLoaderDyn}
;
22 use rustc_middle
::ty
::query
::Providers
;
23 use rustc_middle
::ty
::{self, GlobalCtxt, ResolverOutputs, TyCtxt}
;
25 use rustc_mir_build
as mir_build
;
26 use rustc_parse
::{parse_crate_from_file, parse_crate_from_source_str}
;
27 use rustc_passes
::{self, hir_stats, layout_test}
;
28 use rustc_plugin_impl
as plugin
;
29 use rustc_query_impl
::{OnDiskCache, Queries as TcxQueries}
;
30 use rustc_resolve
::{Resolver, ResolverArenas}
;
31 use rustc_serialize
::json
;
32 use rustc_session
::config
::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode}
;
33 use rustc_session
::lint
;
34 use rustc_session
::output
::{filename_for_input, filename_for_metadata}
;
35 use rustc_session
::search_paths
::PathKind
;
36 use rustc_session
::Session
;
37 use rustc_span
::symbol
::{Ident, Symbol}
;
38 use rustc_span
::FileName
;
39 use rustc_trait_selection
::traits
;
40 use rustc_typeck
as typeck
;
41 use tempfile
::Builder
as TempFileBuilder
;
42 use tracing
::{info, warn}
;
45 use std
::cell
::RefCell
;
46 use std
::ffi
::OsString
;
47 use std
::io
::{self, BufWriter, Write}
;
48 use std
::lazy
::SyncLazy
;
49 use std
::marker
::PhantomPinned
;
50 use std
::path
::PathBuf
;
53 use std
::{env, fs, iter}
;
55 pub fn parse
<'a
>(sess
: &'a Session
, input
: &Input
) -> PResult
<'a
, ast
::Crate
> {
56 let krate
= sess
.time("parse_crate", || match input
{
57 Input
::File(file
) => parse_crate_from_file(file
, &sess
.parse_sess
),
58 Input
::Str { input, name }
=> {
59 parse_crate_from_source_str(name
.clone(), input
.clone(), &sess
.parse_sess
)
63 if sess
.opts
.debugging_opts
.ast_json_noexpand
{
64 println
!("{}", json
::as_json(&krate
));
67 if sess
.opts
.debugging_opts
.input_stats
{
68 eprintln
!("Lines of code: {}", sess
.source_map().count_lines());
69 eprintln
!("Pre-expansion node count: {}", count_nodes(&krate
));
72 if let Some(ref s
) = sess
.opts
.debugging_opts
.show_span
{
73 rustc_ast_passes
::show_span
::run(sess
.diagnostic(), s
, &krate
);
76 if sess
.opts
.debugging_opts
.hir_stats
{
77 hir_stats
::print_ast_stats(&krate
, "PRE EXPANSION AST STATS");
83 fn count_nodes(krate
: &ast
::Crate
) -> usize {
84 let mut counter
= rustc_ast_passes
::node_count
::NodeCounter
::new();
85 visit
::walk_crate(&mut counter
, krate
);
89 pub use boxed_resolver
::BoxedResolver
;
93 pub struct BoxedResolver(Pin
<Box
<BoxedResolverInner
>>);
95 struct BoxedResolverInner
{
96 session
: Lrc
<Session
>,
97 resolver_arenas
: Option
<ResolverArenas
<'
static>>,
98 resolver
: Option
<Resolver
<'
static>>,
102 // Note: Drop order is important to prevent dangling references. Resolver must be dropped first,
103 // then resolver_arenas and session.
104 impl Drop
for BoxedResolverInner
{
106 self.resolver
.take();
107 self.resolver_arenas
.take();
113 session
: Lrc
<Session
>,
114 make_resolver
: impl for<'a
> FnOnce(&'a Session
, &'a ResolverArenas
<'a
>) -> Resolver
<'a
>,
116 let mut boxed_resolver
= Box
::new(BoxedResolverInner
{
118 resolver_arenas
: Some(Resolver
::arenas()),
122 // SAFETY: `make_resolver` takes a resolver arena with an arbitrary lifetime and
123 // returns a resolver with the same lifetime as the arena. We ensure that the arena
124 // outlives the resolver in the drop impl and elsewhere so these transmutes are sound.
126 let resolver
= make_resolver(
127 std
::mem
::transmute
::<&Session
, &Session
>(&boxed_resolver
.session
),
128 std
::mem
::transmute
::<&ResolverArenas
<'_
>, &ResolverArenas
<'_
>>(
129 boxed_resolver
.resolver_arenas
.as_ref().unwrap(),
132 boxed_resolver
.resolver
= Some(resolver
);
133 BoxedResolver(Pin
::new_unchecked(boxed_resolver
))
137 pub fn access
<F
: for<'a
> FnOnce(&mut Resolver
<'a
>) -> R
, R
>(&mut self, f
: F
) -> R
{
138 // SAFETY: The resolver doesn't need to be pinned.
139 let mut resolver
= unsafe {
140 self.0.as_mut().map_unchecked_mut(|boxed_resolver
| &mut boxed_resolver
.resolver
)
142 f((&mut *resolver
).as_mut().unwrap())
145 pub fn to_resolver_outputs(resolver
: Rc
<RefCell
<BoxedResolver
>>) -> ResolverOutputs
{
146 match Rc
::try_unwrap(resolver
) {
148 let mut resolver
= resolver
.into_inner();
149 // SAFETY: The resolver doesn't need to be pinned.
150 let mut resolver
= unsafe {
154 .map_unchecked_mut(|boxed_resolver
| &mut boxed_resolver
.resolver
)
156 resolver
.take().unwrap().into_outputs()
158 Err(resolver
) => resolver
.borrow_mut().access(|resolver
| resolver
.clone_outputs()),
164 pub fn create_resolver(
166 metadata_loader
: Box
<MetadataLoaderDyn
>,
170 tracing
::trace
!("create_resolver");
171 BoxedResolver
::new(sess
, move |sess
, resolver_arenas
| {
172 Resolver
::new(sess
, &krate
, &crate_name
, metadata_loader
, &resolver_arenas
)
176 pub fn register_plugins
<'a
>(
178 metadata_loader
: &'a
dyn MetadataLoader
,
179 register_lints
: impl Fn(&Session
, &mut LintStore
),
180 mut krate
: ast
::Crate
,
182 ) -> Result
<(ast
::Crate
, Lrc
<LintStore
>)> {
183 krate
= sess
.time("attributes_injection", || {
184 rustc_builtin_macros
::cmdline_attrs
::inject(
187 &sess
.opts
.debugging_opts
.crate_attr
,
191 let (krate
, features
) = rustc_expand
::config
::features(sess
, krate
);
192 // these need to be set "early" so that expansion sees `quote` if enabled.
193 sess
.init_features(features
);
195 let crate_types
= util
::collect_crate_types(sess
, &krate
.attrs
);
196 sess
.init_crate_types(crate_types
);
198 let stable_crate_id
= StableCrateId
::new(
200 sess
.crate_types().contains(&CrateType
::Executable
),
201 sess
.opts
.cg
.metadata
.clone(),
203 sess
.stable_crate_id
.set(stable_crate_id
).expect("not yet initialized");
204 rustc_incremental
::prepare_session_directory(sess
, &crate_name
, stable_crate_id
)?
;
206 if sess
.opts
.incremental
.is_some() {
207 sess
.time("incr_comp_garbage_collect_session_directories", || {
208 if let Err(e
) = rustc_incremental
::garbage_collect_session_directories(sess
) {
210 "Error while trying to garbage collect incremental \
211 compilation cache directory: {}",
218 let mut lint_store
= rustc_lint
::new_lint_store(
219 sess
.opts
.debugging_opts
.no_interleave_lints
,
220 sess
.unstable_options(),
222 register_lints(&sess
, &mut lint_store
);
225 sess
.time("plugin_loading", || plugin
::load
::load_plugins(sess
, metadata_loader
, &krate
));
226 sess
.time("plugin_registration", || {
227 let mut registry
= plugin
::Registry { lint_store: &mut lint_store }
;
228 for registrar
in registrars
{
229 registrar(&mut registry
);
233 let lint_store
= Lrc
::new(lint_store
);
234 sess
.init_lint_store(lint_store
.clone());
236 Ok((krate
, lint_store
))
239 fn pre_expansion_lint(
241 lint_store
: &LintStore
,
245 sess
.prof
.generic_activity_with_arg("pre_AST_expansion_lint_checks", crate_name
).run(|| {
246 rustc_lint
::check_ast_crate(
252 rustc_lint
::BuiltinCombinedPreExpansionLintPass
::new(),
257 /// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins,
258 /// syntax expansion, secondary `cfg` expansion, synthesis of a test
259 /// harness if one is to be provided, injection of a dependency on the
260 /// standard library and prelude, and name resolution.
261 pub fn configure_and_expand(
263 lint_store
: &LintStore
,
264 mut krate
: ast
::Crate
,
266 resolver
: &mut Resolver
<'_
>,
267 ) -> Result
<ast
::Crate
> {
268 tracing
::trace
!("configure_and_expand");
269 pre_expansion_lint(sess
, lint_store
, &krate
, crate_name
);
270 rustc_builtin_macros
::register_builtin_macros(resolver
);
272 krate
= sess
.time("crate_injection", || {
273 let alt_std_name
= sess
.opts
.alt_std_name
.as_ref().map(|s
| Symbol
::intern(s
));
274 rustc_builtin_macros
::standard_library_imports
::inject(krate
, resolver
, &sess
, alt_std_name
)
277 util
::check_attr_crate_type(&sess
, &krate
.attrs
, &mut resolver
.lint_buffer());
280 krate
= sess
.time("macro_expand_crate", || {
281 // Windows dlls do not have rpaths, so they don't know how to find their
282 // dependencies. It's up to us to tell the system where to find all the
283 // dependent dlls. Note that this uses cfg!(windows) as opposed to
284 // targ_cfg because syntax extensions are always loaded for the host
285 // compiler, not for the target.
287 // This is somewhat of an inherently racy operation, however, as
288 // multiple threads calling this function could possibly continue
289 // extending PATH far beyond what it should. To solve this for now we
290 // just don't add any new elements to PATH which are already there
291 // within PATH. This is basically a targeted fix at #17360 for rustdoc
292 // which runs rustc in parallel but has been seen (#33844) to cause
293 // problems with PATH becoming too long.
294 let mut old_path
= OsString
::new();
296 old_path
= env
::var_os("PATH").unwrap_or(old_path
);
297 let mut new_path
= sess
.host_filesearch(PathKind
::All
).search_path_dirs();
298 for path
in env
::split_paths(&old_path
) {
299 if !new_path
.contains(&path
) {
306 new_path
.iter().filter(|p
| env
::join_paths(iter
::once(p
)).is_ok()),
312 // Create the config for macro expansion
313 let features
= sess
.features_untracked();
314 let recursion_limit
=
315 rustc_middle
::middle
::limits
::get_recursion_limit(&krate
.attrs
, &sess
);
316 let cfg
= rustc_expand
::expand
::ExpansionConfig
{
317 features
: Some(&features
),
319 trace_mac
: sess
.opts
.debugging_opts
.trace_macros
,
320 should_test
: sess
.opts
.test
,
321 span_debug
: sess
.opts
.debugging_opts
.span_debug
,
322 proc_macro_backtrace
: sess
.opts
.debugging_opts
.proc_macro_backtrace
,
323 ..rustc_expand
::expand
::ExpansionConfig
::default(crate_name
.to_string())
326 let extern_mod_loaded
= |ident
: Ident
, attrs
, items
, span
| {
327 let krate
= ast
::Crate { attrs, items, span }
;
328 pre_expansion_lint(sess
, lint_store
, &krate
, &ident
.name
.as_str());
329 (krate
.attrs
, krate
.items
)
331 let mut ecx
= ExtCtxt
::new(&sess
, cfg
, resolver
, Some(&extern_mod_loaded
));
333 // Expand macros now!
334 let krate
= sess
.time("expand_crate", || ecx
.monotonic_expander().expand_crate(krate
));
336 // The rest is error reporting
338 sess
.time("check_unused_macros", || {
339 ecx
.check_unused_macros();
342 let mut missing_fragment_specifiers
: Vec
<_
> = ecx
345 .missing_fragment_specifiers
348 .map(|(span
, node_id
)| (*span
, *node_id
))
350 missing_fragment_specifiers
.sort_unstable_by_key(|(span
, _
)| *span
);
352 let recursion_limit_hit
= ecx
.reduced_recursion_limit
.is_some();
354 for (span
, node_id
) in missing_fragment_specifiers
{
355 let lint
= lint
::builtin
::MISSING_FRAGMENT_SPECIFIER
;
356 let msg
= "missing fragment specifier";
357 resolver
.lint_buffer().buffer_lint(lint
, node_id
, span
, msg
);
360 env
::set_var("PATH", &old_path
);
363 if recursion_limit_hit
{
364 // If we hit a recursion limit, exit early to avoid later passes getting overwhelmed
372 sess
.time("maybe_building_test_harness", || {
373 rustc_builtin_macros
::test_harness
::inject(&sess
, resolver
, &mut krate
)
376 if let Some(PpMode
::Source(PpSourceMode
::EveryBodyLoops
)) = sess
.opts
.pretty
{
377 tracing
::debug
!("replacing bodies with loop {{}}");
378 util
::ReplaceBodyWithLoop
::new(resolver
).visit_crate(&mut krate
);
381 let has_proc_macro_decls
= sess
.time("AST_validation", || {
382 rustc_ast_passes
::ast_validation
::check_crate(sess
, &krate
, resolver
.lint_buffer())
385 let crate_types
= sess
.crate_types();
386 let is_proc_macro_crate
= crate_types
.contains(&CrateType
::ProcMacro
);
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 let mut msg
= sess
.diagnostic().struct_warn(
396 &"Trying to document proc macro crate \
397 without passing '--crate-type proc-macro to rustdoc",
400 msg
.warn("The generated documentation may be incorrect");
403 krate
= sess
.time("maybe_create_a_macro_crate", || {
404 let num_crate_types
= crate_types
.len();
405 let is_test_crate
= sess
.opts
.test
;
406 rustc_builtin_macros
::proc_macro_harness
::inject(
411 has_proc_macro_decls
,
419 // Done with macro expansion!
421 if sess
.opts
.debugging_opts
.input_stats
{
422 eprintln
!("Post-expansion node count: {}", count_nodes(&krate
));
425 if sess
.opts
.debugging_opts
.hir_stats
{
426 hir_stats
::print_ast_stats(&krate
, "POST EXPANSION AST STATS");
429 if sess
.opts
.debugging_opts
.ast_json
{
430 println
!("{}", json
::as_json(&krate
));
433 resolver
.resolve_crate(&krate
);
435 // Needs to go *after* expansion to be able to check the results of macro expansion.
436 sess
.time("complete_gated_feature_checking", || {
437 rustc_ast_passes
::feature_gate
::check_crate(&krate
, sess
);
440 // Add all buffered lints from the `ParseSess` to the `Session`.
441 sess
.parse_sess
.buffered_lints
.with_lock(|buffered_lints
| {
442 info
!("{} parse sess buffered_lints", buffered_lints
.len());
443 for early_lint
in buffered_lints
.drain(..) {
444 resolver
.lint_buffer().add_early_lint(early_lint
);
451 pub fn lower_to_hir
<'res
, 'tcx
>(
453 lint_store
: &LintStore
,
454 resolver
: &'res
mut Resolver
<'_
>,
455 krate
: Rc
<ast
::Crate
>,
456 arena
: &'tcx rustc_ast_lowering
::Arena
<'tcx
>,
457 ) -> &'tcx Crate
<'tcx
> {
459 let hir_crate
= rustc_ast_lowering
::lower_crate(
463 rustc_parse
::nt_to_tokenstream
,
467 if sess
.opts
.debugging_opts
.hir_stats
{
468 hir_stats
::print_hir_stats(&hir_crate
);
471 sess
.time("early_lint_checks", || {
472 rustc_lint
::check_ast_crate(
477 Some(std
::mem
::take(resolver
.lint_buffer())),
478 rustc_lint
::BuiltinCombinedEarlyLintPass
::new(),
482 // Drop AST to free memory
483 sess
.time("drop_ast", || std
::mem
::drop(krate
));
485 // Discard hygiene data, which isn't required after lowering to HIR.
486 if !sess
.opts
.debugging_opts
.keep_hygiene_data
{
487 rustc_span
::hygiene
::clear_syntax_context_map();
493 // Returns all the paths that correspond to generated files.
494 fn generated_output_paths(
496 outputs
: &OutputFilenames
,
500 let mut out_filenames
= Vec
::new();
501 for output_type
in sess
.opts
.output_types
.keys() {
502 let file
= outputs
.path(*output_type
);
504 // If the filename has been overridden using `-o`, it will not be modified
505 // by appending `.rlib`, `.exe`, etc., so we can skip this transformation.
506 OutputType
::Exe
if !exact_name
=> {
507 for crate_type
in sess
.crate_types().iter() {
508 let p
= filename_for_input(sess
, *crate_type
, crate_name
, outputs
);
509 out_filenames
.push(p
);
512 OutputType
::DepInfo
if sess
.opts
.debugging_opts
.dep_info_omit_d_target
=> {
513 // Don't add the dep-info output when omitting it from dep-info targets
516 out_filenames
.push(file
);
523 // Runs `f` on every output file path and returns the first non-None result, or None if `f`
524 // returns None for every file path.
525 fn check_output
<F
, T
>(output_paths
: &[PathBuf
], f
: F
) -> Option
<T
>
527 F
: Fn(&PathBuf
) -> Option
<T
>,
529 for output_path
in output_paths
{
530 if let Some(result
) = f(output_path
) {
537 fn output_contains_path(output_paths
: &[PathBuf
], input_path
: &PathBuf
) -> bool
{
538 let input_path
= input_path
.canonicalize().ok();
539 if input_path
.is_none() {
542 let check
= |output_path
: &PathBuf
| {
543 if output_path
.canonicalize().ok() == input_path { Some(()) }
else { None }
545 check_output(output_paths
, check
).is_some()
548 fn output_conflicts_with_dir(output_paths
: &[PathBuf
]) -> Option
<PathBuf
> {
549 let check
= |output_path
: &PathBuf
| output_path
.is_dir().then(|| output_path
.clone());
550 check_output(output_paths
, check
)
553 fn escape_dep_filename(filename
: &String
) -> String
{
554 // Apparently clang and gcc *only* escape spaces:
555 // https://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
556 filename
.replace(" ", "\\ ")
559 // Makefile comments only need escaping newlines and `\`.
560 // The result can be unescaped by anything that can unescape `escape_default` and friends.
561 fn escape_dep_env(symbol
: Symbol
) -> String
{
562 let s
= symbol
.as_str();
563 let mut escaped
= String
::with_capacity(s
.len());
566 '
\n'
=> escaped
.push_str(r
"\n"),
567 '
\r'
=> escaped
.push_str(r
"\r"),
568 '
\\'
=> escaped
.push_str(r
"\\"),
569 _
=> escaped
.push(c
),
577 boxed_resolver
: &RefCell
<BoxedResolver
>,
578 outputs
: &OutputFilenames
,
579 out_filenames
: &[PathBuf
],
581 // Write out dependency rules to the dep-info file if requested
582 if !sess
.opts
.output_types
.contains_key(&OutputType
::DepInfo
) {
585 let deps_filename
= outputs
.path(OutputType
::DepInfo
);
587 let result
= (|| -> io
::Result
<()> {
588 // Build a list of files used to compile the output and
589 // write Makefile-compatible dependency rules
590 let mut files
: Vec
<String
> = sess
594 .filter(|fmap
| fmap
.is_real_file())
595 .filter(|fmap
| !fmap
.is_imported())
596 .map(|fmap
| escape_dep_filename(&fmap
.name
.prefer_local().to_string()))
599 // Account for explicitly marked-to-track files
600 // (e.g. accessed in proc macros).
601 let file_depinfo
= sess
.parse_sess
.file_depinfo
.borrow();
602 let extra_tracked_files
= file_depinfo
.iter().map(|path_sym
| {
603 let path
= PathBuf
::from(&*path_sym
.as_str());
604 let file
= FileName
::from(path
);
605 escape_dep_filename(&file
.prefer_local().to_string())
607 files
.extend(extra_tracked_files
);
609 if let Some(ref backend
) = sess
.opts
.debugging_opts
.codegen_backend
{
610 files
.push(backend
.to_string());
613 if sess
.binary_dep_depinfo() {
614 boxed_resolver
.borrow_mut().access(|resolver
| {
615 for cnum
in resolver
.cstore().crates_untracked() {
616 let source
= resolver
.cstore().crate_source_untracked(cnum
);
617 if let Some((path
, _
)) = source
.dylib
{
618 files
.push(escape_dep_filename(&path
.display().to_string()));
620 if let Some((path
, _
)) = source
.rlib
{
621 files
.push(escape_dep_filename(&path
.display().to_string()));
623 if let Some((path
, _
)) = source
.rmeta
{
624 files
.push(escape_dep_filename(&path
.display().to_string()));
630 let mut file
= BufWriter
::new(fs
::File
::create(&deps_filename
)?
);
631 for path
in out_filenames
{
632 writeln
!(file
, "{}: {}\n", path
.display(), files
.join(" "))?
;
635 // Emit a fake target for each input file to the compilation. This
636 // prevents `make` from spitting out an error if a file is later
637 // deleted. For more info see #28735
639 writeln
!(file
, "{}:", path
)?
;
642 // Emit special comments with information about accessed environment variables.
643 let env_depinfo
= sess
.parse_sess
.env_depinfo
.borrow();
644 if !env_depinfo
.is_empty() {
645 let mut envs
: Vec
<_
> = env_depinfo
647 .map(|(k
, v
)| (escape_dep_env(*k
), v
.map(escape_dep_env
)))
649 envs
.sort_unstable();
652 write
!(file
, "# env-dep:{}", k
)?
;
654 write
!(file
, "={}", v
)?
;
665 if sess
.opts
.json_artifact_notifications
{
668 .emit_artifact_notification(&deps_filename
, "dep-info");
671 Err(e
) => sess
.fatal(&format
!(
672 "error writing dependencies to `{}`: {}",
673 deps_filename
.display(),
679 pub fn prepare_outputs(
683 boxed_resolver
: &RefCell
<BoxedResolver
>,
685 ) -> Result
<OutputFilenames
> {
686 let _timer
= sess
.timer("prepare_outputs");
688 // FIXME: rustdoc passes &[] instead of &krate.attrs here
689 let outputs
= util
::build_output_filenames(
691 &compiler
.output_dir
,
692 &compiler
.output_file
,
698 generated_output_paths(sess
, &outputs
, compiler
.output_file
.is_some(), &crate_name
);
700 // Ensure the source file isn't accidentally overwritten during compilation.
701 if let Some(ref input_path
) = compiler
.input_path
{
702 if sess
.opts
.will_create_output_file() {
703 if output_contains_path(&output_paths
, input_path
) {
705 "the input file \"{}\" would be overwritten by the generated \
709 return Err(ErrorReported
);
711 if let Some(dir_path
) = output_conflicts_with_dir(&output_paths
) {
713 "the generated executable for the input file \"{}\" conflicts with the \
714 existing directory \"{}\"",
715 input_path
.display(),
718 return Err(ErrorReported
);
723 write_out_deps(sess
, boxed_resolver
, &outputs
, &output_paths
);
725 let only_dep_info
= sess
.opts
.output_types
.contains_key(&OutputType
::DepInfo
)
726 && sess
.opts
.output_types
.len() == 1;
729 if let Some(ref dir
) = compiler
.output_dir
{
730 if fs
::create_dir_all(dir
).is_err() {
731 sess
.err("failed to find or create the directory specified by `--out-dir`");
732 return Err(ErrorReported
);
740 pub static DEFAULT_QUERY_PROVIDERS
: SyncLazy
<Providers
> = SyncLazy
::new(|| {
741 let providers
= &mut Providers
::default();
742 providers
.analysis
= analysis
;
743 proc_macro_decls
::provide(providers
);
744 rustc_middle
::hir
::provide(providers
);
745 mir
::provide(providers
);
746 mir_build
::provide(providers
);
747 rustc_privacy
::provide(providers
);
748 typeck
::provide(providers
);
749 ty
::provide(providers
);
750 traits
::provide(providers
);
751 rustc_passes
::provide(providers
);
752 rustc_resolve
::provide(providers
);
753 rustc_traits
::provide(providers
);
754 rustc_ty_utils
::provide(providers
);
755 rustc_metadata
::provide(providers
);
756 rustc_lint
::provide(providers
);
757 rustc_symbol_mangling
::provide(providers
);
758 rustc_codegen_ssa
::provide(providers
);
762 pub static DEFAULT_EXTERN_QUERY_PROVIDERS
: SyncLazy
<Providers
> = SyncLazy
::new(|| {
763 let mut extern_providers
= *DEFAULT_QUERY_PROVIDERS
;
764 rustc_metadata
::provide_extern(&mut extern_providers
);
765 rustc_codegen_ssa
::provide_extern(&mut extern_providers
);
769 pub struct QueryContext
<'tcx
> {
770 gcx
: &'tcx GlobalCtxt
<'tcx
>,
773 impl<'tcx
> QueryContext
<'tcx
> {
774 pub fn enter
<F
, R
>(&mut self, f
: F
) -> R
776 F
: FnOnce(TyCtxt
<'tcx
>) -> R
,
778 let icx
= ty
::tls
::ImplicitCtxt
::new(self.gcx
);
779 ty
::tls
::enter_context(&icx
, |_
| f(icx
.tcx
))
783 pub fn create_global_ctxt
<'tcx
>(
784 compiler
: &'tcx Compiler
,
785 lint_store
: Lrc
<LintStore
>,
786 krate
: Rc
<ast
::Crate
>,
788 resolver
: Rc
<RefCell
<BoxedResolver
>>,
789 outputs
: OutputFilenames
,
791 queries
: &'tcx OnceCell
<TcxQueries
<'tcx
>>,
792 global_ctxt
: &'tcx OnceCell
<GlobalCtxt
<'tcx
>>,
793 arena
: &'tcx WorkerLocal
<Arena
<'tcx
>>,
794 hir_arena
: &'tcx WorkerLocal
<rustc_ast_lowering
::Arena
<'tcx
>>,
795 ) -> QueryContext
<'tcx
> {
796 // We're constructing the HIR here; we don't care what we will
797 // read, since we haven't even constructed the *input* to
799 dep_graph
.assert_ignored();
801 let sess
= &compiler
.session();
804 .access(|resolver
| lower_to_hir(sess
, &lint_store
, resolver
, krate
, hir_arena
));
805 let resolver_outputs
= BoxedResolver
::to_resolver_outputs(resolver
);
807 let query_result_on_disk_cache
= rustc_incremental
::load_query_result_cache(sess
);
809 let codegen_backend
= compiler
.codegen_backend();
810 let mut local_providers
= *DEFAULT_QUERY_PROVIDERS
;
811 codegen_backend
.provide(&mut local_providers
);
813 let mut extern_providers
= *DEFAULT_EXTERN_QUERY_PROVIDERS
;
814 codegen_backend
.provide(&mut extern_providers
);
815 codegen_backend
.provide_extern(&mut extern_providers
);
817 if let Some(callback
) = compiler
.override_queries
{
818 callback(sess
, &mut local_providers
, &mut extern_providers
);
821 let queries
= queries
.get_or_init(|| {
822 TcxQueries
::new(local_providers
, extern_providers
, query_result_on_disk_cache
)
825 let gcx
= sess
.time("setup_global_ctxt", || {
826 global_ctxt
.get_or_init(move || {
827 TyCtxt
::create_global_ctxt(
834 queries
.on_disk_cache
.as_ref().map(OnDiskCache
::as_dyn
),
845 /// Runs the resolution, type-checking, region checking and other
846 /// miscellaneous analysis passes on the crate.
847 fn analysis(tcx
: TyCtxt
<'_
>, (): ()) -> Result
<()> {
848 rustc_passes
::hir_id_validator
::check_crate(tcx
);
851 let mut entry_point
= None
;
853 sess
.time("misc_checking_1", || {
856 entry_point
= sess
.time("looking_for_entry_point", || tcx
.entry_fn(()));
858 sess
.time("looking_for_derive_registrar", || {
859 tcx
.ensure().proc_macro_decls_static(())
862 CStore
::from_tcx(tcx
).report_unused_deps(tcx
);
865 par_iter(&tcx
.hir().krate().modules
).for_each(|(&module
, _
)| {
866 tcx
.ensure().check_mod_loops(module
);
867 tcx
.ensure().check_mod_attrs(module
);
868 tcx
.ensure().check_mod_naked_functions(module
);
869 tcx
.ensure().check_mod_unstable_api_usage(module
);
870 tcx
.ensure().check_mod_const_bodies(module
);
874 // We force these querie to run,
875 // since they might not otherwise get called.
876 // This marks the corresponding crate-level attributes
877 // as used, and ensures that their values are valid.
878 tcx
.ensure().limits(());
883 // passes are timed inside typeck
884 typeck
::check_crate(tcx
)?
;
886 sess
.time("misc_checking_2", || {
889 sess
.time("match_checking", || {
890 tcx
.par_body_owners(|def_id
| {
891 tcx
.ensure().check_match(def_id
.to_def_id());
896 sess
.time("liveness_and_intrinsic_checking", || {
897 par_iter(&tcx
.hir().krate().modules
).for_each(|(&module
, _
)| {
898 // this must run before MIR dump, because
899 // "not all control paths return a value" is reported here.
901 // maybe move the check to a MIR pass?
902 tcx
.ensure().check_mod_liveness(module
);
903 tcx
.ensure().check_mod_intrinsics(module
);
910 sess
.time("MIR_borrow_checking", || {
911 tcx
.par_body_owners(|def_id
| tcx
.ensure().mir_borrowck(def_id
));
914 sess
.time("MIR_effect_checking", || {
915 for def_id
in tcx
.body_owners() {
916 tcx
.ensure().thir_check_unsafety(def_id
);
917 if !tcx
.sess
.opts
.debugging_opts
.thir_unsafeck
{
918 mir
::transform
::check_unsafety
::check_unsafety(tcx
, def_id
);
921 if tcx
.hir().body_const_context(def_id
).is_some() {
923 .mir_drops_elaborated_and_const_checked(ty
::WithOptConstParam
::unknown(def_id
));
928 sess
.time("layout_testing", || layout_test
::test_layout(tcx
));
930 // Avoid overwhelming user with errors if borrow checking failed.
931 // I'm not sure how helpful this is, to be honest, but it avoids a
932 // lot of annoying errors in the ui tests (basically,
933 // lint warnings and so on -- kindck used to do this abort, but
934 // kindck is gone now). -nmatsakis
935 if sess
.has_errors() {
936 return Err(ErrorReported
);
939 sess
.time("misc_checking_3", || {
942 tcx
.ensure().privacy_access_levels(());
946 tcx
.ensure().check_private_in_public(());
949 sess
.time("death_checking", || rustc_passes
::dead
::check_crate(tcx
));
952 sess
.time("unused_lib_feature_checking", || {
953 rustc_passes
::stability
::check_unused_or_stable_features(tcx
)
957 sess
.time("lint_checking", || {
958 rustc_lint
::check_crate(tcx
, || {
959 rustc_lint
::BuiltinCombinedLateLintPass
::new()
966 sess
.time("privacy_checking_modules", || {
967 par_iter(&tcx
.hir().krate().modules
).for_each(|(&module
, _
)| {
968 tcx
.ensure().check_mod_privacy(module
);
978 fn encode_and_write_metadata(
980 outputs
: &OutputFilenames
,
981 ) -> (middle
::cstore
::EncodedMetadata
, bool
) {
982 #[derive(PartialEq, Eq, PartialOrd, Ord)]
989 let metadata_kind
= tcx
993 .map(|ty
| match *ty
{
994 CrateType
::Executable
| CrateType
::Staticlib
| CrateType
::Cdylib
=> MetadataKind
::None
,
996 CrateType
::Rlib
=> MetadataKind
::Uncompressed
,
998 CrateType
::Dylib
| CrateType
::ProcMacro
=> MetadataKind
::Compressed
,
1001 .unwrap_or(MetadataKind
::None
);
1003 let metadata
= match metadata_kind
{
1004 MetadataKind
::None
=> middle
::cstore
::EncodedMetadata
::new(),
1005 MetadataKind
::Uncompressed
| MetadataKind
::Compressed
=> tcx
.encode_metadata(),
1008 let _prof_timer
= tcx
.sess
.prof
.generic_activity("write_crate_metadata");
1010 let need_metadata_file
= tcx
.sess
.opts
.output_types
.contains_key(&OutputType
::Metadata
);
1011 if need_metadata_file
{
1012 let crate_name
= &tcx
.crate_name(LOCAL_CRATE
).as_str();
1013 let out_filename
= filename_for_metadata(tcx
.sess
, crate_name
, outputs
);
1014 // To avoid races with another rustc process scanning the output directory,
1015 // we need to write the file somewhere else and atomically move it to its
1016 // final destination, with an `fs::rename` call. In order for the rename to
1017 // always succeed, the temporary file needs to be on the same filesystem,
1018 // which is why we create it inside the output directory specifically.
1019 let metadata_tmpdir
= TempFileBuilder
::new()
1021 .tempdir_in(out_filename
.parent().unwrap())
1022 .unwrap_or_else(|err
| tcx
.sess
.fatal(&format
!("couldn't create a temp dir: {}", err
)));
1023 let metadata_tmpdir
= MaybeTempDir
::new(metadata_tmpdir
, tcx
.sess
.opts
.cg
.save_temps
);
1024 let metadata_filename
= emit_metadata(tcx
.sess
, &metadata
.raw_data
, &metadata_tmpdir
);
1025 if let Err(e
) = util
::non_durable_rename(&metadata_filename
, &out_filename
) {
1026 tcx
.sess
.fatal(&format
!("failed to write {}: {}", out_filename
.display(), e
));
1028 if tcx
.sess
.opts
.json_artifact_notifications
{
1032 .emit_artifact_notification(&out_filename
, "metadata");
1036 let need_metadata_module
= metadata_kind
== MetadataKind
::Compressed
;
1038 (metadata
, need_metadata_module
)
1041 /// Runs the codegen backend, after which the AST and analysis can
1043 pub fn start_codegen
<'tcx
>(
1044 codegen_backend
: &dyn CodegenBackend
,
1046 outputs
: &OutputFilenames
,
1048 info
!("Pre-codegen\n{:?}", tcx
.debug_stats());
1050 let (metadata
, need_metadata_module
) = encode_and_write_metadata(tcx
, outputs
);
1052 let codegen
= tcx
.sess
.time("codegen_crate", move || {
1053 codegen_backend
.codegen_crate(tcx
, metadata
, need_metadata_module
)
1056 // Don't run these test assertions when not doing codegen. Compiletest tries to build
1057 // build-fail tests in check mode first and expects it to not give an error in that case.
1058 if tcx
.sess
.opts
.output_types
.should_codegen() {
1059 rustc_incremental
::assert_module_sources
::assert_module_sources(tcx
);
1060 rustc_symbol_mangling
::test
::report_symbol_names(tcx
);
1063 info
!("Post-codegen\n{:?}", tcx
.debug_stats());
1065 if tcx
.sess
.opts
.output_types
.contains_key(&OutputType
::Mir
) {
1066 if let Err(e
) = mir
::transform
::dump_mir
::emit_mir(tcx
, outputs
) {
1067 tcx
.sess
.err(&format
!("could not emit MIR: {}", e
));
1068 tcx
.sess
.abort_if_errors();