]>
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}; |
dfeec247 | 5 | use crate::filesearch; |
29967ef6 | 6 | use crate::lint::{self, LintId}; |
ba9703b0 | 7 | use crate::parse::ParseSess; |
60c5eb7d | 8 | use crate::search_paths::{PathKind, SearchPath}; |
0531ce1d | 9 | |
3dfed10e | 10 | pub use rustc_ast::attr::MarkedAttrs; |
3dfed10e | 11 | pub use rustc_ast::Attribute; |
ba9703b0 XL |
12 | use rustc_data_structures::flock; |
13 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; | |
14 | use rustc_data_structures::jobserver::{self, Client}; | |
15 | use rustc_data_structures::profiling::{duration_to_secs_str, SelfProfiler, SelfProfilerRef}; | |
0731742a | 16 | use rustc_data_structures::sync::{ |
f9f354fc | 17 | self, AtomicU64, AtomicUsize, Lock, Lrc, OnceCell, OneThread, Ordering, Ordering::SeqCst, |
0731742a | 18 | }; |
dfeec247 | 19 | use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitterWriter; |
ba9703b0 | 20 | use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType}; |
60c5eb7d | 21 | use rustc_errors::json::JsonEmitter; |
f9f354fc | 22 | use rustc_errors::registry::Registry; |
136023e0 XL |
23 | use rustc_errors::{DiagnosticBuilder, DiagnosticId, ErrorReported}; |
24 | use rustc_macros::HashStable_Generic; | |
25 | pub use rustc_span::def_id::StableCrateId; | |
94222f64 | 26 | use rustc_span::edition::Edition; |
f9f354fc | 27 | use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span}; |
3dfed10e | 28 | use rustc_span::{sym, SourceFileHashAlgorithm, Symbol}; |
f9f354fc XL |
29 | use rustc_target::asm::InlineAsmArch; |
30 | use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel}; | |
cdc7bbd5 | 31 | use rustc_target::spec::{SanitizerSet, SplitDebuginfo, Target, TargetTriple, TlsModel}; |
85aaf69f | 32 | |
60c5eb7d | 33 | use std::cell::{self, RefCell}; |
c34b1796 | 34 | use std::env; |
f9f354fc | 35 | use std::fmt; |
c30ab7b3 | 36 | use std::io::Write; |
60c5eb7d | 37 | use std::num::NonZeroU32; |
f9f354fc | 38 | use std::ops::{Div, Mul}; |
0731742a | 39 | use std::path::PathBuf; |
f9f354fc | 40 | use std::str::FromStr; |
e74abb32 | 41 | use std::sync::Arc; |
dfeec247 | 42 | use std::time::Duration; |
532ac7d7 | 43 | |
29967ef6 XL |
44 | pub trait SessionLintStore: sync::Send + sync::Sync { |
45 | fn name_to_lint(&self, lint_name: &str) -> LintId; | |
46 | } | |
47 | ||
0731742a | 48 | pub 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)] | |
57 | pub 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 |
70 | pub struct Limit(pub usize); |
71 | ||
72 | impl 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 |
86 | impl From<usize> for Limit { |
87 | fn from(value: usize) -> Self { | |
88 | Self::new(value) | |
89 | } | |
90 | } | |
91 | ||
f9f354fc XL |
92 | impl fmt::Display for Limit { |
93 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
94 | write!(f, "{}", self.0) | |
95 | } | |
96 | } | |
97 | ||
98 | impl 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 | ||
106 | impl 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)] |
115 | pub 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 | 130 | pub 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 | 211 | pub 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 |
223 | enum 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]. | |
231 | pub 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)] |
240 | pub 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 |
246 | impl 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 | 252 | impl 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 |
1093 | fn 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 | ||
1157 | pub enum DiagnosticOutput { | |
1158 | Default, | |
dfeec247 | 1159 | Raw(Box<dyn Write + Send>), |
532ac7d7 XL |
1160 | } |
1161 | ||
f9f354fc | 1162 | pub 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. | |
1330 | fn 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)] | |
1398 | pub 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 | 1414 | pub 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 | ||
1428 | pub 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 | 1433 | pub 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 | } |