]> git.lizzy.rs Git - rust.git/blob - src/librustc/session/mod.rs
introduce crate rustc_feature and move active, accepted, and removed to it
[rust.git] / src / librustc / session / mod.rs
1 pub use self::code_stats::{DataTypeKind, SizeKind, FieldInfo, VariantInfo};
2 use self::code_stats::CodeStats;
3
4 use crate::dep_graph::cgu_reuse_tracker::CguReuseTracker;
5 use rustc_data_structures::fingerprint::Fingerprint;
6
7 use crate::lint;
8 use crate::session::config::{OutputType, PrintRequest, Sanitizer, SwitchWithOptPath};
9 use crate::session::search_paths::{PathKind, SearchPath};
10 use crate::util::nodemap::{FxHashMap, FxHashSet};
11 use crate::util::common::{duration_to_secs_str, ErrorReported};
12
13 use rustc_data_structures::base_n;
14 use rustc_data_structures::sync::{
15     self, Lrc, Lock, OneThread, Once, AtomicU64, AtomicUsize, Ordering,
16     Ordering::SeqCst,
17 };
18
19 use errors::{DiagnosticBuilder, DiagnosticId, Applicability};
20 use errors::emitter::{Emitter, EmitterWriter};
21 use errors::emitter::HumanReadableErrorType;
22 use errors::annotate_snippet_emitter_writer::{AnnotateSnippetEmitterWriter};
23 use syntax::edition::Edition;
24 use errors::json::JsonEmitter;
25 use syntax::source_map;
26 use syntax::sess::ParseSess;
27 use syntax_pos::{MultiSpan, Span};
28
29 use rustc_target::spec::{PanicStrategy, RelroLevel, Target, TargetTriple};
30 use rustc_data_structures::flock;
31 use rustc_data_structures::jobserver;
32 use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef};
33 use ::jobserver::Client;
34
35 use std;
36 use std::cell::{self, RefCell};
37 use std::env;
38 use std::fmt;
39 use std::io::Write;
40 use std::num::NonZeroU32;
41 use std::path::PathBuf;
42 use std::time::Duration;
43 use std::sync::Arc;
44
45 mod code_stats;
46 pub mod config;
47 pub mod filesearch;
48 pub mod search_paths;
49
50 pub struct OptimizationFuel {
51     /// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`.
52     remaining: u64,
53     /// We're rejecting all further optimizations.
54     out_of_fuel: bool,
55 }
56
57 /// Represents the data associated with a compilation
58 /// session for a single crate.
59 pub struct Session {
60     pub target: config::Config,
61     pub host: Target,
62     pub opts: config::Options,
63     pub host_tlib_path: SearchPath,
64     /// `None` if the host and target are the same.
65     pub target_tlib_path: Option<SearchPath>,
66     pub parse_sess: ParseSess,
67     pub sysroot: PathBuf,
68     /// The name of the root source file of the crate, in the local file system.
69     /// `None` means that there is no source file.
70     pub local_crate_source_file: Option<PathBuf>,
71     /// The directory the compiler has been executed in plus a flag indicating
72     /// if the value stored here has been affected by path remapping.
73     pub working_dir: (PathBuf, bool),
74
75     /// Set of `(DiagnosticId, Option<Span>, message)` tuples tracking
76     /// (sub)diagnostics that have been set once, but should not be set again,
77     /// in order to avoid redundantly verbose output (Issue #24690, #44953).
78     pub one_time_diagnostics: Lock<FxHashSet<(DiagnosticMessageId, Option<Span>, String)>>,
79     pub plugin_llvm_passes: OneThread<RefCell<Vec<String>>>,
80     pub crate_types: Once<Vec<config::CrateType>>,
81     /// The `crate_disambiguator` is constructed out of all the `-C metadata`
82     /// arguments passed to the compiler. Its value together with the crate-name
83     /// forms a unique global identifier for the crate. It is used to allow
84     /// multiple crates with the same name to coexist. See the
85     /// `rustc_codegen_llvm::back::symbol_names` module for more information.
86     pub crate_disambiguator: Once<CrateDisambiguator>,
87
88     features: Once<rustc_feature::Features>,
89
90     /// The maximum recursion limit for potentially infinitely recursive
91     /// operations such as auto-dereference and monomorphization.
92     pub recursion_limit: Once<usize>,
93
94     /// The maximum length of types during monomorphization.
95     pub type_length_limit: Once<usize>,
96
97     /// The maximum number of stackframes allowed in const eval.
98     pub const_eval_stack_frame_limit: usize,
99
100     /// Map from imported macro spans (which consist of
101     /// the localized span for the macro body) to the
102     /// macro name and definition span in the source crate.
103     pub imported_macro_spans: OneThread<RefCell<FxHashMap<Span, (String, Span)>>>,
104
105     incr_comp_session: OneThread<RefCell<IncrCompSession>>,
106     /// Used for incremental compilation tests. Will only be populated if
107     /// `-Zquery-dep-graph` is specified.
108     pub cgu_reuse_tracker: CguReuseTracker,
109
110     /// Used by `-Z self-profile`.
111     pub prof: SelfProfilerRef,
112
113     /// Some measurements that are being gathered during compilation.
114     pub perf_stats: PerfStats,
115
116     /// Data about code being compiled, gathered during compilation.
117     pub code_stats: CodeStats,
118
119     /// If `-zfuel=crate=n` is specified, `Some(crate)`.
120     optimization_fuel_crate: Option<String>,
121
122     /// Tracks fuel info if `-zfuel=crate=n` is specified.
123     optimization_fuel: Lock<OptimizationFuel>,
124
125     // The next two are public because the driver needs to read them.
126     /// If `-zprint-fuel=crate`, `Some(crate)`.
127     pub print_fuel_crate: Option<String>,
128     /// Always set to zero and incremented so that we can print fuel expended by a crate.
129     pub print_fuel: AtomicU64,
130
131     /// Loaded up early on in the initialization of this `Session` to avoid
132     /// false positives about a job server in our environment.
133     pub jobserver: Client,
134
135     /// Metadata about the allocators for the current crate being compiled.
136     pub has_global_allocator: Once<bool>,
137
138     /// Cap lint level specified by a driver specifically.
139     pub driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
140
141     /// `Span`s of trait methods that weren't found to avoid emitting object safety errors
142     pub trait_methods_not_found: Lock<FxHashSet<Span>>,
143
144     /// Mapping from ident span to path span for paths that don't exist as written, but that
145     /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`.
146     pub confused_type_with_std_module: Lock<FxHashMap<Span, Span>>,
147 }
148
149 pub struct PerfStats {
150     /// The accumulated time spent on computing symbol hashes.
151     pub symbol_hash_time: Lock<Duration>,
152     /// The accumulated time spent decoding def path tables from metadata.
153     pub decode_def_path_tables_time: Lock<Duration>,
154     /// Total number of values canonicalized queries constructed.
155     pub queries_canonicalized: AtomicUsize,
156     /// Number of times this query is invoked.
157     pub normalize_ty_after_erasing_regions: AtomicUsize,
158     /// Number of times this query is invoked.
159     pub normalize_projection_ty: AtomicUsize,
160 }
161
162 /// Enum to support dispatch of one-time diagnostics (in `Session.diag_once`).
163 enum DiagnosticBuilderMethod {
164     Note,
165     SpanNote,
166     SpanSuggestion(String), // suggestion
167                             // Add more variants as needed to support one-time diagnostics.
168 }
169
170 /// Diagnostic message ID, used by `Session.one_time_diagnostics` to avoid
171 /// emitting the same message more than once.
172 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
173 pub enum DiagnosticMessageId {
174     ErrorId(u16), // EXXXX error code as integer
175     LintId(lint::LintId),
176     StabilityId(Option<NonZeroU32>), // issue number
177 }
178
179 impl From<&'static lint::Lint> for DiagnosticMessageId {
180     fn from(lint: &'static lint::Lint) -> Self {
181         DiagnosticMessageId::LintId(lint::LintId::of(lint))
182     }
183 }
184
185 impl Session {
186     pub fn local_crate_disambiguator(&self) -> CrateDisambiguator {
187         *self.crate_disambiguator.get()
188     }
189
190     pub fn struct_span_warn<S: Into<MultiSpan>>(
191         &self,
192         sp: S,
193         msg: &str,
194     ) -> DiagnosticBuilder<'_> {
195         self.diagnostic().struct_span_warn(sp, msg)
196     }
197     pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(
198         &self,
199         sp: S,
200         msg: &str,
201         code: DiagnosticId,
202     ) -> DiagnosticBuilder<'_> {
203         self.diagnostic().struct_span_warn_with_code(sp, msg, code)
204     }
205     pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_> {
206         self.diagnostic().struct_warn(msg)
207     }
208     pub fn struct_span_err<S: Into<MultiSpan>>(
209         &self,
210         sp: S,
211         msg: &str,
212     ) -> DiagnosticBuilder<'_> {
213         self.diagnostic().struct_span_err(sp, msg)
214     }
215     pub fn struct_span_err_with_code<S: Into<MultiSpan>>(
216         &self,
217         sp: S,
218         msg: &str,
219         code: DiagnosticId,
220     ) -> DiagnosticBuilder<'_> {
221         self.diagnostic().struct_span_err_with_code(sp, msg, code)
222     }
223     // FIXME: This method should be removed (every error should have an associated error code).
224     pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_> {
225         self.diagnostic().struct_err(msg)
226     }
227     pub fn struct_err_with_code(
228         &self,
229         msg: &str,
230         code: DiagnosticId,
231     ) -> DiagnosticBuilder<'_> {
232         self.diagnostic().struct_err_with_code(msg, code)
233     }
234     pub fn struct_span_fatal<S: Into<MultiSpan>>(
235         &self,
236         sp: S,
237         msg: &str,
238     ) -> DiagnosticBuilder<'_> {
239         self.diagnostic().struct_span_fatal(sp, msg)
240     }
241     pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(
242         &self,
243         sp: S,
244         msg: &str,
245         code: DiagnosticId,
246     ) -> DiagnosticBuilder<'_> {
247         self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
248     }
249     pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_> {
250         self.diagnostic().struct_fatal(msg)
251     }
252
253     pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
254         self.diagnostic().span_fatal(sp, msg).raise()
255     }
256     pub fn span_fatal_with_code<S: Into<MultiSpan>>(
257         &self,
258         sp: S,
259         msg: &str,
260         code: DiagnosticId,
261     ) -> ! {
262         self.diagnostic()
263             .span_fatal_with_code(sp, msg, code)
264             .raise()
265     }
266     pub fn fatal(&self, msg: &str) -> ! {
267         self.diagnostic().fatal(msg).raise()
268     }
269     pub fn span_err_or_warn<S: Into<MultiSpan>>(&self, is_warning: bool, sp: S, msg: &str) {
270         if is_warning {
271             self.span_warn(sp, msg);
272         } else {
273             self.span_err(sp, msg);
274         }
275     }
276     pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
277         self.diagnostic().span_err(sp, msg)
278     }
279     pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
280         self.diagnostic().span_err_with_code(sp, &msg, code)
281     }
282     pub fn err(&self, msg: &str) {
283         self.diagnostic().err(msg)
284     }
285     pub fn err_count(&self) -> usize {
286         self.diagnostic().err_count()
287     }
288     pub fn has_errors(&self) -> bool {
289         self.diagnostic().has_errors()
290     }
291     pub fn has_errors_or_delayed_span_bugs(&self) -> bool {
292         self.diagnostic().has_errors_or_delayed_span_bugs()
293     }
294     pub fn abort_if_errors(&self) {
295         self.diagnostic().abort_if_errors();
296     }
297     pub fn compile_status(&self) -> Result<(), ErrorReported> {
298         if self.has_errors() {
299             self.diagnostic().emit_stashed_diagnostics();
300             Err(ErrorReported)
301         } else {
302             Ok(())
303         }
304     }
305     // FIXME(matthewjasper) Remove this method, it should never be needed.
306     pub fn track_errors<F, T>(&self, f: F) -> Result<T, ErrorReported>
307     where
308         F: FnOnce() -> T,
309     {
310         let old_count = self.err_count();
311         let result = f();
312         let errors = self.err_count() - old_count;
313         if errors == 0 {
314             Ok(result)
315         } else {
316             Err(ErrorReported)
317         }
318     }
319     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
320         self.diagnostic().span_warn(sp, msg)
321     }
322     pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
323         self.diagnostic().span_warn_with_code(sp, msg, code)
324     }
325     pub fn warn(&self, msg: &str) {
326         self.diagnostic().warn(msg)
327     }
328     pub fn opt_span_warn<S: Into<MultiSpan>>(&self, opt_sp: Option<S>, msg: &str) {
329         match opt_sp {
330             Some(sp) => self.span_warn(sp, msg),
331             None => self.warn(msg),
332         }
333     }
334     /// Delay a span_bug() call until abort_if_errors()
335     pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
336         self.diagnostic().delay_span_bug(sp, msg)
337     }
338     pub fn note_without_error(&self, msg: &str) {
339         self.diagnostic().note_without_error(msg)
340     }
341     pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
342         self.diagnostic().span_note_without_error(sp, msg)
343     }
344
345     pub fn diagnostic(&self) -> &errors::Handler {
346         &self.parse_sess.span_diagnostic
347     }
348
349     /// Analogous to calling methods on the given `DiagnosticBuilder`, but
350     /// deduplicates on lint ID, span (if any), and message for this `Session`
351     fn diag_once<'a, 'b>(
352         &'a self,
353         diag_builder: &'b mut DiagnosticBuilder<'a>,
354         method: DiagnosticBuilderMethod,
355         msg_id: DiagnosticMessageId,
356         message: &str,
357         span_maybe: Option<Span>,
358     ) {
359         let id_span_message = (msg_id, span_maybe, message.to_owned());
360         let fresh = self.one_time_diagnostics
361             .borrow_mut()
362             .insert(id_span_message);
363         if fresh {
364             match method {
365                 DiagnosticBuilderMethod::Note => {
366                     diag_builder.note(message);
367                 }
368                 DiagnosticBuilderMethod::SpanNote => {
369                     let span = span_maybe.expect("`span_note` needs a span");
370                     diag_builder.span_note(span, message);
371                 }
372                 DiagnosticBuilderMethod::SpanSuggestion(suggestion) => {
373                     let span = span_maybe.expect("`span_suggestion_*` needs a span");
374                     diag_builder.span_suggestion(
375                         span,
376                         message,
377                         suggestion,
378                         Applicability::Unspecified,
379                     );
380                 }
381             }
382         }
383     }
384
385     pub fn diag_span_note_once<'a, 'b>(
386         &'a self,
387         diag_builder: &'b mut DiagnosticBuilder<'a>,
388         msg_id: DiagnosticMessageId,
389         span: Span,
390         message: &str,
391     ) {
392         self.diag_once(
393             diag_builder,
394             DiagnosticBuilderMethod::SpanNote,
395             msg_id,
396             message,
397             Some(span),
398         );
399     }
400
401     pub fn diag_note_once<'a, 'b>(
402         &'a self,
403         diag_builder: &'b mut DiagnosticBuilder<'a>,
404         msg_id: DiagnosticMessageId,
405         message: &str,
406     ) {
407         self.diag_once(
408             diag_builder,
409             DiagnosticBuilderMethod::Note,
410             msg_id,
411             message,
412             None,
413         );
414     }
415
416     pub fn diag_span_suggestion_once<'a, 'b>(
417         &'a self,
418         diag_builder: &'b mut DiagnosticBuilder<'a>,
419         msg_id: DiagnosticMessageId,
420         span: Span,
421         message: &str,
422         suggestion: String,
423     ) {
424         self.diag_once(
425             diag_builder,
426             DiagnosticBuilderMethod::SpanSuggestion(suggestion),
427             msg_id,
428             message,
429             Some(span),
430         );
431     }
432
433     pub fn source_map(&self) -> &source_map::SourceMap {
434         self.parse_sess.source_map()
435     }
436     pub fn verbose(&self) -> bool {
437         self.opts.debugging_opts.verbose
438     }
439     pub fn time_passes(&self) -> bool {
440         self.opts.debugging_opts.time_passes || self.opts.debugging_opts.time
441     }
442     pub fn time_extended(&self) -> bool {
443         self.opts.debugging_opts.time_passes
444     }
445     pub fn instrument_mcount(&self) -> bool {
446         self.opts.debugging_opts.instrument_mcount
447     }
448     pub fn time_llvm_passes(&self) -> bool {
449         self.opts.debugging_opts.time_llvm_passes
450     }
451     pub fn meta_stats(&self) -> bool {
452         self.opts.debugging_opts.meta_stats
453     }
454     pub fn asm_comments(&self) -> bool {
455         self.opts.debugging_opts.asm_comments
456     }
457     pub fn verify_llvm_ir(&self) -> bool {
458         self.opts.debugging_opts.verify_llvm_ir
459             || cfg!(always_verify_llvm_ir)
460     }
461     pub fn borrowck_stats(&self) -> bool {
462         self.opts.debugging_opts.borrowck_stats
463     }
464     pub fn print_llvm_passes(&self) -> bool {
465         self.opts.debugging_opts.print_llvm_passes
466     }
467     pub fn binary_dep_depinfo(&self) -> bool {
468         self.opts.debugging_opts.binary_dep_depinfo
469     }
470
471     /// Gets the features enabled for the current compilation session.
472     /// DO NOT USE THIS METHOD if there is a TyCtxt available, as it circumvents
473     /// dependency tracking. Use tcx.features() instead.
474     #[inline]
475     pub fn features_untracked(&self) -> &rustc_feature::Features {
476         self.features.get()
477     }
478
479     pub fn init_features(&self, features: rustc_feature::Features) {
480         self.features.set(features);
481     }
482
483     /// Calculates the flavor of LTO to use for this compilation.
484     pub fn lto(&self) -> config::Lto {
485         // If our target has codegen requirements ignore the command line
486         if self.target.target.options.requires_lto {
487             return config::Lto::Fat;
488         }
489
490         // If the user specified something, return that. If they only said `-C
491         // lto` and we've for whatever reason forced off ThinLTO via the CLI,
492         // then ensure we can't use a ThinLTO.
493         match self.opts.cg.lto {
494             config::LtoCli::Unspecified => {
495                 // The compiler was invoked without the `-Clto` flag. Fall
496                 // through to the default handling
497             }
498             config::LtoCli::No => {
499                 // The user explicitly opted out of any kind of LTO
500                 return config::Lto::No;
501             }
502             config::LtoCli::Yes |
503             config::LtoCli::Fat |
504             config::LtoCli::NoParam => {
505                 // All of these mean fat LTO
506                 return config::Lto::Fat;
507             }
508             config::LtoCli::Thin => {
509                 return if self.opts.cli_forced_thinlto_off {
510                     config::Lto::Fat
511                 } else {
512                     config::Lto::Thin
513                 };
514             }
515         }
516
517         // Ok at this point the target doesn't require anything and the user
518         // hasn't asked for anything. Our next decision is whether or not
519         // we enable "auto" ThinLTO where we use multiple codegen units and
520         // then do ThinLTO over those codegen units. The logic below will
521         // either return `No` or `ThinLocal`.
522
523         // If processing command line options determined that we're incompatible
524         // with ThinLTO (e.g., `-C lto --emit llvm-ir`) then return that option.
525         if self.opts.cli_forced_thinlto_off {
526             return config::Lto::No;
527         }
528
529         // If `-Z thinlto` specified process that, but note that this is mostly
530         // a deprecated option now that `-C lto=thin` exists.
531         if let Some(enabled) = self.opts.debugging_opts.thinlto {
532             if enabled {
533                 return config::Lto::ThinLocal;
534             } else {
535                 return config::Lto::No;
536             }
537         }
538
539         // If there's only one codegen unit and LTO isn't enabled then there's
540         // no need for ThinLTO so just return false.
541         if self.codegen_units() == 1 {
542             return config::Lto::No;
543         }
544
545         // Now we're in "defaults" territory. By default we enable ThinLTO for
546         // optimized compiles (anything greater than O0).
547         match self.opts.optimize {
548             config::OptLevel::No => config::Lto::No,
549             _ => config::Lto::ThinLocal,
550         }
551     }
552
553     /// Returns the panic strategy for this compile session. If the user explicitly selected one
554     /// using '-C panic', use that, otherwise use the panic strategy defined by the target.
555     pub fn panic_strategy(&self) -> PanicStrategy {
556         self.opts
557             .cg
558             .panic
559             .unwrap_or(self.target.target.options.panic_strategy)
560     }
561     pub fn fewer_names(&self) -> bool {
562         let more_names = self.opts
563             .output_types
564             .contains_key(&OutputType::LlvmAssembly)
565             || self.opts.output_types.contains_key(&OutputType::Bitcode);
566
567         // Address sanitizer and memory sanitizer use alloca name when reporting an issue.
568         let more_names = match self.opts.debugging_opts.sanitizer {
569             Some(Sanitizer::Address) => true,
570             Some(Sanitizer::Memory) => true,
571             _ => more_names,
572         };
573
574         self.opts.debugging_opts.fewer_names || !more_names
575     }
576
577     pub fn no_landing_pads(&self) -> bool {
578         self.opts.debugging_opts.no_landing_pads || self.panic_strategy() == PanicStrategy::Abort
579     }
580     pub fn unstable_options(&self) -> bool {
581         self.opts.debugging_opts.unstable_options
582     }
583     pub fn overflow_checks(&self) -> bool {
584         self.opts
585             .cg
586             .overflow_checks
587             .or(self.opts.debugging_opts.force_overflow_checks)
588             .unwrap_or(self.opts.debug_assertions)
589     }
590
591     pub fn crt_static(&self) -> bool {
592         // If the target does not opt in to crt-static support, use its default.
593         if self.target.target.options.crt_static_respected {
594             self.crt_static_feature()
595         } else {
596             self.target.target.options.crt_static_default
597         }
598     }
599
600     pub fn crt_static_feature(&self) -> bool {
601         let requested_features = self.opts.cg.target_feature.split(',');
602         let found_negative = requested_features.clone().any(|r| r == "-crt-static");
603         let found_positive = requested_features.clone().any(|r| r == "+crt-static");
604
605         // If the target we're compiling for requests a static crt by default,
606         // then see if the `-crt-static` feature was passed to disable that.
607         // Otherwise if we don't have a static crt by default then see if the
608         // `+crt-static` feature was passed.
609         if self.target.target.options.crt_static_default {
610             !found_negative
611         } else {
612             found_positive
613         }
614     }
615
616     pub fn must_not_eliminate_frame_pointers(&self) -> bool {
617         // "mcount" function relies on stack pointer.
618         // See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
619         if self.instrument_mcount() {
620             true
621         } else if let Some(x) = self.opts.cg.force_frame_pointers {
622             x
623         } else {
624             !self.target.target.options.eliminate_frame_pointer
625         }
626     }
627
628     /// Returns the symbol name for the registrar function,
629     /// given the crate `Svh` and the function `DefIndex`.
630     pub fn generate_plugin_registrar_symbol(&self, disambiguator: CrateDisambiguator) -> String {
631         format!(
632             "__rustc_plugin_registrar_{}__",
633             disambiguator.to_fingerprint().to_hex()
634         )
635     }
636
637     pub fn generate_proc_macro_decls_symbol(&self, disambiguator: CrateDisambiguator) -> String {
638         format!(
639             "__rustc_proc_macro_decls_{}__",
640             disambiguator.to_fingerprint().to_hex()
641         )
642     }
643
644     pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> {
645         filesearch::FileSearch::new(
646             &self.sysroot,
647             self.opts.target_triple.triple(),
648             &self.opts.search_paths,
649             // `target_tlib_path == None` means it's the same as `host_tlib_path`.
650             self.target_tlib_path.as_ref().unwrap_or(&self.host_tlib_path),
651             kind,
652         )
653     }
654     pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> {
655         filesearch::FileSearch::new(
656             &self.sysroot,
657             config::host_triple(),
658             &self.opts.search_paths,
659             &self.host_tlib_path,
660             kind,
661         )
662     }
663
664     pub fn set_incr_session_load_dep_graph(&self, load: bool) {
665         let mut incr_comp_session = self.incr_comp_session.borrow_mut();
666
667         if let IncrCompSession::Active { ref mut load_dep_graph, .. } = *incr_comp_session {
668             *load_dep_graph = load;
669         }
670     }
671
672     pub fn incr_session_load_dep_graph(&self) -> bool {
673         let incr_comp_session = self.incr_comp_session.borrow();
674         match *incr_comp_session {
675             IncrCompSession::Active { load_dep_graph, .. } => load_dep_graph,
676             _ => false,
677         }
678     }
679
680     pub fn init_incr_comp_session(
681         &self,
682         session_dir: PathBuf,
683         lock_file: flock::Lock,
684         load_dep_graph: bool,
685     ) {
686         let mut incr_comp_session = self.incr_comp_session.borrow_mut();
687
688         if let IncrCompSession::NotInitialized = *incr_comp_session {
689         } else {
690             bug!(
691                 "Trying to initialize IncrCompSession `{:?}`",
692                 *incr_comp_session
693             )
694         }
695
696         *incr_comp_session = IncrCompSession::Active {
697             session_directory: session_dir,
698             lock_file,
699             load_dep_graph,
700         };
701     }
702
703     pub fn finalize_incr_comp_session(&self, new_directory_path: PathBuf) {
704         let mut incr_comp_session = self.incr_comp_session.borrow_mut();
705
706         if let IncrCompSession::Active { .. } = *incr_comp_session {
707         } else {
708             bug!(
709                 "trying to finalize `IncrCompSession` `{:?}`",
710                 *incr_comp_session
711             );
712         }
713
714         // Note: this will also drop the lock file, thus unlocking the directory.
715         *incr_comp_session = IncrCompSession::Finalized {
716             session_directory: new_directory_path,
717         };
718     }
719
720     pub fn mark_incr_comp_session_as_invalid(&self) {
721         let mut incr_comp_session = self.incr_comp_session.borrow_mut();
722
723         let session_directory = match *incr_comp_session {
724             IncrCompSession::Active {
725                 ref session_directory,
726                 ..
727             } => session_directory.clone(),
728             IncrCompSession::InvalidBecauseOfErrors { .. } => return,
729             _ => bug!(
730                 "trying to invalidate `IncrCompSession` `{:?}`",
731                 *incr_comp_session
732             ),
733         };
734
735         // Note: this will also drop the lock file, thus unlocking the directory.
736         *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors {
737             session_directory,
738         };
739     }
740
741     pub fn incr_comp_session_dir(&self) -> cell::Ref<'_, PathBuf> {
742         let incr_comp_session = self.incr_comp_session.borrow();
743         cell::Ref::map(
744             incr_comp_session,
745             |incr_comp_session| match *incr_comp_session {
746                 IncrCompSession::NotInitialized => bug!(
747                     "trying to get session directory from `IncrCompSession`: {:?}",
748                     *incr_comp_session,
749                 ),
750                 IncrCompSession::Active {
751                     ref session_directory,
752                     ..
753                 }
754                 | IncrCompSession::Finalized {
755                     ref session_directory,
756                 }
757                 | IncrCompSession::InvalidBecauseOfErrors {
758                     ref session_directory,
759                 } => session_directory,
760             },
761         )
762     }
763
764     pub fn incr_comp_session_dir_opt(&self) -> Option<cell::Ref<'_, PathBuf>> {
765         if self.opts.incremental.is_some() {
766             Some(self.incr_comp_session_dir())
767         } else {
768             None
769         }
770     }
771
772     pub fn print_perf_stats(&self) {
773         println!(
774             "Total time spent computing symbol hashes:      {}",
775             duration_to_secs_str(*self.perf_stats.symbol_hash_time.lock())
776         );
777         println!(
778             "Total time spent decoding DefPath tables:      {}",
779             duration_to_secs_str(*self.perf_stats.decode_def_path_tables_time.lock())
780         );
781         println!("Total queries canonicalized:                   {}",
782                  self.perf_stats.queries_canonicalized.load(Ordering::Relaxed));
783         println!("normalize_ty_after_erasing_regions:            {}",
784                  self.perf_stats.normalize_ty_after_erasing_regions.load(Ordering::Relaxed));
785         println!("normalize_projection_ty:                       {}",
786                  self.perf_stats.normalize_projection_ty.load(Ordering::Relaxed));
787     }
788
789     /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n.
790     /// This expends fuel if applicable, and records fuel if applicable.
791     pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -> bool {
792         let mut ret = true;
793         if let Some(ref c) = self.optimization_fuel_crate {
794             if c == crate_name {
795                 assert_eq!(self.threads(), 1);
796                 let mut fuel = self.optimization_fuel.lock();
797                 ret = fuel.remaining != 0;
798                 if fuel.remaining == 0 && !fuel.out_of_fuel {
799                     eprintln!("optimization-fuel-exhausted: {}", msg());
800                     fuel.out_of_fuel = true;
801                 } else if fuel.remaining > 0 {
802                     fuel.remaining -= 1;
803                 }
804             }
805         }
806         if let Some(ref c) = self.print_fuel_crate {
807             if c == crate_name {
808                 assert_eq!(self.threads(), 1);
809                 self.print_fuel.fetch_add(1, SeqCst);
810             }
811         }
812         ret
813     }
814
815     /// Returns the number of query threads that should be used for this
816     /// compilation
817     pub fn threads(&self) -> usize {
818         self.opts.debugging_opts.threads
819     }
820
821     /// Returns the number of codegen units that should be used for this
822     /// compilation
823     pub fn codegen_units(&self) -> usize {
824         if let Some(n) = self.opts.cli_forced_codegen_units {
825             return n;
826         }
827         if let Some(n) = self.target.target.options.default_codegen_units {
828             return n as usize;
829         }
830
831         // Why is 16 codegen units the default all the time?
832         //
833         // The main reason for enabling multiple codegen units by default is to
834         // leverage the ability for the codegen backend to do codegen and
835         // optimization in parallel. This allows us, especially for large crates, to
836         // make good use of all available resources on the machine once we've
837         // hit that stage of compilation. Large crates especially then often
838         // take a long time in codegen/optimization and this helps us amortize that
839         // cost.
840         //
841         // Note that a high number here doesn't mean that we'll be spawning a
842         // large number of threads in parallel. The backend of rustc contains
843         // global rate limiting through the `jobserver` crate so we'll never
844         // overload the system with too much work, but rather we'll only be
845         // optimizing when we're otherwise cooperating with other instances of
846         // rustc.
847         //
848         // Rather a high number here means that we should be able to keep a lot
849         // of idle cpus busy. By ensuring that no codegen unit takes *too* long
850         // to build we'll be guaranteed that all cpus will finish pretty closely
851         // to one another and we should make relatively optimal use of system
852         // resources
853         //
854         // Note that the main cost of codegen units is that it prevents LLVM
855         // from inlining across codegen units. Users in general don't have a lot
856         // of control over how codegen units are split up so it's our job in the
857         // compiler to ensure that undue performance isn't lost when using
858         // codegen units (aka we can't require everyone to slap `#[inline]` on
859         // everything).
860         //
861         // If we're compiling at `-O0` then the number doesn't really matter too
862         // much because performance doesn't matter and inlining is ok to lose.
863         // In debug mode we just want to try to guarantee that no cpu is stuck
864         // doing work that could otherwise be farmed to others.
865         //
866         // In release mode, however (O1 and above) performance does indeed
867         // matter! To recover the loss in performance due to inlining we'll be
868         // enabling ThinLTO by default (the function for which is just below).
869         // This will ensure that we recover any inlining wins we otherwise lost
870         // through codegen unit partitioning.
871         //
872         // ---
873         //
874         // Ok that's a lot of words but the basic tl;dr; is that we want a high
875         // number here -- but not too high. Additionally we're "safe" to have it
876         // always at the same number at all optimization levels.
877         //
878         // As a result 16 was chosen here! Mostly because it was a power of 2
879         // and most benchmarks agreed it was roughly a local optimum. Not very
880         // scientific.
881         16
882     }
883
884     pub fn teach(&self, code: &DiagnosticId) -> bool {
885         self.opts.debugging_opts.teach && self.diagnostic().must_teach(code)
886     }
887
888     pub fn rust_2015(&self) -> bool {
889         self.opts.edition == Edition::Edition2015
890     }
891
892     /// Are we allowed to use features from the Rust 2018 edition?
893     pub fn rust_2018(&self) -> bool {
894         self.opts.edition >= Edition::Edition2018
895     }
896
897     pub fn edition(&self) -> Edition {
898         self.opts.edition
899     }
900
901     /// Returns `true` if we cannot skip the PLT for shared library calls.
902     pub fn needs_plt(&self) -> bool {
903         // Check if the current target usually needs PLT to be enabled.
904         // The user can use the command line flag to override it.
905         let needs_plt = self.target.target.options.needs_plt;
906
907         let dbg_opts = &self.opts.debugging_opts;
908
909         let relro_level = dbg_opts.relro_level
910             .unwrap_or(self.target.target.options.relro_level);
911
912         // Only enable this optimization by default if full relro is also enabled.
913         // In this case, lazy binding was already unavailable, so nothing is lost.
914         // This also ensures `-Wl,-z,now` is supported by the linker.
915         let full_relro = RelroLevel::Full == relro_level;
916
917         // If user didn't explicitly forced us to use / skip the PLT,
918         // then try to skip it where possible.
919         dbg_opts.plt.unwrap_or(needs_plt || !full_relro)
920     }
921 }
922
923 pub fn build_session(
924     sopts: config::Options,
925     local_crate_source_file: Option<PathBuf>,
926     registry: errors::registry::Registry,
927 ) -> Session {
928     let file_path_mapping = sopts.file_path_mapping();
929
930     build_session_with_source_map(
931         sopts,
932         local_crate_source_file,
933         registry,
934         Lrc::new(source_map::SourceMap::new(file_path_mapping)),
935         DiagnosticOutput::Default,
936         Default::default(),
937     )
938 }
939
940 fn default_emitter(
941     sopts: &config::Options,
942     registry: errors::registry::Registry,
943     source_map: &Lrc<source_map::SourceMap>,
944     emitter_dest: Option<Box<dyn Write + Send>>,
945 ) -> Box<dyn Emitter + sync::Send> {
946     let external_macro_backtrace = sopts.debugging_opts.external_macro_backtrace;
947     match (sopts.error_format, emitter_dest) {
948         (config::ErrorOutputType::HumanReadable(kind), dst) => {
949             let (short, color_config) = kind.unzip();
950
951             if let HumanReadableErrorType::AnnotateSnippet(_) = kind {
952                 let emitter = AnnotateSnippetEmitterWriter::new(
953                     Some(source_map.clone()),
954                     short,
955                     external_macro_backtrace,
956                 );
957                 Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing))
958             } else {
959                 let emitter = match dst {
960                     None => EmitterWriter::stderr(
961                         color_config,
962                         Some(source_map.clone()),
963                         short,
964                         sopts.debugging_opts.teach,
965                         sopts.debugging_opts.terminal_width,
966                         external_macro_backtrace,
967                     ),
968                     Some(dst) => EmitterWriter::new(
969                         dst,
970                         Some(source_map.clone()),
971                         short,
972                         false, // no teach messages when writing to a buffer
973                         false, // no colors when writing to a buffer
974                         None,  // no terminal width
975                         external_macro_backtrace,
976                     ),
977                 };
978                 Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing))
979             }
980         },
981         (config::ErrorOutputType::Json { pretty, json_rendered }, None) => Box::new(
982             JsonEmitter::stderr(
983                 Some(registry),
984                 source_map.clone(),
985                 pretty,
986                 json_rendered,
987                 external_macro_backtrace,
988             ).ui_testing(sopts.debugging_opts.ui_testing),
989         ),
990         (config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new(
991             JsonEmitter::new(
992                 dst,
993                 Some(registry),
994                 source_map.clone(),
995                 pretty,
996                 json_rendered,
997                 external_macro_backtrace,
998             ).ui_testing(sopts.debugging_opts.ui_testing),
999         ),
1000     }
1001 }
1002
1003 pub enum DiagnosticOutput {
1004     Default,
1005     Raw(Box<dyn Write + Send>)
1006 }
1007
1008 pub fn build_session_with_source_map(
1009     sopts: config::Options,
1010     local_crate_source_file: Option<PathBuf>,
1011     registry: errors::registry::Registry,
1012     source_map: Lrc<source_map::SourceMap>,
1013     diagnostics_output: DiagnosticOutput,
1014     lint_caps: FxHashMap<lint::LintId, lint::Level>,
1015 ) -> Session {
1016     // FIXME: This is not general enough to make the warning lint completely override
1017     // normal diagnostic warnings, since the warning lint can also be denied and changed
1018     // later via the source code.
1019     let warnings_allow = sopts
1020         .lint_opts
1021         .iter()
1022         .filter(|&&(ref key, _)| *key == "warnings")
1023         .map(|&(_, ref level)| *level == lint::Allow)
1024         .last()
1025         .unwrap_or(false);
1026     let cap_lints_allow = sopts.lint_cap.map_or(false, |cap| cap == lint::Allow);
1027
1028     let can_emit_warnings = !(warnings_allow || cap_lints_allow);
1029
1030     let treat_err_as_bug = sopts.debugging_opts.treat_err_as_bug;
1031     let dont_buffer_diagnostics = sopts.debugging_opts.dont_buffer_diagnostics;
1032     let report_delayed_bugs = sopts.debugging_opts.report_delayed_bugs;
1033
1034     let external_macro_backtrace = sopts.debugging_opts.external_macro_backtrace;
1035
1036     let write_dest = match diagnostics_output {
1037         DiagnosticOutput::Default => None,
1038         DiagnosticOutput::Raw(write) => Some(write),
1039     };
1040     let emitter = default_emitter(&sopts, registry, &source_map, write_dest);
1041
1042     let diagnostic_handler = errors::Handler::with_emitter_and_flags(
1043         emitter,
1044         errors::HandlerFlags {
1045             can_emit_warnings,
1046             treat_err_as_bug,
1047             report_delayed_bugs,
1048             dont_buffer_diagnostics,
1049             external_macro_backtrace,
1050             ..Default::default()
1051         },
1052     );
1053
1054     build_session_(
1055         sopts,
1056         local_crate_source_file,
1057         diagnostic_handler,
1058         source_map,
1059         lint_caps,
1060     )
1061 }
1062
1063 fn build_session_(
1064     sopts: config::Options,
1065     local_crate_source_file: Option<PathBuf>,
1066     span_diagnostic: errors::Handler,
1067     source_map: Lrc<source_map::SourceMap>,
1068     driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
1069 ) -> Session {
1070     let self_profiler =
1071         if let SwitchWithOptPath::Enabled(ref d) = sopts.debugging_opts.self_profile {
1072             let directory = if let Some(ref directory) = d {
1073                 directory
1074             } else {
1075                 std::path::Path::new(".")
1076             };
1077
1078             let profiler = SelfProfiler::new(
1079                 directory,
1080                 sopts.crate_name.as_ref().map(|s| &s[..]),
1081                 &sopts.debugging_opts.self_profile_events
1082             );
1083             match profiler {
1084                 Ok(profiler) => {
1085                     Some(Arc::new(profiler))
1086                 },
1087                 Err(e) => {
1088                     early_warn(sopts.error_format, &format!("failed to create profiler: {}", e));
1089                     None
1090                 }
1091             }
1092         }
1093         else { None };
1094
1095     let host_triple = TargetTriple::from_triple(config::host_triple());
1096     let host = Target::search(&host_triple).unwrap_or_else(|e|
1097         span_diagnostic
1098             .fatal(&format!("Error loading host specification: {}", e))
1099             .raise()
1100     );
1101     let target_cfg = config::build_target_config(&sopts, &span_diagnostic);
1102
1103     let parse_sess = ParseSess::with_span_handler(
1104         span_diagnostic,
1105         source_map,
1106     );
1107     let sysroot = match &sopts.maybe_sysroot {
1108         Some(sysroot) => sysroot.clone(),
1109         None => filesearch::get_or_default_sysroot(),
1110     };
1111
1112     let host_triple = config::host_triple();
1113     let target_triple = sopts.target_triple.triple();
1114     let host_tlib_path = SearchPath::from_sysroot_and_triple(&sysroot, host_triple);
1115     let target_tlib_path = if host_triple == target_triple {
1116         None
1117     } else {
1118         Some(SearchPath::from_sysroot_and_triple(&sysroot, target_triple))
1119     };
1120
1121     let file_path_mapping = sopts.file_path_mapping();
1122
1123     let local_crate_source_file =
1124         local_crate_source_file.map(|path| file_path_mapping.map_prefix(path).0);
1125
1126     let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone());
1127     let optimization_fuel = Lock::new(OptimizationFuel {
1128         remaining: sopts.debugging_opts.fuel.as_ref().map(|i| i.1).unwrap_or(0),
1129         out_of_fuel: false,
1130     });
1131     let print_fuel_crate = sopts.debugging_opts.print_fuel.clone();
1132     let print_fuel = AtomicU64::new(0);
1133
1134     let working_dir = env::current_dir().unwrap_or_else(|e|
1135         parse_sess.span_diagnostic
1136             .fatal(&format!("Current directory is invalid: {}", e))
1137             .raise()
1138     );
1139     let working_dir = file_path_mapping.map_prefix(working_dir);
1140
1141     let cgu_reuse_tracker = if sopts.debugging_opts.query_dep_graph {
1142         CguReuseTracker::new()
1143     } else {
1144         CguReuseTracker::new_disabled()
1145     };
1146
1147     let sess = Session {
1148         target: target_cfg,
1149         host,
1150         opts: sopts,
1151         host_tlib_path,
1152         target_tlib_path,
1153         parse_sess,
1154         sysroot,
1155         local_crate_source_file,
1156         working_dir,
1157         one_time_diagnostics: Default::default(),
1158         plugin_llvm_passes: OneThread::new(RefCell::new(Vec::new())),
1159         crate_types: Once::new(),
1160         crate_disambiguator: Once::new(),
1161         features: Once::new(),
1162         recursion_limit: Once::new(),
1163         type_length_limit: Once::new(),
1164         const_eval_stack_frame_limit: 100,
1165         imported_macro_spans: OneThread::new(RefCell::new(FxHashMap::default())),
1166         incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
1167         cgu_reuse_tracker,
1168         prof: SelfProfilerRef::new(self_profiler),
1169         perf_stats: PerfStats {
1170             symbol_hash_time: Lock::new(Duration::from_secs(0)),
1171             decode_def_path_tables_time: Lock::new(Duration::from_secs(0)),
1172             queries_canonicalized: AtomicUsize::new(0),
1173             normalize_ty_after_erasing_regions: AtomicUsize::new(0),
1174             normalize_projection_ty: AtomicUsize::new(0),
1175         },
1176         code_stats: Default::default(),
1177         optimization_fuel_crate,
1178         optimization_fuel,
1179         print_fuel_crate,
1180         print_fuel,
1181         jobserver: jobserver::client(),
1182         has_global_allocator: Once::new(),
1183         driver_lint_caps,
1184         trait_methods_not_found: Lock::new(Default::default()),
1185         confused_type_with_std_module: Lock::new(Default::default()),
1186     };
1187
1188     validate_commandline_args_with_session_available(&sess);
1189
1190     sess
1191 }
1192
1193 // If it is useful to have a Session available already for validating a
1194 // commandline argument, you can do so here.
1195 fn validate_commandline_args_with_session_available(sess: &Session) {
1196     // Since we don't know if code in an rlib will be linked to statically or
1197     // dynamically downstream, rustc generates `__imp_` symbols that help the
1198     // MSVC linker deal with this lack of knowledge (#27438). Unfortunately,
1199     // these manually generated symbols confuse LLD when it tries to merge
1200     // bitcode during ThinLTO. Therefore we disallow dynamic linking on MSVC
1201     // when compiling for LLD ThinLTO. This way we can validly just not generate
1202     // the `dllimport` attributes and `__imp_` symbols in that case.
1203     if sess.opts.cg.linker_plugin_lto.enabled() &&
1204        sess.opts.cg.prefer_dynamic &&
1205        sess.target.target.options.is_like_msvc {
1206         sess.err("Linker plugin based LTO is not supported together with \
1207                   `-C prefer-dynamic` when targeting MSVC");
1208     }
1209
1210     // Make sure that any given profiling data actually exists so LLVM can't
1211     // decide to silently skip PGO.
1212     if let Some(ref path) = sess.opts.cg.profile_use {
1213         if !path.exists() {
1214             sess.err(&format!("File `{}` passed to `-C profile-use` does not exist.",
1215                               path.display()));
1216         }
1217     }
1218
1219     // PGO does not work reliably with panic=unwind on Windows. Let's make it
1220     // an error to combine the two for now. It always runs into an assertions
1221     // if LLVM is built with assertions, but without assertions it sometimes
1222     // does not crash and will probably generate a corrupted binary.
1223     // We should only display this error if we're actually going to run PGO.
1224     // If we're just supposed to print out some data, don't show the error (#61002).
1225     if sess.opts.cg.profile_generate.enabled() &&
1226        sess.target.target.options.is_like_msvc &&
1227        sess.panic_strategy() == PanicStrategy::Unwind &&
1228        sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs) {
1229         sess.err("Profile-guided optimization does not yet work in conjunction \
1230                   with `-Cpanic=unwind` on Windows when targeting MSVC. \
1231                   See https://github.com/rust-lang/rust/issues/61002 for details.");
1232     }
1233 }
1234
1235 /// Hash value constructed out of all the `-C metadata` arguments passed to the
1236 /// compiler. Together with the crate-name forms a unique global identifier for
1237 /// the crate.
1238 #[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, RustcEncodable, RustcDecodable)]
1239 pub struct CrateDisambiguator(Fingerprint);
1240
1241 impl CrateDisambiguator {
1242     pub fn to_fingerprint(self) -> Fingerprint {
1243         self.0
1244     }
1245 }
1246
1247 impl fmt::Display for CrateDisambiguator {
1248     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1249         let (a, b) = self.0.as_value();
1250         let as_u128 = a as u128 | ((b as u128) << 64);
1251         f.write_str(&base_n::encode(as_u128, base_n::CASE_INSENSITIVE))
1252     }
1253 }
1254
1255 impl From<Fingerprint> for CrateDisambiguator {
1256     fn from(fingerprint: Fingerprint) -> CrateDisambiguator {
1257         CrateDisambiguator(fingerprint)
1258     }
1259 }
1260
1261 impl_stable_hash_via_hash!(CrateDisambiguator);
1262
1263 /// Holds data on the current incremental compilation session, if there is one.
1264 #[derive(Debug)]
1265 pub enum IncrCompSession {
1266     /// This is the state the session will be in until the incr. comp. dir is
1267     /// needed.
1268     NotInitialized,
1269     /// This is the state during which the session directory is private and can
1270     /// be modified.
1271     Active {
1272         session_directory: PathBuf,
1273         lock_file: flock::Lock,
1274         load_dep_graph: bool,
1275     },
1276     /// This is the state after the session directory has been finalized. In this
1277     /// state, the contents of the directory must not be modified any more.
1278     Finalized { session_directory: PathBuf },
1279     /// This is an error state that is reached when some compilation error has
1280     /// occurred. It indicates that the contents of the session directory must
1281     /// not be used, since they might be invalid.
1282     InvalidBecauseOfErrors { session_directory: PathBuf },
1283 }
1284
1285 pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
1286     let emitter: Box<dyn Emitter + sync::Send> = match output {
1287         config::ErrorOutputType::HumanReadable(kind) => {
1288             let (short, color_config) = kind.unzip();
1289             Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false))
1290         }
1291         config::ErrorOutputType::Json { pretty, json_rendered } =>
1292             Box::new(JsonEmitter::basic(pretty, json_rendered, false)),
1293     };
1294     let handler = errors::Handler::with_emitter(true, None, emitter);
1295     handler.struct_fatal(msg).emit();
1296     errors::FatalError.raise();
1297 }
1298
1299 pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
1300     let emitter: Box<dyn Emitter + sync::Send> = match output {
1301         config::ErrorOutputType::HumanReadable(kind) => {
1302             let (short, color_config) = kind.unzip();
1303             Box::new(EmitterWriter::stderr(color_config, None, short, false, None, false))
1304         }
1305         config::ErrorOutputType::Json { pretty, json_rendered } =>
1306             Box::new(JsonEmitter::basic(pretty, json_rendered, false)),
1307     };
1308     let handler = errors::Handler::with_emitter(true, None, emitter);
1309     handler.struct_warn(msg).emit();
1310 }
1311
1312 pub type CompileResult = Result<(), ErrorReported>;