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