1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 pub use self::code_stats
::{CodeStats, DataTypeKind, FieldInfo}
;
12 pub use self::code_stats
::{SizeKind, TypeSizeInfo, VariantInfo}
;
14 use hir
::def_id
::CrateNum
;
18 use middle
::allocator
::AllocatorKind
;
19 use middle
::dependency_format
;
20 use session
::search_paths
::PathKind
;
21 use session
::config
::{BorrowckMode, DebugInfoLevel, OutputType}
;
23 use util
::nodemap
::{FxHashMap, FxHashSet}
;
24 use util
::common
::{duration_to_secs_str, ErrorReported}
;
26 use syntax
::ast
::NodeId
;
27 use errors
::{self, DiagnosticBuilder, DiagnosticId}
;
28 use errors
::emitter
::{Emitter, EmitterWriter}
;
29 use syntax
::json
::JsonEmitter
;
30 use syntax
::feature_gate
;
32 use syntax
::parse
::ParseSess
;
33 use syntax
::{ast, codemap}
;
34 use syntax
::feature_gate
::AttributeType
;
35 use syntax_pos
::{Span, MultiSpan}
;
37 use rustc_back
::{LinkerFlavor, PanicStrategy}
;
38 use rustc_back
::target
::Target
;
39 use rustc_data_structures
::flock
;
40 use jobserver
::Client
;
42 use std
::cell
::{self, Cell, RefCell}
;
43 use std
::collections
::HashMap
;
47 use std
::path
::{Path, PathBuf}
;
49 use std
::sync
::{Once, ONCE_INIT}
;
50 use std
::time
::Duration
;
57 /// Represents the data associated with a compilation
58 /// session for a single crate.
60 pub target
: config
::Config
,
62 pub opts
: config
::Options
,
63 pub parse_sess
: ParseSess
,
64 /// For a library crate, this is always none
65 pub entry_fn
: RefCell
<Option
<(NodeId
, Span
)>>,
66 pub entry_type
: Cell
<Option
<config
::EntryFnType
>>,
67 pub plugin_registrar_fn
: Cell
<Option
<ast
::NodeId
>>,
68 pub derive_registrar_fn
: Cell
<Option
<ast
::NodeId
>>,
69 pub default_sysroot
: Option
<PathBuf
>,
70 /// The name of the root source file of the crate, in the local file system.
71 /// `None` means that there is no source file.
72 pub local_crate_source_file
: Option
<PathBuf
>,
73 /// The directory the compiler has been executed in plus a flag indicating
74 /// if the value stored here has been affected by path remapping.
75 pub working_dir
: (PathBuf
, bool
),
76 pub lint_store
: RefCell
<lint
::LintStore
>,
77 pub buffered_lints
: RefCell
<Option
<lint
::LintBuffer
>>,
78 /// Set of (DiagnosticId, Option<Span>, message) tuples tracking
79 /// (sub)diagnostics that have been set once, but should not be set again,
80 /// in order to avoid redundantly verbose output (Issue #24690, #44953).
81 pub one_time_diagnostics
: RefCell
<FxHashSet
<(DiagnosticMessageId
, Option
<Span
>, String
)>>,
82 pub plugin_llvm_passes
: RefCell
<Vec
<String
>>,
83 pub plugin_attributes
: RefCell
<Vec
<(String
, AttributeType
)>>,
84 pub crate_types
: RefCell
<Vec
<config
::CrateType
>>,
85 pub dependency_formats
: RefCell
<dependency_format
::Dependencies
>,
86 /// The crate_disambiguator is constructed out of all the `-C metadata`
87 /// arguments passed to the compiler. Its value together with the crate-name
88 /// forms a unique global identifier for the crate. It is used to allow
89 /// multiple crates with the same name to coexist. See the
90 /// trans::back::symbol_names module for more information.
91 pub crate_disambiguator
: RefCell
<Option
<CrateDisambiguator
>>,
92 pub features
: RefCell
<feature_gate
::Features
>,
94 /// The maximum recursion limit for potentially infinitely recursive
95 /// operations such as auto-dereference and monomorphization.
96 pub recursion_limit
: Cell
<usize>,
98 /// The maximum length of types during monomorphization.
99 pub type_length_limit
: Cell
<usize>,
101 /// The metadata::creader module may inject an allocator/panic_runtime
102 /// dependency if it didn't already find one, and this tracks what was
104 pub injected_allocator
: Cell
<Option
<CrateNum
>>,
105 pub allocator_kind
: Cell
<Option
<AllocatorKind
>>,
106 pub injected_panic_runtime
: Cell
<Option
<CrateNum
>>,
108 /// Map from imported macro spans (which consist of
109 /// the localized span for the macro body) to the
110 /// macro name and definition span in the source crate.
111 pub imported_macro_spans
: RefCell
<HashMap
<Span
, (String
, Span
)>>,
113 incr_comp_session
: RefCell
<IncrCompSession
>,
115 /// Some measurements that are being gathered during compilation.
116 pub perf_stats
: PerfStats
,
118 /// Data about code being compiled, gathered during compilation.
119 pub code_stats
: RefCell
<CodeStats
>,
121 next_node_id
: Cell
<ast
::NodeId
>,
123 /// If -zfuel=crate=n is specified, Some(crate).
124 optimization_fuel_crate
: Option
<String
>,
125 /// If -zfuel=crate=n is specified, initially set to n. Otherwise 0.
126 optimization_fuel_limit
: Cell
<u64>,
127 /// We're rejecting all further optimizations.
128 out_of_fuel
: Cell
<bool
>,
130 // The next two are public because the driver needs to read them.
132 /// If -zprint-fuel=crate, Some(crate).
133 pub print_fuel_crate
: Option
<String
>,
134 /// Always set to zero and incremented so that we can print fuel expended by a crate.
135 pub print_fuel
: Cell
<u64>,
137 /// Loaded up early on in the initialization of this `Session` to avoid
138 /// false positives about a job server in our environment.
139 pub jobserver_from_env
: Option
<Client
>,
141 /// Metadata about the allocators for the current crate being compiled
142 pub has_global_allocator
: Cell
<bool
>,
145 pub struct PerfStats
{
146 /// The accumulated time needed for computing the SVH of the crate
147 pub svh_time
: Cell
<Duration
>,
148 /// The accumulated time spent on computing incr. comp. hashes
149 pub incr_comp_hashes_time
: Cell
<Duration
>,
150 /// The number of incr. comp. hash computations performed
151 pub incr_comp_hashes_count
: Cell
<u64>,
152 /// The number of bytes hashed when computing ICH values
153 pub incr_comp_bytes_hashed
: Cell
<u64>,
154 /// The accumulated time spent on computing symbol hashes
155 pub symbol_hash_time
: Cell
<Duration
>,
156 /// The accumulated time spent decoding def path tables from metadata
157 pub decode_def_path_tables_time
: Cell
<Duration
>,
160 /// Enum to support dispatch of one-time diagnostics (in Session.diag_once)
161 enum DiagnosticBuilderMethod
{
164 SpanSuggestion(String
), // suggestion
165 // add more variants as needed to support one-time diagnostics
168 /// Diagnostic message ID—used by `Session.one_time_diagnostics` to avoid
169 /// emitting the same message more than once
170 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
171 pub enum DiagnosticMessageId
{
172 ErrorId(u16), // EXXXX error code as integer
173 LintId(lint
::LintId
),
174 StabilityId(u32) // issue number
177 impl From
<&'
static lint
::Lint
> for DiagnosticMessageId
{
178 fn from(lint
: &'
static lint
::Lint
) -> Self {
179 DiagnosticMessageId
::LintId(lint
::LintId
::of(lint
))
184 pub fn local_crate_disambiguator(&self) -> CrateDisambiguator
{
185 match *self.crate_disambiguator
.borrow() {
186 Some(value
) => value
,
187 None
=> bug
!("accessing disambiguator before initialization"),
190 pub fn struct_span_warn
<'a
, S
: Into
<MultiSpan
>>(&'a
self,
193 -> DiagnosticBuilder
<'a
> {
194 self.diagnostic().struct_span_warn(sp
, msg
)
196 pub fn struct_span_warn_with_code
<'a
, S
: Into
<MultiSpan
>>(&'a
self,
200 -> DiagnosticBuilder
<'a
> {
201 self.diagnostic().struct_span_warn_with_code(sp
, msg
, code
)
203 pub fn struct_warn
<'a
>(&'a
self, msg
: &str) -> DiagnosticBuilder
<'a
> {
204 self.diagnostic().struct_warn(msg
)
206 pub fn struct_span_err
<'a
, S
: Into
<MultiSpan
>>(&'a
self,
209 -> DiagnosticBuilder
<'a
> {
210 self.diagnostic().struct_span_err(sp
, msg
)
212 pub fn struct_span_err_with_code
<'a
, S
: Into
<MultiSpan
>>(&'a
self,
216 -> DiagnosticBuilder
<'a
> {
217 self.diagnostic().struct_span_err_with_code(sp
, msg
, code
)
219 // FIXME: This method should be removed (every error should have an associated error code).
220 pub fn struct_err
<'a
>(&'a
self, msg
: &str) -> DiagnosticBuilder
<'a
> {
221 self.diagnostic().struct_err(msg
)
223 pub fn struct_err_with_code
<'a
>(
227 ) -> DiagnosticBuilder
<'a
> {
228 self.diagnostic().struct_err_with_code(msg
, code
)
230 pub fn struct_span_fatal
<'a
, S
: Into
<MultiSpan
>>(&'a
self,
233 -> DiagnosticBuilder
<'a
> {
234 self.diagnostic().struct_span_fatal(sp
, msg
)
236 pub fn struct_span_fatal_with_code
<'a
, S
: Into
<MultiSpan
>>(&'a
self,
240 -> DiagnosticBuilder
<'a
> {
241 self.diagnostic().struct_span_fatal_with_code(sp
, msg
, code
)
243 pub fn struct_fatal
<'a
>(&'a
self, msg
: &str) -> DiagnosticBuilder
<'a
> {
244 self.diagnostic().struct_fatal(msg
)
247 pub fn span_fatal
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str) -> ! {
248 panic
!(self.diagnostic().span_fatal(sp
, msg
))
250 pub fn span_fatal_with_code
<S
: Into
<MultiSpan
>>(
256 panic
!(self.diagnostic().span_fatal_with_code(sp
, msg
, code
))
258 pub fn fatal(&self, msg
: &str) -> ! {
259 panic
!(self.diagnostic().fatal(msg
))
261 pub fn span_err_or_warn
<S
: Into
<MultiSpan
>>(&self, is_warning
: bool
, sp
: S
, msg
: &str) {
263 self.span_warn(sp
, msg
);
265 self.span_err(sp
, msg
);
268 pub fn span_err
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str) {
269 self.diagnostic().span_err(sp
, msg
)
271 pub fn span_err_with_code
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str, code
: DiagnosticId
) {
272 self.diagnostic().span_err_with_code(sp
, &msg
, code
)
274 pub fn err(&self, msg
: &str) {
275 self.diagnostic().err(msg
)
277 pub fn err_count(&self) -> usize {
278 self.diagnostic().err_count()
280 pub fn has_errors(&self) -> bool
{
281 self.diagnostic().has_errors()
283 pub fn abort_if_errors(&self) {
284 self.diagnostic().abort_if_errors();
286 pub fn compile_status(&self) -> Result
<(), CompileIncomplete
> {
287 compile_result_from_err_count(self.err_count())
289 pub fn track_errors
<F
, T
>(&self, f
: F
) -> Result
<T
, ErrorReported
>
290 where F
: FnOnce() -> T
292 let old_count
= self.err_count();
294 let errors
= self.err_count() - old_count
;
301 pub fn span_warn
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str) {
302 self.diagnostic().span_warn(sp
, msg
)
304 pub fn span_warn_with_code
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str, code
: DiagnosticId
) {
305 self.diagnostic().span_warn_with_code(sp
, msg
, code
)
307 pub fn warn(&self, msg
: &str) {
308 self.diagnostic().warn(msg
)
310 pub fn opt_span_warn
<S
: Into
<MultiSpan
>>(&self, opt_sp
: Option
<S
>, msg
: &str) {
312 Some(sp
) => self.span_warn(sp
, msg
),
313 None
=> self.warn(msg
),
316 /// Delay a span_bug() call until abort_if_errors()
317 pub fn delay_span_bug
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str) {
318 self.diagnostic().delay_span_bug(sp
, msg
)
320 pub fn note_without_error(&self, msg
: &str) {
321 self.diagnostic().note_without_error(msg
)
323 pub fn span_note_without_error
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str) {
324 self.diagnostic().span_note_without_error(sp
, msg
)
326 pub fn span_unimpl
<S
: Into
<MultiSpan
>>(&self, sp
: S
, msg
: &str) -> ! {
327 self.diagnostic().span_unimpl(sp
, msg
)
329 pub fn unimpl(&self, msg
: &str) -> ! {
330 self.diagnostic().unimpl(msg
)
333 pub fn buffer_lint
<S
: Into
<MultiSpan
>>(&self,
334 lint
: &'
static lint
::Lint
,
338 match *self.buffered_lints
.borrow_mut() {
339 Some(ref mut buffer
) => buffer
.add_lint(lint
, id
, sp
.into(), msg
),
340 None
=> bug
!("can't buffer lints after HIR lowering"),
344 pub fn reserve_node_ids(&self, count
: usize) -> ast
::NodeId
{
345 let id
= self.next_node_id
.get();
347 match id
.as_usize().checked_add(count
) {
349 self.next_node_id
.set(ast
::NodeId
::new(next
));
351 None
=> bug
!("Input too large, ran out of node ids!")
356 pub fn next_node_id(&self) -> NodeId
{
357 self.reserve_node_ids(1)
359 pub fn diagnostic
<'a
>(&'a
self) -> &'a errors
::Handler
{
360 &self.parse_sess
.span_diagnostic
363 /// Analogous to calling methods on the given `DiagnosticBuilder`, but
364 /// deduplicates on lint ID, span (if any), and message for this `Session`
365 fn diag_once
<'a
, 'b
>(&'a
self,
366 diag_builder
: &'b
mut DiagnosticBuilder
<'a
>,
367 method
: DiagnosticBuilderMethod
,
368 msg_id
: DiagnosticMessageId
,
370 span_maybe
: Option
<Span
>) {
372 let id_span_message
= (msg_id
, span_maybe
, message
.to_owned());
373 let fresh
= self.one_time_diagnostics
.borrow_mut().insert(id_span_message
);
376 DiagnosticBuilderMethod
::Note
=> {
377 diag_builder
.note(message
);
379 DiagnosticBuilderMethod
::SpanNote
=> {
380 let span
= span_maybe
.expect("span_note needs a span");
381 diag_builder
.span_note(span
, message
);
383 DiagnosticBuilderMethod
::SpanSuggestion(suggestion
) => {
384 let span
= span_maybe
.expect("span_suggestion needs a span");
385 diag_builder
.span_suggestion(span
, message
, suggestion
);
391 pub fn diag_span_note_once
<'a
, 'b
>(&'a
self,
392 diag_builder
: &'b
mut DiagnosticBuilder
<'a
>,
393 msg_id
: DiagnosticMessageId
, span
: Span
, message
: &str) {
394 self.diag_once(diag_builder
, DiagnosticBuilderMethod
::SpanNote
,
395 msg_id
, message
, Some(span
));
398 pub fn diag_note_once
<'a
, 'b
>(&'a
self,
399 diag_builder
: &'b
mut DiagnosticBuilder
<'a
>,
400 msg_id
: DiagnosticMessageId
, message
: &str) {
401 self.diag_once(diag_builder
, DiagnosticBuilderMethod
::Note
, msg_id
, message
, None
);
404 pub fn diag_span_suggestion_once
<'a
, 'b
>(&'a
self,
405 diag_builder
: &'b
mut DiagnosticBuilder
<'a
>,
406 msg_id
: DiagnosticMessageId
,
409 suggestion
: String
) {
410 self.diag_once(diag_builder
, DiagnosticBuilderMethod
::SpanSuggestion(suggestion
),
411 msg_id
, message
, Some(span
));
414 pub fn codemap
<'a
>(&'a
self) -> &'a codemap
::CodeMap
{
415 self.parse_sess
.codemap()
417 pub fn verbose(&self) -> bool { self.opts.debugging_opts.verbose }
418 pub fn time_passes(&self) -> bool { self.opts.debugging_opts.time_passes }
419 pub fn profile_queries(&self) -> bool
{
420 self.opts
.debugging_opts
.profile_queries
||
421 self.opts
.debugging_opts
.profile_queries_and_keys
423 pub fn profile_queries_and_keys(&self) -> bool
{
424 self.opts
.debugging_opts
.profile_queries_and_keys
426 pub fn count_llvm_insns(&self) -> bool
{
427 self.opts
.debugging_opts
.count_llvm_insns
429 pub fn time_llvm_passes(&self) -> bool
{
430 self.opts
.debugging_opts
.time_llvm_passes
432 pub fn trans_stats(&self) -> bool { self.opts.debugging_opts.trans_stats }
433 pub fn meta_stats(&self) -> bool { self.opts.debugging_opts.meta_stats }
434 pub fn asm_comments(&self) -> bool { self.opts.debugging_opts.asm_comments }
435 pub fn no_verify(&self) -> bool { self.opts.debugging_opts.no_verify }
436 pub fn borrowck_stats(&self) -> bool { self.opts.debugging_opts.borrowck_stats }
437 pub fn print_llvm_passes(&self) -> bool
{
438 self.opts
.debugging_opts
.print_llvm_passes
441 /// If true, we should use NLL-style region checking instead of
443 pub fn nll(&self) -> bool
{
444 self.features
.borrow().nll
|| self.opts
.debugging_opts
.nll
447 /// If true, we should use the MIR-based borrowck (we may *also* use
448 /// the AST-based borrowck).
449 pub fn use_mir(&self) -> bool
{
450 self.borrowck_mode().use_mir()
453 /// If true, we should gather causal information during NLL
454 /// checking. This will eventually be the normal thing, but right
455 /// now it is too unoptimized.
456 pub fn nll_dump_cause(&self) -> bool
{
457 self.opts
.debugging_opts
.nll_dump_cause
460 /// If true, we should enable two-phase borrows checks. This is
461 /// done with either `-Ztwo-phase-borrows` or with
462 /// `#![feature(nll)]`.
463 pub fn two_phase_borrows(&self) -> bool
{
464 self.features
.borrow().nll
|| self.opts
.debugging_opts
.two_phase_borrows
467 /// What mode(s) of borrowck should we run? AST? MIR? both?
468 /// (Also considers the `#![feature(nll)]` setting.)
469 pub fn borrowck_mode(&self) -> BorrowckMode
{
470 match self.opts
.borrowck_mode
{
471 mode @ BorrowckMode
::Mir
|
472 mode @ BorrowckMode
::Compare
=> mode
,
474 mode @ BorrowckMode
::Ast
=> {
485 /// Should we emit EndRegion MIR statements? These are consumed by
486 /// MIR borrowck, but not when NLL is used. They are also consumed
487 /// by the validation stuff.
488 pub fn emit_end_regions(&self) -> bool
{
489 // FIXME(#46875) -- we should not emit end regions when NLL is enabled,
490 // but for now we can't stop doing so because it causes false positives
491 self.opts
.debugging_opts
.emit_end_regions
||
492 self.opts
.debugging_opts
.mir_emit_validate
> 0 ||
496 pub fn lto(&self) -> bool
{
497 self.opts
.cg
.lto
|| self.target
.target
.options
.requires_lto
499 /// Returns the panic strategy for this compile session. If the user explicitly selected one
500 /// using '-C panic', use that, otherwise use the panic strategy defined by the target.
501 pub fn panic_strategy(&self) -> PanicStrategy
{
502 self.opts
.cg
.panic
.unwrap_or(self.target
.target
.options
.panic_strategy
)
504 pub fn linker_flavor(&self) -> LinkerFlavor
{
505 self.opts
.debugging_opts
.linker_flavor
.unwrap_or(self.target
.target
.linker_flavor
)
508 pub fn fewer_names(&self) -> bool
{
509 let more_names
= self.opts
.output_types
.contains_key(&OutputType
::LlvmAssembly
) ||
510 self.opts
.output_types
.contains_key(&OutputType
::Bitcode
);
511 self.opts
.debugging_opts
.fewer_names
|| !more_names
514 pub fn no_landing_pads(&self) -> bool
{
515 self.opts
.debugging_opts
.no_landing_pads
|| self.panic_strategy() == PanicStrategy
::Abort
517 pub fn unstable_options(&self) -> bool
{
518 self.opts
.debugging_opts
.unstable_options
520 pub fn nonzeroing_move_hints(&self) -> bool
{
521 self.opts
.debugging_opts
.enable_nonzeroing_move_hints
523 pub fn overflow_checks(&self) -> bool
{
524 self.opts
.cg
.overflow_checks
525 .or(self.opts
.debugging_opts
.force_overflow_checks
)
526 .unwrap_or(self.opts
.debug_assertions
)
529 pub fn crt_static(&self) -> bool
{
530 // If the target does not opt in to crt-static support, use its default.
531 if self.target
.target
.options
.crt_static_respected
{
532 self.crt_static_feature()
534 self.target
.target
.options
.crt_static_default
538 pub fn crt_static_feature(&self) -> bool
{
539 let requested_features
= self.opts
.cg
.target_feature
.split('
,'
);
540 let found_negative
= requested_features
.clone().any(|r
| r
== "-crt-static");
541 let found_positive
= requested_features
.clone().any(|r
| r
== "+crt-static");
543 // If the target we're compiling for requests a static crt by default,
544 // then see if the `-crt-static` feature was passed to disable that.
545 // Otherwise if we don't have a static crt by default then see if the
546 // `+crt-static` feature was passed.
547 if self.target
.target
.options
.crt_static_default
{
554 pub fn must_not_eliminate_frame_pointers(&self) -> bool
{
555 self.opts
.debuginfo
!= DebugInfoLevel
::NoDebugInfo
||
556 !self.target
.target
.options
.eliminate_frame_pointer
559 /// Returns the symbol name for the registrar function,
560 /// given the crate Svh and the function DefIndex.
561 pub fn generate_plugin_registrar_symbol(&self,
562 disambiguator
: CrateDisambiguator
)
564 format
!("__rustc_plugin_registrar_{}__", disambiguator
.to_fingerprint().to_hex())
567 pub fn generate_derive_registrar_symbol(&self,
568 disambiguator
: CrateDisambiguator
)
570 format
!("__rustc_derive_registrar_{}__", disambiguator
.to_fingerprint().to_hex())
573 pub fn sysroot
<'a
>(&'a
self) -> &'a Path
{
574 match self.opts
.maybe_sysroot
{
575 Some (ref sysroot
) => sysroot
,
576 None
=> self.default_sysroot
.as_ref()
577 .expect("missing sysroot and default_sysroot in Session")
580 pub fn target_filesearch(&self, kind
: PathKind
) -> filesearch
::FileSearch
{
581 filesearch
::FileSearch
::new(self.sysroot(),
582 &self.opts
.target_triple
,
583 &self.opts
.search_paths
,
586 pub fn host_filesearch(&self, kind
: PathKind
) -> filesearch
::FileSearch
{
587 filesearch
::FileSearch
::new(
589 config
::host_triple(),
590 &self.opts
.search_paths
,
594 pub fn set_incr_session_load_dep_graph(&self, load
: bool
) {
595 let mut incr_comp_session
= self.incr_comp_session
.borrow_mut();
597 match *incr_comp_session
{
598 IncrCompSession
::Active { ref mut load_dep_graph, .. }
=> {
599 *load_dep_graph
= load
;
605 pub fn incr_session_load_dep_graph(&self) -> bool
{
606 let incr_comp_session
= self.incr_comp_session
.borrow();
607 match *incr_comp_session
{
608 IncrCompSession
::Active { load_dep_graph, .. }
=> load_dep_graph
,
613 pub fn init_incr_comp_session(&self,
614 session_dir
: PathBuf
,
615 lock_file
: flock
::Lock
,
616 load_dep_graph
: bool
) {
617 let mut incr_comp_session
= self.incr_comp_session
.borrow_mut();
619 if let IncrCompSession
::NotInitialized
= *incr_comp_session { }
else {
620 bug
!("Trying to initialize IncrCompSession `{:?}`", *incr_comp_session
)
623 *incr_comp_session
= IncrCompSession
::Active
{
624 session_directory
: session_dir
,
630 pub fn finalize_incr_comp_session(&self, new_directory_path
: PathBuf
) {
631 let mut incr_comp_session
= self.incr_comp_session
.borrow_mut();
633 if let IncrCompSession
::Active { .. }
= *incr_comp_session { }
else {
634 bug
!("Trying to finalize IncrCompSession `{:?}`", *incr_comp_session
)
637 // Note: This will also drop the lock file, thus unlocking the directory
638 *incr_comp_session
= IncrCompSession
::Finalized
{
639 session_directory
: new_directory_path
,
643 pub fn mark_incr_comp_session_as_invalid(&self) {
644 let mut incr_comp_session
= self.incr_comp_session
.borrow_mut();
646 let session_directory
= match *incr_comp_session
{
647 IncrCompSession
::Active { ref session_directory, .. }
=> {
648 session_directory
.clone()
650 _
=> bug
!("Trying to invalidate IncrCompSession `{:?}`",
654 // Note: This will also drop the lock file, thus unlocking the directory
655 *incr_comp_session
= IncrCompSession
::InvalidBecauseOfErrors
{
660 pub fn incr_comp_session_dir(&self) -> cell
::Ref
<PathBuf
> {
661 let incr_comp_session
= self.incr_comp_session
.borrow();
662 cell
::Ref
::map(incr_comp_session
, |incr_comp_session
| {
663 match *incr_comp_session
{
664 IncrCompSession
::NotInitialized
=> {
665 bug
!("Trying to get session directory from IncrCompSession `{:?}`",
668 IncrCompSession
::Active { ref session_directory, .. }
|
669 IncrCompSession
::Finalized { ref session_directory }
|
670 IncrCompSession
::InvalidBecauseOfErrors { ref session_directory }
=> {
677 pub fn incr_comp_session_dir_opt(&self) -> Option
<cell
::Ref
<PathBuf
>> {
678 if self.opts
.incremental
.is_some() {
679 Some(self.incr_comp_session_dir())
685 pub fn print_perf_stats(&self) {
686 println
!("Total time spent computing SVHs: {}",
687 duration_to_secs_str(self.perf_stats
.svh_time
.get()));
688 println
!("Total time spent computing incr. comp. hashes: {}",
689 duration_to_secs_str(self.perf_stats
.incr_comp_hashes_time
.get()));
690 println
!("Total number of incr. comp. hashes computed: {}",
691 self.perf_stats
.incr_comp_hashes_count
.get());
692 println
!("Total number of bytes hashed for incr. comp.: {}",
693 self.perf_stats
.incr_comp_bytes_hashed
.get());
694 if self.perf_stats
.incr_comp_hashes_count
.get() != 0 {
695 println
!("Average bytes hashed per incr. comp. HIR node: {}",
696 self.perf_stats
.incr_comp_bytes_hashed
.get() /
697 self.perf_stats
.incr_comp_hashes_count
.get());
699 println
!("Average bytes hashed per incr. comp. HIR node: N/A");
701 println
!("Total time spent computing symbol hashes: {}",
702 duration_to_secs_str(self.perf_stats
.symbol_hash_time
.get()));
703 println
!("Total time spent decoding DefPath tables: {}",
704 duration_to_secs_str(self.perf_stats
.decode_def_path_tables_time
.get()));
707 /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n.
708 /// This expends fuel if applicable, and records fuel if applicable.
709 pub fn consider_optimizing
<T
: Fn() -> String
>(&self, crate_name
: &str, msg
: T
) -> bool
{
711 match self.optimization_fuel_crate
{
712 Some(ref c
) if c
== crate_name
=> {
713 let fuel
= self.optimization_fuel_limit
.get();
715 if fuel
== 0 && !self.out_of_fuel
.get() {
716 println
!("optimization-fuel-exhausted: {}", msg());
717 self.out_of_fuel
.set(true);
719 self.optimization_fuel_limit
.set(fuel
-1);
724 match self.print_fuel_crate
{
725 Some(ref c
) if c
== crate_name
=> {
726 self.print_fuel
.set(self.print_fuel
.get()+1);
733 /// Returns the number of query threads that should be used for this
735 pub fn query_threads(&self) -> usize {
736 self.opts
.debugging_opts
.query_threads
.unwrap_or(1)
739 /// Returns the number of codegen units that should be used for this
741 pub fn codegen_units(&self) -> usize {
742 if let Some(n
) = self.opts
.cli_forced_codegen_units
{
745 if let Some(n
) = self.target
.target
.options
.default_codegen_units
{
749 // Why is 16 codegen units the default all the time?
751 // The main reason for enabling multiple codegen units by default is to
752 // leverage the ability for the trans backend to do translation and
753 // codegen in parallel. This allows us, especially for large crates, to
754 // make good use of all available resources on the machine once we've
755 // hit that stage of compilation. Large crates especially then often
756 // take a long time in trans/codegen and this helps us amortize that
759 // Note that a high number here doesn't mean that we'll be spawning a
760 // large number of threads in parallel. The backend of rustc contains
761 // global rate limiting through the `jobserver` crate so we'll never
762 // overload the system with too much work, but rather we'll only be
763 // optimizing when we're otherwise cooperating with other instances of
766 // Rather a high number here means that we should be able to keep a lot
767 // of idle cpus busy. By ensuring that no codegen unit takes *too* long
768 // to build we'll be guaranteed that all cpus will finish pretty closely
769 // to one another and we should make relatively optimal use of system
772 // Note that the main cost of codegen units is that it prevents LLVM
773 // from inlining across codegen units. Users in general don't have a lot
774 // of control over how codegen units are split up so it's our job in the
775 // compiler to ensure that undue performance isn't lost when using
776 // codegen units (aka we can't require everyone to slap `#[inline]` on
779 // If we're compiling at `-O0` then the number doesn't really matter too
780 // much because performance doesn't matter and inlining is ok to lose.
781 // In debug mode we just want to try to guarantee that no cpu is stuck
782 // doing work that could otherwise be farmed to others.
784 // In release mode, however (O1 and above) performance does indeed
785 // matter! To recover the loss in performance due to inlining we'll be
786 // enabling ThinLTO by default (the function for which is just below).
787 // This will ensure that we recover any inlining wins we otherwise lost
788 // through codegen unit partitioning.
792 // Ok that's a lot of words but the basic tl;dr; is that we want a high
793 // number here -- but not too high. Additionally we're "safe" to have it
794 // always at the same number at all optimization levels.
796 // As a result 16 was chosen here! Mostly because it was a power of 2
797 // and most benchmarks agreed it was roughly a local optimum. Not very
802 /// Returns whether ThinLTO is enabled for this compilation
803 pub fn thinlto(&self) -> bool
{
804 // If processing command line options determined that we're incompatible
805 // with ThinLTO (e.g. `-C lto --emit llvm-ir`) then return that option.
806 if let Some(enabled
) = self.opts
.cli_forced_thinlto
{
810 // If explicitly specified, use that with the next highest priority
811 if let Some(enabled
) = self.opts
.debugging_opts
.thinlto
{
815 // If LTO is enabled we right now unconditionally disable ThinLTO.
816 // This'll come at a later date! (full crate graph ThinLTO)
821 // If there's only one codegen unit or then there's no need for ThinLTO
822 // so just return false.
823 if self.codegen_units() == 1 {
827 // Right now ThinLTO isn't compatible with incremental compilation.
828 if self.opts
.incremental
.is_some() {
832 // Now we're in "defaults" territory. By default we enable ThinLTO for
833 // optimized compiles (anything greater than O0).
834 match self.opts
.optimize
{
835 config
::OptLevel
::No
=> false,
841 pub fn build_session(sopts
: config
::Options
,
842 local_crate_source_file
: Option
<PathBuf
>,
843 registry
: errors
::registry
::Registry
)
845 let file_path_mapping
= sopts
.file_path_mapping();
847 build_session_with_codemap(sopts
,
848 local_crate_source_file
,
850 Rc
::new(codemap
::CodeMap
::new(file_path_mapping
)),
854 pub fn build_session_with_codemap(sopts
: config
::Options
,
855 local_crate_source_file
: Option
<PathBuf
>,
856 registry
: errors
::registry
::Registry
,
857 codemap
: Rc
<codemap
::CodeMap
>,
858 emitter_dest
: Option
<Box
<Write
+ Send
>>)
860 // FIXME: This is not general enough to make the warning lint completely override
861 // normal diagnostic warnings, since the warning lint can also be denied and changed
862 // later via the source code.
863 let warnings_allow
= sopts
.lint_opts
865 .filter(|&&(ref key
, _
)| *key
== "warnings")
866 .map(|&(_
, ref level
)| *level
== lint
::Allow
)
869 let cap_lints_allow
= sopts
.lint_cap
.map_or(false, |cap
| cap
== lint
::Allow
);
871 let can_emit_warnings
= !(warnings_allow
|| cap_lints_allow
);
873 let treat_err_as_bug
= sopts
.debugging_opts
.treat_err_as_bug
;
875 let external_macro_backtrace
= sopts
.debugging_opts
.external_macro_backtrace
;
877 let emitter
: Box
<Emitter
> = match (sopts
.error_format
, emitter_dest
) {
878 (config
::ErrorOutputType
::HumanReadable(color_config
), None
) => {
879 Box
::new(EmitterWriter
::stderr(color_config
, Some(codemap
.clone()), false))
881 (config
::ErrorOutputType
::HumanReadable(_
), Some(dst
)) => {
882 Box
::new(EmitterWriter
::new(dst
, Some(codemap
.clone()), false))
884 (config
::ErrorOutputType
::Json(pretty
), None
) => {
885 Box
::new(JsonEmitter
::stderr(Some(registry
), codemap
.clone(), pretty
))
887 (config
::ErrorOutputType
::Json(pretty
), Some(dst
)) => {
888 Box
::new(JsonEmitter
::new(dst
, Some(registry
), codemap
.clone(), pretty
))
890 (config
::ErrorOutputType
::Short(color_config
), None
) => {
891 Box
::new(EmitterWriter
::stderr(color_config
, Some(codemap
.clone()), true))
893 (config
::ErrorOutputType
::Short(_
), Some(dst
)) => {
894 Box
::new(EmitterWriter
::new(dst
, Some(codemap
.clone()), true))
898 let diagnostic_handler
=
899 errors
::Handler
::with_emitter_and_flags(
901 errors
::HandlerFlags
{
904 external_macro_backtrace
,
905 .. Default
::default()
908 build_session_(sopts
,
909 local_crate_source_file
,
914 pub fn build_session_(sopts
: config
::Options
,
915 local_crate_source_file
: Option
<PathBuf
>,
916 span_diagnostic
: errors
::Handler
,
917 codemap
: Rc
<codemap
::CodeMap
>)
919 let host
= match Target
::search(config
::host_triple()) {
922 panic
!(span_diagnostic
.fatal(&format
!("Error loading host specification: {}", e
)));
925 let target_cfg
= config
::build_target_config(&sopts
, &span_diagnostic
);
927 let p_s
= parse
::ParseSess
::with_span_handler(span_diagnostic
, codemap
);
928 let default_sysroot
= match sopts
.maybe_sysroot
{
930 None
=> Some(filesearch
::get_or_default_sysroot())
933 let file_path_mapping
= sopts
.file_path_mapping();
935 let local_crate_source_file
= local_crate_source_file
.map(|path
| {
936 file_path_mapping
.map_prefix(path
).0
939 let optimization_fuel_crate
= sopts
.debugging_opts
.fuel
.as_ref().map(|i
| i
.0.clone());
940 let optimization_fuel_limit
= Cell
::new(sopts
.debugging_opts
.fuel
.as_ref()
941 .map(|i
| i
.1).unwrap_or(0));
942 let print_fuel_crate
= sopts
.debugging_opts
.print_fuel
.clone();
943 let print_fuel
= Cell
::new(0);
945 let working_dir
= match env
::current_dir() {
948 panic
!(p_s
.span_diagnostic
.fatal(&format
!("Current directory is invalid: {}", e
)))
951 let working_dir
= file_path_mapping
.map_prefix(working_dir
);
958 // For a library crate, this is always none
959 entry_fn
: RefCell
::new(None
),
960 entry_type
: Cell
::new(None
),
961 plugin_registrar_fn
: Cell
::new(None
),
962 derive_registrar_fn
: Cell
::new(None
),
964 local_crate_source_file
,
966 lint_store
: RefCell
::new(lint
::LintStore
::new()),
967 buffered_lints
: RefCell
::new(Some(lint
::LintBuffer
::new())),
968 one_time_diagnostics
: RefCell
::new(FxHashSet()),
969 plugin_llvm_passes
: RefCell
::new(Vec
::new()),
970 plugin_attributes
: RefCell
::new(Vec
::new()),
971 crate_types
: RefCell
::new(Vec
::new()),
972 dependency_formats
: RefCell
::new(FxHashMap()),
973 crate_disambiguator
: RefCell
::new(None
),
974 features
: RefCell
::new(feature_gate
::Features
::new()),
975 recursion_limit
: Cell
::new(64),
976 type_length_limit
: Cell
::new(1048576),
977 next_node_id
: Cell
::new(NodeId
::new(1)),
978 injected_allocator
: Cell
::new(None
),
979 allocator_kind
: Cell
::new(None
),
980 injected_panic_runtime
: Cell
::new(None
),
981 imported_macro_spans
: RefCell
::new(HashMap
::new()),
982 incr_comp_session
: RefCell
::new(IncrCompSession
::NotInitialized
),
983 perf_stats
: PerfStats
{
984 svh_time
: Cell
::new(Duration
::from_secs(0)),
985 incr_comp_hashes_time
: Cell
::new(Duration
::from_secs(0)),
986 incr_comp_hashes_count
: Cell
::new(0),
987 incr_comp_bytes_hashed
: Cell
::new(0),
988 symbol_hash_time
: Cell
::new(Duration
::from_secs(0)),
989 decode_def_path_tables_time
: Cell
::new(Duration
::from_secs(0)),
991 code_stats
: RefCell
::new(CodeStats
::new()),
992 optimization_fuel_crate
,
993 optimization_fuel_limit
,
996 out_of_fuel
: Cell
::new(false),
997 // Note that this is unsafe because it may misinterpret file descriptors
998 // on Unix as jobserver file descriptors. We hopefully execute this near
999 // the beginning of the process though to ensure we don't get false
1000 // positives, or in other words we try to execute this before we open
1001 // any file descriptors ourselves.
1003 // Also note that we stick this in a global because there could be
1004 // multiple `Session` instances in this process, and the jobserver is
1006 jobserver_from_env
: unsafe {
1007 static mut GLOBAL_JOBSERVER
: *mut Option
<Client
> = 0 as *mut _
;
1008 static INIT
: Once
= ONCE_INIT
;
1010 GLOBAL_JOBSERVER
= Box
::into_raw(Box
::new(Client
::from_env()));
1012 (*GLOBAL_JOBSERVER
).clone()
1014 has_global_allocator
: Cell
::new(false),
1020 /// Hash value constructed out of all the `-C metadata` arguments passed to the
1021 /// compiler. Together with the crate-name forms a unique global identifier for
1023 #[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, RustcEncodable, RustcDecodable)]
1024 pub struct CrateDisambiguator(Fingerprint
);
1026 impl CrateDisambiguator
{
1027 pub fn to_fingerprint(self) -> Fingerprint
{
1032 impl From
<Fingerprint
> for CrateDisambiguator
{
1033 fn from(fingerprint
: Fingerprint
) -> CrateDisambiguator
{
1034 CrateDisambiguator(fingerprint
)
1038 impl_stable_hash_for
!(tuple_struct CrateDisambiguator { fingerprint }
);
1040 /// Holds data on the current incremental compilation session, if there is one.
1042 pub enum IncrCompSession
{
1043 /// This is the state the session will be in until the incr. comp. dir is
1046 /// This is the state during which the session directory is private and can
1049 session_directory
: PathBuf
,
1050 lock_file
: flock
::Lock
,
1051 load_dep_graph
: bool
,
1053 /// This is the state after the session directory has been finalized. In this
1054 /// state, the contents of the directory must not be modified any more.
1056 session_directory
: PathBuf
,
1058 /// This is an error state that is reached when some compilation error has
1059 /// occurred. It indicates that the contents of the session directory must
1060 /// not be used, since they might be invalid.
1061 InvalidBecauseOfErrors
{
1062 session_directory
: PathBuf
,
1066 pub fn early_error(output
: config
::ErrorOutputType
, msg
: &str) -> ! {
1067 let emitter
: Box
<Emitter
> = match output
{
1068 config
::ErrorOutputType
::HumanReadable(color_config
) => {
1069 Box
::new(EmitterWriter
::stderr(color_config
, None
, false))
1071 config
::ErrorOutputType
::Json(pretty
) => Box
::new(JsonEmitter
::basic(pretty
)),
1072 config
::ErrorOutputType
::Short(color_config
) => {
1073 Box
::new(EmitterWriter
::stderr(color_config
, None
, true))
1076 let handler
= errors
::Handler
::with_emitter(true, false, emitter
);
1077 handler
.emit(&MultiSpan
::new(), msg
, errors
::Level
::Fatal
);
1078 panic
!(errors
::FatalError
);
1081 pub fn early_warn(output
: config
::ErrorOutputType
, msg
: &str) {
1082 let emitter
: Box
<Emitter
> = match output
{
1083 config
::ErrorOutputType
::HumanReadable(color_config
) => {
1084 Box
::new(EmitterWriter
::stderr(color_config
, None
, false))
1086 config
::ErrorOutputType
::Json(pretty
) => Box
::new(JsonEmitter
::basic(pretty
)),
1087 config
::ErrorOutputType
::Short(color_config
) => {
1088 Box
::new(EmitterWriter
::stderr(color_config
, None
, true))
1091 let handler
= errors
::Handler
::with_emitter(true, false, emitter
);
1092 handler
.emit(&MultiSpan
::new(), msg
, errors
::Level
::Warning
);
1095 #[derive(Copy, Clone, Debug)]
1096 pub enum CompileIncomplete
{
1098 Errored(ErrorReported
)
1100 impl From
<ErrorReported
> for CompileIncomplete
{
1101 fn from(err
: ErrorReported
) -> CompileIncomplete
{
1102 CompileIncomplete
::Errored(err
)
1105 pub type CompileResult
= Result
<(), CompileIncomplete
>;
1107 pub fn compile_result_from_err_count(err_count
: usize) -> CompileResult
{
1111 Err(CompileIncomplete
::Errored(ErrorReported
))
1117 pub fn bug_fmt(file
: &'
static str, line
: u32, args
: fmt
::Arguments
) -> ! {
1118 // this wrapper mostly exists so I don't have to write a fully
1119 // qualified path of None::<Span> inside the bug!() macro definition
1120 opt_span_bug_fmt(file
, line
, None
::<Span
>, args
);
1125 pub fn span_bug_fmt
<S
: Into
<MultiSpan
>>(file
: &'
static str,
1128 args
: fmt
::Arguments
) -> ! {
1129 opt_span_bug_fmt(file
, line
, Some(span
), args
);
1132 fn opt_span_bug_fmt
<S
: Into
<MultiSpan
>>(file
: &'
static str,
1135 args
: fmt
::Arguments
) -> ! {
1136 tls
::with_opt(move |tcx
| {
1137 let msg
= format
!("{}:{}: {}", file
, line
, args
);
1139 (Some(tcx
), Some(span
)) => tcx
.sess
.diagnostic().span_bug(span
, &msg
),
1140 (Some(tcx
), None
) => tcx
.sess
.diagnostic().bug(&msg
),
1141 (None
, _
) => panic
!(msg
)