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