1use std::any::Any;
2use std::path::PathBuf;
3use std::str::FromStr;
4use std::sync::Arc;
5use std::sync::atomic::AtomicBool;
6use std::{env, io};
7
8use rand::{RngCore, rng};
9use rustc_data_structures::base_n::{CASE_INSENSITIVE, ToBaseN};
10use rustc_data_structures::flock;
11use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
12use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef};
13use rustc_data_structures::sync::{DynSend, DynSync, Lock, MappedReadGuard, ReadGuard, RwLock};
14use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter;
15use rustc_errors::codes::*;
16use rustc_errors::emitter::{
17 DynEmitter, HumanEmitter, HumanReadableErrorType, OutputTheme, stderr_destination,
18};
19use rustc_errors::json::JsonEmitter;
20use rustc_errors::timings::TimingSectionHandler;
21use rustc_errors::translation::Translator;
22use rustc_errors::{
23 Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, Diagnostic, ErrorGuaranteed, FatalAbort,
24 TerminalUrl, fallback_fluent_bundle,
25};
26use rustc_hir::limit::Limit;
27use rustc_macros::HashStable_Generic;
28pub use rustc_span::def_id::StableCrateId;
29use rustc_span::edition::Edition;
30use rustc_span::source_map::{FilePathMapping, SourceMap};
31use rustc_span::{RealFileName, Span, Symbol};
32use rustc_target::asm::InlineAsmArch;
33use rustc_target::spec::{
34 Arch, CodeModel, DebuginfoKind, Os, PanicStrategy, RelocModel, RelroLevel, SanitizerSet,
35 SmallDataThresholdSupport, SplitDebuginfo, StackProtector, SymbolVisibility, Target,
36 TargetTuple, TlsModel, apple,
37};
38
39use crate::code_stats::CodeStats;
40pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
41use crate::config::{
42 self, CoverageLevel, CoverageOptions, CrateType, DebugInfo, ErrorOutputType, FunctionReturn,
43 Input, InstrumentCoverage, OptLevel, OutFileName, OutputType, SwitchWithOptPath,
44};
45use crate::filesearch::FileSearch;
46use crate::lint::LintId;
47use crate::parse::{ParseSess, add_feature_diagnostics};
48use crate::search_paths::SearchPath;
49use crate::{errors, filesearch, lint};
50
51#[derive(Clone, Copy)]
53pub enum CtfeBacktrace {
54 Disabled,
56 Capture,
59 Immediate,
61}
62
63#[derive(Clone, Copy, Debug, HashStable_Generic)]
64pub struct Limits {
65 pub recursion_limit: Limit,
68 pub move_size_limit: Limit,
71 pub type_length_limit: Limit,
73 pub pattern_complexity_limit: Limit,
75}
76
77pub struct CompilerIO {
78 pub input: Input,
79 pub output_dir: Option<PathBuf>,
80 pub output_file: Option<OutFileName>,
81 pub temps_dir: Option<PathBuf>,
82}
83
84pub trait DynLintStore: Any + DynSync + DynSend {
85 fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = LintGroup> + '_>;
87}
88
89pub struct Session {
92 pub target: Target,
93 pub host: Target,
94 pub opts: config::Options,
95 pub target_tlib_path: Arc<SearchPath>,
96 pub psess: ParseSess,
97 pub io: CompilerIO,
99
100 incr_comp_session: RwLock<IncrCompSession>,
101
102 pub prof: SelfProfilerRef,
104
105 pub timings: TimingSectionHandler,
107
108 pub code_stats: CodeStats,
110
111 pub lint_store: Option<Arc<dyn DynLintStore>>,
113
114 pub driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
116
117 pub ctfe_backtrace: Lock<CtfeBacktrace>,
124
125 miri_unleashed_features: Lock<Vec<(Span, Option<Symbol>)>>,
130
131 pub asm_arch: Option<InlineAsmArch>,
133
134 pub target_features: FxIndexSet<Symbol>,
136
137 pub unstable_target_features: FxIndexSet<Symbol>,
139
140 pub cfg_version: &'static str,
142
143 pub using_internal_features: &'static AtomicBool,
148
149 target_filesearch: FileSearch,
150 host_filesearch: FileSearch,
151
152 pub invocation_temp: Option<String>,
159}
160
161#[derive(Clone, Copy)]
162pub enum CodegenUnits {
163 User(usize),
166
167 Default(usize),
171}
172
173impl CodegenUnits {
174 pub fn as_usize(self) -> usize {
175 match self {
176 CodegenUnits::User(n) => n,
177 CodegenUnits::Default(n) => n,
178 }
179 }
180}
181
182pub struct LintGroup {
183 pub name: &'static str,
184 pub lints: Vec<LintId>,
185 pub is_externally_loaded: bool,
186}
187
188impl Session {
189 pub fn miri_unleashed_feature(&self, span: Span, feature_gate: Option<Symbol>) {
190 self.miri_unleashed_features.lock().push((span, feature_gate));
191 }
192
193 pub fn local_crate_source_file(&self) -> Option<RealFileName> {
194 Some(
195 self.source_map()
196 .path_mapping()
197 .to_real_filename(self.source_map().working_dir(), self.io.input.opt_path()?),
198 )
199 }
200
201 fn check_miri_unleashed_features(&self) -> Option<ErrorGuaranteed> {
202 let mut guar = None;
203 let unleashed_features = self.miri_unleashed_features.lock();
204 if !unleashed_features.is_empty() {
205 let mut must_err = false;
206 self.dcx().emit_warn(errors::SkippingConstChecks {
208 unleashed_features: unleashed_features
209 .iter()
210 .map(|(span, gate)| {
211 gate.map(|gate| {
212 must_err = true;
213 errors::UnleashedFeatureHelp::Named { span: *span, gate }
214 })
215 .unwrap_or(errors::UnleashedFeatureHelp::Unnamed { span: *span })
216 })
217 .collect(),
218 });
219
220 if must_err && self.dcx().has_errors().is_none() {
222 guar = Some(self.dcx().emit_err(errors::NotCircumventFeature));
224 }
225 }
226 guar
227 }
228
229 pub fn finish_diagnostics(&self) -> Option<ErrorGuaranteed> {
231 let mut guar = None;
232 guar = guar.or(self.check_miri_unleashed_features());
233 guar = guar.or(self.dcx().emit_stashed_diagnostics());
234 self.dcx().print_error_count();
235 if self.opts.json_future_incompat {
236 self.dcx().emit_future_breakage_report();
237 }
238 guar
239 }
240
241 pub fn is_test_crate(&self) -> bool {
243 self.opts.test
244 }
245
246 #[track_caller]
248 pub fn create_feature_err<'a>(&'a self, err: impl Diagnostic<'a>, feature: Symbol) -> Diag<'a> {
249 let mut err = self.dcx().create_err(err);
250 if err.code.is_none() {
251 #[allow(rustc::diagnostic_outside_of_impl)]
252 err.code(E0658);
253 }
254 add_feature_diagnostics(&mut err, self, feature);
255 err
256 }
257
258 pub fn record_trimmed_def_paths(&self) {
261 if self.opts.unstable_opts.print_type_sizes
262 || self.opts.unstable_opts.query_dep_graph
263 || self.opts.unstable_opts.dump_mir.is_some()
264 || self.opts.unstable_opts.unpretty.is_some()
265 || self.prof.is_args_recording_enabled()
266 || self.opts.output_types.contains_key(&OutputType::Mir)
267 || std::env::var_os("RUSTC_LOG").is_some()
268 {
269 return;
270 }
271
272 self.dcx().set_must_produce_diag()
273 }
274
275 #[inline]
276 pub fn dcx(&self) -> DiagCtxtHandle<'_> {
277 self.psess.dcx()
278 }
279
280 #[inline]
281 pub fn source_map(&self) -> &SourceMap {
282 self.psess.source_map()
283 }
284
285 pub fn enable_internal_lints(&self) -> bool {
289 self.unstable_options() && !self.opts.actually_rustdoc
290 }
291
292 pub fn instrument_coverage(&self) -> bool {
293 self.opts.cg.instrument_coverage() != InstrumentCoverage::No
294 }
295
296 pub fn instrument_coverage_branch(&self) -> bool {
297 self.instrument_coverage()
298 && self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Branch
299 }
300
301 pub fn instrument_coverage_condition(&self) -> bool {
302 self.instrument_coverage()
303 && self.opts.unstable_opts.coverage_options.level >= CoverageLevel::Condition
304 }
305
306 pub fn coverage_options(&self) -> &CoverageOptions {
310 &self.opts.unstable_opts.coverage_options
311 }
312
313 pub fn is_sanitizer_cfi_enabled(&self) -> bool {
314 self.sanitizers().contains(SanitizerSet::CFI)
315 }
316
317 pub fn is_sanitizer_cfi_canonical_jump_tables_disabled(&self) -> bool {
318 self.opts.unstable_opts.sanitizer_cfi_canonical_jump_tables == Some(false)
319 }
320
321 pub fn is_sanitizer_cfi_canonical_jump_tables_enabled(&self) -> bool {
322 self.opts.unstable_opts.sanitizer_cfi_canonical_jump_tables == Some(true)
323 }
324
325 pub fn is_sanitizer_cfi_generalize_pointers_enabled(&self) -> bool {
326 self.opts.unstable_opts.sanitizer_cfi_generalize_pointers == Some(true)
327 }
328
329 pub fn is_sanitizer_cfi_normalize_integers_enabled(&self) -> bool {
330 self.opts.unstable_opts.sanitizer_cfi_normalize_integers == Some(true)
331 }
332
333 pub fn is_sanitizer_kcfi_arity_enabled(&self) -> bool {
334 self.opts.unstable_opts.sanitizer_kcfi_arity == Some(true)
335 }
336
337 pub fn is_sanitizer_kcfi_enabled(&self) -> bool {
338 self.sanitizers().contains(SanitizerSet::KCFI)
339 }
340
341 pub fn is_split_lto_unit_enabled(&self) -> bool {
342 self.opts.unstable_opts.split_lto_unit == Some(true)
343 }
344
345 pub fn crt_static(&self, crate_type: Option<CrateType>) -> bool {
347 if !self.target.crt_static_respected {
348 return self.target.crt_static_default;
350 }
351
352 let requested_features = self.opts.cg.target_feature.split(',');
353 let found_negative = requested_features.clone().any(|r| r == "-crt-static");
354 let found_positive = requested_features.clone().any(|r| r == "+crt-static");
355
356 #[allow(rustc::bad_opt_access)]
358 if found_positive || found_negative {
359 found_positive
360 } else if crate_type == Some(CrateType::ProcMacro)
361 || crate_type == None && self.opts.crate_types.contains(&CrateType::ProcMacro)
362 {
363 false
367 } else {
368 self.target.crt_static_default
369 }
370 }
371
372 pub fn is_wasi_reactor(&self) -> bool {
373 self.target.options.os == Os::Wasi
374 && matches!(
375 self.opts.unstable_opts.wasi_exec_model,
376 Some(config::WasiExecModel::Reactor)
377 )
378 }
379
380 pub fn target_can_use_split_dwarf(&self) -> bool {
382 self.target.debuginfo_kind == DebuginfoKind::Dwarf
383 }
384
385 pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String {
386 format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.as_u64())
387 }
388
389 pub fn target_filesearch(&self) -> &filesearch::FileSearch {
390 &self.target_filesearch
391 }
392 pub fn host_filesearch(&self) -> &filesearch::FileSearch {
393 &self.host_filesearch
394 }
395
396 pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec<PathBuf> {
400 let search_paths = self
401 .opts
402 .sysroot
403 .all_paths()
404 .map(|sysroot| filesearch::make_target_bin_path(&sysroot, config::host_tuple()));
405
406 if self_contained {
407 search_paths.flat_map(|path| [path.clone(), path.join("self-contained")]).collect()
411 } else {
412 search_paths.collect()
413 }
414 }
415
416 pub fn init_incr_comp_session(&self, session_dir: PathBuf, lock_file: flock::Lock) {
417 let mut incr_comp_session = self.incr_comp_session.borrow_mut();
418
419 if let IncrCompSession::NotInitialized = *incr_comp_session {
420 } else {
421 panic!("Trying to initialize IncrCompSession `{:?}`", *incr_comp_session)
422 }
423
424 *incr_comp_session =
425 IncrCompSession::Active { session_directory: session_dir, _lock_file: lock_file };
426 }
427
428 pub fn finalize_incr_comp_session(&self, new_directory_path: PathBuf) {
429 let mut incr_comp_session = self.incr_comp_session.borrow_mut();
430
431 if let IncrCompSession::Active { .. } = *incr_comp_session {
432 } else {
433 panic!("trying to finalize `IncrCompSession` `{:?}`", *incr_comp_session);
434 }
435
436 *incr_comp_session = IncrCompSession::Finalized { session_directory: new_directory_path };
438 }
439
440 pub fn mark_incr_comp_session_as_invalid(&self) {
441 let mut incr_comp_session = self.incr_comp_session.borrow_mut();
442
443 let session_directory = match *incr_comp_session {
444 IncrCompSession::Active { ref session_directory, .. } => session_directory.clone(),
445 IncrCompSession::InvalidBecauseOfErrors { .. } => return,
446 _ => panic!("trying to invalidate `IncrCompSession` `{:?}`", *incr_comp_session),
447 };
448
449 *incr_comp_session = IncrCompSession::InvalidBecauseOfErrors { session_directory };
451 }
452
453 pub fn incr_comp_session_dir(&self) -> MappedReadGuard<'_, PathBuf> {
454 let incr_comp_session = self.incr_comp_session.borrow();
455 ReadGuard::map(incr_comp_session, |incr_comp_session| match *incr_comp_session {
456 IncrCompSession::NotInitialized => panic!(
457 "trying to get session directory from `IncrCompSession`: {:?}",
458 *incr_comp_session,
459 ),
460 IncrCompSession::Active { ref session_directory, .. }
461 | IncrCompSession::Finalized { ref session_directory }
462 | IncrCompSession::InvalidBecauseOfErrors { ref session_directory } => {
463 session_directory
464 }
465 })
466 }
467
468 pub fn incr_comp_session_dir_opt(&self) -> Option<MappedReadGuard<'_, PathBuf>> {
469 self.opts.incremental.as_ref().map(|_| self.incr_comp_session_dir())
470 }
471
472 pub fn is_rust_2015(&self) -> bool {
474 self.edition().is_rust_2015()
475 }
476
477 pub fn at_least_rust_2018(&self) -> bool {
479 self.edition().at_least_rust_2018()
480 }
481
482 pub fn at_least_rust_2021(&self) -> bool {
484 self.edition().at_least_rust_2021()
485 }
486
487 pub fn at_least_rust_2024(&self) -> bool {
489 self.edition().at_least_rust_2024()
490 }
491
492 pub fn needs_plt(&self) -> bool {
494 let want_plt = self.target.plt_by_default;
497
498 let dbg_opts = &self.opts.unstable_opts;
499
500 let relro_level = self.opts.cg.relro_level.unwrap_or(self.target.relro_level);
501
502 let full_relro = RelroLevel::Full == relro_level;
506
507 dbg_opts.plt.unwrap_or(want_plt || !full_relro)
510 }
511
512 pub fn emit_lifetime_markers(&self) -> bool {
514 self.opts.optimize != config::OptLevel::No
515 || self.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
519 }
520
521 pub fn diagnostic_width(&self) -> usize {
522 let default_column_width = 140;
523 if let Some(width) = self.opts.diagnostic_width {
524 width
525 } else if self.opts.unstable_opts.ui_testing {
526 default_column_width
527 } else {
528 termize::dimensions().map_or(default_column_width, |(w, _)| w)
529 }
530 }
531
532 pub fn default_visibility(&self) -> SymbolVisibility {
534 self.opts
535 .unstable_opts
536 .default_visibility
537 .or(self.target.options.default_visibility)
538 .unwrap_or(SymbolVisibility::Interposable)
539 }
540
541 pub fn staticlib_components(&self, verbatim: bool) -> (&str, &str) {
542 if verbatim {
543 ("", "")
544 } else {
545 (&*self.target.staticlib_prefix, &*self.target.staticlib_suffix)
546 }
547 }
548
549 pub fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = LintGroup> + '_> {
550 match self.lint_store {
551 Some(ref lint_store) => lint_store.lint_groups_iter(),
552 None => Box::new(std::iter::empty()),
553 }
554 }
555}
556
557#[allow(rustc::bad_opt_access)]
559impl Session {
560 pub fn verbose_internals(&self) -> bool {
561 self.opts.unstable_opts.verbose_internals
562 }
563
564 pub fn print_llvm_stats(&self) -> bool {
565 self.opts.unstable_opts.print_codegen_stats
566 }
567
568 pub fn verify_llvm_ir(&self) -> bool {
569 self.opts.unstable_opts.verify_llvm_ir || option_env!("RUSTC_VERIFY_LLVM_IR").is_some()
570 }
571
572 pub fn binary_dep_depinfo(&self) -> bool {
573 self.opts.unstable_opts.binary_dep_depinfo
574 }
575
576 pub fn mir_opt_level(&self) -> usize {
577 self.opts
578 .unstable_opts
579 .mir_opt_level
580 .unwrap_or_else(|| if self.opts.optimize != OptLevel::No { 2 } else { 1 })
581 }
582
583 pub fn lto(&self) -> config::Lto {
585 if self.target.requires_lto {
587 return config::Lto::Fat;
588 }
589
590 match self.opts.cg.lto {
594 config::LtoCli::Unspecified => {
595 }
598 config::LtoCli::No => {
599 return config::Lto::No;
601 }
602 config::LtoCli::Yes | config::LtoCli::Fat | config::LtoCli::NoParam => {
603 return config::Lto::Fat;
605 }
606 config::LtoCli::Thin => {
607 return config::Lto::Thin;
609 }
610 }
611
612 if self.opts.cli_forced_local_thinlto_off {
621 return config::Lto::No;
622 }
623
624 if let Some(enabled) = self.opts.unstable_opts.thinlto {
627 if enabled {
628 return config::Lto::ThinLocal;
629 } else {
630 return config::Lto::No;
631 }
632 }
633
634 if self.codegen_units().as_usize() == 1 {
637 return config::Lto::No;
638 }
639
640 match self.opts.optimize {
643 config::OptLevel::No => config::Lto::No,
644 _ => config::Lto::ThinLocal,
645 }
646 }
647
648 pub fn panic_strategy(&self) -> PanicStrategy {
651 self.opts.cg.panic.unwrap_or(self.target.panic_strategy)
652 }
653
654 pub fn fewer_names(&self) -> bool {
655 if let Some(fewer_names) = self.opts.unstable_opts.fewer_names {
656 fewer_names
657 } else {
658 let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
659 || self.opts.output_types.contains_key(&OutputType::Bitcode)
660 || self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
662 !more_names
663 }
664 }
665
666 pub fn unstable_options(&self) -> bool {
667 self.opts.unstable_opts.unstable_options
668 }
669
670 pub fn is_nightly_build(&self) -> bool {
671 self.opts.unstable_features.is_nightly_build()
672 }
673
674 pub fn overflow_checks(&self) -> bool {
675 self.opts.cg.overflow_checks.unwrap_or(self.opts.debug_assertions)
676 }
677
678 pub fn ub_checks(&self) -> bool {
679 self.opts.unstable_opts.ub_checks.unwrap_or(self.opts.debug_assertions)
680 }
681
682 pub fn contract_checks(&self) -> bool {
683 self.opts.unstable_opts.contract_checks.unwrap_or(false)
684 }
685
686 pub fn relocation_model(&self) -> RelocModel {
687 self.opts.cg.relocation_model.unwrap_or(self.target.relocation_model)
688 }
689
690 pub fn code_model(&self) -> Option<CodeModel> {
691 self.opts.cg.code_model.or(self.target.code_model)
692 }
693
694 pub fn tls_model(&self) -> TlsModel {
695 self.opts.unstable_opts.tls_model.unwrap_or(self.target.tls_model)
696 }
697
698 pub fn direct_access_external_data(&self) -> Option<bool> {
699 self.opts
700 .unstable_opts
701 .direct_access_external_data
702 .or(self.target.direct_access_external_data)
703 }
704
705 pub fn split_debuginfo(&self) -> SplitDebuginfo {
706 self.opts.cg.split_debuginfo.unwrap_or(self.target.split_debuginfo)
707 }
708
709 pub fn dwarf_version(&self) -> u32 {
711 self.opts
712 .cg
713 .dwarf_version
714 .or(self.opts.unstable_opts.dwarf_version)
715 .unwrap_or(self.target.default_dwarf_version)
716 }
717
718 pub fn stack_protector(&self) -> StackProtector {
719 if self.target.options.supports_stack_protector {
720 self.opts.unstable_opts.stack_protector
721 } else {
722 StackProtector::None
723 }
724 }
725
726 pub fn must_emit_unwind_tables(&self) -> bool {
727 self.target.requires_uwtable
756 || self
757 .opts
758 .cg
759 .force_unwind_tables
760 .unwrap_or(self.panic_strategy().unwinds() || self.target.default_uwtable)
761 }
762
763 #[inline]
766 pub fn threads(&self) -> usize {
767 self.opts.unstable_opts.threads
768 }
769
770 pub fn codegen_units(&self) -> CodegenUnits {
773 if let Some(n) = self.opts.cli_forced_codegen_units {
774 return CodegenUnits::User(n);
775 }
776 if let Some(n) = self.target.default_codegen_units {
777 return CodegenUnits::Default(n as usize);
778 }
779
780 if self.opts.incremental.is_some() {
784 return CodegenUnits::Default(256);
785 }
786
787 CodegenUnits::Default(16)
838 }
839
840 pub fn teach(&self, code: ErrCode) -> bool {
841 self.opts.unstable_opts.teach && self.dcx().must_teach(code)
842 }
843
844 pub fn edition(&self) -> Edition {
845 self.opts.edition
846 }
847
848 pub fn link_dead_code(&self) -> bool {
849 self.opts.cg.link_dead_code.unwrap_or(false)
850 }
851
852 pub fn apple_deployment_target(&self) -> apple::OSVersion {
857 let min = apple::OSVersion::minimum_deployment_target(&self.target);
858 let env_var = apple::deployment_target_env_var(&self.target.os);
859
860 if let Ok(deployment_target) = env::var(env_var) {
862 match apple::OSVersion::from_str(&deployment_target) {
863 Ok(version) => {
864 let os_min = apple::OSVersion::os_minimum_deployment_target(&self.target.os);
865 if version < os_min {
870 self.dcx().emit_warn(errors::AppleDeploymentTarget::TooLow {
871 env_var,
872 version: version.fmt_pretty().to_string(),
873 os_min: os_min.fmt_pretty().to_string(),
874 });
875 }
876
877 version.max(min)
879 }
880 Err(error) => {
881 self.dcx().emit_err(errors::AppleDeploymentTarget::Invalid { env_var, error });
882 min
883 }
884 }
885 } else {
886 min
888 }
889 }
890
891 pub fn sanitizers(&self) -> SanitizerSet {
892 return self.opts.unstable_opts.sanitizer | self.target.options.default_sanitizers;
893 }
894}
895
896#[allow(rustc::bad_opt_access)]
898fn default_emitter(
899 sopts: &config::Options,
900 source_map: Arc<SourceMap>,
901 translator: Translator,
902) -> Box<DynEmitter> {
903 let macro_backtrace = sopts.unstable_opts.macro_backtrace;
904 let track_diagnostics = sopts.unstable_opts.track_diagnostics;
905 let terminal_url = match sopts.unstable_opts.terminal_urls {
906 TerminalUrl::Auto => {
907 match (std::env::var("COLORTERM").as_deref(), std::env::var("TERM").as_deref()) {
908 (Ok("truecolor"), Ok("xterm-256color"))
909 if sopts.unstable_features.is_nightly_build() =>
910 {
911 TerminalUrl::Yes
912 }
913 _ => TerminalUrl::No,
914 }
915 }
916 t => t,
917 };
918
919 let source_map = if sopts.unstable_opts.link_only { None } else { Some(source_map) };
920
921 match sopts.error_format {
922 config::ErrorOutputType::HumanReadable { kind, color_config } => match kind {
923 HumanReadableErrorType::AnnotateSnippet { short, unicode } => {
924 let emitter =
925 AnnotateSnippetEmitter::new(stderr_destination(color_config), translator)
926 .sm(source_map)
927 .short_message(short)
928 .diagnostic_width(sopts.diagnostic_width)
929 .macro_backtrace(macro_backtrace)
930 .track_diagnostics(track_diagnostics)
931 .terminal_url(terminal_url)
932 .theme(if unicode { OutputTheme::Unicode } else { OutputTheme::Ascii })
933 .ignored_directories_in_source_blocks(
934 sopts
935 .unstable_opts
936 .ignore_directory_in_diagnostics_source_blocks
937 .clone(),
938 );
939 Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
940 }
941 HumanReadableErrorType::Default { short } => {
942 let emitter = HumanEmitter::new(stderr_destination(color_config), translator)
943 .sm(source_map)
944 .short_message(short)
945 .diagnostic_width(sopts.diagnostic_width)
946 .macro_backtrace(macro_backtrace)
947 .track_diagnostics(track_diagnostics)
948 .terminal_url(terminal_url)
949 .theme(OutputTheme::Ascii)
950 .ignored_directories_in_source_blocks(
951 sopts.unstable_opts.ignore_directory_in_diagnostics_source_blocks.clone(),
952 );
953 Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
954 }
955 },
956 config::ErrorOutputType::Json { pretty, json_rendered, color_config } => Box::new(
957 JsonEmitter::new(
958 Box::new(io::BufWriter::new(io::stderr())),
959 source_map,
960 translator,
961 pretty,
962 json_rendered,
963 color_config,
964 )
965 .ui_testing(sopts.unstable_opts.ui_testing)
966 .ignored_directories_in_source_blocks(
967 sopts.unstable_opts.ignore_directory_in_diagnostics_source_blocks.clone(),
968 )
969 .diagnostic_width(sopts.diagnostic_width)
970 .macro_backtrace(macro_backtrace)
971 .track_diagnostics(track_diagnostics)
972 .terminal_url(terminal_url),
973 ),
974 }
975}
976
977#[allow(rustc::bad_opt_access)]
979#[allow(rustc::untranslatable_diagnostic)] pub fn build_session(
981 sopts: config::Options,
982 io: CompilerIO,
983 fluent_bundle: Option<Arc<rustc_errors::FluentBundle>>,
984 registry: rustc_errors::registry::Registry,
985 fluent_resources: Vec<&'static str>,
986 driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
987 target: Target,
988 cfg_version: &'static str,
989 ice_file: Option<PathBuf>,
990 using_internal_features: &'static AtomicBool,
991) -> Session {
992 let warnings_allow = sopts
996 .lint_opts
997 .iter()
998 .rfind(|&(key, _)| *key == "warnings")
999 .is_some_and(|&(_, level)| level == lint::Allow);
1000 let cap_lints_allow = sopts.lint_cap.is_some_and(|cap| cap == lint::Allow);
1001 let can_emit_warnings = !(warnings_allow || cap_lints_allow);
1002
1003 let translator = Translator {
1004 fluent_bundle,
1005 fallback_fluent_bundle: fallback_fluent_bundle(
1006 fluent_resources,
1007 sopts.unstable_opts.translate_directionality_markers,
1008 ),
1009 };
1010 let source_map = rustc_span::source_map::get_source_map().unwrap();
1011 let emitter = default_emitter(&sopts, Arc::clone(&source_map), translator);
1012
1013 let mut dcx = DiagCtxt::new(emitter)
1014 .with_flags(sopts.unstable_opts.dcx_flags(can_emit_warnings))
1015 .with_registry(registry);
1016 if let Some(ice_file) = ice_file {
1017 dcx = dcx.with_ice_file(ice_file);
1018 }
1019
1020 let host_triple = TargetTuple::from_tuple(config::host_tuple());
1021 let (host, target_warnings) = Target::search(&host_triple, sopts.sysroot.path())
1022 .unwrap_or_else(|e| dcx.handle().fatal(format!("Error loading host specification: {e}")));
1023 for warning in target_warnings.warning_messages() {
1024 dcx.handle().warn(warning)
1025 }
1026
1027 let self_profiler = if let SwitchWithOptPath::Enabled(ref d) = sopts.unstable_opts.self_profile
1028 {
1029 let directory = if let Some(directory) = d { directory } else { std::path::Path::new(".") };
1030
1031 let profiler = SelfProfiler::new(
1032 directory,
1033 sopts.crate_name.as_deref(),
1034 sopts.unstable_opts.self_profile_events.as_deref(),
1035 &sopts.unstable_opts.self_profile_counter,
1036 );
1037 match profiler {
1038 Ok(profiler) => Some(Arc::new(profiler)),
1039 Err(e) => {
1040 dcx.handle().emit_warn(errors::FailedToCreateProfiler { err: e.to_string() });
1041 None
1042 }
1043 }
1044 } else {
1045 None
1046 };
1047
1048 let mut psess = ParseSess::with_dcx(dcx, source_map);
1049 psess.assume_incomplete_release = sopts.unstable_opts.assume_incomplete_release;
1050
1051 let host_triple = config::host_tuple();
1052 let target_triple = sopts.target_triple.tuple();
1053 let host_tlib_path =
1055 Arc::new(SearchPath::from_sysroot_and_triple(sopts.sysroot.path(), host_triple));
1056 let target_tlib_path = if host_triple == target_triple {
1057 Arc::clone(&host_tlib_path)
1060 } else {
1061 Arc::new(SearchPath::from_sysroot_and_triple(sopts.sysroot.path(), target_triple))
1062 };
1063
1064 let prof = SelfProfilerRef::new(
1065 self_profiler,
1066 sopts.unstable_opts.time_passes.then(|| sopts.unstable_opts.time_passes_format),
1067 );
1068
1069 let ctfe_backtrace = Lock::new(match env::var("RUSTC_CTFE_BACKTRACE") {
1070 Ok(ref val) if val == "immediate" => CtfeBacktrace::Immediate,
1071 Ok(ref val) if val != "0" => CtfeBacktrace::Capture,
1072 _ => CtfeBacktrace::Disabled,
1073 });
1074
1075 let asm_arch = if target.allow_asm { InlineAsmArch::from_arch(&target.arch) } else { None };
1076 let target_filesearch =
1077 filesearch::FileSearch::new(&sopts.search_paths, &target_tlib_path, &target);
1078 let host_filesearch = filesearch::FileSearch::new(&sopts.search_paths, &host_tlib_path, &host);
1079
1080 let invocation_temp = sopts
1081 .incremental
1082 .as_ref()
1083 .map(|_| rng().next_u32().to_base_fixed_len(CASE_INSENSITIVE).to_string());
1084
1085 let timings = TimingSectionHandler::new(sopts.json_timings);
1086
1087 let sess = Session {
1088 target,
1089 host,
1090 opts: sopts,
1091 target_tlib_path,
1092 psess,
1093 io,
1094 incr_comp_session: RwLock::new(IncrCompSession::NotInitialized),
1095 prof,
1096 timings,
1097 code_stats: Default::default(),
1098 lint_store: None,
1099 driver_lint_caps,
1100 ctfe_backtrace,
1101 miri_unleashed_features: Lock::new(Default::default()),
1102 asm_arch,
1103 target_features: Default::default(),
1104 unstable_target_features: Default::default(),
1105 cfg_version,
1106 using_internal_features,
1107 target_filesearch,
1108 host_filesearch,
1109 invocation_temp,
1110 };
1111
1112 validate_commandline_args_with_session_available(&sess);
1113
1114 sess
1115}
1116
1117#[allow(rustc::bad_opt_access)]
1123fn validate_commandline_args_with_session_available(sess: &Session) {
1124 if sess.opts.cg.linker_plugin_lto.enabled()
1132 && sess.opts.cg.prefer_dynamic
1133 && sess.target.is_like_windows
1134 {
1135 sess.dcx().emit_err(errors::LinkerPluginToWindowsNotSupported);
1136 }
1137
1138 if let Some(ref path) = sess.opts.cg.profile_use {
1141 if !path.exists() {
1142 sess.dcx().emit_err(errors::ProfileUseFileDoesNotExist { path });
1143 }
1144 }
1145
1146 if let Some(ref path) = sess.opts.unstable_opts.profile_sample_use {
1148 if !path.exists() {
1149 sess.dcx().emit_err(errors::ProfileSampleUseFileDoesNotExist { path });
1150 }
1151 }
1152
1153 if let Some(include_uwtables) = sess.opts.cg.force_unwind_tables {
1155 if sess.target.requires_uwtable && !include_uwtables {
1156 sess.dcx().emit_err(errors::TargetRequiresUnwindTables);
1157 }
1158 }
1159
1160 let supported_sanitizers = sess.target.options.supported_sanitizers;
1162 let mut unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
1163 if sess.opts.unstable_opts.fixed_x18 && sess.target.arch == Arch::AArch64 {
1166 unsupported_sanitizers -= SanitizerSet::SHADOWCALLSTACK;
1167 }
1168 match unsupported_sanitizers.into_iter().count() {
1169 0 => {}
1170 1 => {
1171 sess.dcx()
1172 .emit_err(errors::SanitizerNotSupported { us: unsupported_sanitizers.to_string() });
1173 }
1174 _ => {
1175 sess.dcx().emit_err(errors::SanitizersNotSupported {
1176 us: unsupported_sanitizers.to_string(),
1177 });
1178 }
1179 }
1180
1181 if let Some((first, second)) = sess.opts.unstable_opts.sanitizer.mutually_exclusive() {
1183 sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
1184 first: first.to_string(),
1185 second: second.to_string(),
1186 });
1187 }
1188
1189 if sess.crt_static(None)
1191 && !sess.opts.unstable_opts.sanitizer.is_empty()
1192 && !sess.target.is_like_msvc
1193 {
1194 sess.dcx().emit_err(errors::CannotEnableCrtStaticLinux);
1195 }
1196
1197 if sess.is_sanitizer_cfi_enabled()
1199 && !(sess.lto() == config::Lto::Fat || sess.opts.cg.linker_plugin_lto.enabled())
1200 {
1201 sess.dcx().emit_err(errors::SanitizerCfiRequiresLto);
1202 }
1203
1204 if sess.is_sanitizer_kcfi_enabled() && sess.panic_strategy().unwinds() {
1206 sess.dcx().emit_err(errors::SanitizerKcfiRequiresPanicAbort);
1207 }
1208
1209 if sess.is_sanitizer_cfi_enabled()
1211 && sess.lto() == config::Lto::Fat
1212 && (sess.codegen_units().as_usize() != 1)
1213 {
1214 sess.dcx().emit_err(errors::SanitizerCfiRequiresSingleCodegenUnit);
1215 }
1216
1217 if sess.is_sanitizer_cfi_canonical_jump_tables_disabled() {
1219 if !sess.is_sanitizer_cfi_enabled() {
1220 sess.dcx().emit_err(errors::SanitizerCfiCanonicalJumpTablesRequiresCfi);
1221 }
1222 }
1223
1224 if sess.is_sanitizer_kcfi_arity_enabled() && !sess.is_sanitizer_kcfi_enabled() {
1226 sess.dcx().emit_err(errors::SanitizerKcfiArityRequiresKcfi);
1227 }
1228
1229 if sess.is_sanitizer_cfi_generalize_pointers_enabled() {
1231 if !(sess.is_sanitizer_cfi_enabled() || sess.is_sanitizer_kcfi_enabled()) {
1232 sess.dcx().emit_err(errors::SanitizerCfiGeneralizePointersRequiresCfi);
1233 }
1234 }
1235
1236 if sess.is_sanitizer_cfi_normalize_integers_enabled() {
1238 if !(sess.is_sanitizer_cfi_enabled() || sess.is_sanitizer_kcfi_enabled()) {
1239 sess.dcx().emit_err(errors::SanitizerCfiNormalizeIntegersRequiresCfi);
1240 }
1241 }
1242
1243 if sess.is_split_lto_unit_enabled()
1245 && !(sess.lto() == config::Lto::Fat
1246 || sess.lto() == config::Lto::Thin
1247 || sess.opts.cg.linker_plugin_lto.enabled())
1248 {
1249 sess.dcx().emit_err(errors::SplitLtoUnitRequiresLto);
1250 }
1251
1252 if sess.lto() != config::Lto::Fat {
1254 if sess.opts.unstable_opts.virtual_function_elimination {
1255 sess.dcx().emit_err(errors::UnstableVirtualFunctionElimination);
1256 }
1257 }
1258
1259 if sess.opts.unstable_opts.stack_protector != StackProtector::None {
1260 if !sess.target.options.supports_stack_protector {
1261 sess.dcx().emit_warn(errors::StackProtectorNotSupportedForTarget {
1262 stack_protector: sess.opts.unstable_opts.stack_protector,
1263 target_triple: &sess.opts.target_triple,
1264 });
1265 }
1266 }
1267
1268 if sess.opts.unstable_opts.small_data_threshold.is_some() {
1269 if sess.target.small_data_threshold_support() == SmallDataThresholdSupport::None {
1270 sess.dcx().emit_warn(errors::SmallDataThresholdNotSupportedForTarget {
1271 target_triple: &sess.opts.target_triple,
1272 })
1273 }
1274 }
1275
1276 if sess.opts.unstable_opts.branch_protection.is_some() && sess.target.arch != Arch::AArch64 {
1277 sess.dcx().emit_err(errors::BranchProtectionRequiresAArch64);
1278 }
1279
1280 if let Some(dwarf_version) =
1281 sess.opts.cg.dwarf_version.or(sess.opts.unstable_opts.dwarf_version)
1282 {
1283 if dwarf_version < 2 || dwarf_version > 5 {
1285 sess.dcx().emit_err(errors::UnsupportedDwarfVersion { dwarf_version });
1286 }
1287 }
1288
1289 if !sess.target.options.supported_split_debuginfo.contains(&sess.split_debuginfo())
1290 && !sess.opts.unstable_opts.unstable_options
1291 {
1292 sess.dcx()
1293 .emit_err(errors::SplitDebugInfoUnstablePlatform { debuginfo: sess.split_debuginfo() });
1294 }
1295
1296 if sess.opts.unstable_opts.embed_source {
1297 let dwarf_version = sess.dwarf_version();
1298
1299 if dwarf_version < 5 {
1300 sess.dcx().emit_warn(errors::EmbedSourceInsufficientDwarfVersion { dwarf_version });
1301 }
1302
1303 if sess.opts.debuginfo == DebugInfo::None {
1304 sess.dcx().emit_warn(errors::EmbedSourceRequiresDebugInfo);
1305 }
1306 }
1307
1308 if sess.opts.unstable_opts.instrument_xray.is_some() && !sess.target.options.supports_xray {
1309 sess.dcx().emit_err(errors::InstrumentationNotSupported { us: "XRay".to_string() });
1310 }
1311
1312 if let Some(flavor) = sess.opts.cg.linker_flavor
1313 && let Some(compatible_list) = sess.target.linker_flavor.check_compatibility(flavor)
1314 {
1315 let flavor = flavor.desc();
1316 sess.dcx().emit_err(errors::IncompatibleLinkerFlavor { flavor, compatible_list });
1317 }
1318
1319 if sess.opts.unstable_opts.function_return != FunctionReturn::default() {
1320 if !matches!(sess.target.arch, Arch::X86 | Arch::X86_64) {
1321 sess.dcx().emit_err(errors::FunctionReturnRequiresX86OrX8664);
1322 }
1323 }
1324
1325 if sess.opts.unstable_opts.indirect_branch_cs_prefix {
1326 if !matches!(sess.target.arch, Arch::X86 | Arch::X86_64) {
1327 sess.dcx().emit_err(errors::IndirectBranchCsPrefixRequiresX86OrX8664);
1328 }
1329 }
1330
1331 if let Some(regparm) = sess.opts.unstable_opts.regparm {
1332 if regparm > 3 {
1333 sess.dcx().emit_err(errors::UnsupportedRegparm { regparm });
1334 }
1335 if sess.target.arch != Arch::X86 {
1336 sess.dcx().emit_err(errors::UnsupportedRegparmArch);
1337 }
1338 }
1339 if sess.opts.unstable_opts.reg_struct_return {
1340 if sess.target.arch != Arch::X86 {
1341 sess.dcx().emit_err(errors::UnsupportedRegStructReturnArch);
1342 }
1343 }
1344
1345 match sess.opts.unstable_opts.function_return {
1349 FunctionReturn::Keep => (),
1350 FunctionReturn::ThunkExtern => {
1351 if let Some(code_model) = sess.code_model()
1354 && code_model == CodeModel::Large
1355 {
1356 sess.dcx().emit_err(errors::FunctionReturnThunkExternRequiresNonLargeCodeModel);
1357 }
1358 }
1359 }
1360
1361 if sess.opts.cg.soft_float {
1362 if sess.target.arch == Arch::Arm {
1363 sess.dcx().emit_warn(errors::SoftFloatDeprecated);
1364 } else {
1365 sess.dcx().emit_warn(errors::SoftFloatIgnored);
1368 }
1369 }
1370}
1371
1372#[derive(Debug)]
1374enum IncrCompSession {
1375 NotInitialized,
1378 Active { session_directory: PathBuf, _lock_file: flock::Lock },
1383 Finalized { session_directory: PathBuf },
1386 InvalidBecauseOfErrors { session_directory: PathBuf },
1390}
1391
1392pub struct EarlyDiagCtxt {
1394 dcx: DiagCtxt,
1395}
1396
1397impl EarlyDiagCtxt {
1398 pub fn new(output: ErrorOutputType) -> Self {
1399 let emitter = mk_emitter(output);
1400 Self { dcx: DiagCtxt::new(emitter) }
1401 }
1402
1403 pub fn set_error_format(&mut self, output: ErrorOutputType) {
1406 assert!(self.dcx.handle().has_errors().is_none());
1407
1408 let emitter = mk_emitter(output);
1409 self.dcx = DiagCtxt::new(emitter);
1410 }
1411
1412 #[allow(rustc::untranslatable_diagnostic)]
1413 #[allow(rustc::diagnostic_outside_of_impl)]
1414 pub fn early_note(&self, msg: impl Into<DiagMessage>) {
1415 self.dcx.handle().note(msg)
1416 }
1417
1418 #[allow(rustc::untranslatable_diagnostic)]
1419 #[allow(rustc::diagnostic_outside_of_impl)]
1420 pub fn early_help(&self, msg: impl Into<DiagMessage>) {
1421 self.dcx.handle().struct_help(msg).emit()
1422 }
1423
1424 #[allow(rustc::untranslatable_diagnostic)]
1425 #[allow(rustc::diagnostic_outside_of_impl)]
1426 #[must_use = "raise_fatal must be called on the returned ErrorGuaranteed in order to exit with a non-zero status code"]
1427 pub fn early_err(&self, msg: impl Into<DiagMessage>) -> ErrorGuaranteed {
1428 self.dcx.handle().err(msg)
1429 }
1430
1431 #[allow(rustc::untranslatable_diagnostic)]
1432 #[allow(rustc::diagnostic_outside_of_impl)]
1433 pub fn early_fatal(&self, msg: impl Into<DiagMessage>) -> ! {
1434 self.dcx.handle().fatal(msg)
1435 }
1436
1437 #[allow(rustc::untranslatable_diagnostic)]
1438 #[allow(rustc::diagnostic_outside_of_impl)]
1439 pub fn early_struct_fatal(&self, msg: impl Into<DiagMessage>) -> Diag<'_, FatalAbort> {
1440 self.dcx.handle().struct_fatal(msg)
1441 }
1442
1443 #[allow(rustc::untranslatable_diagnostic)]
1444 #[allow(rustc::diagnostic_outside_of_impl)]
1445 pub fn early_warn(&self, msg: impl Into<DiagMessage>) {
1446 self.dcx.handle().warn(msg)
1447 }
1448
1449 #[allow(rustc::untranslatable_diagnostic)]
1450 #[allow(rustc::diagnostic_outside_of_impl)]
1451 pub fn early_struct_warn(&self, msg: impl Into<DiagMessage>) -> Diag<'_, ()> {
1452 self.dcx.handle().struct_warn(msg)
1453 }
1454}
1455
1456fn mk_emitter(output: ErrorOutputType) -> Box<DynEmitter> {
1457 let translator =
1460 Translator::with_fallback_bundle(vec![rustc_errors::DEFAULT_LOCALE_RESOURCE], false);
1461 let emitter: Box<DynEmitter> = match output {
1462 config::ErrorOutputType::HumanReadable { kind, color_config } => match kind {
1463 HumanReadableErrorType::AnnotateSnippet { short, unicode } => Box::new(
1464 AnnotateSnippetEmitter::new(stderr_destination(color_config), translator)
1465 .theme(if unicode { OutputTheme::Unicode } else { OutputTheme::Ascii })
1466 .short_message(short),
1467 ),
1468 HumanReadableErrorType::Default { short } => Box::new(
1469 HumanEmitter::new(stderr_destination(color_config), translator)
1470 .theme(OutputTheme::Ascii)
1471 .short_message(short),
1472 ),
1473 },
1474 config::ErrorOutputType::Json { pretty, json_rendered, color_config } => {
1475 Box::new(JsonEmitter::new(
1476 Box::new(io::BufWriter::new(io::stderr())),
1477 Some(Arc::new(SourceMap::new(FilePathMapping::empty()))),
1478 translator,
1479 pretty,
1480 json_rendered,
1481 color_config,
1482 ))
1483 }
1484 };
1485 emitter
1486}