• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::cgu_reuse_tracker::CguReuseTracker;
2 use crate::code_stats::CodeStats;
3 pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
4 use crate::config::{
5     self, CrateType, InstrumentCoverage, OptLevel, OutFileName, OutputType, SwitchWithOptPath,
6 };
7 use crate::config::{ErrorOutputType, Input};
8 use crate::errors;
9 use crate::parse::{add_feature_diagnostics, ParseSess};
10 use crate::search_paths::{PathKind, SearchPath};
11 use crate::{filesearch, lint};
12 
13 pub use rustc_ast::attr::MarkedAttrs;
14 pub use rustc_ast::Attribute;
15 use rustc_data_structures::flock;
16 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
17 use rustc_data_structures::jobserver::{self, Client};
18 use rustc_data_structures::profiling::{duration_to_secs_str, SelfProfiler, SelfProfilerRef};
19 use rustc_data_structures::sync::{
20     self, AtomicU64, AtomicUsize, Lock, Lrc, OnceCell, OneThread, Ordering, Ordering::SeqCst,
21 };
22 use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitterWriter;
23 use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType};
24 use rustc_errors::json::JsonEmitter;
25 use rustc_errors::registry::Registry;
26 use rustc_errors::{
27     error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
28     ErrorGuaranteed, FluentBundle, Handler, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted,
29     TerminalUrl,
30 };
31 use rustc_macros::HashStable_Generic;
32 pub use rustc_span::def_id::StableCrateId;
33 use rustc_span::edition::Edition;
34 use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMap, Span};
35 use rustc_span::{SourceFileHashAlgorithm, Symbol};
36 use rustc_target::asm::InlineAsmArch;
37 use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
38 use rustc_target::spec::{
39     DebuginfoKind, SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel,
40 };
41 
42 use std::cell::{self, RefCell};
43 use std::env;
44 use std::fmt;
45 use std::ops::{Div, Mul};
46 use std::path::{Path, PathBuf};
47 use std::str::FromStr;
48 use std::sync::Arc;
49 use std::time::Duration;
50 
51 pub struct OptimizationFuel {
52     /// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`.
53     remaining: u64,
54     /// We're rejecting all further optimizations.
55     out_of_fuel: bool,
56 }
57 
58 /// The behavior of the CTFE engine when an error occurs with regards to backtraces.
59 #[derive(Clone, Copy)]
60 pub enum CtfeBacktrace {
61     /// Do nothing special, return the error as usual without a backtrace.
62     Disabled,
63     /// Capture a backtrace at the point the error is created and return it in the error
64     /// (to be printed later if/when the error ever actually gets shown to the user).
65     Capture,
66     /// Capture a backtrace at the point the error is created and immediately print it out.
67     Immediate,
68 }
69 
70 /// New-type wrapper around `usize` for representing limits. Ensures that comparisons against
71 /// limits are consistent throughout the compiler.
72 #[derive(Clone, Copy, Debug, HashStable_Generic)]
73 pub struct Limit(pub usize);
74 
75 impl Limit {
76     /// Create a new limit from a `usize`.
new(value: usize) -> Self77     pub fn new(value: usize) -> Self {
78         Limit(value)
79     }
80 
81     /// Check that `value` is within the limit. Ensures that the same comparisons are used
82     /// throughout the compiler, as mismatches can cause ICEs, see #72540.
83     #[inline]
value_within_limit(&self, value: usize) -> bool84     pub fn value_within_limit(&self, value: usize) -> bool {
85         value <= self.0
86     }
87 }
88 
89 impl From<usize> for Limit {
from(value: usize) -> Self90     fn from(value: usize) -> Self {
91         Self::new(value)
92     }
93 }
94 
95 impl fmt::Display for Limit {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result96     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97         self.0.fmt(f)
98     }
99 }
100 
101 impl Div<usize> for Limit {
102     type Output = Limit;
103 
div(self, rhs: usize) -> Self::Output104     fn div(self, rhs: usize) -> Self::Output {
105         Limit::new(self.0 / rhs)
106     }
107 }
108 
109 impl Mul<usize> for Limit {
110     type Output = Limit;
111 
mul(self, rhs: usize) -> Self::Output112     fn mul(self, rhs: usize) -> Self::Output {
113         Limit::new(self.0 * rhs)
114     }
115 }
116 
117 impl rustc_errors::IntoDiagnosticArg for Limit {
into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static>118     fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
119         self.to_string().into_diagnostic_arg()
120     }
121 }
122 
123 #[derive(Clone, Copy, Debug, HashStable_Generic)]
124 pub struct Limits {
125     /// The maximum recursion limit for potentially infinitely recursive
126     /// operations such as auto-dereference and monomorphization.
127     pub recursion_limit: Limit,
128     /// The size at which the `large_assignments` lint starts
129     /// being emitted.
130     pub move_size_limit: Limit,
131     /// The maximum length of types during monomorphization.
132     pub type_length_limit: Limit,
133 }
134 
135 pub struct CompilerIO {
136     pub input: Input,
137     pub output_dir: Option<PathBuf>,
138     pub output_file: Option<OutFileName>,
139     pub temps_dir: Option<PathBuf>,
140 }
141 
142 /// Represents the data associated with a compilation
143 /// session for a single crate.
144 pub struct Session {
145     pub target: Target,
146     pub host: Target,
147     pub opts: config::Options,
148     pub host_tlib_path: Lrc<SearchPath>,
149     pub target_tlib_path: Lrc<SearchPath>,
150     pub parse_sess: ParseSess,
151     pub sysroot: PathBuf,
152     /// Input, input file path and output file path to this compilation process.
153     pub io: CompilerIO,
154 
155     crate_types: OnceCell<Vec<CrateType>>,
156     /// The `stable_crate_id` is constructed out of the crate name and all the
157     /// `-C metadata` arguments passed to the compiler. Its value forms a unique
158     /// global identifier for the crate. It is used to allow multiple crates
159     /// with the same name to coexist. See the
160     /// `rustc_symbol_mangling` crate for more information.
161     pub stable_crate_id: OnceCell<StableCrateId>,
162 
163     features: OnceCell<rustc_feature::Features>,
164 
165     incr_comp_session: OneThread<RefCell<IncrCompSession>>,
166     /// Used for incremental compilation tests. Will only be populated if
167     /// `-Zquery-dep-graph` is specified.
168     pub cgu_reuse_tracker: CguReuseTracker,
169 
170     /// Used by `-Z self-profile`.
171     pub prof: SelfProfilerRef,
172 
173     /// Some measurements that are being gathered during compilation.
174     pub perf_stats: PerfStats,
175 
176     /// Data about code being compiled, gathered during compilation.
177     pub code_stats: CodeStats,
178 
179     /// Tracks fuel info if `-zfuel=crate=n` is specified.
180     optimization_fuel: Lock<OptimizationFuel>,
181 
182     /// Always set to zero and incremented so that we can print fuel expended by a crate.
183     pub print_fuel: AtomicU64,
184 
185     /// Loaded up early on in the initialization of this `Session` to avoid
186     /// false positives about a job server in our environment.
187     pub jobserver: Client,
188 
189     /// Cap lint level specified by a driver specifically.
190     pub driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
191 
192     /// Tracks the current behavior of the CTFE engine when an error occurs.
193     /// Options range from returning the error without a backtrace to returning an error
194     /// and immediately printing the backtrace to stderr.
195     /// The `Lock` is only used by miri to allow setting `ctfe_backtrace` after analysis when
196     /// `MIRI_BACKTRACE` is set. This makes it only apply to miri's errors and not to all CTFE
197     /// errors.
198     pub ctfe_backtrace: Lock<CtfeBacktrace>,
199 
200     /// This tracks where `-Zunleash-the-miri-inside-of-you` was used to get around a
201     /// const check, optionally with the relevant feature gate. We use this to
202     /// warn about unleashing, but with a single diagnostic instead of dozens that
203     /// drown everything else in noise.
204     miri_unleashed_features: Lock<Vec<(Span, Option<Symbol>)>>,
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: FxIndexSet<Symbol>,
211 
212     /// Set of enabled features for the current target, including unstable ones.
213     pub unstable_target_features: FxIndexSet<Symbol>,
214 
215     /// The version of the rustc process, possibly including a commit hash and description.
216     pub cfg_version: &'static str,
217 }
218 
219 pub struct PerfStats {
220     /// The accumulated time spent on computing symbol hashes.
221     pub symbol_hash_time: Lock<Duration>,
222     /// Total number of values canonicalized queries constructed.
223     pub queries_canonicalized: AtomicUsize,
224     /// Number of times this query is invoked.
225     pub normalize_generic_arg_after_erasing_regions: AtomicUsize,
226     /// Number of times this query is invoked.
227     pub normalize_projection_ty: AtomicUsize,
228 }
229 
230 #[derive(PartialEq, Eq, PartialOrd, Ord)]
231 pub enum MetadataKind {
232     None,
233     Uncompressed,
234     Compressed,
235 }
236 
237 #[derive(Clone, Copy)]
238 pub enum CodegenUnits {
239     /// Specified by the user. In this case we try fairly hard to produce the
240     /// number of CGUs requested.
241     User(usize),
242 
243     /// A default value, i.e. not specified by the user. In this case we take
244     /// more liberties about CGU formation, e.g. avoid producing very small
245     /// CGUs.
246     Default(usize),
247 }
248 
249 impl CodegenUnits {
as_usize(self) -> usize250     pub fn as_usize(self) -> usize {
251         match self {
252             CodegenUnits::User(n) => n,
253             CodegenUnits::Default(n) => n,
254         }
255     }
256 }
257 
258 impl Session {
miri_unleashed_feature(&self, span: Span, feature_gate: Option<Symbol>)259     pub fn miri_unleashed_feature(&self, span: Span, feature_gate: Option<Symbol>) {
260         self.miri_unleashed_features.lock().push((span, feature_gate));
261     }
262 
local_crate_source_file(&self) -> Option<PathBuf>263     pub fn local_crate_source_file(&self) -> Option<PathBuf> {
264         let path = self.io.input.opt_path()?;
265         Some(self.opts.file_path_mapping().map_prefix(path).0.into_owned())
266     }
267 
check_miri_unleashed_features(&self)268     fn check_miri_unleashed_features(&self) {
269         let unleashed_features = self.miri_unleashed_features.lock();
270         if !unleashed_features.is_empty() {
271             let mut must_err = false;
272             // Create a diagnostic pointing at where things got unleashed.
273             self.emit_warning(errors::SkippingConstChecks {
274                 unleashed_features: unleashed_features
275                     .iter()
276                     .map(|(span, gate)| {
277                         gate.map(|gate| {
278                             must_err = true;
279                             errors::UnleashedFeatureHelp::Named { span: *span, gate }
280                         })
281                         .unwrap_or(errors::UnleashedFeatureHelp::Unnamed { span: *span })
282                     })
283                     .collect(),
284             });
285 
286             // If we should err, make sure we did.
287             if must_err && self.has_errors().is_none() {
288                 // We have skipped a feature gate, and not run into other errors... reject.
289                 self.emit_err(errors::NotCircumventFeature);
290             }
291         }
292     }
293 
294     /// Invoked all the way at the end to finish off diagnostics printing.
finish_diagnostics(&self, registry: &Registry)295     pub fn finish_diagnostics(&self, registry: &Registry) {
296         self.check_miri_unleashed_features();
297         self.diagnostic().print_error_count(registry);
298         self.emit_future_breakage();
299     }
300 
emit_future_breakage(&self)301     fn emit_future_breakage(&self) {
302         if !self.opts.json_future_incompat {
303             return;
304         }
305 
306         let diags = self.diagnostic().take_future_breakage_diagnostics();
307         if diags.is_empty() {
308             return;
309         }
310         self.parse_sess.span_diagnostic.emit_future_breakage_report(diags);
311     }
312 
local_stable_crate_id(&self) -> StableCrateId313     pub fn local_stable_crate_id(&self) -> StableCrateId {
314         self.stable_crate_id.get().copied().unwrap()
315     }
316 
crate_types(&self) -> &[CrateType]317     pub fn crate_types(&self) -> &[CrateType] {
318         self.crate_types.get().unwrap().as_slice()
319     }
320 
321     /// Returns true if the crate is a testing one.
is_test_crate(&self) -> bool322     pub fn is_test_crate(&self) -> bool {
323         self.opts.test
324     }
325 
needs_crate_hash(&self) -> bool326     pub fn needs_crate_hash(&self) -> bool {
327         // Why is the crate hash needed for these configurations?
328         // - debug_assertions: for the "fingerprint the result" check in
329         //   `rustc_query_system::query::plumbing::execute_job`.
330         // - incremental: for query lookups.
331         // - needs_metadata: for putting into crate metadata.
332         // - instrument_coverage: for putting into coverage data (see
333         //   `hash_mir_source`).
334         cfg!(debug_assertions)
335             || self.opts.incremental.is_some()
336             || self.needs_metadata()
337             || self.instrument_coverage()
338     }
339 
metadata_kind(&self) -> MetadataKind340     pub fn metadata_kind(&self) -> MetadataKind {
341         self.crate_types()
342             .iter()
343             .map(|ty| match *ty {
344                 CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => {
345                     MetadataKind::None
346                 }
347                 CrateType::Rlib => MetadataKind::Uncompressed,
348                 CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed,
349             })
350             .max()
351             .unwrap_or(MetadataKind::None)
352     }
353 
needs_metadata(&self) -> bool354     pub fn needs_metadata(&self) -> bool {
355         self.metadata_kind() != MetadataKind::None
356     }
357 
init_crate_types(&self, crate_types: Vec<CrateType>)358     pub fn init_crate_types(&self, crate_types: Vec<CrateType>) {
359         self.crate_types.set(crate_types).expect("`crate_types` was initialized twice")
360     }
361 
362     #[rustc_lint_diagnostics]
363     #[track_caller]
struct_span_warn<S: Into<MultiSpan>>( &self, sp: S, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ()>364     pub fn struct_span_warn<S: Into<MultiSpan>>(
365         &self,
366         sp: S,
367         msg: impl Into<DiagnosticMessage>,
368     ) -> DiagnosticBuilder<'_, ()> {
369         self.diagnostic().struct_span_warn(sp, msg)
370     }
371     #[rustc_lint_diagnostics]
372     #[track_caller]
struct_span_warn_with_expectation<S: Into<MultiSpan>>( &self, sp: S, msg: impl Into<DiagnosticMessage>, id: lint::LintExpectationId, ) -> DiagnosticBuilder<'_, ()>373     pub fn struct_span_warn_with_expectation<S: Into<MultiSpan>>(
374         &self,
375         sp: S,
376         msg: impl Into<DiagnosticMessage>,
377         id: lint::LintExpectationId,
378     ) -> DiagnosticBuilder<'_, ()> {
379         self.diagnostic().struct_span_warn_with_expectation(sp, msg, id)
380     }
381     #[rustc_lint_diagnostics]
382     #[track_caller]
struct_span_warn_with_code<S: Into<MultiSpan>>( &self, sp: S, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, ) -> DiagnosticBuilder<'_, ()>383     pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(
384         &self,
385         sp: S,
386         msg: impl Into<DiagnosticMessage>,
387         code: DiagnosticId,
388     ) -> DiagnosticBuilder<'_, ()> {
389         self.diagnostic().struct_span_warn_with_code(sp, msg, code)
390     }
391     #[rustc_lint_diagnostics]
392     #[track_caller]
struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()>393     pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
394         self.diagnostic().struct_warn(msg)
395     }
396     #[rustc_lint_diagnostics]
397     #[track_caller]
struct_warn_with_expectation( &self, msg: impl Into<DiagnosticMessage>, id: lint::LintExpectationId, ) -> DiagnosticBuilder<'_, ()>398     pub fn struct_warn_with_expectation(
399         &self,
400         msg: impl Into<DiagnosticMessage>,
401         id: lint::LintExpectationId,
402     ) -> DiagnosticBuilder<'_, ()> {
403         self.diagnostic().struct_warn_with_expectation(msg, id)
404     }
405     #[rustc_lint_diagnostics]
406     #[track_caller]
struct_span_allow<S: Into<MultiSpan>>( &self, sp: S, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ()>407     pub fn struct_span_allow<S: Into<MultiSpan>>(
408         &self,
409         sp: S,
410         msg: impl Into<DiagnosticMessage>,
411     ) -> DiagnosticBuilder<'_, ()> {
412         self.diagnostic().struct_span_allow(sp, msg)
413     }
414     #[rustc_lint_diagnostics]
415     #[track_caller]
struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()>416     pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
417         self.diagnostic().struct_allow(msg)
418     }
419     #[rustc_lint_diagnostics]
420     #[track_caller]
struct_expect( &self, msg: impl Into<DiagnosticMessage>, id: lint::LintExpectationId, ) -> DiagnosticBuilder<'_, ()>421     pub fn struct_expect(
422         &self,
423         msg: impl Into<DiagnosticMessage>,
424         id: lint::LintExpectationId,
425     ) -> DiagnosticBuilder<'_, ()> {
426         self.diagnostic().struct_expect(msg, id)
427     }
428     #[rustc_lint_diagnostics]
429     #[track_caller]
struct_span_err<S: Into<MultiSpan>>( &self, sp: S, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ErrorGuaranteed>430     pub fn struct_span_err<S: Into<MultiSpan>>(
431         &self,
432         sp: S,
433         msg: impl Into<DiagnosticMessage>,
434     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
435         self.diagnostic().struct_span_err(sp, msg)
436     }
437     #[rustc_lint_diagnostics]
438     #[track_caller]
struct_span_err_with_code<S: Into<MultiSpan>>( &self, sp: S, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, ) -> DiagnosticBuilder<'_, ErrorGuaranteed>439     pub fn struct_span_err_with_code<S: Into<MultiSpan>>(
440         &self,
441         sp: S,
442         msg: impl Into<DiagnosticMessage>,
443         code: DiagnosticId,
444     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
445         self.diagnostic().struct_span_err_with_code(sp, msg, code)
446     }
447     // FIXME: This method should be removed (every error should have an associated error code).
448     #[rustc_lint_diagnostics]
449     #[track_caller]
struct_err( &self, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ErrorGuaranteed>450     pub fn struct_err(
451         &self,
452         msg: impl Into<DiagnosticMessage>,
453     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
454         self.parse_sess.struct_err(msg)
455     }
456     #[track_caller]
457     #[rustc_lint_diagnostics]
struct_err_with_code( &self, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, ) -> DiagnosticBuilder<'_, ErrorGuaranteed>458     pub fn struct_err_with_code(
459         &self,
460         msg: impl Into<DiagnosticMessage>,
461         code: DiagnosticId,
462     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
463         self.diagnostic().struct_err_with_code(msg, code)
464     }
465     #[rustc_lint_diagnostics]
466     #[track_caller]
struct_warn_with_code( &self, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, ) -> DiagnosticBuilder<'_, ()>467     pub fn struct_warn_with_code(
468         &self,
469         msg: impl Into<DiagnosticMessage>,
470         code: DiagnosticId,
471     ) -> DiagnosticBuilder<'_, ()> {
472         self.diagnostic().struct_warn_with_code(msg, code)
473     }
474     #[rustc_lint_diagnostics]
475     #[track_caller]
struct_span_fatal<S: Into<MultiSpan>>( &self, sp: S, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, !>476     pub fn struct_span_fatal<S: Into<MultiSpan>>(
477         &self,
478         sp: S,
479         msg: impl Into<DiagnosticMessage>,
480     ) -> DiagnosticBuilder<'_, !> {
481         self.diagnostic().struct_span_fatal(sp, msg)
482     }
483     #[rustc_lint_diagnostics]
struct_span_fatal_with_code<S: Into<MultiSpan>>( &self, sp: S, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, ) -> DiagnosticBuilder<'_, !>484     pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(
485         &self,
486         sp: S,
487         msg: impl Into<DiagnosticMessage>,
488         code: DiagnosticId,
489     ) -> DiagnosticBuilder<'_, !> {
490         self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
491     }
492     #[rustc_lint_diagnostics]
struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !>493     pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
494         self.diagnostic().struct_fatal(msg)
495     }
496 
497     #[rustc_lint_diagnostics]
498     #[track_caller]
span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> !499     pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
500         self.diagnostic().span_fatal(sp, msg)
501     }
502     #[rustc_lint_diagnostics]
span_fatal_with_code<S: Into<MultiSpan>>( &self, sp: S, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, ) -> !503     pub fn span_fatal_with_code<S: Into<MultiSpan>>(
504         &self,
505         sp: S,
506         msg: impl Into<DiagnosticMessage>,
507         code: DiagnosticId,
508     ) -> ! {
509         self.diagnostic().span_fatal_with_code(sp, msg, code)
510     }
511     #[rustc_lint_diagnostics]
fatal(&self, msg: impl Into<DiagnosticMessage>) -> !512     pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
513         self.diagnostic().fatal(msg).raise()
514     }
515     #[rustc_lint_diagnostics]
516     #[track_caller]
span_err<S: Into<MultiSpan>>( &self, sp: S, msg: impl Into<DiagnosticMessage>, ) -> ErrorGuaranteed517     pub fn span_err<S: Into<MultiSpan>>(
518         &self,
519         sp: S,
520         msg: impl Into<DiagnosticMessage>,
521     ) -> ErrorGuaranteed {
522         self.diagnostic().span_err(sp, msg)
523     }
524     #[rustc_lint_diagnostics]
span_err_with_code<S: Into<MultiSpan>>( &self, sp: S, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, )525     pub fn span_err_with_code<S: Into<MultiSpan>>(
526         &self,
527         sp: S,
528         msg: impl Into<DiagnosticMessage>,
529         code: DiagnosticId,
530     ) {
531         self.diagnostic().span_err_with_code(sp, msg, code)
532     }
533     #[rustc_lint_diagnostics]
534     #[allow(rustc::untranslatable_diagnostic)]
535     #[allow(rustc::diagnostic_outside_of_impl)]
err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed536     pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
537         self.diagnostic().err(msg)
538     }
539     #[track_caller]
create_err<'a>( &'a self, err: impl IntoDiagnostic<'a>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed>540     pub fn create_err<'a>(
541         &'a self,
542         err: impl IntoDiagnostic<'a>,
543     ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
544         self.parse_sess.create_err(err)
545     }
546     #[track_caller]
create_feature_err<'a>( &'a self, err: impl IntoDiagnostic<'a>, feature: Symbol, ) -> DiagnosticBuilder<'a, ErrorGuaranteed>547     pub fn create_feature_err<'a>(
548         &'a self,
549         err: impl IntoDiagnostic<'a>,
550         feature: Symbol,
551     ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
552         let mut err = self.parse_sess.create_err(err);
553         if err.code.is_none() {
554             err.code = std::option::Option::Some(error_code!(E0658));
555         }
556         add_feature_diagnostics(&mut err, &self.parse_sess, feature);
557         err
558     }
559     #[track_caller]
emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed560     pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
561         self.parse_sess.emit_err(err)
562     }
563     #[track_caller]
create_warning<'a>( &'a self, err: impl IntoDiagnostic<'a, ()>, ) -> DiagnosticBuilder<'a, ()>564     pub fn create_warning<'a>(
565         &'a self,
566         err: impl IntoDiagnostic<'a, ()>,
567     ) -> DiagnosticBuilder<'a, ()> {
568         self.parse_sess.create_warning(err)
569     }
570     #[track_caller]
emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>)571     pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
572         self.parse_sess.emit_warning(warning)
573     }
574     #[track_caller]
create_note<'a>( &'a self, note: impl IntoDiagnostic<'a, Noted>, ) -> DiagnosticBuilder<'a, Noted>575     pub fn create_note<'a>(
576         &'a self,
577         note: impl IntoDiagnostic<'a, Noted>,
578     ) -> DiagnosticBuilder<'a, Noted> {
579         self.parse_sess.create_note(note)
580     }
581     #[track_caller]
emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted582     pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted {
583         self.parse_sess.emit_note(note)
584     }
585     #[track_caller]
create_fatal<'a>( &'a self, fatal: impl IntoDiagnostic<'a, !>, ) -> DiagnosticBuilder<'a, !>586     pub fn create_fatal<'a>(
587         &'a self,
588         fatal: impl IntoDiagnostic<'a, !>,
589     ) -> DiagnosticBuilder<'a, !> {
590         self.parse_sess.create_fatal(fatal)
591     }
592     #[track_caller]
emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> !593     pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! {
594         self.parse_sess.emit_fatal(fatal)
595     }
596     #[inline]
err_count(&self) -> usize597     pub fn err_count(&self) -> usize {
598         self.diagnostic().err_count()
599     }
has_errors(&self) -> Option<ErrorGuaranteed>600     pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
601         self.diagnostic().has_errors()
602     }
has_errors_or_delayed_span_bugs(&self) -> Option<ErrorGuaranteed>603     pub fn has_errors_or_delayed_span_bugs(&self) -> Option<ErrorGuaranteed> {
604         self.diagnostic().has_errors_or_delayed_span_bugs()
605     }
is_compilation_going_to_fail(&self) -> Option<ErrorGuaranteed>606     pub fn is_compilation_going_to_fail(&self) -> Option<ErrorGuaranteed> {
607         self.diagnostic().is_compilation_going_to_fail()
608     }
abort_if_errors(&self)609     pub fn abort_if_errors(&self) {
610         self.diagnostic().abort_if_errors();
611     }
compile_status(&self) -> Result<(), ErrorGuaranteed>612     pub fn compile_status(&self) -> Result<(), ErrorGuaranteed> {
613         if let Some(reported) = self.diagnostic().has_errors_or_lint_errors() {
614             let _ = self.diagnostic().emit_stashed_diagnostics();
615             Err(reported)
616         } else {
617             Ok(())
618         }
619     }
620     // FIXME(matthewjasper) Remove this method, it should never be needed.
track_errors<F, T>(&self, f: F) -> Result<T, ErrorGuaranteed> where F: FnOnce() -> T,621     pub fn track_errors<F, T>(&self, f: F) -> Result<T, ErrorGuaranteed>
622     where
623         F: FnOnce() -> T,
624     {
625         let old_count = self.err_count();
626         let result = f();
627         if self.err_count() == old_count {
628             Ok(result)
629         } else {
630             Err(self.delay_span_bug(
631                 rustc_span::DUMMY_SP,
632                 "`self.err_count()` changed but an error was not emitted",
633             ))
634         }
635     }
636 
637     #[rustc_lint_diagnostics]
638     #[allow(rustc::untranslatable_diagnostic)]
639     #[allow(rustc::diagnostic_outside_of_impl)]
640     #[track_caller]
span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>)641     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
642         self.diagnostic().span_warn(sp, msg)
643     }
644 
645     #[rustc_lint_diagnostics]
646     #[allow(rustc::untranslatable_diagnostic)]
647     #[allow(rustc::diagnostic_outside_of_impl)]
span_warn_with_code<S: Into<MultiSpan>>( &self, sp: S, msg: impl Into<DiagnosticMessage>, code: DiagnosticId, )648     pub fn span_warn_with_code<S: Into<MultiSpan>>(
649         &self,
650         sp: S,
651         msg: impl Into<DiagnosticMessage>,
652         code: DiagnosticId,
653     ) {
654         self.diagnostic().span_warn_with_code(sp, msg, code)
655     }
656 
657     #[rustc_lint_diagnostics]
658     #[allow(rustc::untranslatable_diagnostic)]
659     #[allow(rustc::diagnostic_outside_of_impl)]
warn(&self, msg: impl Into<DiagnosticMessage>)660     pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
661         self.diagnostic().warn(msg)
662     }
663 
664     /// Ensures that compilation cannot succeed.
665     ///
666     /// If this function has been called but no errors have been emitted and
667     /// compilation succeeds, it will cause an internal compiler error (ICE).
668     ///
669     /// This can be used in code paths that should never run on successful compilations.
670     /// For example, it can be used to create an [`ErrorGuaranteed`]
671     /// (but you should prefer threading through the [`ErrorGuaranteed`] from an error emission directly).
672     ///
673     /// If no span is available, use [`DUMMY_SP`].
674     ///
675     /// [`DUMMY_SP`]: rustc_span::DUMMY_SP
676     #[track_caller]
delay_span_bug<S: Into<MultiSpan>>( &self, sp: S, msg: impl Into<DiagnosticMessage>, ) -> ErrorGuaranteed677     pub fn delay_span_bug<S: Into<MultiSpan>>(
678         &self,
679         sp: S,
680         msg: impl Into<DiagnosticMessage>,
681     ) -> ErrorGuaranteed {
682         self.diagnostic().delay_span_bug(sp, msg)
683     }
684 
685     /// Used for code paths of expensive computations that should only take place when
686     /// warnings or errors are emitted. If no messages are emitted ("good path"), then
687     /// it's likely a bug.
delay_good_path_bug(&self, msg: impl Into<DiagnosticMessage>)688     pub fn delay_good_path_bug(&self, msg: impl Into<DiagnosticMessage>) {
689         if self.opts.unstable_opts.print_type_sizes
690             || self.opts.unstable_opts.query_dep_graph
691             || self.opts.unstable_opts.dump_mir.is_some()
692             || self.opts.unstable_opts.unpretty.is_some()
693             || self.opts.output_types.contains_key(&OutputType::Mir)
694             || std::env::var_os("RUSTC_LOG").is_some()
695         {
696             return;
697         }
698 
699         self.diagnostic().delay_good_path_bug(msg)
700     }
701 
702     #[rustc_lint_diagnostics]
703     #[allow(rustc::untranslatable_diagnostic)]
704     #[allow(rustc::diagnostic_outside_of_impl)]
note_without_error(&self, msg: impl Into<DiagnosticMessage>)705     pub fn note_without_error(&self, msg: impl Into<DiagnosticMessage>) {
706         self.diagnostic().note_without_error(msg)
707     }
708 
709     #[track_caller]
710     #[rustc_lint_diagnostics]
711     #[allow(rustc::untranslatable_diagnostic)]
712     #[allow(rustc::diagnostic_outside_of_impl)]
span_note_without_error<S: Into<MultiSpan>>( &self, sp: S, msg: impl Into<DiagnosticMessage>, )713     pub fn span_note_without_error<S: Into<MultiSpan>>(
714         &self,
715         sp: S,
716         msg: impl Into<DiagnosticMessage>,
717     ) {
718         self.diagnostic().span_note_without_error(sp, msg)
719     }
720 
721     #[rustc_lint_diagnostics]
722     #[allow(rustc::untranslatable_diagnostic)]
723     #[allow(rustc::diagnostic_outside_of_impl)]
struct_note_without_error( &self, msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'_, ()>724     pub fn struct_note_without_error(
725         &self,
726         msg: impl Into<DiagnosticMessage>,
727     ) -> DiagnosticBuilder<'_, ()> {
728         self.diagnostic().struct_note_without_error(msg)
729     }
730 
731     #[inline]
diagnostic(&self) -> &rustc_errors::Handler732     pub fn diagnostic(&self) -> &rustc_errors::Handler {
733         &self.parse_sess.span_diagnostic
734     }
735 
736     #[inline]
source_map(&self) -> &SourceMap737     pub fn source_map(&self) -> &SourceMap {
738         self.parse_sess.source_map()
739     }
740 
741     /// Returns `true` if internal lints should be added to the lint store - i.e. if
742     /// `-Zunstable-options` is provided and this isn't rustdoc (internal lints can trigger errors
743     /// to be emitted under rustdoc).
enable_internal_lints(&self) -> bool744     pub fn enable_internal_lints(&self) -> bool {
745         self.unstable_options() && !self.opts.actually_rustdoc
746     }
747 
instrument_coverage(&self) -> bool748     pub fn instrument_coverage(&self) -> bool {
749         self.opts.cg.instrument_coverage() != InstrumentCoverage::Off
750     }
751 
instrument_coverage_except_unused_generics(&self) -> bool752     pub fn instrument_coverage_except_unused_generics(&self) -> bool {
753         self.opts.cg.instrument_coverage() == InstrumentCoverage::ExceptUnusedGenerics
754     }
755 
instrument_coverage_except_unused_functions(&self) -> bool756     pub fn instrument_coverage_except_unused_functions(&self) -> bool {
757         self.opts.cg.instrument_coverage() == InstrumentCoverage::ExceptUnusedFunctions
758     }
759 
760     /// Gets the features enabled for the current compilation session.
761     /// DO NOT USE THIS METHOD if there is a TyCtxt available, as it circumvents
762     /// dependency tracking. Use tcx.features() instead.
763     #[inline]
features_untracked(&self) -> &rustc_feature::Features764     pub fn features_untracked(&self) -> &rustc_feature::Features {
765         self.features.get().unwrap()
766     }
767 
init_features(&self, features: rustc_feature::Features)768     pub fn init_features(&self, features: rustc_feature::Features) {
769         match self.features.set(features) {
770             Ok(()) => {}
771             Err(_) => panic!("`features` was initialized twice"),
772         }
773     }
774 
is_sanitizer_cfi_enabled(&self) -> bool775     pub fn is_sanitizer_cfi_enabled(&self) -> bool {
776         self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
777     }
778 
is_sanitizer_cfi_canonical_jump_tables_disabled(&self) -> bool779     pub fn is_sanitizer_cfi_canonical_jump_tables_disabled(&self) -> bool {
780         self.opts.unstable_opts.sanitizer_cfi_canonical_jump_tables == Some(false)
781     }
782 
is_sanitizer_cfi_canonical_jump_tables_enabled(&self) -> bool783     pub fn is_sanitizer_cfi_canonical_jump_tables_enabled(&self) -> bool {
784         self.opts.unstable_opts.sanitizer_cfi_canonical_jump_tables == Some(true)
785     }
786 
is_sanitizer_cfi_generalize_pointers_enabled(&self) -> bool787     pub fn is_sanitizer_cfi_generalize_pointers_enabled(&self) -> bool {
788         self.opts.unstable_opts.sanitizer_cfi_generalize_pointers == Some(true)
789     }
790 
is_sanitizer_cfi_normalize_integers_enabled(&self) -> bool791     pub fn is_sanitizer_cfi_normalize_integers_enabled(&self) -> bool {
792         self.opts.unstable_opts.sanitizer_cfi_normalize_integers == Some(true)
793     }
794 
is_sanitizer_kcfi_enabled(&self) -> bool795     pub fn is_sanitizer_kcfi_enabled(&self) -> bool {
796         self.opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI)
797     }
798 
is_split_lto_unit_enabled(&self) -> bool799     pub fn is_split_lto_unit_enabled(&self) -> bool {
800         self.opts.unstable_opts.split_lto_unit == Some(true)
801     }
802 
803     /// Check whether this compile session and crate type use static crt.
crt_static(&self, crate_type: Option<CrateType>) -> bool804     pub fn crt_static(&self, crate_type: Option<CrateType>) -> bool {
805         if !self.target.crt_static_respected {
806             // If the target does not opt in to crt-static support, use its default.
807             return self.target.crt_static_default;
808         }
809 
810         let requested_features = self.opts.cg.target_feature.split(',');
811         let found_negative = requested_features.clone().any(|r| r == "-crt-static");
812         let found_positive = requested_features.clone().any(|r| r == "+crt-static");
813 
814         // JUSTIFICATION: necessary use of crate_types directly (see FIXME below)
815         #[allow(rustc::bad_opt_access)]
816         if found_positive || found_negative {
817             found_positive
818         } else if crate_type == Some(CrateType::ProcMacro)
819             || crate_type == None && self.opts.crate_types.contains(&CrateType::ProcMacro)
820         {
821             // FIXME: When crate_type is not available,
822             // we use compiler options to determine the crate_type.
823             // We can't check `#![crate_type = "proc-macro"]` here.
824             false
825         } else {
826             self.target.crt_static_default
827         }
828     }
829 
is_wasi_reactor(&self) -> bool830     pub fn is_wasi_reactor(&self) -> bool {
831         self.target.options.os == "wasi"
832             && matches!(
833                 self.opts.unstable_opts.wasi_exec_model,
834                 Some(config::WasiExecModel::Reactor)
835             )
836     }
837 
838     /// Returns `true` if the target can use the current split debuginfo configuration.
target_can_use_split_dwarf(&self) -> bool839     pub fn target_can_use_split_dwarf(&self) -> bool {
840         self.target.debuginfo_kind == DebuginfoKind::Dwarf
841     }
842 
generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String843     pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String {
844         format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.as_u64())
845     }
846 
target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_>847     pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> {
848         filesearch::FileSearch::new(
849             &self.sysroot,
850             self.opts.target_triple.triple(),
851             &self.opts.search_paths,
852             &self.target_tlib_path,
853             kind,
854         )
855     }
host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_>856     pub fn host_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> {
857         filesearch::FileSearch::new(
858             &self.sysroot,
859             config::host_triple(),
860             &self.opts.search_paths,
861             &self.host_tlib_path,
862             kind,
863         )
864     }
865 
866     /// Returns a list of directories where target-specific tool binaries are located.
get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf>867     pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> {
868         let rustlib_path = rustc_target::target_rustlib_path(&self.sysroot, &config::host_triple());
869         let p = PathBuf::from_iter([
870             Path::new(&self.sysroot),
871             Path::new(&rustlib_path),
872             Path::new("bin"),
873         ]);
874         if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] }
875     }
876 
init_incr_comp_session( &self, session_dir: PathBuf, lock_file: flock::Lock, load_dep_graph: bool, )877     pub fn init_incr_comp_session(
878         &self,
879         session_dir: PathBuf,
880         lock_file: flock::Lock,
881         load_dep_graph: bool,
882     ) {
883         let mut incr_comp_session = self.incr_comp_session.borrow_mut();
884 
885         if let IncrCompSession::NotInitialized = *incr_comp_session {
886         } else {
887             panic!("Trying to initialize IncrCompSession `{:?}`", *incr_comp_session)
888         }
889 
890         *incr_comp_session =
891             IncrCompSession::Active { session_directory: session_dir, lock_file, load_dep_graph };
892     }
893 
finalize_incr_comp_session(&self, new_directory_path: PathBuf)894     pub fn finalize_incr_comp_session(&self, new_directory_path: PathBuf) {
895         let mut incr_comp_session = self.incr_comp_session.borrow_mut();
896 
897         if let IncrCompSession::Active { .. } = *incr_comp_session {
898         } else {
899             panic!("trying to finalize `IncrCompSession` `{:?}`", *incr_comp_session);
900         }
901 
902         // Note: this will also drop the lock file, thus unlocking the directory.
903         *incr_comp_session = IncrCompSession::Finalized { session_directory: new_directory_path };
904     }
905 
mark_incr_comp_session_as_invalid(&self)906     pub fn mark_incr_comp_session_as_invalid(&self) {
907         let mut incr_comp_session = self.incr_comp_session.borrow_mut();
908 
909         let session_directory = match *incr_comp_session {
910             IncrCompSession::Active { ref session_directory, .. } => session_directory.clone(),
911             IncrCompSession::InvalidBecauseOfErrors { .. } => return,
912             _ => panic!("trying to invalidate `IncrCompSession` `{:?}`", *incr_comp_session),
913         };
914 
915         // Note: this will also drop the lock file, thus unlocking the directory.
916         *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors { session_directory };
917     }
918 
incr_comp_session_dir(&self) -> cell::Ref<'_, PathBuf>919     pub fn incr_comp_session_dir(&self) -> cell::Ref<'_, PathBuf> {
920         let incr_comp_session = self.incr_comp_session.borrow();
921         cell::Ref::map(incr_comp_session, |incr_comp_session| match *incr_comp_session {
922             IncrCompSession::NotInitialized => panic!(
923                 "trying to get session directory from `IncrCompSession`: {:?}",
924                 *incr_comp_session,
925             ),
926             IncrCompSession::Active { ref session_directory, .. }
927             | IncrCompSession::Finalized { ref session_directory }
928             | IncrCompSession::InvalidBecauseOfErrors { ref session_directory } => {
929                 session_directory
930             }
931         })
932     }
933 
incr_comp_session_dir_opt(&self) -> Option<cell::Ref<'_, PathBuf>>934     pub fn incr_comp_session_dir_opt(&self) -> Option<cell::Ref<'_, PathBuf>> {
935         self.opts.incremental.as_ref().map(|_| self.incr_comp_session_dir())
936     }
937 
print_perf_stats(&self)938     pub fn print_perf_stats(&self) {
939         eprintln!(
940             "Total time spent computing symbol hashes:      {}",
941             duration_to_secs_str(*self.perf_stats.symbol_hash_time.lock())
942         );
943         eprintln!(
944             "Total queries canonicalized:                   {}",
945             self.perf_stats.queries_canonicalized.load(Ordering::Relaxed)
946         );
947         eprintln!(
948             "normalize_generic_arg_after_erasing_regions:   {}",
949             self.perf_stats.normalize_generic_arg_after_erasing_regions.load(Ordering::Relaxed)
950         );
951         eprintln!(
952             "normalize_projection_ty:                       {}",
953             self.perf_stats.normalize_projection_ty.load(Ordering::Relaxed)
954         );
955     }
956 
957     /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n.
958     /// This expends fuel if applicable, and records fuel if applicable.
consider_optimizing( &self, get_crate_name: impl Fn() -> Symbol, msg: impl Fn() -> String, ) -> bool959     pub fn consider_optimizing(
960         &self,
961         get_crate_name: impl Fn() -> Symbol,
962         msg: impl Fn() -> String,
963     ) -> bool {
964         let mut ret = true;
965         if let Some((ref c, _)) = self.opts.unstable_opts.fuel {
966             if c == get_crate_name().as_str() {
967                 assert_eq!(self.threads(), 1);
968                 let mut fuel = self.optimization_fuel.lock();
969                 ret = fuel.remaining != 0;
970                 if fuel.remaining == 0 && !fuel.out_of_fuel {
971                     if self.diagnostic().can_emit_warnings() {
972                         // We only call `msg` in case we can actually emit warnings.
973                         // Otherwise, this could cause a `delay_good_path_bug` to
974                         // trigger (issue #79546).
975                         self.emit_warning(errors::OptimisationFuelExhausted { msg: msg() });
976                     }
977                     fuel.out_of_fuel = true;
978                 } else if fuel.remaining > 0 {
979                     fuel.remaining -= 1;
980                 }
981             }
982         }
983         if let Some(ref c) = self.opts.unstable_opts.print_fuel {
984             if c == get_crate_name().as_str() {
985                 assert_eq!(self.threads(), 1);
986                 self.print_fuel.fetch_add(1, SeqCst);
987             }
988         }
989         ret
990     }
991 
992     /// Is this edition 2015?
is_rust_2015(&self) -> bool993     pub fn is_rust_2015(&self) -> bool {
994         self.edition().is_rust_2015()
995     }
996 
997     /// Are we allowed to use features from the Rust 2018 edition?
rust_2018(&self) -> bool998     pub fn rust_2018(&self) -> bool {
999         self.edition().rust_2018()
1000     }
1001 
1002     /// Are we allowed to use features from the Rust 2021 edition?
rust_2021(&self) -> bool1003     pub fn rust_2021(&self) -> bool {
1004         self.edition().rust_2021()
1005     }
1006 
1007     /// Are we allowed to use features from the Rust 2024 edition?
rust_2024(&self) -> bool1008     pub fn rust_2024(&self) -> bool {
1009         self.edition().rust_2024()
1010     }
1011 
1012     /// Returns `true` if we should use the PLT for shared library calls.
needs_plt(&self) -> bool1013     pub fn needs_plt(&self) -> bool {
1014         // Check if the current target usually wants PLT to be enabled.
1015         // The user can use the command line flag to override it.
1016         let want_plt = self.target.plt_by_default;
1017 
1018         let dbg_opts = &self.opts.unstable_opts;
1019 
1020         let relro_level = self.opts.cg.relro_level.unwrap_or(self.target.relro_level);
1021 
1022         // Only enable this optimization by default if full relro is also enabled.
1023         // In this case, lazy binding was already unavailable, so nothing is lost.
1024         // This also ensures `-Wl,-z,now` is supported by the linker.
1025         let full_relro = RelroLevel::Full == relro_level;
1026 
1027         // If user didn't explicitly forced us to use / skip the PLT,
1028         // then use it unless the target doesn't want it by default or the full relro forces it on.
1029         dbg_opts.plt.unwrap_or(want_plt || !full_relro)
1030     }
1031 
1032     /// Checks if LLVM lifetime markers should be emitted.
emit_lifetime_markers(&self) -> bool1033     pub fn emit_lifetime_markers(&self) -> bool {
1034         self.opts.optimize != config::OptLevel::No
1035         // AddressSanitizer and KernelAddressSanitizer uses lifetimes to detect use after scope bugs.
1036         // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
1037         // HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future.
1038         || self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
1039     }
1040 
diagnostic_width(&self) -> usize1041     pub fn diagnostic_width(&self) -> usize {
1042         let default_column_width = 140;
1043         if let Some(width) = self.opts.diagnostic_width {
1044             width
1045         } else if self.opts.unstable_opts.ui_testing {
1046             default_column_width
1047         } else {
1048             termize::dimensions().map_or(default_column_width, |(w, _)| w)
1049         }
1050     }
1051 }
1052 
1053 // JUSTIFICATION: defn of the suggested wrapper fns
1054 #[allow(rustc::bad_opt_access)]
1055 impl Session {
verbose(&self) -> bool1056     pub fn verbose(&self) -> bool {
1057         self.opts.unstable_opts.verbose
1058     }
1059 
verify_llvm_ir(&self) -> bool1060     pub fn verify_llvm_ir(&self) -> bool {
1061         self.opts.unstable_opts.verify_llvm_ir || option_env!("RUSTC_VERIFY_LLVM_IR").is_some()
1062     }
1063 
binary_dep_depinfo(&self) -> bool1064     pub fn binary_dep_depinfo(&self) -> bool {
1065         self.opts.unstable_opts.binary_dep_depinfo
1066     }
1067 
mir_opt_level(&self) -> usize1068     pub fn mir_opt_level(&self) -> usize {
1069         self.opts
1070             .unstable_opts
1071             .mir_opt_level
1072             .unwrap_or_else(|| if self.opts.optimize != OptLevel::No { 2 } else { 1 })
1073     }
1074 
1075     /// Calculates the flavor of LTO to use for this compilation.
lto(&self) -> config::Lto1076     pub fn lto(&self) -> config::Lto {
1077         // If our target has codegen requirements ignore the command line
1078         if self.target.requires_lto {
1079             return config::Lto::Fat;
1080         }
1081 
1082         // If the user specified something, return that. If they only said `-C
1083         // lto` and we've for whatever reason forced off ThinLTO via the CLI,
1084         // then ensure we can't use a ThinLTO.
1085         match self.opts.cg.lto {
1086             config::LtoCli::Unspecified => {
1087                 // The compiler was invoked without the `-Clto` flag. Fall
1088                 // through to the default handling
1089             }
1090             config::LtoCli::No => {
1091                 // The user explicitly opted out of any kind of LTO
1092                 return config::Lto::No;
1093             }
1094             config::LtoCli::Yes | config::LtoCli::Fat | config::LtoCli::NoParam => {
1095                 // All of these mean fat LTO
1096                 return config::Lto::Fat;
1097             }
1098             config::LtoCli::Thin => {
1099                 // The user explicitly asked for ThinLTO
1100                 return config::Lto::Thin;
1101             }
1102         }
1103 
1104         // Ok at this point the target doesn't require anything and the user
1105         // hasn't asked for anything. Our next decision is whether or not
1106         // we enable "auto" ThinLTO where we use multiple codegen units and
1107         // then do ThinLTO over those codegen units. The logic below will
1108         // either return `No` or `ThinLocal`.
1109 
1110         // If processing command line options determined that we're incompatible
1111         // with ThinLTO (e.g., `-C lto --emit llvm-ir`) then return that option.
1112         if self.opts.cli_forced_local_thinlto_off {
1113             return config::Lto::No;
1114         }
1115 
1116         // If `-Z thinlto` specified process that, but note that this is mostly
1117         // a deprecated option now that `-C lto=thin` exists.
1118         if let Some(enabled) = self.opts.unstable_opts.thinlto {
1119             if enabled {
1120                 return config::Lto::ThinLocal;
1121             } else {
1122                 return config::Lto::No;
1123             }
1124         }
1125 
1126         // If there's only one codegen unit and LTO isn't enabled then there's
1127         // no need for ThinLTO so just return false.
1128         if self.codegen_units().as_usize() == 1 {
1129             return config::Lto::No;
1130         }
1131 
1132         // Now we're in "defaults" territory. By default we enable ThinLTO for
1133         // optimized compiles (anything greater than O0).
1134         match self.opts.optimize {
1135             config::OptLevel::No => config::Lto::No,
1136             _ => config::Lto::ThinLocal,
1137         }
1138     }
1139 
1140     /// Returns the panic strategy for this compile session. If the user explicitly selected one
1141     /// using '-C panic', use that, otherwise use the panic strategy defined by the target.
panic_strategy(&self) -> PanicStrategy1142     pub fn panic_strategy(&self) -> PanicStrategy {
1143         self.opts.cg.panic.unwrap_or(self.target.panic_strategy)
1144     }
1145 
fewer_names(&self) -> bool1146     pub fn fewer_names(&self) -> bool {
1147         if let Some(fewer_names) = self.opts.unstable_opts.fewer_names {
1148             fewer_names
1149         } else {
1150             let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
1151                 || self.opts.output_types.contains_key(&OutputType::Bitcode)
1152                 // AddressSanitizer and MemorySanitizer use alloca name when reporting an issue.
1153                 || self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
1154             !more_names
1155         }
1156     }
1157 
unstable_options(&self) -> bool1158     pub fn unstable_options(&self) -> bool {
1159         self.opts.unstable_opts.unstable_options
1160     }
1161 
is_nightly_build(&self) -> bool1162     pub fn is_nightly_build(&self) -> bool {
1163         self.opts.unstable_features.is_nightly_build()
1164     }
1165 
overflow_checks(&self) -> bool1166     pub fn overflow_checks(&self) -> bool {
1167         self.opts.cg.overflow_checks.unwrap_or(self.opts.debug_assertions)
1168     }
1169 
relocation_model(&self) -> RelocModel1170     pub fn relocation_model(&self) -> RelocModel {
1171         self.opts.cg.relocation_model.unwrap_or(self.target.relocation_model)
1172     }
1173 
code_model(&self) -> Option<CodeModel>1174     pub fn code_model(&self) -> Option<CodeModel> {
1175         self.opts.cg.code_model.or(self.target.code_model)
1176     }
1177 
tls_model(&self) -> TlsModel1178     pub fn tls_model(&self) -> TlsModel {
1179         self.opts.unstable_opts.tls_model.unwrap_or(self.target.tls_model)
1180     }
1181 
split_debuginfo(&self) -> SplitDebuginfo1182     pub fn split_debuginfo(&self) -> SplitDebuginfo {
1183         self.opts.cg.split_debuginfo.unwrap_or(self.target.split_debuginfo)
1184     }
1185 
stack_protector(&self) -> StackProtector1186     pub fn stack_protector(&self) -> StackProtector {
1187         if self.target.options.supports_stack_protector {
1188             self.opts.unstable_opts.stack_protector
1189         } else {
1190             StackProtector::None
1191         }
1192     }
1193 
must_emit_unwind_tables(&self) -> bool1194     pub fn must_emit_unwind_tables(&self) -> bool {
1195         // This is used to control the emission of the `uwtable` attribute on
1196         // LLVM functions.
1197         //
1198         // Unwind tables are needed when compiling with `-C panic=unwind`, but
1199         // LLVM won't omit unwind tables unless the function is also marked as
1200         // `nounwind`, so users are allowed to disable `uwtable` emission.
1201         // Historically rustc always emits `uwtable` attributes by default, so
1202         // even they can be disabled, they're still emitted by default.
1203         //
1204         // On some targets (including windows), however, exceptions include
1205         // other events such as illegal instructions, segfaults, etc. This means
1206         // that on Windows we end up still needing unwind tables even if the `-C
1207         // panic=abort` flag is passed.
1208         //
1209         // You can also find more info on why Windows needs unwind tables in:
1210         //      https://bugzilla.mozilla.org/show_bug.cgi?id=1302078
1211         //
1212         // If a target requires unwind tables, then they must be emitted.
1213         // Otherwise, we can defer to the `-C force-unwind-tables=<yes/no>`
1214         // value, if it is provided, or disable them, if not.
1215         self.target.requires_uwtable
1216             || self.opts.cg.force_unwind_tables.unwrap_or(
1217                 self.panic_strategy() == PanicStrategy::Unwind || self.target.default_uwtable,
1218             )
1219     }
1220 
1221     /// Returns the number of query threads that should be used for this
1222     /// compilation
1223     #[inline]
threads(&self) -> usize1224     pub fn threads(&self) -> usize {
1225         self.opts.unstable_opts.threads
1226     }
1227 
1228     /// Returns the number of codegen units that should be used for this
1229     /// compilation
codegen_units(&self) -> CodegenUnits1230     pub fn codegen_units(&self) -> CodegenUnits {
1231         if let Some(n) = self.opts.cli_forced_codegen_units {
1232             return CodegenUnits::User(n);
1233         }
1234         if let Some(n) = self.target.default_codegen_units {
1235             return CodegenUnits::Default(n as usize);
1236         }
1237 
1238         // If incremental compilation is turned on, we default to a high number
1239         // codegen units in order to reduce the "collateral damage" small
1240         // changes cause.
1241         if self.opts.incremental.is_some() {
1242             return CodegenUnits::Default(256);
1243         }
1244 
1245         // Why is 16 codegen units the default all the time?
1246         //
1247         // The main reason for enabling multiple codegen units by default is to
1248         // leverage the ability for the codegen backend to do codegen and
1249         // optimization in parallel. This allows us, especially for large crates, to
1250         // make good use of all available resources on the machine once we've
1251         // hit that stage of compilation. Large crates especially then often
1252         // take a long time in codegen/optimization and this helps us amortize that
1253         // cost.
1254         //
1255         // Note that a high number here doesn't mean that we'll be spawning a
1256         // large number of threads in parallel. The backend of rustc contains
1257         // global rate limiting through the `jobserver` crate so we'll never
1258         // overload the system with too much work, but rather we'll only be
1259         // optimizing when we're otherwise cooperating with other instances of
1260         // rustc.
1261         //
1262         // Rather a high number here means that we should be able to keep a lot
1263         // of idle cpus busy. By ensuring that no codegen unit takes *too* long
1264         // to build we'll be guaranteed that all cpus will finish pretty closely
1265         // to one another and we should make relatively optimal use of system
1266         // resources
1267         //
1268         // Note that the main cost of codegen units is that it prevents LLVM
1269         // from inlining across codegen units. Users in general don't have a lot
1270         // of control over how codegen units are split up so it's our job in the
1271         // compiler to ensure that undue performance isn't lost when using
1272         // codegen units (aka we can't require everyone to slap `#[inline]` on
1273         // everything).
1274         //
1275         // If we're compiling at `-O0` then the number doesn't really matter too
1276         // much because performance doesn't matter and inlining is ok to lose.
1277         // In debug mode we just want to try to guarantee that no cpu is stuck
1278         // doing work that could otherwise be farmed to others.
1279         //
1280         // In release mode, however (O1 and above) performance does indeed
1281         // matter! To recover the loss in performance due to inlining we'll be
1282         // enabling ThinLTO by default (the function for which is just below).
1283         // This will ensure that we recover any inlining wins we otherwise lost
1284         // through codegen unit partitioning.
1285         //
1286         // ---
1287         //
1288         // Ok that's a lot of words but the basic tl;dr; is that we want a high
1289         // number here -- but not too high. Additionally we're "safe" to have it
1290         // always at the same number at all optimization levels.
1291         //
1292         // As a result 16 was chosen here! Mostly because it was a power of 2
1293         // and most benchmarks agreed it was roughly a local optimum. Not very
1294         // scientific.
1295         CodegenUnits::Default(16)
1296     }
1297 
teach(&self, code: &DiagnosticId) -> bool1298     pub fn teach(&self, code: &DiagnosticId) -> bool {
1299         self.opts.unstable_opts.teach && self.diagnostic().must_teach(code)
1300     }
1301 
edition(&self) -> Edition1302     pub fn edition(&self) -> Edition {
1303         self.opts.edition
1304     }
1305 
link_dead_code(&self) -> bool1306     pub fn link_dead_code(&self) -> bool {
1307         self.opts.cg.link_dead_code.unwrap_or(false)
1308     }
1309 }
1310 
1311 // JUSTIFICATION: part of session construction
1312 #[allow(rustc::bad_opt_access)]
default_emitter( sopts: &config::Options, registry: rustc_errors::registry::Registry, source_map: Lrc<SourceMap>, bundle: Option<Lrc<FluentBundle>>, fallback_bundle: LazyFallbackBundle, ) -> Box<dyn Emitter + sync::Send>1313 fn default_emitter(
1314     sopts: &config::Options,
1315     registry: rustc_errors::registry::Registry,
1316     source_map: Lrc<SourceMap>,
1317     bundle: Option<Lrc<FluentBundle>>,
1318     fallback_bundle: LazyFallbackBundle,
1319 ) -> Box<dyn Emitter + sync::Send> {
1320     let macro_backtrace = sopts.unstable_opts.macro_backtrace;
1321     let track_diagnostics = sopts.unstable_opts.track_diagnostics;
1322     let terminal_url = match sopts.unstable_opts.terminal_urls {
1323         TerminalUrl::Auto => {
1324             match (std::env::var("COLORTERM").as_deref(), std::env::var("TERM").as_deref()) {
1325                 (Ok("truecolor"), Ok("xterm-256color"))
1326                     if sopts.unstable_features.is_nightly_build() =>
1327                 {
1328                     TerminalUrl::Yes
1329                 }
1330                 _ => TerminalUrl::No,
1331             }
1332         }
1333         t => t,
1334     };
1335     match sopts.error_format {
1336         config::ErrorOutputType::HumanReadable(kind) => {
1337             let (short, color_config) = kind.unzip();
1338 
1339             if let HumanReadableErrorType::AnnotateSnippet(_) = kind {
1340                 let emitter = AnnotateSnippetEmitterWriter::new(
1341                     Some(source_map),
1342                     bundle,
1343                     fallback_bundle,
1344                     short,
1345                     macro_backtrace,
1346                 );
1347                 Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
1348             } else {
1349                 let emitter = EmitterWriter::stderr(
1350                     color_config,
1351                     Some(source_map),
1352                     bundle,
1353                     fallback_bundle,
1354                     short,
1355                     sopts.unstable_opts.teach,
1356                     sopts.diagnostic_width,
1357                     macro_backtrace,
1358                     track_diagnostics,
1359                     terminal_url,
1360                 );
1361                 Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
1362             }
1363         }
1364         config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(
1365             JsonEmitter::stderr(
1366                 Some(registry),
1367                 source_map,
1368                 bundle,
1369                 fallback_bundle,
1370                 pretty,
1371                 json_rendered,
1372                 sopts.diagnostic_width,
1373                 macro_backtrace,
1374                 track_diagnostics,
1375                 terminal_url,
1376             )
1377             .ui_testing(sopts.unstable_opts.ui_testing),
1378         ),
1379     }
1380 }
1381 
1382 // JUSTIFICATION: literally session construction
1383 #[allow(rustc::bad_opt_access)]
build_session( handler: &EarlyErrorHandler, sopts: config::Options, io: CompilerIO, bundle: Option<Lrc<rustc_errors::FluentBundle>>, registry: rustc_errors::registry::Registry, fluent_resources: Vec<&'static str>, driver_lint_caps: FxHashMap<lint::LintId, lint::Level>, file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>, target_override: Option<Target>, cfg_version: &'static str, ) -> Session1384 pub fn build_session(
1385     handler: &EarlyErrorHandler,
1386     sopts: config::Options,
1387     io: CompilerIO,
1388     bundle: Option<Lrc<rustc_errors::FluentBundle>>,
1389     registry: rustc_errors::registry::Registry,
1390     fluent_resources: Vec<&'static str>,
1391     driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
1392     file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
1393     target_override: Option<Target>,
1394     cfg_version: &'static str,
1395 ) -> Session {
1396     // FIXME: This is not general enough to make the warning lint completely override
1397     // normal diagnostic warnings, since the warning lint can also be denied and changed
1398     // later via the source code.
1399     let warnings_allow = sopts
1400         .lint_opts
1401         .iter()
1402         .rfind(|&(key, _)| *key == "warnings")
1403         .is_some_and(|&(_, level)| level == lint::Allow);
1404     let cap_lints_allow = sopts.lint_cap.is_some_and(|cap| cap == lint::Allow);
1405     let can_emit_warnings = !(warnings_allow || cap_lints_allow);
1406 
1407     let sysroot = match &sopts.maybe_sysroot {
1408         Some(sysroot) => sysroot.clone(),
1409         None => filesearch::get_or_default_sysroot().expect("Failed finding sysroot"),
1410     };
1411 
1412     let target_cfg = config::build_target_config(handler, &sopts, target_override, &sysroot);
1413     let host_triple = TargetTriple::from_triple(config::host_triple());
1414     let (host, target_warnings) = Target::search(&host_triple, &sysroot)
1415         .unwrap_or_else(|e| handler.early_error(format!("Error loading host specification: {e}")));
1416     for warning in target_warnings.warning_messages() {
1417         handler.early_warn(warning)
1418     }
1419 
1420     let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
1421     let hash_kind = sopts.unstable_opts.src_hash_algorithm.unwrap_or_else(|| {
1422         if target_cfg.is_like_msvc {
1423             SourceFileHashAlgorithm::Sha1
1424         } else {
1425             SourceFileHashAlgorithm::Md5
1426         }
1427     });
1428     let source_map = Lrc::new(SourceMap::with_file_loader_and_hash_kind(
1429         loader,
1430         sopts.file_path_mapping(),
1431         hash_kind,
1432     ));
1433 
1434     let fallback_bundle = fallback_fluent_bundle(
1435         fluent_resources,
1436         sopts.unstable_opts.translate_directionality_markers,
1437     );
1438     let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle);
1439 
1440     let span_diagnostic = rustc_errors::Handler::with_emitter_and_flags(
1441         emitter,
1442         sopts.unstable_opts.diagnostic_handler_flags(can_emit_warnings),
1443     );
1444 
1445     let self_profiler = if let SwitchWithOptPath::Enabled(ref d) = sopts.unstable_opts.self_profile
1446     {
1447         let directory =
1448             if let Some(ref directory) = d { directory } else { std::path::Path::new(".") };
1449 
1450         let profiler = SelfProfiler::new(
1451             directory,
1452             sopts.crate_name.as_deref(),
1453             sopts.unstable_opts.self_profile_events.as_deref(),
1454             &sopts.unstable_opts.self_profile_counter,
1455         );
1456         match profiler {
1457             Ok(profiler) => Some(Arc::new(profiler)),
1458             Err(e) => {
1459                 handler.early_warn(format!("failed to create profiler: {e}"));
1460                 None
1461             }
1462         }
1463     } else {
1464         None
1465     };
1466 
1467     let mut parse_sess = ParseSess::with_span_handler(span_diagnostic, source_map);
1468     parse_sess.assume_incomplete_release = sopts.unstable_opts.assume_incomplete_release;
1469 
1470     let host_triple = config::host_triple();
1471     let target_triple = sopts.target_triple.triple();
1472     let host_tlib_path = Lrc::new(SearchPath::from_sysroot_and_triple(&sysroot, host_triple));
1473     let target_tlib_path = if host_triple == target_triple {
1474         // Use the same `SearchPath` if host and target triple are identical to avoid unnecessary
1475         // rescanning of the target lib path and an unnecessary allocation.
1476         host_tlib_path.clone()
1477     } else {
1478         Lrc::new(SearchPath::from_sysroot_and_triple(&sysroot, target_triple))
1479     };
1480 
1481     let optimization_fuel = Lock::new(OptimizationFuel {
1482         remaining: sopts.unstable_opts.fuel.as_ref().map_or(0, |&(_, i)| i),
1483         out_of_fuel: false,
1484     });
1485     let print_fuel = AtomicU64::new(0);
1486 
1487     let cgu_reuse_tracker = if sopts.unstable_opts.query_dep_graph {
1488         CguReuseTracker::new()
1489     } else {
1490         CguReuseTracker::new_disabled()
1491     };
1492 
1493     let prof = SelfProfilerRef::new(
1494         self_profiler,
1495         sopts.unstable_opts.time_passes.then(|| sopts.unstable_opts.time_passes_format),
1496     );
1497 
1498     let ctfe_backtrace = Lock::new(match env::var("RUSTC_CTFE_BACKTRACE") {
1499         Ok(ref val) if val == "immediate" => CtfeBacktrace::Immediate,
1500         Ok(ref val) if val != "0" => CtfeBacktrace::Capture,
1501         _ => CtfeBacktrace::Disabled,
1502     });
1503 
1504     let asm_arch =
1505         if target_cfg.allow_asm { InlineAsmArch::from_str(&target_cfg.arch).ok() } else { None };
1506 
1507     let sess = Session {
1508         target: target_cfg,
1509         host,
1510         opts: sopts,
1511         host_tlib_path,
1512         target_tlib_path,
1513         parse_sess,
1514         sysroot,
1515         io,
1516         crate_types: OnceCell::new(),
1517         stable_crate_id: OnceCell::new(),
1518         features: OnceCell::new(),
1519         incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
1520         cgu_reuse_tracker,
1521         prof,
1522         perf_stats: PerfStats {
1523             symbol_hash_time: Lock::new(Duration::from_secs(0)),
1524             queries_canonicalized: AtomicUsize::new(0),
1525             normalize_generic_arg_after_erasing_regions: AtomicUsize::new(0),
1526             normalize_projection_ty: AtomicUsize::new(0),
1527         },
1528         code_stats: Default::default(),
1529         optimization_fuel,
1530         print_fuel,
1531         jobserver: jobserver::client(),
1532         driver_lint_caps,
1533         ctfe_backtrace,
1534         miri_unleashed_features: Lock::new(Default::default()),
1535         asm_arch,
1536         target_features: Default::default(),
1537         unstable_target_features: Default::default(),
1538         cfg_version,
1539     };
1540 
1541     validate_commandline_args_with_session_available(&sess);
1542 
1543     sess
1544 }
1545 
1546 /// Validate command line arguments with a `Session`.
1547 ///
1548 /// If it is useful to have a Session available already for validating a commandline argument, you
1549 /// can do so here.
1550 // JUSTIFICATION: needs to access args to validate them
1551 #[allow(rustc::bad_opt_access)]
validate_commandline_args_with_session_available(sess: &Session)1552 fn validate_commandline_args_with_session_available(sess: &Session) {
1553     // Since we don't know if code in an rlib will be linked to statically or
1554     // dynamically downstream, rustc generates `__imp_` symbols that help linkers
1555     // on Windows deal with this lack of knowledge (#27438). Unfortunately,
1556     // these manually generated symbols confuse LLD when it tries to merge
1557     // bitcode during ThinLTO. Therefore we disallow dynamic linking on Windows
1558     // when compiling for LLD ThinLTO. This way we can validly just not generate
1559     // the `dllimport` attributes and `__imp_` symbols in that case.
1560     if sess.opts.cg.linker_plugin_lto.enabled()
1561         && sess.opts.cg.prefer_dynamic
1562         && sess.target.is_like_windows
1563     {
1564         sess.emit_err(errors::LinkerPluginToWindowsNotSupported);
1565     }
1566 
1567     // Make sure that any given profiling data actually exists so LLVM can't
1568     // decide to silently skip PGO.
1569     if let Some(ref path) = sess.opts.cg.profile_use {
1570         if !path.exists() {
1571             sess.emit_err(errors::ProfileUseFileDoesNotExist { path });
1572         }
1573     }
1574 
1575     // Do the same for sample profile data.
1576     if let Some(ref path) = sess.opts.unstable_opts.profile_sample_use {
1577         if !path.exists() {
1578             sess.emit_err(errors::ProfileSampleUseFileDoesNotExist { path });
1579         }
1580     }
1581 
1582     // Unwind tables cannot be disabled if the target requires them.
1583     if let Some(include_uwtables) = sess.opts.cg.force_unwind_tables {
1584         if sess.target.requires_uwtable && !include_uwtables {
1585             sess.emit_err(errors::TargetRequiresUnwindTables);
1586         }
1587     }
1588 
1589     // Sanitizers can only be used on platforms that we know have working sanitizer codegen.
1590     let supported_sanitizers = sess.target.options.supported_sanitizers;
1591     let unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
1592     match unsupported_sanitizers.into_iter().count() {
1593         0 => {}
1594         1 => {
1595             sess.emit_err(errors::SanitizerNotSupported { us: unsupported_sanitizers.to_string() });
1596         }
1597         _ => {
1598             sess.emit_err(errors::SanitizersNotSupported {
1599                 us: unsupported_sanitizers.to_string(),
1600             });
1601         }
1602     }
1603     // Cannot mix and match sanitizers.
1604     let mut sanitizer_iter = sess.opts.unstable_opts.sanitizer.into_iter();
1605     if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
1606         sess.emit_err(errors::CannotMixAndMatchSanitizers {
1607             first: first.to_string(),
1608             second: second.to_string(),
1609         });
1610     }
1611 
1612     // Cannot enable crt-static with sanitizers on Linux
1613     if sess.crt_static(None) && !sess.opts.unstable_opts.sanitizer.is_empty() {
1614         sess.emit_err(errors::CannotEnableCrtStaticLinux);
1615     }
1616 
1617     // LLVM CFI requires LTO.
1618     if sess.is_sanitizer_cfi_enabled()
1619         && !(sess.lto() == config::Lto::Fat
1620             || sess.lto() == config::Lto::Thin
1621             || sess.opts.cg.linker_plugin_lto.enabled())
1622     {
1623         sess.emit_err(errors::SanitizerCfiRequiresLto);
1624     }
1625 
1626     // LLVM CFI is incompatible with LLVM KCFI.
1627     if sess.is_sanitizer_cfi_enabled() && sess.is_sanitizer_kcfi_enabled() {
1628         sess.emit_err(errors::CannotMixAndMatchSanitizers {
1629             first: "cfi".to_string(),
1630             second: "kcfi".to_string(),
1631         });
1632     }
1633 
1634     // Canonical jump tables requires CFI.
1635     if sess.is_sanitizer_cfi_canonical_jump_tables_disabled() {
1636         if !sess.is_sanitizer_cfi_enabled() {
1637             sess.emit_err(errors::SanitizerCfiCanonicalJumpTablesRequiresCfi);
1638         }
1639     }
1640 
1641     // LLVM CFI pointer generalization requires CFI or KCFI.
1642     if sess.is_sanitizer_cfi_generalize_pointers_enabled() {
1643         if !(sess.is_sanitizer_cfi_enabled() || sess.is_sanitizer_kcfi_enabled()) {
1644             sess.emit_err(errors::SanitizerCfiGeneralizePointersRequiresCfi);
1645         }
1646     }
1647 
1648     // LLVM CFI integer normalization requires CFI or KCFI.
1649     if sess.is_sanitizer_cfi_normalize_integers_enabled() {
1650         if !(sess.is_sanitizer_cfi_enabled() || sess.is_sanitizer_kcfi_enabled()) {
1651             sess.emit_err(errors::SanitizerCfiNormalizeIntegersRequiresCfi);
1652         }
1653     }
1654 
1655     // LTO unit splitting requires LTO.
1656     if sess.is_split_lto_unit_enabled()
1657         && !(sess.lto() == config::Lto::Fat
1658             || sess.lto() == config::Lto::Thin
1659             || sess.opts.cg.linker_plugin_lto.enabled())
1660     {
1661         sess.emit_err(errors::SplitLtoUnitRequiresLto);
1662     }
1663 
1664     // VFE requires LTO.
1665     if sess.lto() != config::Lto::Fat {
1666         if sess.opts.unstable_opts.virtual_function_elimination {
1667             sess.emit_err(errors::UnstableVirtualFunctionElimination);
1668         }
1669     }
1670 
1671     if sess.opts.unstable_opts.stack_protector != StackProtector::None {
1672         if !sess.target.options.supports_stack_protector {
1673             sess.emit_warning(errors::StackProtectorNotSupportedForTarget {
1674                 stack_protector: sess.opts.unstable_opts.stack_protector,
1675                 target_triple: &sess.opts.target_triple,
1676             });
1677         }
1678     }
1679 
1680     if sess.opts.unstable_opts.branch_protection.is_some() && sess.target.arch != "aarch64" {
1681         sess.emit_err(errors::BranchProtectionRequiresAArch64);
1682     }
1683 
1684     if let Some(dwarf_version) = sess.opts.unstable_opts.dwarf_version {
1685         if dwarf_version > 5 {
1686             sess.emit_err(errors::UnsupportedDwarfVersion { dwarf_version });
1687         }
1688     }
1689 
1690     if !sess.target.options.supported_split_debuginfo.contains(&sess.split_debuginfo())
1691         && !sess.opts.unstable_opts.unstable_options
1692     {
1693         sess.emit_err(errors::SplitDebugInfoUnstablePlatform { debuginfo: sess.split_debuginfo() });
1694     }
1695 
1696     if sess.opts.unstable_opts.instrument_xray.is_some() && !sess.target.options.supports_xray {
1697         sess.emit_err(errors::InstrumentationNotSupported { us: "XRay".to_string() });
1698     }
1699 
1700     if let Some(flavor) = sess.opts.cg.linker_flavor {
1701         if let Some(compatible_list) = sess.target.linker_flavor.check_compatibility(flavor) {
1702             let flavor = flavor.desc();
1703             sess.emit_err(errors::IncompatibleLinkerFlavor { flavor, compatible_list });
1704         }
1705     }
1706 }
1707 
1708 /// Holds data on the current incremental compilation session, if there is one.
1709 #[derive(Debug)]
1710 pub enum IncrCompSession {
1711     /// This is the state the session will be in until the incr. comp. dir is
1712     /// needed.
1713     NotInitialized,
1714     /// This is the state during which the session directory is private and can
1715     /// be modified.
1716     Active { session_directory: PathBuf, lock_file: flock::Lock, load_dep_graph: bool },
1717     /// This is the state after the session directory has been finalized. In this
1718     /// state, the contents of the directory must not be modified any more.
1719     Finalized { session_directory: PathBuf },
1720     /// This is an error state that is reached when some compilation error has
1721     /// occurred. It indicates that the contents of the session directory must
1722     /// not be used, since they might be invalid.
1723     InvalidBecauseOfErrors { session_directory: PathBuf },
1724 }
1725 
1726 /// A wrapper around an [`Handler`] that is used for early error emissions.
1727 pub struct EarlyErrorHandler {
1728     handler: Handler,
1729 }
1730 
1731 impl EarlyErrorHandler {
new(output: ErrorOutputType) -> Self1732     pub fn new(output: ErrorOutputType) -> Self {
1733         let emitter = mk_emitter(output);
1734         Self { handler: rustc_errors::Handler::with_emitter(true, None, emitter) }
1735     }
1736 
abort_if_errors(&self)1737     pub fn abort_if_errors(&self) {
1738         self.handler.abort_if_errors()
1739     }
1740 
1741     /// Swap out the underlying handler once we acquire the user's preference on error emission
1742     /// format. Any errors prior to that will cause an abort and all stashed diagnostics of the
1743     /// previous handler will be emitted.
abort_if_error_and_set_error_format(&mut self, output: ErrorOutputType)1744     pub fn abort_if_error_and_set_error_format(&mut self, output: ErrorOutputType) {
1745         self.handler.abort_if_errors();
1746 
1747         let emitter = mk_emitter(output);
1748         self.handler = Handler::with_emitter(true, None, emitter);
1749     }
1750 
1751     #[allow(rustc::untranslatable_diagnostic)]
1752     #[allow(rustc::diagnostic_outside_of_impl)]
early_note(&self, msg: impl Into<DiagnosticMessage>)1753     pub fn early_note(&self, msg: impl Into<DiagnosticMessage>) {
1754         self.handler.struct_note_without_error(msg).emit()
1755     }
1756 
1757     #[allow(rustc::untranslatable_diagnostic)]
1758     #[allow(rustc::diagnostic_outside_of_impl)]
early_help(&self, msg: impl Into<DiagnosticMessage>)1759     pub fn early_help(&self, msg: impl Into<DiagnosticMessage>) {
1760         self.handler.struct_help(msg).emit()
1761     }
1762 
1763     #[allow(rustc::untranslatable_diagnostic)]
1764     #[allow(rustc::diagnostic_outside_of_impl)]
1765     #[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"]
early_error_no_abort(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed1766     pub fn early_error_no_abort(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
1767         self.handler.struct_err(msg).emit()
1768     }
1769 
1770     #[allow(rustc::untranslatable_diagnostic)]
1771     #[allow(rustc::diagnostic_outside_of_impl)]
early_error(&self, msg: impl Into<DiagnosticMessage>) -> !1772     pub fn early_error(&self, msg: impl Into<DiagnosticMessage>) -> ! {
1773         self.handler.struct_fatal(msg).emit()
1774     }
1775 
1776     #[allow(rustc::untranslatable_diagnostic)]
1777     #[allow(rustc::diagnostic_outside_of_impl)]
early_warn(&self, msg: impl Into<DiagnosticMessage>)1778     pub fn early_warn(&self, msg: impl Into<DiagnosticMessage>) {
1779         self.handler.struct_warn(msg).emit()
1780     }
1781 }
1782 
mk_emitter(output: ErrorOutputType) -> Box<dyn Emitter + sync::Send + 'static>1783 fn mk_emitter(output: ErrorOutputType) -> Box<dyn Emitter + sync::Send + 'static> {
1784     // FIXME(#100717): early errors aren't translated at the moment, so this is fine, but it will
1785     // need to reference every crate that might emit an early error for translation to work.
1786     let fallback_bundle =
1787         fallback_fluent_bundle(vec![rustc_errors::DEFAULT_LOCALE_RESOURCE], false);
1788     let emitter: Box<dyn Emitter + sync::Send> = match output {
1789         config::ErrorOutputType::HumanReadable(kind) => {
1790             let (short, color_config) = kind.unzip();
1791             Box::new(EmitterWriter::stderr(
1792                 color_config,
1793                 None,
1794                 None,
1795                 fallback_bundle,
1796                 short,
1797                 false,
1798                 None,
1799                 false,
1800                 false,
1801                 TerminalUrl::No,
1802             ))
1803         }
1804         config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic(
1805             pretty,
1806             json_rendered,
1807             None,
1808             fallback_bundle,
1809             None,
1810             false,
1811             false,
1812             TerminalUrl::No,
1813         )),
1814     };
1815     emitter
1816 }
1817