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