1 use crate::code_stats
::CodeStats
;
2 pub use crate::code_stats
::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}
;
4 use crate::cgu_reuse_tracker
::CguReuseTracker
;
5 use rustc_data_structures
::fingerprint
::Fingerprint
;
6 use rustc_data_structures
::fx
::{FxHashMap, FxHashSet}
;
8 use crate::config
::{self, OutputType, PrintRequest, Sanitizer, SwitchWithOptPath}
;
11 use crate::search_paths
::{PathKind, SearchPath}
;
12 use rustc_data_structures
::profiling
::duration_to_secs_str
;
13 use rustc_errors
::ErrorReported
;
15 use rustc_data_structures
::base_n
;
16 use rustc_data_structures
::impl_stable_hash_via_hash
;
17 use rustc_data_structures
::sync
::{
18 self, AtomicU64
, AtomicUsize
, Lock
, Lrc
, Once
, OneThread
, Ordering
, Ordering
::SeqCst
,
21 use crate::parse
::ParseSess
;
22 use rustc_errors
::annotate_snippet_emitter_writer
::AnnotateSnippetEmitterWriter
;
23 use rustc_errors
::emitter
::HumanReadableErrorType
;
24 use rustc_errors
::emitter
::{Emitter, EmitterWriter}
;
25 use rustc_errors
::json
::JsonEmitter
;
26 use rustc_errors
::{Applicability, DiagnosticBuilder, DiagnosticId}
;
27 use rustc_span
::edition
::Edition
;
28 use rustc_span
::source_map
;
29 use rustc_span
::{MultiSpan, Span}
;
31 use rustc_data_structures
::flock
;
32 use rustc_data_structures
::jobserver
::{self, Client}
;
33 use rustc_data_structures
::profiling
::{SelfProfiler, SelfProfilerRef}
;
34 use rustc_target
::spec
::{PanicStrategy, RelroLevel, Target, TargetTriple}
;
36 use std
::cell
::{self, RefCell}
;
40 use std
::num
::NonZeroU32
;
41 use std
::path
::PathBuf
;
43 use std
::time
::Duration
;
45 pub struct OptimizationFuel
{
46 /// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`.
48 /// We're rejecting all further optimizations.
52 /// Represents the data associated with a compilation
53 /// session for a single crate.
55 pub target
: config
::Config
,
57 pub opts
: config
::Options
,
58 pub host_tlib_path
: SearchPath
,
59 /// `None` if the host and target are the same.
60 pub target_tlib_path
: Option
<SearchPath
>,
61 pub parse_sess
: ParseSess
,
63 /// The name of the root source file of the crate, in the local file system.
64 /// `None` means that there is no source file.
65 pub local_crate_source_file
: Option
<PathBuf
>,
66 /// The directory the compiler has been executed in plus a flag indicating
67 /// if the value stored here has been affected by path remapping.
68 pub working_dir
: (PathBuf
, bool
),
70 /// Set of `(DiagnosticId, Option<Span>, message)` tuples tracking
71 /// (sub)diagnostics that have been set once, but should not be set again,
72 /// in order to avoid redundantly verbose output (Issue #24690, #44953).
73 pub one_time_diagnostics
: Lock
<FxHashSet
<(DiagnosticMessageId
, Option
<Span
>, String
)>>,
74 pub crate_types
: Once
<Vec
<config
::CrateType
>>,
75 /// The `crate_disambiguator` is constructed out of all the `-C metadata`
76 /// arguments passed to the compiler. Its value together with the crate-name
77 /// forms a unique global identifier for the crate. It is used to allow
78 /// multiple crates with the same name to coexist. See the
79 /// `rustc_codegen_llvm::back::symbol_names` module for more information.
80 pub crate_disambiguator
: Once
<CrateDisambiguator
>,
82 features
: Once
<rustc_feature
::Features
>,
84 /// The maximum recursion limit for potentially infinitely recursive
85 /// operations such as auto-dereference and monomorphization.
86 pub recursion_limit
: Once
<usize>,
88 /// The maximum length of types during monomorphization.
89 pub type_length_limit
: Once
<usize>,
91 /// The maximum blocks a const expression can evaluate.
92 pub const_eval_limit
: Once
<usize>,
94 /// Map from imported macro spans (which consist of
95 /// the localized span for the macro body) to the
96 /// macro name and definition span in the source crate.
97 pub imported_macro_spans
: OneThread
<RefCell
<FxHashMap
<Span
, (String
, Span
)>>>,
99 incr_comp_session
: OneThread
<RefCell
<IncrCompSession
>>,
100 /// Used for incremental compilation tests. Will only be populated if
101 /// `-Zquery-dep-graph` is specified.
102 pub cgu_reuse_tracker
: CguReuseTracker
,
104 /// Used by `-Z self-profile`.
105 pub prof
: SelfProfilerRef
,
107 /// Some measurements that are being gathered during compilation.
108 pub perf_stats
: PerfStats
,
110 /// Data about code being compiled, gathered during compilation.
111 pub code_stats
: CodeStats
,
113 /// If `-zfuel=crate=n` is specified, `Some(crate)`.
114 optimization_fuel_crate
: Option
<String
>,
116 /// Tracks fuel info if `-zfuel=crate=n` is specified.
117 optimization_fuel
: Lock
<OptimizationFuel
>,
119 // The next two are public because the driver needs to read them.
120 /// If `-zprint-fuel=crate`, `Some(crate)`.
121 pub print_fuel_crate
: Option
<String
>,
122 /// Always set to zero and incremented so that we can print fuel expended by a crate.
123 pub print_fuel
: AtomicU64
,
125 /// Loaded up early on in the initialization of this `Session` to avoid
126 /// false positives about a job server in our environment.
127 pub jobserver
: Client
,
129 /// Cap lint level specified by a driver specifically.
130 pub driver_lint_caps
: FxHashMap
<lint
::LintId
, lint
::Level
>,
132 /// `Span`s of trait methods that weren't found to avoid emitting object safety errors
133 pub trait_methods_not_found
: Lock
<FxHashSet
<Span
>>,
135 /// Mapping from ident span to path span for paths that don't exist as written, but that
136 /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`.
137 pub confused_type_with_std_module
: Lock
<FxHashMap
<Span
, Span
>>,
139 /// Path for libraries that will take preference over libraries shipped by Rust.
140 /// Used by windows-gnu targets to priortize system mingw-w64 libraries.
141 pub system_library_path
: OneThread
<RefCell
<Option
<Option
<PathBuf
>>>>,
144 pub struct PerfStats
{
145 /// The accumulated time spent on computing symbol hashes.
146 pub symbol_hash_time
: Lock
<Duration
>,
147 /// The accumulated time spent decoding def path tables from metadata.
148 pub decode_def_path_tables_time
: Lock
<Duration
>,
149 /// Total number of values canonicalized queries constructed.
150 pub queries_canonicalized
: AtomicUsize
,
151 /// Number of times this query is invoked.
152 pub normalize_ty_after_erasing_regions
: AtomicUsize
,
153 /// Number of times this query is invoked.
154 pub normalize_projection_ty
: AtomicUsize
,
157 /// Enum to support dispatch of one-time diagnostics (in `Session.diag_once`).
158 enum DiagnosticBuilderMethod
{
161 SpanSuggestion(String
), // suggestion
162 // Add more variants as needed to support one-time diagnostics.
165 /// Diagnostic message ID, used by `Session.one_time_diagnostics` to avoid
166 /// emitting the same message more than once.
167 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
168 pub enum DiagnosticMessageId
{
169 ErrorId(u16), // EXXXX error code as integer
170 LintId(lint
::LintId
),
171 StabilityId(Option
<NonZeroU32
>), // issue number
174 impl From
<&'
static lint
::Lint
> for DiagnosticMessageId
{
175 fn from(lint
: &'
static lint
::Lint
) -> Self {
176 DiagnosticMessageId
::LintId(lint
::LintId
::of(lint
))
181 pub fn local_crate_disambiguator(&self) -> CrateDisambiguator
{
182 *self.crate_disambiguator
.get()
185 pub fn struct_span_warn
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str) -> DiagnosticBuilder
<'_
> {
186 self.diagnostic().struct_span_warn(sp
, msg
)
188 pub fn struct_span_warn_with_code
<S
: Into
<MultiSpan
>>(
193 ) -> DiagnosticBuilder
<'_
> {
194 self.diagnostic().struct_span_warn_with_code(sp
, msg
, code
)
196 pub fn struct_warn(&self, msg
: &str) -> DiagnosticBuilder
<'_
> {
197 self.diagnostic().struct_warn(msg
)
199 pub fn struct_span_err
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str) -> DiagnosticBuilder
<'_
> {
200 self.diagnostic().struct_span_err(sp
, msg
)
202 pub fn struct_span_err_with_code
<S
: Into
<MultiSpan
>>(
207 ) -> DiagnosticBuilder
<'_
> {
208 self.diagnostic().struct_span_err_with_code(sp
, msg
, code
)
210 // FIXME: This method should be removed (every error should have an associated error code).
211 pub fn struct_err(&self, msg
: &str) -> DiagnosticBuilder
<'_
> {
212 self.diagnostic().struct_err(msg
)
214 pub fn struct_err_with_code(&self, msg
: &str, code
: DiagnosticId
) -> DiagnosticBuilder
<'_
> {
215 self.diagnostic().struct_err_with_code(msg
, code
)
217 pub fn struct_span_fatal
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str) -> DiagnosticBuilder
<'_
> {
218 self.diagnostic().struct_span_fatal(sp
, msg
)
220 pub fn struct_span_fatal_with_code
<S
: Into
<MultiSpan
>>(
225 ) -> DiagnosticBuilder
<'_
> {
226 self.diagnostic().struct_span_fatal_with_code(sp
, msg
, code
)
228 pub fn struct_fatal(&self, msg
: &str) -> DiagnosticBuilder
<'_
> {
229 self.diagnostic().struct_fatal(msg
)
232 pub fn span_fatal
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str) -> ! {
233 self.diagnostic().span_fatal(sp
, msg
).raise()
235 pub fn span_fatal_with_code
<S
: Into
<MultiSpan
>>(
241 self.diagnostic().span_fatal_with_code(sp
, msg
, code
).raise()
243 pub fn fatal(&self, msg
: &str) -> ! {
244 self.diagnostic().fatal(msg
).raise()
246 pub fn span_err_or_warn
<S
: Into
<MultiSpan
>>(&self, is_warning
: bool
, sp
: S
, msg
: &str) {
248 self.span_warn(sp
, msg
);
250 self.span_err(sp
, msg
);
253 pub fn span_err
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str) {
254 self.diagnostic().span_err(sp
, msg
)
256 pub fn span_err_with_code
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str, code
: DiagnosticId
) {
257 self.diagnostic().span_err_with_code(sp
, &msg
, code
)
259 pub fn err(&self, msg
: &str) {
260 self.diagnostic().err(msg
)
262 pub fn err_count(&self) -> usize {
263 self.diagnostic().err_count()
265 pub fn has_errors(&self) -> bool
{
266 self.diagnostic().has_errors()
268 pub fn has_errors_or_delayed_span_bugs(&self) -> bool
{
269 self.diagnostic().has_errors_or_delayed_span_bugs()
271 pub fn abort_if_errors(&self) {
272 self.diagnostic().abort_if_errors();
274 pub fn compile_status(&self) -> Result
<(), ErrorReported
> {
275 if self.has_errors() {
276 self.diagnostic().emit_stashed_diagnostics();
282 // FIXME(matthewjasper) Remove this method, it should never be needed.
283 pub fn track_errors
<F
, T
>(&self, f
: F
) -> Result
<T
, ErrorReported
>
287 let old_count
= self.err_count();
289 let errors
= self.err_count() - old_count
;
290 if errors
== 0 { Ok(result) }
else { Err(ErrorReported) }
292 pub fn span_warn
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str) {
293 self.diagnostic().span_warn(sp
, msg
)
295 pub fn span_warn_with_code
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str, code
: DiagnosticId
) {
296 self.diagnostic().span_warn_with_code(sp
, msg
, code
)
298 pub fn warn(&self, msg
: &str) {
299 self.diagnostic().warn(msg
)
301 pub fn opt_span_warn
<S
: Into
<MultiSpan
>>(&self, opt_sp
: Option
<S
>, msg
: &str) {
303 Some(sp
) => self.span_warn(sp
, msg
),
304 None
=> self.warn(msg
),
307 /// Delay a span_bug() call until abort_if_errors()
308 pub fn delay_span_bug
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str) {
309 self.diagnostic().delay_span_bug(sp
, msg
)
311 pub fn note_without_error(&self, msg
: &str) {
312 self.diagnostic().note_without_error(msg
)
314 pub fn span_note_without_error
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str) {
315 self.diagnostic().span_note_without_error(sp
, msg
)
318 pub fn diagnostic(&self) -> &rustc_errors
::Handler
{
319 &self.parse_sess
.span_diagnostic
322 /// Analogous to calling methods on the given `DiagnosticBuilder`, but
323 /// deduplicates on lint ID, span (if any), and message for this `Session`
324 fn diag_once
<'a
, 'b
>(
326 diag_builder
: &'b
mut DiagnosticBuilder
<'a
>,
327 method
: DiagnosticBuilderMethod
,
328 msg_id
: DiagnosticMessageId
,
330 span_maybe
: Option
<Span
>,
332 let id_span_message
= (msg_id
, span_maybe
, message
.to_owned());
333 let fresh
= self.one_time_diagnostics
.borrow_mut().insert(id_span_message
);
336 DiagnosticBuilderMethod
::Note
=> {
337 diag_builder
.note(message
);
339 DiagnosticBuilderMethod
::SpanNote
=> {
340 let span
= span_maybe
.expect("`span_note` needs a span");
341 diag_builder
.span_note(span
, message
);
343 DiagnosticBuilderMethod
::SpanSuggestion(suggestion
) => {
344 let span
= span_maybe
.expect("`span_suggestion_*` needs a span");
345 diag_builder
.span_suggestion(
349 Applicability
::Unspecified
,
356 pub fn diag_span_note_once
<'a
, 'b
>(
358 diag_builder
: &'b
mut DiagnosticBuilder
<'a
>,
359 msg_id
: DiagnosticMessageId
,
365 DiagnosticBuilderMethod
::SpanNote
,
372 pub fn diag_note_once
<'a
, 'b
>(
374 diag_builder
: &'b
mut DiagnosticBuilder
<'a
>,
375 msg_id
: DiagnosticMessageId
,
378 self.diag_once(diag_builder
, DiagnosticBuilderMethod
::Note
, msg_id
, message
, None
);
381 pub fn diag_span_suggestion_once
<'a
, 'b
>(
383 diag_builder
: &'b
mut DiagnosticBuilder
<'a
>,
384 msg_id
: DiagnosticMessageId
,
391 DiagnosticBuilderMethod
::SpanSuggestion(suggestion
),
399 pub fn source_map(&self) -> &source_map
::SourceMap
{
400 self.parse_sess
.source_map()
402 pub fn verbose(&self) -> bool
{
403 self.opts
.debugging_opts
.verbose
405 pub fn time_passes(&self) -> bool
{
406 self.opts
.debugging_opts
.time_passes
|| self.opts
.debugging_opts
.time
408 pub fn instrument_mcount(&self) -> bool
{
409 self.opts
.debugging_opts
.instrument_mcount
411 pub fn time_llvm_passes(&self) -> bool
{
412 self.opts
.debugging_opts
.time_llvm_passes
414 pub fn meta_stats(&self) -> bool
{
415 self.opts
.debugging_opts
.meta_stats
417 pub fn asm_comments(&self) -> bool
{
418 self.opts
.debugging_opts
.asm_comments
420 pub fn verify_llvm_ir(&self) -> bool
{
421 self.opts
.debugging_opts
.verify_llvm_ir
|| cfg
!(always_verify_llvm_ir
)
423 pub fn borrowck_stats(&self) -> bool
{
424 self.opts
.debugging_opts
.borrowck_stats
426 pub fn print_llvm_passes(&self) -> bool
{
427 self.opts
.debugging_opts
.print_llvm_passes
429 pub fn binary_dep_depinfo(&self) -> bool
{
430 self.opts
.debugging_opts
.binary_dep_depinfo
433 /// Gets the features enabled for the current compilation session.
434 /// DO NOT USE THIS METHOD if there is a TyCtxt available, as it circumvents
435 /// dependency tracking. Use tcx.features() instead.
437 pub fn features_untracked(&self) -> &rustc_feature
::Features
{
441 pub fn init_features(&self, features
: rustc_feature
::Features
) {
442 self.features
.set(features
);
445 /// Calculates the flavor of LTO to use for this compilation.
446 pub fn lto(&self) -> config
::Lto
{
447 // If our target has codegen requirements ignore the command line
448 if self.target
.target
.options
.requires_lto
{
449 return config
::Lto
::Fat
;
452 // If the user specified something, return that. If they only said `-C
453 // lto` and we've for whatever reason forced off ThinLTO via the CLI,
454 // then ensure we can't use a ThinLTO.
455 match self.opts
.cg
.lto
{
456 config
::LtoCli
::Unspecified
=> {
457 // The compiler was invoked without the `-Clto` flag. Fall
458 // through to the default handling
460 config
::LtoCli
::No
=> {
461 // The user explicitly opted out of any kind of LTO
462 return config
::Lto
::No
;
464 config
::LtoCli
::Yes
| config
::LtoCli
::Fat
| config
::LtoCli
::NoParam
=> {
465 // All of these mean fat LTO
466 return config
::Lto
::Fat
;
468 config
::LtoCli
::Thin
=> {
469 return if self.opts
.cli_forced_thinlto_off
{
477 // Ok at this point the target doesn't require anything and the user
478 // hasn't asked for anything. Our next decision is whether or not
479 // we enable "auto" ThinLTO where we use multiple codegen units and
480 // then do ThinLTO over those codegen units. The logic below will
481 // either return `No` or `ThinLocal`.
483 // If processing command line options determined that we're incompatible
484 // with ThinLTO (e.g., `-C lto --emit llvm-ir`) then return that option.
485 if self.opts
.cli_forced_thinlto_off
{
486 return config
::Lto
::No
;
489 // If `-Z thinlto` specified process that, but note that this is mostly
490 // a deprecated option now that `-C lto=thin` exists.
491 if let Some(enabled
) = self.opts
.debugging_opts
.thinlto
{
493 return config
::Lto
::ThinLocal
;
495 return config
::Lto
::No
;
499 // If there's only one codegen unit and LTO isn't enabled then there's
500 // no need for ThinLTO so just return false.
501 if self.codegen_units() == 1 {
502 return config
::Lto
::No
;
505 // Now we're in "defaults" territory. By default we enable ThinLTO for
506 // optimized compiles (anything greater than O0).
507 match self.opts
.optimize
{
508 config
::OptLevel
::No
=> config
::Lto
::No
,
509 _
=> config
::Lto
::ThinLocal
,
513 /// Returns the panic strategy for this compile session. If the user explicitly selected one
514 /// using '-C panic', use that, otherwise use the panic strategy defined by the target.
515 pub fn panic_strategy(&self) -> PanicStrategy
{
516 self.opts
.cg
.panic
.unwrap_or(self.target
.target
.options
.panic_strategy
)
518 pub fn fewer_names(&self) -> bool
{
519 let more_names
= self.opts
.output_types
.contains_key(&OutputType
::LlvmAssembly
)
520 || self.opts
.output_types
.contains_key(&OutputType
::Bitcode
);
522 // Address sanitizer and memory sanitizer use alloca name when reporting an issue.
523 let more_names
= match self.opts
.debugging_opts
.sanitizer
{
524 Some(Sanitizer
::Address
) => true,
525 Some(Sanitizer
::Memory
) => true,
529 self.opts
.debugging_opts
.fewer_names
|| !more_names
532 pub fn no_landing_pads(&self) -> bool
{
533 self.opts
.debugging_opts
.no_landing_pads
|| self.panic_strategy() == PanicStrategy
::Abort
535 pub fn unstable_options(&self) -> bool
{
536 self.opts
.debugging_opts
.unstable_options
538 pub fn overflow_checks(&self) -> bool
{
542 .or(self.opts
.debugging_opts
.force_overflow_checks
)
543 .unwrap_or(self.opts
.debug_assertions
)
546 pub fn crt_static(&self) -> bool
{
547 // If the target does not opt in to crt-static support, use its default.
548 if self.target
.target
.options
.crt_static_respected
{
549 self.crt_static_feature()
551 self.target
.target
.options
.crt_static_default
555 pub fn crt_static_feature(&self) -> bool
{
556 let requested_features
= self.opts
.cg
.target_feature
.split('
,'
);
557 let found_negative
= requested_features
.clone().any(|r
| r
== "-crt-static");
558 let found_positive
= requested_features
.clone().any(|r
| r
== "+crt-static");
560 // If the target we're compiling for requests a static crt by default,
561 // then see if the `-crt-static` feature was passed to disable that.
562 // Otherwise if we don't have a static crt by default then see if the
563 // `+crt-static` feature was passed.
564 if self.target
.target
.options
.crt_static_default { !found_negative }
else { found_positive }
567 pub fn must_not_eliminate_frame_pointers(&self) -> bool
{
568 // "mcount" function relies on stack pointer.
569 // See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
570 if self.instrument_mcount() {
572 } else if let Some(x
) = self.opts
.cg
.force_frame_pointers
{
575 !self.target
.target
.options
.eliminate_frame_pointer
579 /// Returns the symbol name for the registrar function,
580 /// given the crate `Svh` and the function `DefIndex`.
581 pub fn generate_plugin_registrar_symbol(&self, disambiguator
: CrateDisambiguator
) -> String
{
582 format
!("__rustc_plugin_registrar_{}__", disambiguator
.to_fingerprint().to_hex())
585 pub fn generate_proc_macro_decls_symbol(&self, disambiguator
: CrateDisambiguator
) -> String
{
586 format
!("__rustc_proc_macro_decls_{}__", disambiguator
.to_fingerprint().to_hex())
589 pub fn target_filesearch(&self, kind
: PathKind
) -> filesearch
::FileSearch
<'_
> {
590 filesearch
::FileSearch
::new(
592 self.opts
.target_triple
.triple(),
593 &self.opts
.search_paths
,
594 // `target_tlib_path == None` means it's the same as `host_tlib_path`.
595 self.target_tlib_path
.as_ref().unwrap_or(&self.host_tlib_path
),
599 pub fn host_filesearch(&self, kind
: PathKind
) -> filesearch
::FileSearch
<'_
> {
600 filesearch
::FileSearch
::new(
602 config
::host_triple(),
603 &self.opts
.search_paths
,
604 &self.host_tlib_path
,
609 pub fn set_incr_session_load_dep_graph(&self, load
: bool
) {
610 let mut incr_comp_session
= self.incr_comp_session
.borrow_mut();
612 if let IncrCompSession
::Active { ref mut load_dep_graph, .. }
= *incr_comp_session
{
613 *load_dep_graph
= load
;
617 pub fn incr_session_load_dep_graph(&self) -> bool
{
618 let incr_comp_session
= self.incr_comp_session
.borrow();
619 match *incr_comp_session
{
620 IncrCompSession
::Active { load_dep_graph, .. }
=> load_dep_graph
,
625 pub fn init_incr_comp_session(
627 session_dir
: PathBuf
,
628 lock_file
: flock
::Lock
,
629 load_dep_graph
: bool
,
631 let mut incr_comp_session
= self.incr_comp_session
.borrow_mut();
633 if let IncrCompSession
::NotInitialized
= *incr_comp_session
{
635 panic
!("Trying to initialize IncrCompSession `{:?}`", *incr_comp_session
)
639 IncrCompSession
::Active { session_directory: session_dir, lock_file, load_dep_graph }
;
642 pub fn finalize_incr_comp_session(&self, new_directory_path
: PathBuf
) {
643 let mut incr_comp_session
= self.incr_comp_session
.borrow_mut();
645 if let IncrCompSession
::Active { .. }
= *incr_comp_session
{
647 panic
!("trying to finalize `IncrCompSession` `{:?}`", *incr_comp_session
);
650 // Note: this will also drop the lock file, thus unlocking the directory.
651 *incr_comp_session
= IncrCompSession
::Finalized { session_directory: new_directory_path }
;
654 pub fn mark_incr_comp_session_as_invalid(&self) {
655 let mut incr_comp_session
= self.incr_comp_session
.borrow_mut();
657 let session_directory
= match *incr_comp_session
{
658 IncrCompSession
::Active { ref session_directory, .. }
=> session_directory
.clone(),
659 IncrCompSession
::InvalidBecauseOfErrors { .. }
=> return,
660 _
=> panic
!("trying to invalidate `IncrCompSession` `{:?}`", *incr_comp_session
),
663 // Note: this will also drop the lock file, thus unlocking the directory.
664 *incr_comp_session
= IncrCompSession
::InvalidBecauseOfErrors { session_directory }
;
667 pub fn incr_comp_session_dir(&self) -> cell
::Ref
<'_
, PathBuf
> {
668 let incr_comp_session
= self.incr_comp_session
.borrow();
669 cell
::Ref
::map(incr_comp_session
, |incr_comp_session
| match *incr_comp_session
{
670 IncrCompSession
::NotInitialized
=> panic
!(
671 "trying to get session directory from `IncrCompSession`: {:?}",
674 IncrCompSession
::Active { ref session_directory, .. }
675 | IncrCompSession
::Finalized { ref session_directory }
676 | IncrCompSession
::InvalidBecauseOfErrors { ref session_directory }
=> {
682 pub fn incr_comp_session_dir_opt(&self) -> Option
<cell
::Ref
<'_
, PathBuf
>> {
683 self.opts
.incremental
.as_ref().map(|_
| self.incr_comp_session_dir())
686 pub fn print_perf_stats(&self) {
688 "Total time spent computing symbol hashes: {}",
689 duration_to_secs_str(*self.perf_stats
.symbol_hash_time
.lock())
692 "Total time spent decoding DefPath tables: {}",
693 duration_to_secs_str(*self.perf_stats
.decode_def_path_tables_time
.lock())
696 "Total queries canonicalized: {}",
697 self.perf_stats
.queries_canonicalized
.load(Ordering
::Relaxed
)
700 "normalize_ty_after_erasing_regions: {}",
701 self.perf_stats
.normalize_ty_after_erasing_regions
.load(Ordering
::Relaxed
)
704 "normalize_projection_ty: {}",
705 self.perf_stats
.normalize_projection_ty
.load(Ordering
::Relaxed
)
709 /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n.
710 /// This expends fuel if applicable, and records fuel if applicable.
711 pub fn consider_optimizing
<T
: Fn() -> String
>(&self, crate_name
: &str, msg
: T
) -> bool
{
713 if let Some(ref c
) = self.optimization_fuel_crate
{
715 assert_eq
!(self.threads(), 1);
716 let mut fuel
= self.optimization_fuel
.lock();
717 ret
= fuel
.remaining
!= 0;
718 if fuel
.remaining
== 0 && !fuel
.out_of_fuel
{
719 eprintln
!("optimization-fuel-exhausted: {}", msg());
720 fuel
.out_of_fuel
= true;
721 } else if fuel
.remaining
> 0 {
726 if let Some(ref c
) = self.print_fuel_crate
{
728 assert_eq
!(self.threads(), 1);
729 self.print_fuel
.fetch_add(1, SeqCst
);
735 /// Returns the number of query threads that should be used for this
737 pub fn threads(&self) -> usize {
738 self.opts
.debugging_opts
.threads
741 /// Returns the number of codegen units that should be used for this
743 pub fn codegen_units(&self) -> usize {
744 if let Some(n
) = self.opts
.cli_forced_codegen_units
{
747 if let Some(n
) = self.target
.target
.options
.default_codegen_units
{
751 // Why is 16 codegen units the default all the time?
753 // The main reason for enabling multiple codegen units by default is to
754 // leverage the ability for the codegen backend to do codegen and
755 // optimization in parallel. This allows us, especially for large crates, to
756 // make good use of all available resources on the machine once we've
757 // hit that stage of compilation. Large crates especially then often
758 // take a long time in codegen/optimization and this helps us amortize that
761 // Note that a high number here doesn't mean that we'll be spawning a
762 // large number of threads in parallel. The backend of rustc contains
763 // global rate limiting through the `jobserver` crate so we'll never
764 // overload the system with too much work, but rather we'll only be
765 // optimizing when we're otherwise cooperating with other instances of
768 // Rather a high number here means that we should be able to keep a lot
769 // of idle cpus busy. By ensuring that no codegen unit takes *too* long
770 // to build we'll be guaranteed that all cpus will finish pretty closely
771 // to one another and we should make relatively optimal use of system
774 // Note that the main cost of codegen units is that it prevents LLVM
775 // from inlining across codegen units. Users in general don't have a lot
776 // of control over how codegen units are split up so it's our job in the
777 // compiler to ensure that undue performance isn't lost when using
778 // codegen units (aka we can't require everyone to slap `#[inline]` on
781 // If we're compiling at `-O0` then the number doesn't really matter too
782 // much because performance doesn't matter and inlining is ok to lose.
783 // In debug mode we just want to try to guarantee that no cpu is stuck
784 // doing work that could otherwise be farmed to others.
786 // In release mode, however (O1 and above) performance does indeed
787 // matter! To recover the loss in performance due to inlining we'll be
788 // enabling ThinLTO by default (the function for which is just below).
789 // This will ensure that we recover any inlining wins we otherwise lost
790 // through codegen unit partitioning.
794 // Ok that's a lot of words but the basic tl;dr; is that we want a high
795 // number here -- but not too high. Additionally we're "safe" to have it
796 // always at the same number at all optimization levels.
798 // As a result 16 was chosen here! Mostly because it was a power of 2
799 // and most benchmarks agreed it was roughly a local optimum. Not very
804 pub fn teach(&self, code
: &DiagnosticId
) -> bool
{
805 self.opts
.debugging_opts
.teach
&& self.diagnostic().must_teach(code
)
808 pub fn rust_2015(&self) -> bool
{
809 self.opts
.edition
== Edition
::Edition2015
812 /// Are we allowed to use features from the Rust 2018 edition?
813 pub fn rust_2018(&self) -> bool
{
814 self.opts
.edition
>= Edition
::Edition2018
817 pub fn edition(&self) -> Edition
{
821 /// Returns `true` if we cannot skip the PLT for shared library calls.
822 pub fn needs_plt(&self) -> bool
{
823 // Check if the current target usually needs PLT to be enabled.
824 // The user can use the command line flag to override it.
825 let needs_plt
= self.target
.target
.options
.needs_plt
;
827 let dbg_opts
= &self.opts
.debugging_opts
;
829 let relro_level
= dbg_opts
.relro_level
.unwrap_or(self.target
.target
.options
.relro_level
);
831 // Only enable this optimization by default if full relro is also enabled.
832 // In this case, lazy binding was already unavailable, so nothing is lost.
833 // This also ensures `-Wl,-z,now` is supported by the linker.
834 let full_relro
= RelroLevel
::Full
== relro_level
;
836 // If user didn't explicitly forced us to use / skip the PLT,
837 // then try to skip it where possible.
838 dbg_opts
.plt
.unwrap_or(needs_plt
|| !full_relro
)
842 pub fn build_session(
843 sopts
: config
::Options
,
844 local_crate_source_file
: Option
<PathBuf
>,
845 registry
: rustc_errors
::registry
::Registry
,
847 let file_path_mapping
= sopts
.file_path_mapping();
849 build_session_with_source_map(
851 local_crate_source_file
,
853 Lrc
::new(source_map
::SourceMap
::new(file_path_mapping
)),
854 DiagnosticOutput
::Default
,
860 sopts
: &config
::Options
,
861 registry
: rustc_errors
::registry
::Registry
,
862 source_map
: &Lrc
<source_map
::SourceMap
>,
863 emitter_dest
: Option
<Box
<dyn Write
+ Send
>>,
864 ) -> Box
<dyn Emitter
+ sync
::Send
> {
865 let macro_backtrace
= sopts
.debugging_opts
.macro_backtrace
;
866 match (sopts
.error_format
, emitter_dest
) {
867 (config
::ErrorOutputType
::HumanReadable(kind
), dst
) => {
868 let (short
, color_config
) = kind
.unzip();
870 if let HumanReadableErrorType
::AnnotateSnippet(_
) = kind
{
871 let emitter
= AnnotateSnippetEmitterWriter
::new(
872 Some(source_map
.clone()),
876 Box
::new(emitter
.ui_testing(sopts
.debugging_opts
.ui_testing()))
878 let emitter
= match dst
{
879 None
=> EmitterWriter
::stderr(
881 Some(source_map
.clone()),
883 sopts
.debugging_opts
.teach
,
884 sopts
.debugging_opts
.terminal_width
,
887 Some(dst
) => EmitterWriter
::new(
889 Some(source_map
.clone()),
891 false, // no teach messages when writing to a buffer
892 false, // no colors when writing to a buffer
893 None
, // no terminal width
897 Box
::new(emitter
.ui_testing(sopts
.debugging_opts
.ui_testing()))
900 (config
::ErrorOutputType
::Json { pretty, json_rendered }
, None
) => Box
::new(
908 .ui_testing(sopts
.debugging_opts
.ui_testing()),
910 (config
::ErrorOutputType
::Json { pretty, json_rendered }
, Some(dst
)) => Box
::new(
919 .ui_testing(sopts
.debugging_opts
.ui_testing()),
924 pub enum DiagnosticOutput
{
926 Raw(Box
<dyn Write
+ Send
>),
929 pub fn build_session_with_source_map(
930 sopts
: config
::Options
,
931 local_crate_source_file
: Option
<PathBuf
>,
932 registry
: rustc_errors
::registry
::Registry
,
933 source_map
: Lrc
<source_map
::SourceMap
>,
934 diagnostics_output
: DiagnosticOutput
,
935 lint_caps
: FxHashMap
<lint
::LintId
, lint
::Level
>,
937 // FIXME: This is not general enough to make the warning lint completely override
938 // normal diagnostic warnings, since the warning lint can also be denied and changed
939 // later via the source code.
940 let warnings_allow
= sopts
943 .filter(|&&(ref key
, _
)| *key
== "warnings")
944 .map(|&(_
, ref level
)| *level
== lint
::Allow
)
947 let cap_lints_allow
= sopts
.lint_cap
.map_or(false, |cap
| cap
== lint
::Allow
);
948 let can_emit_warnings
= !(warnings_allow
|| cap_lints_allow
);
950 let write_dest
= match diagnostics_output
{
951 DiagnosticOutput
::Default
=> None
,
952 DiagnosticOutput
::Raw(write
) => Some(write
),
954 let emitter
= default_emitter(&sopts
, registry
, &source_map
, write_dest
);
956 let diagnostic_handler
= rustc_errors
::Handler
::with_emitter_and_flags(
958 sopts
.debugging_opts
.diagnostic_handler_flags(can_emit_warnings
),
961 build_session_(sopts
, local_crate_source_file
, diagnostic_handler
, source_map
, lint_caps
)
965 sopts
: config
::Options
,
966 local_crate_source_file
: Option
<PathBuf
>,
967 span_diagnostic
: rustc_errors
::Handler
,
968 source_map
: Lrc
<source_map
::SourceMap
>,
969 driver_lint_caps
: FxHashMap
<lint
::LintId
, lint
::Level
>,
971 let self_profiler
= if let SwitchWithOptPath
::Enabled(ref d
) = sopts
.debugging_opts
.self_profile
974 if let Some(ref directory
) = d { directory }
else { std::path::Path::new(".") }
;
976 let profiler
= SelfProfiler
::new(
978 sopts
.crate_name
.as_ref().map(|s
| &s
[..]),
979 &sopts
.debugging_opts
.self_profile_events
,
982 Ok(profiler
) => Some(Arc
::new(profiler
)),
984 early_warn(sopts
.error_format
, &format
!("failed to create profiler: {}", e
));
992 let host_triple
= TargetTriple
::from_triple(config
::host_triple());
993 let host
= Target
::search(&host_triple
).unwrap_or_else(|e
| {
994 span_diagnostic
.fatal(&format
!("Error loading host specification: {}", e
)).raise()
996 let target_cfg
= config
::build_target_config(&sopts
, &span_diagnostic
);
998 let parse_sess
= ParseSess
::with_span_handler(span_diagnostic
, source_map
);
999 let sysroot
= match &sopts
.maybe_sysroot
{
1000 Some(sysroot
) => sysroot
.clone(),
1001 None
=> filesearch
::get_or_default_sysroot(),
1004 let host_triple
= config
::host_triple();
1005 let target_triple
= sopts
.target_triple
.triple();
1006 let host_tlib_path
= SearchPath
::from_sysroot_and_triple(&sysroot
, host_triple
);
1007 let target_tlib_path
= if host_triple
== target_triple
{
1010 Some(SearchPath
::from_sysroot_and_triple(&sysroot
, target_triple
))
1013 let file_path_mapping
= sopts
.file_path_mapping();
1015 let local_crate_source_file
=
1016 local_crate_source_file
.map(|path
| file_path_mapping
.map_prefix(path
).0);
1018 let optimization_fuel_crate
= sopts
.debugging_opts
.fuel
.as_ref().map(|i
| i
.0.clone());
1019 let optimization_fuel
= Lock
::new(OptimizationFuel
{
1020 remaining
: sopts
.debugging_opts
.fuel
.as_ref().map(|i
| i
.1).unwrap_or(0),
1023 let print_fuel_crate
= sopts
.debugging_opts
.print_fuel
.clone();
1024 let print_fuel
= AtomicU64
::new(0);
1026 let working_dir
= env
::current_dir().unwrap_or_else(|e
| {
1027 parse_sess
.span_diagnostic
.fatal(&format
!("Current directory is invalid: {}", e
)).raise()
1029 let working_dir
= file_path_mapping
.map_prefix(working_dir
);
1031 let cgu_reuse_tracker
= if sopts
.debugging_opts
.query_dep_graph
{
1032 CguReuseTracker
::new()
1034 CguReuseTracker
::new_disabled()
1037 let prof
= SelfProfilerRef
::new(
1039 sopts
.debugging_opts
.time_passes
|| sopts
.debugging_opts
.time
,
1040 sopts
.debugging_opts
.time_passes
,
1043 let sess
= Session
{
1051 local_crate_source_file
,
1053 one_time_diagnostics
: Default
::default(),
1054 crate_types
: Once
::new(),
1055 crate_disambiguator
: Once
::new(),
1056 features
: Once
::new(),
1057 recursion_limit
: Once
::new(),
1058 type_length_limit
: Once
::new(),
1059 const_eval_limit
: Once
::new(),
1060 imported_macro_spans
: OneThread
::new(RefCell
::new(FxHashMap
::default())),
1061 incr_comp_session
: OneThread
::new(RefCell
::new(IncrCompSession
::NotInitialized
)),
1064 perf_stats
: PerfStats
{
1065 symbol_hash_time
: Lock
::new(Duration
::from_secs(0)),
1066 decode_def_path_tables_time
: Lock
::new(Duration
::from_secs(0)),
1067 queries_canonicalized
: AtomicUsize
::new(0),
1068 normalize_ty_after_erasing_regions
: AtomicUsize
::new(0),
1069 normalize_projection_ty
: AtomicUsize
::new(0),
1071 code_stats
: Default
::default(),
1072 optimization_fuel_crate
,
1076 jobserver
: jobserver
::client(),
1078 trait_methods_not_found
: Lock
::new(Default
::default()),
1079 confused_type_with_std_module
: Lock
::new(Default
::default()),
1080 system_library_path
: OneThread
::new(RefCell
::new(Default
::default())),
1083 validate_commandline_args_with_session_available(&sess
);
1088 // If it is useful to have a Session available already for validating a
1089 // commandline argument, you can do so here.
1090 fn validate_commandline_args_with_session_available(sess
: &Session
) {
1091 // Since we don't know if code in an rlib will be linked to statically or
1092 // dynamically downstream, rustc generates `__imp_` symbols that help the
1093 // MSVC linker deal with this lack of knowledge (#27438). Unfortunately,
1094 // these manually generated symbols confuse LLD when it tries to merge
1095 // bitcode during ThinLTO. Therefore we disallow dynamic linking on MSVC
1096 // when compiling for LLD ThinLTO. This way we can validly just not generate
1097 // the `dllimport` attributes and `__imp_` symbols in that case.
1098 if sess
.opts
.cg
.linker_plugin_lto
.enabled()
1099 && sess
.opts
.cg
.prefer_dynamic
1100 && sess
.target
.target
.options
.is_like_msvc
1103 "Linker plugin based LTO is not supported together with \
1104 `-C prefer-dynamic` when targeting MSVC",
1108 // Make sure that any given profiling data actually exists so LLVM can't
1109 // decide to silently skip PGO.
1110 if let Some(ref path
) = sess
.opts
.cg
.profile_use
{
1113 "File `{}` passed to `-C profile-use` does not exist.",
1119 // PGO does not work reliably with panic=unwind on Windows. Let's make it
1120 // an error to combine the two for now. It always runs into an assertions
1121 // if LLVM is built with assertions, but without assertions it sometimes
1122 // does not crash and will probably generate a corrupted binary.
1123 // We should only display this error if we're actually going to run PGO.
1124 // If we're just supposed to print out some data, don't show the error (#61002).
1125 if sess
.opts
.cg
.profile_generate
.enabled()
1126 && sess
.target
.target
.options
.is_like_msvc
1127 && sess
.panic_strategy() == PanicStrategy
::Unwind
1128 && sess
.opts
.prints
.iter().all(|&p
| p
== PrintRequest
::NativeStaticLibs
)
1131 "Profile-guided optimization does not yet work in conjunction \
1132 with `-Cpanic=unwind` on Windows when targeting MSVC. \
1133 See issue #61002 <https://github.com/rust-lang/rust/issues/61002> \
1134 for more information.",
1138 // Sanitizers can only be used on some tested platforms.
1139 if let Some(ref sanitizer
) = sess
.opts
.debugging_opts
.sanitizer
{
1140 const ASAN_SUPPORTED_TARGETS
: &[&str] = &[
1141 "x86_64-unknown-linux-gnu",
1142 "x86_64-apple-darwin",
1146 const TSAN_SUPPORTED_TARGETS
: &[&str] =
1147 &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
1148 const LSAN_SUPPORTED_TARGETS
: &[&str] =
1149 &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
1150 const MSAN_SUPPORTED_TARGETS
: &[&str] = &["x86_64-unknown-linux-gnu"];
1152 let supported_targets
= match *sanitizer
{
1153 Sanitizer
::Address
=> ASAN_SUPPORTED_TARGETS
,
1154 Sanitizer
::Thread
=> TSAN_SUPPORTED_TARGETS
,
1155 Sanitizer
::Leak
=> LSAN_SUPPORTED_TARGETS
,
1156 Sanitizer
::Memory
=> MSAN_SUPPORTED_TARGETS
,
1159 if !supported_targets
.contains(&&*sess
.opts
.target_triple
.triple()) {
1161 "{:?}Sanitizer only works with the `{}` target",
1163 supported_targets
.join("` or `")
1169 /// Hash value constructed out of all the `-C metadata` arguments passed to the
1170 /// compiler. Together with the crate-name forms a unique global identifier for
1172 #[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, RustcEncodable, RustcDecodable)]
1173 pub struct CrateDisambiguator(Fingerprint
);
1175 impl CrateDisambiguator
{
1176 pub fn to_fingerprint(self) -> Fingerprint
{
1181 impl fmt
::Display
for CrateDisambiguator
{
1182 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> Result
<(), fmt
::Error
> {
1183 let (a
, b
) = self.0.as_value();
1184 let as_u128
= a
as u128
| ((b
as u128
) << 64);
1185 f
.write_str(&base_n
::encode(as_u128
, base_n
::CASE_INSENSITIVE
))
1189 impl From
<Fingerprint
> for CrateDisambiguator
{
1190 fn from(fingerprint
: Fingerprint
) -> CrateDisambiguator
{
1191 CrateDisambiguator(fingerprint
)
1195 impl_stable_hash_via_hash
!(CrateDisambiguator
);
1197 /// Holds data on the current incremental compilation session, if there is one.
1199 pub enum IncrCompSession
{
1200 /// This is the state the session will be in until the incr. comp. dir is
1203 /// This is the state during which the session directory is private and can
1205 Active { session_directory: PathBuf, lock_file: flock::Lock, load_dep_graph: bool }
,
1206 /// This is the state after the session directory has been finalized. In this
1207 /// state, the contents of the directory must not be modified any more.
1208 Finalized { session_directory: PathBuf }
,
1209 /// This is an error state that is reached when some compilation error has
1210 /// occurred. It indicates that the contents of the session directory must
1211 /// not be used, since they might be invalid.
1212 InvalidBecauseOfErrors { session_directory: PathBuf }
,
1215 pub fn early_error(output
: config
::ErrorOutputType
, msg
: &str) -> ! {
1216 let emitter
: Box
<dyn Emitter
+ sync
::Send
> = match output
{
1217 config
::ErrorOutputType
::HumanReadable(kind
) => {
1218 let (short
, color_config
) = kind
.unzip();
1219 Box
::new(EmitterWriter
::stderr(color_config
, None
, short
, false, None
, false))
1221 config
::ErrorOutputType
::Json { pretty, json_rendered }
=> {
1222 Box
::new(JsonEmitter
::basic(pretty
, json_rendered
, false))
1225 let handler
= rustc_errors
::Handler
::with_emitter(true, None
, emitter
);
1226 handler
.struct_fatal(msg
).emit();
1227 rustc_errors
::FatalError
.raise();
1230 pub fn early_warn(output
: config
::ErrorOutputType
, msg
: &str) {
1231 let emitter
: Box
<dyn Emitter
+ sync
::Send
> = match output
{
1232 config
::ErrorOutputType
::HumanReadable(kind
) => {
1233 let (short
, color_config
) = kind
.unzip();
1234 Box
::new(EmitterWriter
::stderr(color_config
, None
, short
, false, None
, false))
1236 config
::ErrorOutputType
::Json { pretty, json_rendered }
=> {
1237 Box
::new(JsonEmitter
::basic(pretty
, json_rendered
, false))
1240 let handler
= rustc_errors
::Handler
::with_emitter(true, None
, emitter
);
1241 handler
.struct_warn(msg
).emit();
1244 pub type CompileResult
= Result
<(), ErrorReported
>;