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