]> git.lizzy.rs Git - rust.git/blob - src/librustc/session/mod.rs
rustdoc: pretty-print Unevaluated expressions in types.
[rust.git] / src / librustc / session / mod.rs
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.
4 //
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.
10
11 pub use self::code_stats::{CodeStats, DataTypeKind, FieldInfo};
12 pub use self::code_stats::{SizeKind, TypeSizeInfo, VariantInfo};
13
14 use dep_graph::DepGraph;
15 use hir::def_id::{CrateNum, DefIndex};
16
17 use lint;
18 use middle::allocator::AllocatorKind;
19 use middle::dependency_format;
20 use session::search_paths::PathKind;
21 use session::config::DebugInfoLevel;
22 use ty::tls;
23 use util::nodemap::{FxHashMap, FxHashSet};
24 use util::common::{duration_to_secs_str, ErrorReported};
25
26 use syntax::ast::NodeId;
27 use errors::{self, DiagnosticBuilder};
28 use errors::emitter::{Emitter, EmitterWriter};
29 use syntax::json::JsonEmitter;
30 use syntax::feature_gate;
31 use syntax::parse;
32 use syntax::parse::ParseSess;
33 use syntax::symbol::Symbol;
34 use syntax::{ast, codemap};
35 use syntax::feature_gate::AttributeType;
36 use syntax_pos::{Span, MultiSpan};
37
38 use rustc_back::{LinkerFlavor, PanicStrategy};
39 use rustc_back::target::Target;
40 use rustc_data_structures::flock;
41 use jobserver::Client;
42
43 use std::cell::{self, Cell, RefCell};
44 use std::collections::HashMap;
45 use std::env;
46 use std::fmt;
47 use std::io::Write;
48 use std::path::{Path, PathBuf};
49 use std::rc::Rc;
50 use std::sync::{Once, ONCE_INIT};
51 use std::time::Duration;
52
53 mod code_stats;
54 pub mod config;
55 pub mod filesearch;
56 pub mod search_paths;
57
58 // Represents the data associated with a compilation
59 // session for a single crate.
60 pub struct Session {
61     pub dep_graph: DepGraph,
62     pub target: config::Config,
63     pub host: Target,
64     pub opts: config::Options,
65     pub parse_sess: ParseSess,
66     // For a library crate, this is always none
67     pub entry_fn: RefCell<Option<(NodeId, Span)>>,
68     pub entry_type: Cell<Option<config::EntryFnType>>,
69     pub plugin_registrar_fn: Cell<Option<ast::NodeId>>,
70     pub derive_registrar_fn: Cell<Option<ast::NodeId>>,
71     pub default_sysroot: Option<PathBuf>,
72     // The name of the root source file of the crate, in the local file system.
73     // The path is always expected to be absolute. `None` means that there is no
74     // source file.
75     pub local_crate_source_file: Option<String>,
76     // The directory the compiler has been executed in plus a flag indicating
77     // if the value stored here has been affected by path remapping.
78     pub working_dir: (String, bool),
79     pub lint_store: RefCell<lint::LintStore>,
80     pub buffered_lints: RefCell<Option<lint::LintBuffer>>,
81     /// Set of (LintId, Option<Span>, message) tuples tracking lint
82     /// (sub)diagnostics that have been set once, but should not be set again,
83     /// in order to avoid redundantly verbose output (Issue #24690).
84     pub one_time_diagnostics: RefCell<FxHashSet<(lint::LintId, Option<Span>, String)>>,
85     pub plugin_llvm_passes: RefCell<Vec<String>>,
86     pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
87     pub crate_types: RefCell<Vec<config::CrateType>>,
88     pub dependency_formats: RefCell<dependency_format::Dependencies>,
89     // The crate_disambiguator is constructed out of all the `-C metadata`
90     // arguments passed to the compiler. Its value together with the crate-name
91     // forms a unique global identifier for the crate. It is used to allow
92     // multiple crates with the same name to coexist. See the
93     // trans::back::symbol_names module for more information.
94     pub crate_disambiguator: RefCell<Symbol>,
95     pub features: RefCell<feature_gate::Features>,
96
97     /// The maximum recursion limit for potentially infinitely recursive
98     /// operations such as auto-dereference and monomorphization.
99     pub recursion_limit: Cell<usize>,
100
101     /// The maximum length of types during monomorphization.
102     pub type_length_limit: Cell<usize>,
103
104     /// The metadata::creader module may inject an allocator/panic_runtime
105     /// dependency if it didn't already find one, and this tracks what was
106     /// injected.
107     pub injected_allocator: Cell<Option<CrateNum>>,
108     pub allocator_kind: Cell<Option<AllocatorKind>>,
109     pub injected_panic_runtime: Cell<Option<CrateNum>>,
110
111     /// Map from imported macro spans (which consist of
112     /// the localized span for the macro body) to the
113     /// macro name and definition span in the source crate.
114     pub imported_macro_spans: RefCell<HashMap<Span, (String, Span)>>,
115
116     incr_comp_session: RefCell<IncrCompSession>,
117
118     /// Some measurements that are being gathered during compilation.
119     pub perf_stats: PerfStats,
120
121     /// Data about code being compiled, gathered during compilation.
122     pub code_stats: RefCell<CodeStats>,
123
124     next_node_id: Cell<ast::NodeId>,
125
126     /// If -zfuel=crate=n is specified, Some(crate).
127     optimization_fuel_crate: Option<String>,
128     /// If -zfuel=crate=n is specified, initially set to n. Otherwise 0.
129     optimization_fuel_limit: Cell<u64>,
130     /// We're rejecting all further optimizations.
131     out_of_fuel: Cell<bool>,
132
133     // The next two are public because the driver needs to read them.
134
135     /// If -zprint-fuel=crate, Some(crate).
136     pub print_fuel_crate: Option<String>,
137     /// Always set to zero and incremented so that we can print fuel expended by a crate.
138     pub print_fuel: Cell<u64>,
139
140     /// Loaded up early on in the initialization of this `Session` to avoid
141     /// false positives about a job server in our environment.
142     pub jobserver_from_env: Option<Client>,
143
144     /// Metadata about the allocators for the current crate being compiled
145     pub has_global_allocator: Cell<bool>,
146 }
147
148 pub struct PerfStats {
149     // The accumulated time needed for computing the SVH of the crate
150     pub svh_time: Cell<Duration>,
151     // The accumulated time spent on computing incr. comp. hashes
152     pub incr_comp_hashes_time: Cell<Duration>,
153     // The number of incr. comp. hash computations performed
154     pub incr_comp_hashes_count: Cell<u64>,
155     // The number of bytes hashed when computing ICH values
156     pub incr_comp_bytes_hashed: Cell<u64>,
157     // The accumulated time spent on computing symbol hashes
158     pub symbol_hash_time: Cell<Duration>,
159     // The accumulated time spent decoding def path tables from metadata
160     pub decode_def_path_tables_time: Cell<Duration>,
161 }
162
163 /// Enum to support dispatch of one-time diagnostics (in Session.diag_once)
164 enum DiagnosticBuilderMethod {
165     Note,
166     SpanNote,
167     // add more variants as needed to support one-time diagnostics
168 }
169
170 impl Session {
171     pub fn local_crate_disambiguator(&self) -> Symbol {
172         *self.crate_disambiguator.borrow()
173     }
174     pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
175                                                     sp: S,
176                                                     msg: &str)
177                                                     -> DiagnosticBuilder<'a> {
178         self.diagnostic().struct_span_warn(sp, msg)
179     }
180     pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self,
181                                                               sp: S,
182                                                               msg: &str,
183                                                               code: &str)
184                                                               -> DiagnosticBuilder<'a> {
185         self.diagnostic().struct_span_warn_with_code(sp, msg, code)
186     }
187     pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a>  {
188         self.diagnostic().struct_warn(msg)
189     }
190     pub fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self,
191                                                    sp: S,
192                                                    msg: &str)
193                                                    -> DiagnosticBuilder<'a> {
194         self.diagnostic().struct_span_err(sp, msg)
195     }
196     pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
197                                                              sp: S,
198                                                              msg: &str,
199                                                              code: &str)
200                                                              -> DiagnosticBuilder<'a> {
201         self.diagnostic().struct_span_err_with_code(sp, msg, code)
202     }
203     // FIXME: This method should be removed (every error should have an associated error code).
204     pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
205         self.diagnostic().struct_err(msg)
206     }
207     pub fn struct_err_with_code<'a>(&'a self, msg: &str, code: &str) -> DiagnosticBuilder<'a> {
208         self.diagnostic().struct_err_with_code(msg, code)
209     }
210     pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
211                                                      sp: S,
212                                                      msg: &str)
213                                                      -> DiagnosticBuilder<'a> {
214         self.diagnostic().struct_span_fatal(sp, msg)
215     }
216     pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self,
217                                                                sp: S,
218                                                                msg: &str,
219                                                                code: &str)
220                                                                -> DiagnosticBuilder<'a> {
221         self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
222     }
223     pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a>  {
224         self.diagnostic().struct_fatal(msg)
225     }
226
227     pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
228         panic!(self.diagnostic().span_fatal(sp, msg))
229     }
230     pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) -> ! {
231         panic!(self.diagnostic().span_fatal_with_code(sp, msg, code))
232     }
233     pub fn fatal(&self, msg: &str) -> ! {
234         panic!(self.diagnostic().fatal(msg))
235     }
236     pub fn span_err_or_warn<S: Into<MultiSpan>>(&self, is_warning: bool, sp: S, msg: &str) {
237         if is_warning {
238             self.span_warn(sp, msg);
239         } else {
240             self.span_err(sp, msg);
241         }
242     }
243     pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
244         self.diagnostic().span_err(sp, msg)
245     }
246     pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
247         self.diagnostic().span_err_with_code(sp, &msg, code)
248     }
249     pub fn err(&self, msg: &str) {
250         self.diagnostic().err(msg)
251     }
252     pub fn err_count(&self) -> usize {
253         self.diagnostic().err_count()
254     }
255     pub fn has_errors(&self) -> bool {
256         self.diagnostic().has_errors()
257     }
258     pub fn abort_if_errors(&self) {
259         self.diagnostic().abort_if_errors();
260     }
261     pub fn compile_status(&self) -> Result<(), CompileIncomplete> {
262         compile_result_from_err_count(self.err_count())
263     }
264     pub fn track_errors<F, T>(&self, f: F) -> Result<T, ErrorReported>
265         where F: FnOnce() -> T
266     {
267         let old_count = self.err_count();
268         let result = f();
269         let errors = self.err_count() - old_count;
270         if errors == 0 {
271             Ok(result)
272         } else {
273             Err(ErrorReported)
274         }
275     }
276     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
277         self.diagnostic().span_warn(sp, msg)
278     }
279     pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
280         self.diagnostic().span_warn_with_code(sp, msg, code)
281     }
282     pub fn warn(&self, msg: &str) {
283         self.diagnostic().warn(msg)
284     }
285     pub fn opt_span_warn<S: Into<MultiSpan>>(&self, opt_sp: Option<S>, msg: &str) {
286         match opt_sp {
287             Some(sp) => self.span_warn(sp, msg),
288             None => self.warn(msg),
289         }
290     }
291     /// Delay a span_bug() call until abort_if_errors()
292     pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
293         self.diagnostic().delay_span_bug(sp, msg)
294     }
295     pub fn note_without_error(&self, msg: &str) {
296         self.diagnostic().note_without_error(msg)
297     }
298     pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
299         self.diagnostic().span_note_without_error(sp, msg)
300     }
301     pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
302         self.diagnostic().span_unimpl(sp, msg)
303     }
304     pub fn unimpl(&self, msg: &str) -> ! {
305         self.diagnostic().unimpl(msg)
306     }
307
308     pub fn buffer_lint<S: Into<MultiSpan>>(&self,
309                                            lint: &'static lint::Lint,
310                                            id: ast::NodeId,
311                                            sp: S,
312                                            msg: &str) {
313         match *self.buffered_lints.borrow_mut() {
314             Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(), msg),
315             None => bug!("can't buffer lints after HIR lowering"),
316         }
317     }
318
319     pub fn reserve_node_ids(&self, count: usize) -> ast::NodeId {
320         let id = self.next_node_id.get();
321
322         match id.as_usize().checked_add(count) {
323             Some(next) => {
324                 self.next_node_id.set(ast::NodeId::new(next));
325             }
326             None => bug!("Input too large, ran out of node ids!")
327         }
328
329         id
330     }
331     pub fn next_node_id(&self) -> NodeId {
332         self.reserve_node_ids(1)
333     }
334     pub fn diagnostic<'a>(&'a self) -> &'a errors::Handler {
335         &self.parse_sess.span_diagnostic
336     }
337
338     /// Analogous to calling methods on the given `DiagnosticBuilder`, but
339     /// deduplicates on lint ID, span (if any), and message for this `Session`
340     /// if we're not outputting in JSON mode.
341     fn diag_once<'a, 'b>(&'a self,
342                          diag_builder: &'b mut DiagnosticBuilder<'a>,
343                          method: DiagnosticBuilderMethod,
344                          lint: &'static lint::Lint, message: &str, span: Option<Span>) {
345         let mut do_method = || {
346             match method {
347                 DiagnosticBuilderMethod::Note => {
348                     diag_builder.note(message);
349                 },
350                 DiagnosticBuilderMethod::SpanNote => {
351                     diag_builder.span_note(span.expect("span_note expects a span"), message);
352                 }
353             }
354         };
355
356         match self.opts.error_format {
357             // when outputting JSON for tool consumption, the tool might want
358             // the duplicates
359             config::ErrorOutputType::Json => {
360                 do_method()
361             },
362             _ => {
363                 let lint_id = lint::LintId::of(lint);
364                 let id_span_message = (lint_id, span, message.to_owned());
365                 let fresh = self.one_time_diagnostics.borrow_mut().insert(id_span_message);
366                 if fresh {
367                     do_method()
368                 }
369             }
370         }
371     }
372
373     pub fn diag_span_note_once<'a, 'b>(&'a self,
374                                        diag_builder: &'b mut DiagnosticBuilder<'a>,
375                                        lint: &'static lint::Lint, span: Span, message: &str) {
376         self.diag_once(diag_builder, DiagnosticBuilderMethod::SpanNote, lint, message, Some(span));
377     }
378
379     pub fn diag_note_once<'a, 'b>(&'a self,
380                                   diag_builder: &'b mut DiagnosticBuilder<'a>,
381                                   lint: &'static lint::Lint, message: &str) {
382         self.diag_once(diag_builder, DiagnosticBuilderMethod::Note, lint, message, None);
383     }
384
385     pub fn codemap<'a>(&'a self) -> &'a codemap::CodeMap {
386         self.parse_sess.codemap()
387     }
388     pub fn verbose(&self) -> bool { self.opts.debugging_opts.verbose }
389     pub fn time_passes(&self) -> bool { self.opts.debugging_opts.time_passes }
390     pub fn profile_queries(&self) -> bool {
391         self.opts.debugging_opts.profile_queries ||
392             self.opts.debugging_opts.profile_queries_and_keys
393     }
394     pub fn profile_queries_and_keys(&self) -> bool {
395         self.opts.debugging_opts.profile_queries_and_keys
396     }
397     pub fn count_llvm_insns(&self) -> bool {
398         self.opts.debugging_opts.count_llvm_insns
399     }
400     pub fn time_llvm_passes(&self) -> bool {
401         self.opts.debugging_opts.time_llvm_passes
402     }
403     pub fn trans_stats(&self) -> bool { self.opts.debugging_opts.trans_stats }
404     pub fn meta_stats(&self) -> bool { self.opts.debugging_opts.meta_stats }
405     pub fn asm_comments(&self) -> bool { self.opts.debugging_opts.asm_comments }
406     pub fn no_verify(&self) -> bool { self.opts.debugging_opts.no_verify }
407     pub fn borrowck_stats(&self) -> bool { self.opts.debugging_opts.borrowck_stats }
408     pub fn print_llvm_passes(&self) -> bool {
409         self.opts.debugging_opts.print_llvm_passes
410     }
411     pub fn emit_end_regions(&self) -> bool {
412         self.opts.debugging_opts.emit_end_regions ||
413             (self.opts.debugging_opts.mir_emit_validate > 0)
414     }
415     pub fn lto(&self) -> bool {
416         self.opts.cg.lto
417     }
418     /// Returns the panic strategy for this compile session. If the user explicitly selected one
419     /// using '-C panic', use that, otherwise use the panic strategy defined by the target.
420     pub fn panic_strategy(&self) -> PanicStrategy {
421         self.opts.cg.panic.unwrap_or(self.target.target.options.panic_strategy)
422     }
423     pub fn linker_flavor(&self) -> LinkerFlavor {
424         self.opts.debugging_opts.linker_flavor.unwrap_or(self.target.target.linker_flavor)
425     }
426     pub fn no_landing_pads(&self) -> bool {
427         self.opts.debugging_opts.no_landing_pads || self.panic_strategy() == PanicStrategy::Abort
428     }
429     pub fn unstable_options(&self) -> bool {
430         self.opts.debugging_opts.unstable_options
431     }
432     pub fn nonzeroing_move_hints(&self) -> bool {
433         self.opts.debugging_opts.enable_nonzeroing_move_hints
434     }
435     pub fn overflow_checks(&self) -> bool {
436         self.opts.cg.overflow_checks
437             .or(self.opts.debugging_opts.force_overflow_checks)
438             .unwrap_or(self.opts.debug_assertions)
439     }
440
441     pub fn crt_static(&self) -> bool {
442         // If the target does not opt in to crt-static support, use its default.
443         if self.target.target.options.crt_static_respected {
444             self.crt_static_feature()
445         } else {
446             self.target.target.options.crt_static_default
447         }
448     }
449
450     pub fn crt_static_feature(&self) -> bool {
451         let requested_features = self.opts.cg.target_feature.split(',');
452         let found_negative = requested_features.clone().any(|r| r == "-crt-static");
453         let found_positive = requested_features.clone().any(|r| r == "+crt-static");
454
455         // If the target we're compiling for requests a static crt by default,
456         // then see if the `-crt-static` feature was passed to disable that.
457         // Otherwise if we don't have a static crt by default then see if the
458         // `+crt-static` feature was passed.
459         if self.target.target.options.crt_static_default {
460             !found_negative
461         } else {
462             found_positive
463         }
464     }
465
466     pub fn must_not_eliminate_frame_pointers(&self) -> bool {
467         self.opts.debuginfo != DebugInfoLevel::NoDebugInfo ||
468         !self.target.target.options.eliminate_frame_pointer
469     }
470
471     /// Returns the symbol name for the registrar function,
472     /// given the crate Svh and the function DefIndex.
473     pub fn generate_plugin_registrar_symbol(&self, disambiguator: Symbol, index: DefIndex)
474                                             -> String {
475         format!("__rustc_plugin_registrar__{}_{}", disambiguator, index.as_usize())
476     }
477
478     pub fn generate_derive_registrar_symbol(&self, disambiguator: Symbol, index: DefIndex)
479                                             -> String {
480         format!("__rustc_derive_registrar__{}_{}", disambiguator, index.as_usize())
481     }
482
483     pub fn sysroot<'a>(&'a self) -> &'a Path {
484         match self.opts.maybe_sysroot {
485             Some (ref sysroot) => sysroot,
486             None => self.default_sysroot.as_ref()
487                         .expect("missing sysroot and default_sysroot in Session")
488         }
489     }
490     pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch {
491         filesearch::FileSearch::new(self.sysroot(),
492                                     &self.opts.target_triple,
493                                     &self.opts.search_paths,
494                                     kind)
495     }
496     pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch {
497         filesearch::FileSearch::new(
498             self.sysroot(),
499             config::host_triple(),
500             &self.opts.search_paths,
501             kind)
502     }
503
504     pub fn init_incr_comp_session(&self,
505                                   session_dir: PathBuf,
506                                   lock_file: flock::Lock) {
507         let mut incr_comp_session = self.incr_comp_session.borrow_mut();
508
509         if let IncrCompSession::NotInitialized = *incr_comp_session { } else {
510             bug!("Trying to initialize IncrCompSession `{:?}`", *incr_comp_session)
511         }
512
513         *incr_comp_session = IncrCompSession::Active {
514             session_directory: session_dir,
515             lock_file,
516         };
517     }
518
519     pub fn finalize_incr_comp_session(&self, new_directory_path: PathBuf) {
520         let mut incr_comp_session = self.incr_comp_session.borrow_mut();
521
522         if let IncrCompSession::Active { .. } = *incr_comp_session { } else {
523             bug!("Trying to finalize IncrCompSession `{:?}`", *incr_comp_session)
524         }
525
526         // Note: This will also drop the lock file, thus unlocking the directory
527         *incr_comp_session = IncrCompSession::Finalized {
528             session_directory: new_directory_path,
529         };
530     }
531
532     pub fn mark_incr_comp_session_as_invalid(&self) {
533         let mut incr_comp_session = self.incr_comp_session.borrow_mut();
534
535         let session_directory = match *incr_comp_session {
536             IncrCompSession::Active { ref session_directory, .. } => {
537                 session_directory.clone()
538             }
539             _ => bug!("Trying to invalidate IncrCompSession `{:?}`",
540                       *incr_comp_session),
541         };
542
543         // Note: This will also drop the lock file, thus unlocking the directory
544         *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors {
545             session_directory,
546         };
547     }
548
549     pub fn incr_comp_session_dir(&self) -> cell::Ref<PathBuf> {
550         let incr_comp_session = self.incr_comp_session.borrow();
551         cell::Ref::map(incr_comp_session, |incr_comp_session| {
552             match *incr_comp_session {
553                 IncrCompSession::NotInitialized => {
554                     bug!("Trying to get session directory from IncrCompSession `{:?}`",
555                         *incr_comp_session)
556                 }
557                 IncrCompSession::Active { ref session_directory, .. } |
558                 IncrCompSession::Finalized { ref session_directory } |
559                 IncrCompSession::InvalidBecauseOfErrors { ref session_directory } => {
560                     session_directory
561                 }
562             }
563         })
564     }
565
566     pub fn incr_comp_session_dir_opt(&self) -> Option<cell::Ref<PathBuf>> {
567         if self.opts.incremental.is_some() {
568             Some(self.incr_comp_session_dir())
569         } else {
570             None
571         }
572     }
573
574     pub fn print_perf_stats(&self) {
575         println!("Total time spent computing SVHs:               {}",
576                  duration_to_secs_str(self.perf_stats.svh_time.get()));
577         println!("Total time spent computing incr. comp. hashes: {}",
578                  duration_to_secs_str(self.perf_stats.incr_comp_hashes_time.get()));
579         println!("Total number of incr. comp. hashes computed:   {}",
580                  self.perf_stats.incr_comp_hashes_count.get());
581         println!("Total number of bytes hashed for incr. comp.:  {}",
582                  self.perf_stats.incr_comp_bytes_hashed.get());
583         println!("Average bytes hashed per incr. comp. HIR node: {}",
584                  self.perf_stats.incr_comp_bytes_hashed.get() /
585                  self.perf_stats.incr_comp_hashes_count.get());
586         println!("Total time spent computing symbol hashes:      {}",
587                  duration_to_secs_str(self.perf_stats.symbol_hash_time.get()));
588         println!("Total time spent decoding DefPath tables:      {}",
589                  duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get()));
590     }
591
592     /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n.
593     /// This expends fuel if applicable, and records fuel if applicable.
594     pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -> bool {
595         let mut ret = true;
596         match self.optimization_fuel_crate {
597             Some(ref c) if c == crate_name => {
598                 let fuel = self.optimization_fuel_limit.get();
599                 ret = fuel != 0;
600                 if fuel == 0 && !self.out_of_fuel.get() {
601                     println!("optimization-fuel-exhausted: {}", msg());
602                     self.out_of_fuel.set(true);
603                 } else if fuel > 0 {
604                     self.optimization_fuel_limit.set(fuel-1);
605                 }
606             }
607             _ => {}
608         }
609         match self.print_fuel_crate {
610             Some(ref c) if c == crate_name=> {
611                 self.print_fuel.set(self.print_fuel.get()+1);
612             },
613             _ => {}
614         }
615         ret
616     }
617 }
618
619 pub fn build_session(sopts: config::Options,
620                      dep_graph: &DepGraph,
621                      local_crate_source_file: Option<PathBuf>,
622                      registry: errors::registry::Registry)
623                      -> Session {
624     let file_path_mapping = sopts.file_path_mapping();
625
626     build_session_with_codemap(sopts,
627                                dep_graph,
628                                local_crate_source_file,
629                                registry,
630                                Rc::new(codemap::CodeMap::new(file_path_mapping)),
631                                None)
632 }
633
634 pub fn build_session_with_codemap(sopts: config::Options,
635                                   dep_graph: &DepGraph,
636                                   local_crate_source_file: Option<PathBuf>,
637                                   registry: errors::registry::Registry,
638                                   codemap: Rc<codemap::CodeMap>,
639                                   emitter_dest: Option<Box<Write + Send>>)
640                                   -> Session {
641     // FIXME: This is not general enough to make the warning lint completely override
642     // normal diagnostic warnings, since the warning lint can also be denied and changed
643     // later via the source code.
644     let can_print_warnings = sopts.lint_opts
645         .iter()
646         .filter(|&&(ref key, _)| *key == "warnings")
647         .map(|&(_, ref level)| *level != lint::Allow)
648         .last()
649         .unwrap_or(true);
650     let treat_err_as_bug = sopts.debugging_opts.treat_err_as_bug;
651
652     let emitter: Box<Emitter> = match (sopts.error_format, emitter_dest) {
653         (config::ErrorOutputType::HumanReadable(color_config), None) => {
654             Box::new(EmitterWriter::stderr(color_config,
655                                            Some(codemap.clone())))
656         }
657         (config::ErrorOutputType::HumanReadable(_), Some(dst)) => {
658             Box::new(EmitterWriter::new(dst,
659                                         Some(codemap.clone())))
660         }
661         (config::ErrorOutputType::Json, None) => {
662             Box::new(JsonEmitter::stderr(Some(registry), codemap.clone()))
663         }
664         (config::ErrorOutputType::Json, Some(dst)) => {
665             Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone()))
666         }
667     };
668
669     let diagnostic_handler =
670         errors::Handler::with_emitter(can_print_warnings,
671                                       treat_err_as_bug,
672                                       emitter);
673
674     build_session_(sopts,
675                    dep_graph,
676                    local_crate_source_file,
677                    diagnostic_handler,
678                    codemap)
679 }
680
681 pub fn build_session_(sopts: config::Options,
682                       dep_graph: &DepGraph,
683                       local_crate_source_file: Option<PathBuf>,
684                       span_diagnostic: errors::Handler,
685                       codemap: Rc<codemap::CodeMap>)
686                       -> Session {
687     let host = match Target::search(config::host_triple()) {
688         Ok(t) => t,
689         Err(e) => {
690             panic!(span_diagnostic.fatal(&format!("Error loading host specification: {}", e)));
691         }
692     };
693     let target_cfg = config::build_target_config(&sopts, &span_diagnostic);
694
695     let p_s = parse::ParseSess::with_span_handler(span_diagnostic, codemap);
696     let default_sysroot = match sopts.maybe_sysroot {
697         Some(_) => None,
698         None => Some(filesearch::get_or_default_sysroot())
699     };
700
701     let file_path_mapping = sopts.file_path_mapping();
702
703     // Make the path absolute, if necessary
704     let local_crate_source_file = local_crate_source_file.map(|path| {
705         file_path_mapping.map_prefix(path.to_string_lossy().into_owned()).0
706     });
707
708     let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone());
709     let optimization_fuel_limit = Cell::new(sopts.debugging_opts.fuel.as_ref()
710         .map(|i| i.1).unwrap_or(0));
711     let print_fuel_crate = sopts.debugging_opts.print_fuel.clone();
712     let print_fuel = Cell::new(0);
713
714     let working_dir = env::current_dir().unwrap().to_string_lossy().into_owned();
715     let working_dir = file_path_mapping.map_prefix(working_dir);
716
717     let sess = Session {
718         dep_graph: dep_graph.clone(),
719         target: target_cfg,
720         host,
721         opts: sopts,
722         parse_sess: p_s,
723         // For a library crate, this is always none
724         entry_fn: RefCell::new(None),
725         entry_type: Cell::new(None),
726         plugin_registrar_fn: Cell::new(None),
727         derive_registrar_fn: Cell::new(None),
728         default_sysroot,
729         local_crate_source_file,
730         working_dir,
731         lint_store: RefCell::new(lint::LintStore::new()),
732         buffered_lints: RefCell::new(Some(lint::LintBuffer::new())),
733         one_time_diagnostics: RefCell::new(FxHashSet()),
734         plugin_llvm_passes: RefCell::new(Vec::new()),
735         plugin_attributes: RefCell::new(Vec::new()),
736         crate_types: RefCell::new(Vec::new()),
737         dependency_formats: RefCell::new(FxHashMap()),
738         crate_disambiguator: RefCell::new(Symbol::intern("")),
739         features: RefCell::new(feature_gate::Features::new()),
740         recursion_limit: Cell::new(64),
741         type_length_limit: Cell::new(1048576),
742         next_node_id: Cell::new(NodeId::new(1)),
743         injected_allocator: Cell::new(None),
744         allocator_kind: Cell::new(None),
745         injected_panic_runtime: Cell::new(None),
746         imported_macro_spans: RefCell::new(HashMap::new()),
747         incr_comp_session: RefCell::new(IncrCompSession::NotInitialized),
748         perf_stats: PerfStats {
749             svh_time: Cell::new(Duration::from_secs(0)),
750             incr_comp_hashes_time: Cell::new(Duration::from_secs(0)),
751             incr_comp_hashes_count: Cell::new(0),
752             incr_comp_bytes_hashed: Cell::new(0),
753             symbol_hash_time: Cell::new(Duration::from_secs(0)),
754             decode_def_path_tables_time: Cell::new(Duration::from_secs(0)),
755         },
756         code_stats: RefCell::new(CodeStats::new()),
757         optimization_fuel_crate,
758         optimization_fuel_limit,
759         print_fuel_crate,
760         print_fuel,
761         out_of_fuel: Cell::new(false),
762         // Note that this is unsafe because it may misinterpret file descriptors
763         // on Unix as jobserver file descriptors. We hopefully execute this near
764         // the beginning of the process though to ensure we don't get false
765         // positives, or in other words we try to execute this before we open
766         // any file descriptors ourselves.
767         //
768         // Also note that we stick this in a global because there could be
769         // multiple `Session` instances in this process, and the jobserver is
770         // per-process.
771         jobserver_from_env: unsafe {
772             static mut GLOBAL_JOBSERVER: *mut Option<Client> = 0 as *mut _;
773             static INIT: Once = ONCE_INIT;
774             INIT.call_once(|| {
775                 GLOBAL_JOBSERVER = Box::into_raw(Box::new(Client::from_env()));
776             });
777             (*GLOBAL_JOBSERVER).clone()
778         },
779         has_global_allocator: Cell::new(false),
780     };
781
782     sess
783 }
784
785 /// Holds data on the current incremental compilation session, if there is one.
786 #[derive(Debug)]
787 pub enum IncrCompSession {
788     // This is the state the session will be in until the incr. comp. dir is
789     // needed.
790     NotInitialized,
791     // This is the state during which the session directory is private and can
792     // be modified.
793     Active {
794         session_directory: PathBuf,
795         lock_file: flock::Lock,
796     },
797     // This is the state after the session directory has been finalized. In this
798     // state, the contents of the directory must not be modified any more.
799     Finalized {
800         session_directory: PathBuf,
801     },
802     // This is an error state that is reached when some compilation error has
803     // occurred. It indicates that the contents of the session directory must
804     // not be used, since they might be invalid.
805     InvalidBecauseOfErrors {
806         session_directory: PathBuf,
807     }
808 }
809
810 pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
811     let emitter: Box<Emitter> = match output {
812         config::ErrorOutputType::HumanReadable(color_config) => {
813             Box::new(EmitterWriter::stderr(color_config,
814                                            None))
815         }
816         config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()),
817     };
818     let handler = errors::Handler::with_emitter(true, false, emitter);
819     handler.emit(&MultiSpan::new(), msg, errors::Level::Fatal);
820     panic!(errors::FatalError);
821 }
822
823 pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
824     let emitter: Box<Emitter> = match output {
825         config::ErrorOutputType::HumanReadable(color_config) => {
826             Box::new(EmitterWriter::stderr(color_config,
827                                            None))
828         }
829         config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()),
830     };
831     let handler = errors::Handler::with_emitter(true, false, emitter);
832     handler.emit(&MultiSpan::new(), msg, errors::Level::Warning);
833 }
834
835 #[derive(Copy, Clone, Debug)]
836 pub enum CompileIncomplete {
837     Stopped,
838     Errored(ErrorReported)
839 }
840 impl From<ErrorReported> for CompileIncomplete {
841     fn from(err: ErrorReported) -> CompileIncomplete {
842         CompileIncomplete::Errored(err)
843     }
844 }
845 pub type CompileResult = Result<(), CompileIncomplete>;
846
847 pub fn compile_result_from_err_count(err_count: usize) -> CompileResult {
848     if err_count == 0 {
849         Ok(())
850     } else {
851         Err(CompileIncomplete::Errored(ErrorReported))
852     }
853 }
854
855 #[cold]
856 #[inline(never)]
857 pub fn bug_fmt(file: &'static str, line: u32, args: fmt::Arguments) -> ! {
858     // this wrapper mostly exists so I don't have to write a fully
859     // qualified path of None::<Span> inside the bug!() macro definition
860     opt_span_bug_fmt(file, line, None::<Span>, args);
861 }
862
863 #[cold]
864 #[inline(never)]
865 pub fn span_bug_fmt<S: Into<MultiSpan>>(file: &'static str,
866                                         line: u32,
867                                         span: S,
868                                         args: fmt::Arguments) -> ! {
869     opt_span_bug_fmt(file, line, Some(span), args);
870 }
871
872 fn opt_span_bug_fmt<S: Into<MultiSpan>>(file: &'static str,
873                                         line: u32,
874                                         span: Option<S>,
875                                         args: fmt::Arguments) -> ! {
876     tls::with_opt(move |tcx| {
877         let msg = format!("{}:{}: {}", file, line, args);
878         match (tcx, span) {
879             (Some(tcx), Some(span)) => tcx.sess.diagnostic().span_bug(span, &msg),
880             (Some(tcx), None) => tcx.sess.diagnostic().bug(&msg),
881             (None, _) => panic!(msg)
882         }
883     });
884     unreachable!();
885 }