1use std::collections::BTreeMap;
2use std::num::{IntErrorKind, NonZero};
3use std::path::PathBuf;
4use std::str;
5
6use rustc_abi::Align;
7use rustc_data_structures::fx::FxIndexMap;
8use rustc_data_structures::profiling::TimePassesFormat;
9use rustc_data_structures::stable_hasher::StableHasher;
10use rustc_errors::{ColorConfig, LanguageIdentifier, TerminalUrl};
11use rustc_feature::UnstableFeatures;
12use rustc_hashes::Hash64;
13use rustc_macros::{Decodable, Encodable};
14use rustc_span::edition::Edition;
15use rustc_span::{RealFileName, SourceFileHashAlgorithm};
16use rustc_target::spec::{
17 CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy,
18 RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility,
19 TargetTuple, TlsModel,
20};
21
22use crate::config::*;
23use crate::search_paths::SearchPath;
24use crate::utils::NativeLib;
25use crate::{EarlyDiagCtxt, lint};
26
27macro_rules! insert {
28 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr) => {
29 if $sub_hashes
30 .insert(stringify!($opt_name), $opt_expr as &dyn dep_tracking::DepTrackingHash)
31 .is_some()
32 {
33 panic!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
34 }
35 };
36}
37
38macro_rules! hash_opt {
39 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, $_for_crate_hash: ident, [UNTRACKED]) => {{}};
40 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, $_for_crate_hash: ident, [TRACKED]) => {{ insert!($opt_name, $opt_expr, $sub_hashes) }};
41 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, $for_crate_hash: ident, [TRACKED_NO_CRATE_HASH]) => {{
42 if !$for_crate_hash {
43 insert!($opt_name, $opt_expr, $sub_hashes)
44 }
45 }};
46 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, $_for_crate_hash: ident, [SUBSTRUCT]) => {{}};
47}
48
49macro_rules! hash_substruct {
50 ($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [UNTRACKED]) => {{}};
51 ($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [TRACKED]) => {{}};
52 ($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [TRACKED_NO_CRATE_HASH]) => {{}};
53 ($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [SUBSTRUCT]) => {
54 use crate::config::dep_tracking::DepTrackingHash;
55 $opt_expr.dep_tracking_hash($for_crate_hash, $error_format).hash(
56 $hasher,
57 $error_format,
58 $for_crate_hash,
59 );
60 };
61}
62
63pub struct ExtendedTargetModifierInfo {
68 pub prefix: String,
70 pub name: String,
72 pub tech_value: String,
74}
75
76#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
79pub struct TargetModifier {
80 pub opt: OptionsTargetModifiers,
82 pub value_name: String,
84}
85
86impl TargetModifier {
87 pub fn extend(&self) -> ExtendedTargetModifierInfo {
88 self.opt.reparse(&self.value_name)
89 }
90}
91
92fn tmod_push_impl(
93 opt: OptionsTargetModifiers,
94 tmod_vals: &BTreeMap<OptionsTargetModifiers, String>,
95 tmods: &mut Vec<TargetModifier>,
96) {
97 if let Some(v) = tmod_vals.get(&opt) {
98 tmods.push(TargetModifier { opt, value_name: v.clone() })
99 }
100}
101
102macro_rules! tmod_push {
103 ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr) => {
104 if *$opt_expr != $init {
105 tmod_push_impl(
106 OptionsTargetModifiers::$struct_name($tmod_enum_name::$opt_name),
107 $tmod_vals,
108 $mods,
109 );
110 }
111 };
112}
113
114macro_rules! gather_tmods {
115 ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
116 [SUBSTRUCT], [TARGET_MODIFIER]) => {
117 compile_error!("SUBSTRUCT can't be target modifier");
118 };
119 ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
120 [UNTRACKED], [TARGET_MODIFIER]) => {
121 tmod_push!($struct_name, $tmod_enum_name, $opt_name, $opt_expr, $init, $mods, $tmod_vals)
122 };
123 ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
124 [TRACKED], [TARGET_MODIFIER]) => {
125 tmod_push!($struct_name, $tmod_enum_name, $opt_name, $opt_expr, $init, $mods, $tmod_vals)
126 };
127 ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
128 [TRACKED_NO_CRATE_HASH], [TARGET_MODIFIER]) => {
129 tmod_push!($struct_name, $tmod_enum_name, $opt_name, $opt_expr, $init, $mods, $tmod_vals)
130 };
131 ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
132 [SUBSTRUCT], []) => {
133 $opt_expr.gather_target_modifiers($mods, $tmod_vals);
134 };
135 ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
136 [UNTRACKED], []) => {{}};
137 ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
138 [TRACKED], []) => {{}};
139 ($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
140 [TRACKED_NO_CRATE_HASH], []) => {{}};
141}
142
143macro_rules! gather_tmods_top_level {
144 ($_opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, [SUBSTRUCT $substruct_enum:ident]) => {
145 $opt_expr.gather_target_modifiers($mods, $tmod_vals);
146 };
147 ($opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, [$non_substruct:ident TARGET_MODIFIER]) => {
148 compile_error!("Top level option can't be target modifier");
149 };
150 ($opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr, [$non_substruct:ident]) => {};
151}
152
153macro_rules! top_level_tmod_enum {
174 ($( {$($optinfo:tt)*} ),* $(,)*) => {
175 top_level_tmod_enum! { @parse {}, (user_value){}; $($($optinfo)*|)* }
176 };
177 (
179 @parse
180 {$($variant:tt($substruct_enum:tt))*},
181 ($user_value:ident){$($pout:tt)*};
182 ) => {
183 #[allow(non_camel_case_types)]
184 #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone, Encodable, Decodable)]
185 pub enum OptionsTargetModifiers {
186 $($variant($substruct_enum)),*
187 }
188 impl OptionsTargetModifiers {
189 #[allow(unused_variables)]
190 pub fn reparse(&self, $user_value: &str) -> ExtendedTargetModifierInfo {
191 #[allow(unreachable_patterns)]
192 match self {
193 $($pout)*
194 _ => panic!("unknown target modifier option: {:?}", *self)
195 }
196 }
197 pub fn is_target_modifier(flag_name: &str) -> bool {
198 $($substruct_enum::is_target_modifier(flag_name))||*
199 }
200 }
201 };
202 (
204 @parse {$($eout:tt)*}, ($puser_value:ident){$($pout:tt)*};
205 [SUBSTRUCT $substruct_enum:ident $variant:ident] |
206 $($tail:tt)*
207 ) => {
208 top_level_tmod_enum! {
209 @parse
210 {
211 $($eout)*
212 $variant($substruct_enum)
213 },
214 ($puser_value){
215 $($pout)*
216 Self::$variant(v) => v.reparse($puser_value),
217 };
218 $($tail)*
219 }
220 };
221 (
223 @parse {$($eout:tt)*}, ($puser_value:ident){$($pout:tt)*};
224 [$non_substruct:ident] |
225 $($tail:tt)*
226 ) => {
227 top_level_tmod_enum! {
228 @parse
229 {
230 $($eout)*
231 },
232 ($puser_value){
233 $($pout)*
234 };
235 $($tail)*
236 }
237 };
238}
239
240macro_rules! top_level_options {
241 ( $( #[$top_level_attr:meta] )* pub struct Options { $(
242 $( #[$attr:meta] )*
243 $opt:ident : $t:ty [$dep_tracking_marker:ident $( $tmod:ident $variant:ident )?],
244 )* } ) => (
245 top_level_tmod_enum!( {$([$dep_tracking_marker $($tmod $variant),*])|*} );
246
247 #[derive(Clone)]
248 $( #[$top_level_attr] )*
249 pub struct Options {
250 $(
251 $( #[$attr] )*
252 pub $opt: $t
253 ),*,
254 pub target_modifiers: BTreeMap<OptionsTargetModifiers, String>,
255 }
256
257 impl Options {
258 pub fn dep_tracking_hash(&self, for_crate_hash: bool) -> Hash64 {
259 let mut sub_hashes = BTreeMap::new();
260 $({
261 hash_opt!($opt,
262 &self.$opt,
263 &mut sub_hashes,
264 for_crate_hash,
265 [$dep_tracking_marker]);
266 })*
267 let mut hasher = StableHasher::new();
268 dep_tracking::stable_hash(sub_hashes,
269 &mut hasher,
270 self.error_format,
271 for_crate_hash);
272 $({
273 hash_substruct!($opt,
274 &self.$opt,
275 self.error_format,
276 for_crate_hash,
277 &mut hasher,
278 [$dep_tracking_marker]);
279 })*
280 hasher.finish()
281 }
282
283 pub fn gather_target_modifiers(&self) -> Vec<TargetModifier> {
284 let mut mods = Vec::<TargetModifier>::new();
285 $({
286 gather_tmods_top_level!($opt,
287 &self.$opt, &mut mods, &self.target_modifiers,
288 [$dep_tracking_marker $($tmod),*]);
289 })*
290 mods.sort_by(|a, b| a.opt.cmp(&b.opt));
291 mods
292 }
293 }
294 );
295}
296
297top_level_options!(
298 #[rustc_lint_opt_ty]
323 pub struct Options {
324 #[rustc_lint_opt_deny_field_access("use `TyCtxt::crate_types` instead of this field")]
327 crate_types: Vec<CrateType> [TRACKED],
328 optimize: OptLevel [TRACKED],
329 debug_assertions: bool [TRACKED],
332 debuginfo: DebugInfo [TRACKED],
333 debuginfo_compression: DebugInfoCompression [TRACKED],
334 lint_opts: Vec<(String, lint::Level)> [TRACKED_NO_CRATE_HASH],
335 lint_cap: Option<lint::Level> [TRACKED_NO_CRATE_HASH],
336 describe_lints: bool [UNTRACKED],
337 output_types: OutputTypes [TRACKED],
338 search_paths: Vec<SearchPath> [UNTRACKED],
339 libs: Vec<NativeLib> [TRACKED],
340 sysroot: Sysroot [UNTRACKED],
341
342 target_triple: TargetTuple [TRACKED],
343
344 logical_env: FxIndexMap<String, String> [TRACKED],
346
347 test: bool [TRACKED],
348 error_format: ErrorOutputType [UNTRACKED],
349 diagnostic_width: Option<usize> [UNTRACKED],
350
351 incremental: Option<PathBuf> [UNTRACKED],
354 assert_incr_state: Option<IncrementalStateAssertion> [UNTRACKED],
355 #[rustc_lint_opt_deny_field_access("should only be used via `Config::hash_untracked_state`")]
358 untracked_state_hash: Hash64 [TRACKED_NO_CRATE_HASH],
359
360 unstable_opts: UnstableOptions [SUBSTRUCT UnstableOptionsTargetModifiers UnstableOptions],
361 prints: Vec<PrintRequest> [UNTRACKED],
362 cg: CodegenOptions [SUBSTRUCT CodegenOptionsTargetModifiers CodegenOptions],
363 externs: Externs [UNTRACKED],
364 crate_name: Option<String> [TRACKED],
365 unstable_features: UnstableFeatures [TRACKED],
367
368 actually_rustdoc: bool [TRACKED],
372 resolve_doc_links: ResolveDocLinks [TRACKED],
374
375 trimmed_def_paths: bool [TRACKED],
377
378 #[rustc_lint_opt_deny_field_access("use `Session::codegen_units` instead of this field")]
384 cli_forced_codegen_units: Option<usize> [UNTRACKED],
385 #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
386 cli_forced_local_thinlto_off: bool [UNTRACKED],
387
388 remap_path_prefix: Vec<(PathBuf, PathBuf)> [TRACKED_NO_CRATE_HASH],
390
391 real_rust_source_base_dir: Option<PathBuf> [TRACKED_NO_CRATE_HASH],
399
400 real_rustc_dev_source_base_dir: Option<PathBuf> [TRACKED_NO_CRATE_HASH],
408
409 edition: Edition [TRACKED],
410
411 json_artifact_notifications: bool [TRACKED],
414
415 json_timings: bool [UNTRACKED],
418
419 json_unused_externs: JsonUnusedExterns [UNTRACKED],
421
422 json_future_incompat: bool [TRACKED],
424
425 pretty: Option<PpMode> [UNTRACKED],
426
427 working_dir: RealFileName [TRACKED],
429 color: ColorConfig [UNTRACKED],
430
431 verbose: bool [TRACKED_NO_CRATE_HASH],
432 }
433);
434
435macro_rules! tmod_enum_opt {
436 ($struct_name:ident, $tmod_enum_name:ident, $opt:ident, $v:ident) => {
437 Some(OptionsTargetModifiers::$struct_name($tmod_enum_name::$opt))
438 };
439 ($struct_name:ident, $tmod_enum_name:ident, $opt:ident, ) => {
440 None
441 };
442}
443
444macro_rules! tmod_enum {
445 ($tmod_enum_name:ident, $prefix:expr, $( {$($optinfo:tt)*} ),* $(,)*) => {
446 tmod_enum! { $tmod_enum_name, $prefix, @parse {}, (user_value){}; $($($optinfo)*|)* }
447 };
448 (
450 $tmod_enum_name:ident, $prefix:expr,
451 @parse
452 {$($eout:tt)*},
453 ($user_value:ident){$($pout:tt)*};
454 ) => {
455 #[allow(non_camel_case_types)]
456 #[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Copy, Clone, Encodable, Decodable)]
457 pub enum $tmod_enum_name {
458 $($eout),*
459 }
460 impl $tmod_enum_name {
461 #[allow(unused_variables)]
462 pub fn reparse(&self, $user_value: &str) -> ExtendedTargetModifierInfo {
463 #[allow(unreachable_patterns)]
464 match self {
465 $($pout)*
466 _ => panic!("unknown target modifier option: {:?}", *self)
467 }
468 }
469 pub fn is_target_modifier(flag_name: &str) -> bool {
470 match flag_name.replace('-', "_").as_str() {
471 $(stringify!($eout) => true,)*
472 _ => false,
473 }
474 }
475 }
476 };
477 (
479 $tmod_enum_name:ident, $prefix:expr,
480 @parse {$($eout:tt)*}, ($puser_value:ident){$($pout:tt)*};
481 $opt:ident, $parse:ident, $t:ty, [TARGET_MODIFIER] |
482 $($tail:tt)*
483 ) => {
484 tmod_enum! {
485 $tmod_enum_name, $prefix,
486 @parse
487 {
488 $($eout)*
489 $opt
490 },
491 ($puser_value){
492 $($pout)*
493 Self::$opt => {
494 let mut parsed : $t = Default::default();
495 let val = if $puser_value.is_empty() { None } else { Some($puser_value) };
496 parse::$parse(&mut parsed, val);
497 ExtendedTargetModifierInfo {
498 prefix: $prefix.to_string(),
499 name: stringify!($opt).to_string().replace('_', "-"),
500 tech_value: format!("{:?}", parsed),
501 }
502 },
503 };
504 $($tail)*
505 }
506 };
507 (
509 $tmod_enum_name:ident, $prefix:expr,
510 @parse {$($eout:tt)*}, ($puser_value:ident){$($pout:tt)*};
511 $opt:ident, $parse:ident, $t:ty, [] |
512 $($tail:tt)*
513 ) => {
514 tmod_enum! {
515 $tmod_enum_name, $prefix,
516 @parse
517 {
518 $($eout)*
519 },
520 ($puser_value){
521 $($pout)*
522 };
523 $($tail)*
524 }
525 };
526}
527
528macro_rules! options {
537 ($struct_name:ident, $tmod_enum_name:ident, $stat:ident, $optmod:ident, $prefix:expr, $outputname:expr,
538 $($( #[$attr:meta] )* $opt:ident : $t:ty = (
539 $init:expr,
540 $parse:ident,
541 [$dep_tracking_marker:ident $( $tmod:ident )?],
542 $desc:expr
543 $(, deprecated_do_nothing: $dnn:literal )?)
544 ),* ,) =>
545(
546 #[derive(Clone)]
547 #[rustc_lint_opt_ty]
548 pub struct $struct_name { $( $( #[$attr] )* pub $opt: $t),* }
549
550 tmod_enum!( $tmod_enum_name, $prefix, {$($opt, $parse, $t, [$($tmod),*])|*} );
551
552 impl Default for $struct_name {
553 fn default() -> $struct_name {
554 $struct_name { $($opt: $init),* }
555 }
556 }
557
558 impl $struct_name {
559 pub fn build(
560 early_dcx: &EarlyDiagCtxt,
561 matches: &getopts::Matches,
562 target_modifiers: &mut BTreeMap<OptionsTargetModifiers, String>,
563 ) -> $struct_name {
564 build_options(early_dcx, matches, target_modifiers, $stat, $prefix, $outputname)
565 }
566
567 fn dep_tracking_hash(&self, for_crate_hash: bool, error_format: ErrorOutputType) -> Hash64 {
568 let mut sub_hashes = BTreeMap::new();
569 $({
570 hash_opt!($opt,
571 &self.$opt,
572 &mut sub_hashes,
573 for_crate_hash,
574 [$dep_tracking_marker]);
575 })*
576 let mut hasher = StableHasher::new();
577 dep_tracking::stable_hash(sub_hashes,
578 &mut hasher,
579 error_format,
580 for_crate_hash
581 );
582 hasher.finish()
583 }
584
585 pub fn gather_target_modifiers(
586 &self,
587 _mods: &mut Vec<TargetModifier>,
588 _tmod_vals: &BTreeMap<OptionsTargetModifiers, String>,
589 ) {
590 $({
591 gather_tmods!($struct_name, $tmod_enum_name, $opt, &self.$opt, $init, _mods, _tmod_vals,
592 [$dep_tracking_marker], [$($tmod),*]);
593 })*
594 }
595 }
596
597 pub const $stat: OptionDescrs<$struct_name> =
598 &[ $( OptionDesc{ name: stringify!($opt), setter: $optmod::$opt,
599 type_desc: desc::$parse, desc: $desc, is_deprecated_and_do_nothing: false $( || $dnn )?,
600 tmod: tmod_enum_opt!($struct_name, $tmod_enum_name, $opt, $($tmod),*) } ),* ];
601
602 mod $optmod {
603 $(
604 pub(super) fn $opt(cg: &mut super::$struct_name, v: Option<&str>) -> bool {
605 super::parse::$parse(&mut redirect_field!(cg.$opt), v)
606 }
607 )*
608 }
609
610) }
611
612impl CodegenOptions {
613 #[allow(rustc::bad_opt_access)]
615 pub fn instrument_coverage(&self) -> InstrumentCoverage {
616 self.instrument_coverage
617 }
618}
619
620macro_rules! redirect_field {
623 ($cg:ident.link_arg) => {
624 $cg.link_args
625 };
626 ($cg:ident.pre_link_arg) => {
627 $cg.pre_link_args
628 };
629 ($cg:ident.$field:ident) => {
630 $cg.$field
631 };
632}
633
634type OptionSetter<O> = fn(&mut O, v: Option<&str>) -> bool;
635type OptionDescrs<O> = &'static [OptionDesc<O>];
636
637pub struct OptionDesc<O> {
638 name: &'static str,
639 setter: OptionSetter<O>,
640 type_desc: &'static str,
642 desc: &'static str,
644 is_deprecated_and_do_nothing: bool,
645 tmod: Option<OptionsTargetModifiers>,
646}
647
648impl<O> OptionDesc<O> {
649 pub fn name(&self) -> &'static str {
650 self.name
651 }
652
653 pub fn desc(&self) -> &'static str {
654 self.desc
655 }
656}
657
658#[allow(rustc::untranslatable_diagnostic)] fn build_options<O: Default>(
660 early_dcx: &EarlyDiagCtxt,
661 matches: &getopts::Matches,
662 target_modifiers: &mut BTreeMap<OptionsTargetModifiers, String>,
663 descrs: OptionDescrs<O>,
664 prefix: &str,
665 outputname: &str,
666) -> O {
667 let mut op = O::default();
668 for option in matches.opt_strs(prefix) {
669 let (key, value) = match option.split_once('=') {
670 None => (option, None),
671 Some((k, v)) => (k.to_string(), Some(v)),
672 };
673
674 let option_to_lookup = key.replace('-', "_");
675 match descrs.iter().find(|opt_desc| opt_desc.name == option_to_lookup) {
676 Some(OptionDesc {
677 name: _,
678 setter,
679 type_desc,
680 desc,
681 is_deprecated_and_do_nothing,
682 tmod,
683 }) => {
684 if *is_deprecated_and_do_nothing {
685 assert!(!prefix.is_empty());
687 early_dcx.early_warn(format!("`-{prefix} {key}`: {desc}"));
688 }
689 if !setter(&mut op, value) {
690 match value {
691 None => early_dcx.early_fatal(
692 format!(
693 "{outputname} option `{key}` requires {type_desc} ({prefix} {key}=<value>)"
694 ),
695 ),
696 Some(value) => early_dcx.early_fatal(
697 format!(
698 "incorrect value `{value}` for {outputname} option `{key}` - {type_desc} was expected"
699 ),
700 ),
701 }
702 }
703 if let Some(tmod) = *tmod {
704 let v = value.map_or(String::new(), ToOwned::to_owned);
705 target_modifiers.insert(tmod, v);
706 }
707 }
708 None => early_dcx.early_fatal(format!("unknown {outputname} option: `{key}`")),
709 }
710 }
711 op
712}
713
714#[allow(non_upper_case_globals)]
715mod desc {
716 pub(crate) const parse_no_value: &str = "no value";
717 pub(crate) const parse_bool: &str =
718 "one of: `y`, `yes`, `on`, `true`, `n`, `no`, `off` or `false`";
719 pub(crate) const parse_opt_bool: &str = parse_bool;
720 pub(crate) const parse_string: &str = "a string";
721 pub(crate) const parse_opt_string: &str = parse_string;
722 pub(crate) const parse_string_push: &str = parse_string;
723 pub(crate) const parse_opt_langid: &str = "a language identifier";
724 pub(crate) const parse_opt_pathbuf: &str = "a path";
725 pub(crate) const parse_list: &str = "a space-separated list of strings";
726 pub(crate) const parse_list_with_polarity: &str =
727 "a comma-separated list of strings, with elements beginning with + or -";
728 pub(crate) const parse_autodiff: &str = "a comma separated list of settings: `Enable`, `PrintSteps`, `PrintTA`, `PrintTAFn`, `PrintAA`, `PrintPerf`, `PrintModBefore`, `PrintModAfter`, `PrintModFinal`, `PrintPasses`, `NoPostopt`, `LooseTypes`, `Inline`";
729 pub(crate) const parse_comma_list: &str = "a comma-separated list of strings";
730 pub(crate) const parse_opt_comma_list: &str = parse_comma_list;
731 pub(crate) const parse_number: &str = "a number";
732 pub(crate) const parse_opt_number: &str = parse_number;
733 pub(crate) const parse_frame_pointer: &str = "one of `true`/`yes`/`on`, `false`/`no`/`off`, or (with -Zunstable-options) `non-leaf` or `always`";
734 pub(crate) const parse_threads: &str = parse_number;
735 pub(crate) const parse_time_passes_format: &str = "`text` (default) or `json`";
736 pub(crate) const parse_passes: &str = "a space-separated list of passes, or `all`";
737 pub(crate) const parse_panic_strategy: &str = "either `unwind` or `abort`";
738 pub(crate) const parse_on_broken_pipe: &str = "either `kill`, `error`, or `inherit`";
739 pub(crate) const parse_patchable_function_entry: &str = "either two comma separated integers (total_nops,prefix_nops), with prefix_nops <= total_nops, or one integer (total_nops)";
740 pub(crate) const parse_opt_panic_strategy: &str = parse_panic_strategy;
741 pub(crate) const parse_oom_strategy: &str = "either `panic` or `abort`";
742 pub(crate) const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
743 pub(crate) const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, or `thread`";
744 pub(crate) const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
745 pub(crate) const parse_cfguard: &str =
746 "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
747 pub(crate) const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)";
748 pub(crate) const parse_debuginfo: &str = "either an integer (0, 1, 2), `none`, `line-directives-only`, `line-tables-only`, `limited`, or `full`";
749 pub(crate) const parse_debuginfo_compression: &str = "one of `none`, `zlib`, or `zstd`";
750 pub(crate) const parse_mir_strip_debuginfo: &str =
751 "one of `none`, `locals-in-tiny-functions`, or `all-locals`";
752 pub(crate) const parse_collapse_macro_debuginfo: &str = "one of `no`, `external`, or `yes`";
753 pub(crate) const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
754 pub(crate) const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
755 pub(crate) const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
756 pub(crate) const parse_instrument_coverage: &str = parse_bool;
757 pub(crate) const parse_coverage_options: &str =
758 "`block` | `branch` | `condition` | `mcdc` | `no-mir-spans`";
759 pub(crate) const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`";
760 pub(crate) const parse_unpretty: &str = "`string` or `string=string`";
761 pub(crate) const parse_treat_err_as_bug: &str = "either no value or a non-negative number";
762 pub(crate) const parse_next_solver_config: &str =
763 "either `globally` (when used without an argument), `coherence` (default) or `no`";
764 pub(crate) const parse_lto: &str =
765 "either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted";
766 pub(crate) const parse_linker_plugin_lto: &str =
767 "either a boolean (`yes`, `no`, `on`, `off`, etc), or the path to the linker plugin";
768 pub(crate) const parse_location_detail: &str = "either `none`, or a comma separated list of location details to track: `file`, `line`, or `column`";
769 pub(crate) const parse_fmt_debug: &str = "either `full`, `shallow`, or `none`";
770 pub(crate) const parse_switch_with_opt_path: &str =
771 "an optional path to the profiling data output directory";
772 pub(crate) const parse_merge_functions: &str =
773 "one of: `disabled`, `trampolines`, or `aliases`";
774 pub(crate) const parse_symbol_mangling_version: &str =
775 "one of: `legacy`, `v0` (RFC 2603), or `hashed`";
776 pub(crate) const parse_opt_symbol_visibility: &str =
777 "one of: `hidden`, `protected`, or `interposable`";
778 pub(crate) const parse_cargo_src_file_hash: &str =
779 "one of `blake3`, `md5`, `sha1`, or `sha256`";
780 pub(crate) const parse_src_file_hash: &str = "one of `md5`, `sha1`, or `sha256`";
781 pub(crate) const parse_relocation_model: &str =
782 "one of supported relocation models (`rustc --print relocation-models`)";
783 pub(crate) const parse_code_model: &str =
784 "one of supported code models (`rustc --print code-models`)";
785 pub(crate) const parse_tls_model: &str =
786 "one of supported TLS models (`rustc --print tls-models`)";
787 pub(crate) const parse_target_feature: &str = parse_string;
788 pub(crate) const parse_terminal_url: &str =
789 "either a boolean (`yes`, `no`, `on`, `off`, etc), or `auto`";
790 pub(crate) const parse_wasi_exec_model: &str = "either `command` or `reactor`";
791 pub(crate) const parse_split_debuginfo: &str =
792 "one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
793 pub(crate) const parse_split_dwarf_kind: &str =
794 "one of supported split dwarf modes (`split` or `single`)";
795 pub(crate) const parse_link_self_contained: &str = "one of: `y`, `yes`, `on`, `n`, `no`, `off`, or a list of enabled (`+` prefix) and disabled (`-` prefix) \
796 components: `crto`, `libc`, `unwind`, `linker`, `sanitizers`, `mingw`";
797 pub(crate) const parse_linker_features: &str =
798 "a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld`";
799 pub(crate) const parse_polonius: &str = "either no value or `legacy` (the default), or `next`";
800 pub(crate) const parse_stack_protector: &str =
801 "one of (`none` (default), `basic`, `strong`, or `all`)";
802 pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `pac-ret`, followed by a combination of `pc`, `b-key`, or `leaf`";
803 pub(crate) const parse_proc_macro_execution_strategy: &str =
804 "one of supported execution strategies (`same-thread`, or `cross-thread`)";
805 pub(crate) const parse_remap_path_scope: &str =
806 "comma separated list of scopes: `macro`, `diagnostics`, `debuginfo`, `object`, `all`";
807 pub(crate) const parse_inlining_threshold: &str =
808 "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number";
809 pub(crate) const parse_llvm_module_flag: &str = "<key>:<type>:<value>:<behavior>. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)";
810 pub(crate) const parse_function_return: &str = "`keep` or `thunk-extern`";
811 pub(crate) const parse_wasm_c_abi: &str = "`spec`";
812 pub(crate) const parse_mir_include_spans: &str =
813 "either a boolean (`yes`, `no`, `on`, `off`, etc), or `nll` (default: `nll`)";
814 pub(crate) const parse_align: &str = "a number that is a power of 2 between 1 and 2^29";
815}
816
817pub mod parse {
818 use std::str::FromStr;
819
820 pub(crate) use super::*;
821 pub(crate) const MAX_THREADS_CAP: usize = 256;
822
823 pub(crate) fn parse_no_value(slot: &mut bool, v: Option<&str>) -> bool {
829 match v {
830 None => {
831 *slot = true;
832 true
833 }
834 Some(_) => false,
836 }
837 }
838
839 pub(crate) fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
841 match v {
842 Some("y") | Some("yes") | Some("on") | Some("true") | None => {
843 *slot = true;
844 true
845 }
846 Some("n") | Some("no") | Some("off") | Some("false") => {
847 *slot = false;
848 true
849 }
850 _ => false,
851 }
852 }
853
854 pub(crate) fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
858 match v {
859 Some("y") | Some("yes") | Some("on") | Some("true") | None => {
860 *slot = Some(true);
861 true
862 }
863 Some("n") | Some("no") | Some("off") | Some("false") => {
864 *slot = Some(false);
865 true
866 }
867 _ => false,
868 }
869 }
870
871 pub(crate) fn parse_polonius(slot: &mut Polonius, v: Option<&str>) -> bool {
873 match v {
874 Some("legacy") | None => {
875 *slot = Polonius::Legacy;
876 true
877 }
878 Some("next") => {
879 *slot = Polonius::Next;
880 true
881 }
882 _ => false,
883 }
884 }
885
886 pub(crate) fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
888 match v {
889 Some(s) => {
890 *slot = s.to_string();
891 true
892 }
893 None => false,
894 }
895 }
896
897 pub(crate) fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
899 match v {
900 Some(s) => {
901 *slot = Some(s.to_string());
902 true
903 }
904 None => false,
905 }
906 }
907
908 pub(crate) fn parse_opt_langid(slot: &mut Option<LanguageIdentifier>, v: Option<&str>) -> bool {
910 match v {
911 Some(s) => {
912 *slot = rustc_errors::LanguageIdentifier::from_str(s).ok();
913 true
914 }
915 None => false,
916 }
917 }
918
919 pub(crate) fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
920 match v {
921 Some(s) => {
922 *slot = Some(PathBuf::from(s));
923 true
924 }
925 None => false,
926 }
927 }
928
929 pub(crate) fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
930 match v {
931 Some(s) => {
932 slot.push(s.to_string());
933 true
934 }
935 None => false,
936 }
937 }
938
939 pub(crate) fn parse_list(slot: &mut Vec<String>, v: Option<&str>) -> bool {
940 match v {
941 Some(s) => {
942 slot.extend(s.split_whitespace().map(|s| s.to_string()));
943 true
944 }
945 None => false,
946 }
947 }
948
949 pub(crate) fn parse_list_with_polarity(
950 slot: &mut Vec<(String, bool)>,
951 v: Option<&str>,
952 ) -> bool {
953 match v {
954 Some(s) => {
955 for s in s.split(',') {
956 let Some(pass_name) = s.strip_prefix(&['+', '-'][..]) else { return false };
957 slot.push((pass_name.to_string(), &s[..1] == "+"));
958 }
959 true
960 }
961 None => false,
962 }
963 }
964
965 pub(crate) fn parse_fmt_debug(opt: &mut FmtDebug, v: Option<&str>) -> bool {
966 *opt = match v {
967 Some("full") => FmtDebug::Full,
968 Some("shallow") => FmtDebug::Shallow,
969 Some("none") => FmtDebug::None,
970 _ => return false,
971 };
972 true
973 }
974
975 pub(crate) fn parse_location_detail(ld: &mut LocationDetail, v: Option<&str>) -> bool {
976 if let Some(v) = v {
977 ld.line = false;
978 ld.file = false;
979 ld.column = false;
980 if v == "none" {
981 return true;
982 }
983 for s in v.split(',') {
984 match s {
985 "file" => ld.file = true,
986 "line" => ld.line = true,
987 "column" => ld.column = true,
988 _ => return false,
989 }
990 }
991 true
992 } else {
993 false
994 }
995 }
996
997 pub(crate) fn parse_comma_list(slot: &mut Vec<String>, v: Option<&str>) -> bool {
998 match v {
999 Some(s) => {
1000 let mut v: Vec<_> = s.split(',').map(|s| s.to_string()).collect();
1001 v.sort_unstable();
1002 *slot = v;
1003 true
1004 }
1005 None => false,
1006 }
1007 }
1008
1009 pub(crate) fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
1010 match v {
1011 Some(s) => {
1012 let mut v: Vec<_> = s.split(',').map(|s| s.to_string()).collect();
1013 v.sort_unstable();
1014 *slot = Some(v);
1015 true
1016 }
1017 None => false,
1018 }
1019 }
1020
1021 pub(crate) fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
1022 let ret = match v.and_then(|s| s.parse().ok()) {
1023 Some(0) => {
1024 *slot = std::thread::available_parallelism().map_or(1, NonZero::<usize>::get);
1025 true
1026 }
1027 Some(i) => {
1028 *slot = i;
1029 true
1030 }
1031 None => false,
1032 };
1033 *slot = slot.clone().min(MAX_THREADS_CAP);
1036 ret
1037 }
1038
1039 pub(crate) fn parse_number<T: Copy + FromStr>(slot: &mut T, v: Option<&str>) -> bool {
1041 match v.and_then(|s| s.parse().ok()) {
1042 Some(i) => {
1043 *slot = i;
1044 true
1045 }
1046 None => false,
1047 }
1048 }
1049
1050 pub(crate) fn parse_opt_number<T: Copy + FromStr>(
1052 slot: &mut Option<T>,
1053 v: Option<&str>,
1054 ) -> bool {
1055 match v {
1056 Some(s) => {
1057 *slot = s.parse().ok();
1058 slot.is_some()
1059 }
1060 None => false,
1061 }
1062 }
1063
1064 pub(crate) fn parse_frame_pointer(slot: &mut FramePointer, v: Option<&str>) -> bool {
1065 let mut yes = false;
1066 match v {
1067 _ if parse_bool(&mut yes, v) && yes => slot.ratchet(FramePointer::Always),
1068 _ if parse_bool(&mut yes, v) => slot.ratchet(FramePointer::MayOmit),
1069 Some("always") => slot.ratchet(FramePointer::Always),
1070 Some("non-leaf") => slot.ratchet(FramePointer::NonLeaf),
1071 _ => return false,
1072 };
1073 true
1074 }
1075
1076 pub(crate) fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
1077 match v {
1078 Some("all") => {
1079 *slot = Passes::All;
1080 true
1081 }
1082 v => {
1083 let mut passes = vec![];
1084 if parse_list(&mut passes, v) {
1085 slot.extend(passes);
1086 true
1087 } else {
1088 false
1089 }
1090 }
1091 }
1092 }
1093
1094 pub(crate) fn parse_opt_panic_strategy(
1095 slot: &mut Option<PanicStrategy>,
1096 v: Option<&str>,
1097 ) -> bool {
1098 match v {
1099 Some("unwind") => *slot = Some(PanicStrategy::Unwind),
1100 Some("abort") => *slot = Some(PanicStrategy::Abort),
1101 _ => return false,
1102 }
1103 true
1104 }
1105
1106 pub(crate) fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
1107 match v {
1108 Some("unwind") => *slot = PanicStrategy::Unwind,
1109 Some("abort") => *slot = PanicStrategy::Abort,
1110 _ => return false,
1111 }
1112 true
1113 }
1114
1115 pub(crate) fn parse_on_broken_pipe(slot: &mut OnBrokenPipe, v: Option<&str>) -> bool {
1116 match v {
1117 Some("kill") => *slot = OnBrokenPipe::Kill,
1119 Some("error") => *slot = OnBrokenPipe::Error,
1120 Some("inherit") => *slot = OnBrokenPipe::Inherit,
1121 _ => return false,
1122 }
1123 true
1124 }
1125
1126 pub(crate) fn parse_patchable_function_entry(
1127 slot: &mut PatchableFunctionEntry,
1128 v: Option<&str>,
1129 ) -> bool {
1130 let mut total_nops = 0;
1131 let mut prefix_nops = 0;
1132
1133 if !parse_number(&mut total_nops, v) {
1134 let parts = v.and_then(|v| v.split_once(',')).unzip();
1135 if !parse_number(&mut total_nops, parts.0) {
1136 return false;
1137 }
1138 if !parse_number(&mut prefix_nops, parts.1) {
1139 return false;
1140 }
1141 }
1142
1143 if let Some(pfe) =
1144 PatchableFunctionEntry::from_total_and_prefix_nops(total_nops, prefix_nops)
1145 {
1146 *slot = pfe;
1147 return true;
1148 }
1149 false
1150 }
1151
1152 pub(crate) fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool {
1153 match v {
1154 Some("panic") => *slot = OomStrategy::Panic,
1155 Some("abort") => *slot = OomStrategy::Abort,
1156 _ => return false,
1157 }
1158 true
1159 }
1160
1161 pub(crate) fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
1162 match v {
1163 Some(s) => match s.parse::<RelroLevel>() {
1164 Ok(level) => *slot = Some(level),
1165 _ => return false,
1166 },
1167 _ => return false,
1168 }
1169 true
1170 }
1171
1172 pub(crate) fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
1173 if let Some(v) = v {
1174 for s in v.split(',') {
1175 *slot |= match s {
1176 "address" => SanitizerSet::ADDRESS,
1177 "cfi" => SanitizerSet::CFI,
1178 "dataflow" => SanitizerSet::DATAFLOW,
1179 "kcfi" => SanitizerSet::KCFI,
1180 "kernel-address" => SanitizerSet::KERNELADDRESS,
1181 "leak" => SanitizerSet::LEAK,
1182 "memory" => SanitizerSet::MEMORY,
1183 "memtag" => SanitizerSet::MEMTAG,
1184 "shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
1185 "thread" => SanitizerSet::THREAD,
1186 "hwaddress" => SanitizerSet::HWADDRESS,
1187 "safestack" => SanitizerSet::SAFESTACK,
1188 _ => return false,
1189 }
1190 }
1191 true
1192 } else {
1193 false
1194 }
1195 }
1196
1197 pub(crate) fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool {
1198 match v {
1199 Some("2") | None => {
1200 *slot = 2;
1201 true
1202 }
1203 Some("1") => {
1204 *slot = 1;
1205 true
1206 }
1207 Some("0") => {
1208 *slot = 0;
1209 true
1210 }
1211 Some(_) => false,
1212 }
1213 }
1214
1215 pub(crate) fn parse_strip(slot: &mut Strip, v: Option<&str>) -> bool {
1216 match v {
1217 Some("none") => *slot = Strip::None,
1218 Some("debuginfo") => *slot = Strip::Debuginfo,
1219 Some("symbols") => *slot = Strip::Symbols,
1220 _ => return false,
1221 }
1222 true
1223 }
1224
1225 pub(crate) fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool {
1226 if v.is_some() {
1227 let mut bool_arg = None;
1228 if parse_opt_bool(&mut bool_arg, v) {
1229 *slot = if bool_arg.unwrap() { CFGuard::Checks } else { CFGuard::Disabled };
1230 return true;
1231 }
1232 }
1233
1234 *slot = match v {
1235 None => CFGuard::Checks,
1236 Some("checks") => CFGuard::Checks,
1237 Some("nochecks") => CFGuard::NoChecks,
1238 Some(_) => return false,
1239 };
1240 true
1241 }
1242
1243 pub(crate) fn parse_cfprotection(slot: &mut CFProtection, v: Option<&str>) -> bool {
1244 if v.is_some() {
1245 let mut bool_arg = None;
1246 if parse_opt_bool(&mut bool_arg, v) {
1247 *slot = if bool_arg.unwrap() { CFProtection::Full } else { CFProtection::None };
1248 return true;
1249 }
1250 }
1251
1252 *slot = match v {
1253 None | Some("none") => CFProtection::None,
1254 Some("branch") => CFProtection::Branch,
1255 Some("return") => CFProtection::Return,
1256 Some("full") => CFProtection::Full,
1257 Some(_) => return false,
1258 };
1259 true
1260 }
1261
1262 pub(crate) fn parse_debuginfo(slot: &mut DebugInfo, v: Option<&str>) -> bool {
1263 match v {
1264 Some("0") | Some("none") => *slot = DebugInfo::None,
1265 Some("line-directives-only") => *slot = DebugInfo::LineDirectivesOnly,
1266 Some("line-tables-only") => *slot = DebugInfo::LineTablesOnly,
1267 Some("1") | Some("limited") => *slot = DebugInfo::Limited,
1268 Some("2") | Some("full") => *slot = DebugInfo::Full,
1269 _ => return false,
1270 }
1271 true
1272 }
1273
1274 pub(crate) fn parse_debuginfo_compression(
1275 slot: &mut DebugInfoCompression,
1276 v: Option<&str>,
1277 ) -> bool {
1278 match v {
1279 Some("none") => *slot = DebugInfoCompression::None,
1280 Some("zlib") => *slot = DebugInfoCompression::Zlib,
1281 Some("zstd") => *slot = DebugInfoCompression::Zstd,
1282 _ => return false,
1283 };
1284 true
1285 }
1286
1287 pub(crate) fn parse_mir_strip_debuginfo(slot: &mut MirStripDebugInfo, v: Option<&str>) -> bool {
1288 match v {
1289 Some("none") => *slot = MirStripDebugInfo::None,
1290 Some("locals-in-tiny-functions") => *slot = MirStripDebugInfo::LocalsInTinyFunctions,
1291 Some("all-locals") => *slot = MirStripDebugInfo::AllLocals,
1292 _ => return false,
1293 };
1294 true
1295 }
1296
1297 pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavorCli>, v: Option<&str>) -> bool {
1298 match v.and_then(LinkerFlavorCli::from_str) {
1299 Some(lf) => *slot = Some(lf),
1300 _ => return false,
1301 }
1302 true
1303 }
1304
1305 pub(crate) fn parse_opt_symbol_visibility(
1306 slot: &mut Option<SymbolVisibility>,
1307 v: Option<&str>,
1308 ) -> bool {
1309 if let Some(v) = v {
1310 if let Ok(vis) = SymbolVisibility::from_str(v) {
1311 *slot = Some(vis);
1312 } else {
1313 return false;
1314 }
1315 }
1316 true
1317 }
1318
1319 pub(crate) fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
1320 match v {
1321 None => false,
1322 Some(s) if s.split('=').count() <= 2 => {
1323 *slot = Some(s.to_string());
1324 true
1325 }
1326 _ => false,
1327 }
1328 }
1329
1330 pub(crate) fn parse_time_passes_format(slot: &mut TimePassesFormat, v: Option<&str>) -> bool {
1331 match v {
1332 None => true,
1333 Some("json") => {
1334 *slot = TimePassesFormat::Json;
1335 true
1336 }
1337 Some("text") => {
1338 *slot = TimePassesFormat::Text;
1339 true
1340 }
1341 Some(_) => false,
1342 }
1343 }
1344
1345 pub(crate) fn parse_dump_mono_stats(slot: &mut DumpMonoStatsFormat, v: Option<&str>) -> bool {
1346 match v {
1347 None => true,
1348 Some("json") => {
1349 *slot = DumpMonoStatsFormat::Json;
1350 true
1351 }
1352 Some("markdown") => {
1353 *slot = DumpMonoStatsFormat::Markdown;
1354 true
1355 }
1356 Some(_) => false,
1357 }
1358 }
1359
1360 pub(crate) fn parse_autodiff(slot: &mut Vec<AutoDiff>, v: Option<&str>) -> bool {
1361 let Some(v) = v else {
1362 *slot = vec![];
1363 return true;
1364 };
1365 let mut v: Vec<&str> = v.split(",").collect();
1366 v.sort_unstable();
1367 for &val in v.iter() {
1368 let (key, arg) = match val.split_once('=') {
1370 Some((k, a)) => (k, Some(a)),
1371 None => (val, None),
1372 };
1373
1374 let variant = match key {
1375 "Enable" => AutoDiff::Enable,
1376 "PrintTA" => AutoDiff::PrintTA,
1377 "PrintTAFn" => {
1378 if let Some(fun) = arg {
1379 AutoDiff::PrintTAFn(fun.to_string())
1380 } else {
1381 return false;
1382 }
1383 }
1384 "PrintAA" => AutoDiff::PrintAA,
1385 "PrintPerf" => AutoDiff::PrintPerf,
1386 "PrintSteps" => AutoDiff::PrintSteps,
1387 "PrintModBefore" => AutoDiff::PrintModBefore,
1388 "PrintModAfter" => AutoDiff::PrintModAfter,
1389 "PrintModFinal" => AutoDiff::PrintModFinal,
1390 "NoPostopt" => AutoDiff::NoPostopt,
1391 "PrintPasses" => AutoDiff::PrintPasses,
1392 "LooseTypes" => AutoDiff::LooseTypes,
1393 "Inline" => AutoDiff::Inline,
1394 _ => {
1395 return false;
1397 }
1398 };
1399 slot.push(variant);
1400 }
1401
1402 true
1403 }
1404
1405 pub(crate) fn parse_instrument_coverage(
1406 slot: &mut InstrumentCoverage,
1407 v: Option<&str>,
1408 ) -> bool {
1409 if v.is_some() {
1410 let mut bool_arg = false;
1411 if parse_bool(&mut bool_arg, v) {
1412 *slot = if bool_arg { InstrumentCoverage::Yes } else { InstrumentCoverage::No };
1413 return true;
1414 }
1415 }
1416
1417 let Some(v) = v else {
1418 *slot = InstrumentCoverage::Yes;
1419 return true;
1420 };
1421
1422 *slot = match v {
1425 "all" => InstrumentCoverage::Yes,
1426 "0" => InstrumentCoverage::No,
1427 _ => return false,
1428 };
1429 true
1430 }
1431
1432 pub(crate) fn parse_coverage_options(slot: &mut CoverageOptions, v: Option<&str>) -> bool {
1433 let Some(v) = v else { return true };
1434
1435 for option in v.split(',') {
1436 match option {
1437 "block" => slot.level = CoverageLevel::Block,
1438 "branch" => slot.level = CoverageLevel::Branch,
1439 "condition" => slot.level = CoverageLevel::Condition,
1440 "mcdc" => slot.level = CoverageLevel::Mcdc,
1441 "no-mir-spans" => slot.no_mir_spans = true,
1442 "discard-all-spans-in-codegen" => slot.discard_all_spans_in_codegen = true,
1443 _ => return false,
1444 }
1445 }
1446 true
1447 }
1448
1449 pub(crate) fn parse_instrument_xray(
1450 slot: &mut Option<InstrumentXRay>,
1451 v: Option<&str>,
1452 ) -> bool {
1453 if v.is_some() {
1454 let mut bool_arg = None;
1455 if parse_opt_bool(&mut bool_arg, v) {
1456 *slot = if bool_arg.unwrap() { Some(InstrumentXRay::default()) } else { None };
1457 return true;
1458 }
1459 }
1460
1461 let options = slot.get_or_insert_default();
1462 let mut seen_always = false;
1463 let mut seen_never = false;
1464 let mut seen_ignore_loops = false;
1465 let mut seen_instruction_threshold = false;
1466 let mut seen_skip_entry = false;
1467 let mut seen_skip_exit = false;
1468 for option in v.into_iter().flat_map(|v| v.split(',')) {
1469 match option {
1470 "always" if !seen_always && !seen_never => {
1471 options.always = true;
1472 options.never = false;
1473 seen_always = true;
1474 }
1475 "never" if !seen_never && !seen_always => {
1476 options.never = true;
1477 options.always = false;
1478 seen_never = true;
1479 }
1480 "ignore-loops" if !seen_ignore_loops => {
1481 options.ignore_loops = true;
1482 seen_ignore_loops = true;
1483 }
1484 option
1485 if option.starts_with("instruction-threshold")
1486 && !seen_instruction_threshold =>
1487 {
1488 let Some(("instruction-threshold", n)) = option.split_once('=') else {
1489 return false;
1490 };
1491 match n.parse() {
1492 Ok(n) => options.instruction_threshold = Some(n),
1493 Err(_) => return false,
1494 }
1495 seen_instruction_threshold = true;
1496 }
1497 "skip-entry" if !seen_skip_entry => {
1498 options.skip_entry = true;
1499 seen_skip_entry = true;
1500 }
1501 "skip-exit" if !seen_skip_exit => {
1502 options.skip_exit = true;
1503 seen_skip_exit = true;
1504 }
1505 _ => return false,
1506 }
1507 }
1508 true
1509 }
1510
1511 pub(crate) fn parse_treat_err_as_bug(
1512 slot: &mut Option<NonZero<usize>>,
1513 v: Option<&str>,
1514 ) -> bool {
1515 match v {
1516 Some(s) => match s.parse() {
1517 Ok(val) => {
1518 *slot = Some(val);
1519 true
1520 }
1521 Err(e) => {
1522 *slot = None;
1523 e.kind() == &IntErrorKind::Zero
1524 }
1525 },
1526 None => {
1527 *slot = NonZero::new(1);
1528 true
1529 }
1530 }
1531 }
1532
1533 pub(crate) fn parse_next_solver_config(slot: &mut NextSolverConfig, v: Option<&str>) -> bool {
1534 if let Some(config) = v {
1535 *slot = match config {
1536 "no" => NextSolverConfig { coherence: false, globally: false },
1537 "coherence" => NextSolverConfig { coherence: true, globally: false },
1538 "globally" => NextSolverConfig { coherence: true, globally: true },
1539 _ => return false,
1540 };
1541 } else {
1542 *slot = NextSolverConfig { coherence: true, globally: true };
1543 }
1544
1545 true
1546 }
1547
1548 pub(crate) fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
1549 if v.is_some() {
1550 let mut bool_arg = None;
1551 if parse_opt_bool(&mut bool_arg, v) {
1552 *slot = if bool_arg.unwrap() { LtoCli::Yes } else { LtoCli::No };
1553 return true;
1554 }
1555 }
1556
1557 *slot = match v {
1558 None => LtoCli::NoParam,
1559 Some("thin") => LtoCli::Thin,
1560 Some("fat") => LtoCli::Fat,
1561 Some(_) => return false,
1562 };
1563 true
1564 }
1565
1566 pub(crate) fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
1567 if v.is_some() {
1568 let mut bool_arg = None;
1569 if parse_opt_bool(&mut bool_arg, v) {
1570 *slot = if bool_arg.unwrap() {
1571 LinkerPluginLto::LinkerPluginAuto
1572 } else {
1573 LinkerPluginLto::Disabled
1574 };
1575 return true;
1576 }
1577 }
1578
1579 *slot = match v {
1580 None => LinkerPluginLto::LinkerPluginAuto,
1581 Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
1582 };
1583 true
1584 }
1585
1586 pub(crate) fn parse_switch_with_opt_path(
1587 slot: &mut SwitchWithOptPath,
1588 v: Option<&str>,
1589 ) -> bool {
1590 *slot = match v {
1591 None => SwitchWithOptPath::Enabled(None),
1592 Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
1593 };
1594 true
1595 }
1596
1597 pub(crate) fn parse_merge_functions(
1598 slot: &mut Option<MergeFunctions>,
1599 v: Option<&str>,
1600 ) -> bool {
1601 match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
1602 Some(mergefunc) => *slot = Some(mergefunc),
1603 _ => return false,
1604 }
1605 true
1606 }
1607
1608 pub(crate) fn parse_remap_path_scope(
1609 slot: &mut RemapPathScopeComponents,
1610 v: Option<&str>,
1611 ) -> bool {
1612 if let Some(v) = v {
1613 *slot = RemapPathScopeComponents::empty();
1614 for s in v.split(',') {
1615 *slot |= match s {
1616 "macro" => RemapPathScopeComponents::MACRO,
1617 "diagnostics" => RemapPathScopeComponents::DIAGNOSTICS,
1618 "debuginfo" => RemapPathScopeComponents::DEBUGINFO,
1619 "object" => RemapPathScopeComponents::OBJECT,
1620 "all" => RemapPathScopeComponents::all(),
1621 _ => return false,
1622 }
1623 }
1624 true
1625 } else {
1626 false
1627 }
1628 }
1629
1630 pub(crate) fn parse_relocation_model(slot: &mut Option<RelocModel>, v: Option<&str>) -> bool {
1631 match v.and_then(|s| RelocModel::from_str(s).ok()) {
1632 Some(relocation_model) => *slot = Some(relocation_model),
1633 None if v == Some("default") => *slot = None,
1634 _ => return false,
1635 }
1636 true
1637 }
1638
1639 pub(crate) fn parse_code_model(slot: &mut Option<CodeModel>, v: Option<&str>) -> bool {
1640 match v.and_then(|s| CodeModel::from_str(s).ok()) {
1641 Some(code_model) => *slot = Some(code_model),
1642 _ => return false,
1643 }
1644 true
1645 }
1646
1647 pub(crate) fn parse_tls_model(slot: &mut Option<TlsModel>, v: Option<&str>) -> bool {
1648 match v.and_then(|s| TlsModel::from_str(s).ok()) {
1649 Some(tls_model) => *slot = Some(tls_model),
1650 _ => return false,
1651 }
1652 true
1653 }
1654
1655 pub(crate) fn parse_terminal_url(slot: &mut TerminalUrl, v: Option<&str>) -> bool {
1656 *slot = match v {
1657 Some("on" | "" | "yes" | "y") | None => TerminalUrl::Yes,
1658 Some("off" | "no" | "n") => TerminalUrl::No,
1659 Some("auto") => TerminalUrl::Auto,
1660 _ => return false,
1661 };
1662 true
1663 }
1664
1665 pub(crate) fn parse_symbol_mangling_version(
1666 slot: &mut Option<SymbolManglingVersion>,
1667 v: Option<&str>,
1668 ) -> bool {
1669 *slot = match v {
1670 Some("legacy") => Some(SymbolManglingVersion::Legacy),
1671 Some("v0") => Some(SymbolManglingVersion::V0),
1672 Some("hashed") => Some(SymbolManglingVersion::Hashed),
1673 _ => return false,
1674 };
1675 true
1676 }
1677
1678 pub(crate) fn parse_src_file_hash(
1679 slot: &mut Option<SourceFileHashAlgorithm>,
1680 v: Option<&str>,
1681 ) -> bool {
1682 match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) {
1683 Some(hash_kind) => *slot = Some(hash_kind),
1684 _ => return false,
1685 }
1686 true
1687 }
1688
1689 pub(crate) fn parse_cargo_src_file_hash(
1690 slot: &mut Option<SourceFileHashAlgorithm>,
1691 v: Option<&str>,
1692 ) -> bool {
1693 match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) {
1694 Some(hash_kind) => {
1695 *slot = Some(hash_kind);
1696 }
1697 _ => return false,
1698 }
1699 true
1700 }
1701
1702 pub(crate) fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
1703 match v {
1704 Some(s) => {
1705 if !slot.is_empty() {
1706 slot.push(',');
1707 }
1708 slot.push_str(s);
1709 true
1710 }
1711 None => false,
1712 }
1713 }
1714
1715 pub(crate) fn parse_link_self_contained(slot: &mut LinkSelfContained, v: Option<&str>) -> bool {
1716 let s = v.unwrap_or("y");
1721 match s {
1722 "y" | "yes" | "on" => {
1723 slot.set_all_explicitly(true);
1724 return true;
1725 }
1726 "n" | "no" | "off" => {
1727 slot.set_all_explicitly(false);
1728 return true;
1729 }
1730 _ => {}
1731 }
1732
1733 for comp in s.split(',') {
1735 if slot.handle_cli_component(comp).is_none() {
1736 return false;
1737 }
1738 }
1739
1740 true
1741 }
1742
1743 pub(crate) fn parse_linker_features(slot: &mut LinkerFeaturesCli, v: Option<&str>) -> bool {
1745 match v {
1746 Some(s) => {
1747 for feature in s.split(',') {
1748 if slot.handle_cli_feature(feature).is_none() {
1749 return false;
1750 }
1751 }
1752
1753 true
1754 }
1755 None => false,
1756 }
1757 }
1758
1759 pub(crate) fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool {
1760 match v {
1761 Some("command") => *slot = Some(WasiExecModel::Command),
1762 Some("reactor") => *slot = Some(WasiExecModel::Reactor),
1763 _ => return false,
1764 }
1765 true
1766 }
1767
1768 pub(crate) fn parse_split_debuginfo(
1769 slot: &mut Option<SplitDebuginfo>,
1770 v: Option<&str>,
1771 ) -> bool {
1772 match v.and_then(|s| SplitDebuginfo::from_str(s).ok()) {
1773 Some(e) => *slot = Some(e),
1774 _ => return false,
1775 }
1776 true
1777 }
1778
1779 pub(crate) fn parse_split_dwarf_kind(slot: &mut SplitDwarfKind, v: Option<&str>) -> bool {
1780 match v.and_then(|s| SplitDwarfKind::from_str(s).ok()) {
1781 Some(e) => *slot = e,
1782 _ => return false,
1783 }
1784 true
1785 }
1786
1787 pub(crate) fn parse_stack_protector(slot: &mut StackProtector, v: Option<&str>) -> bool {
1788 match v.and_then(|s| StackProtector::from_str(s).ok()) {
1789 Some(ssp) => *slot = ssp,
1790 _ => return false,
1791 }
1792 true
1793 }
1794
1795 pub(crate) fn parse_branch_protection(
1796 slot: &mut Option<BranchProtection>,
1797 v: Option<&str>,
1798 ) -> bool {
1799 match v {
1800 Some(s) => {
1801 let slot = slot.get_or_insert_default();
1802 for opt in s.split(',') {
1803 match opt {
1804 "bti" => slot.bti = true,
1805 "pac-ret" if slot.pac_ret.is_none() => {
1806 slot.pac_ret = Some(PacRet { leaf: false, pc: false, key: PAuthKey::A })
1807 }
1808 "leaf" => match slot.pac_ret.as_mut() {
1809 Some(pac) => pac.leaf = true,
1810 _ => return false,
1811 },
1812 "b-key" => match slot.pac_ret.as_mut() {
1813 Some(pac) => pac.key = PAuthKey::B,
1814 _ => return false,
1815 },
1816 "pc" => match slot.pac_ret.as_mut() {
1817 Some(pac) => pac.pc = true,
1818 _ => return false,
1819 },
1820 _ => return false,
1821 };
1822 }
1823 }
1824 _ => return false,
1825 }
1826 true
1827 }
1828
1829 pub(crate) fn parse_collapse_macro_debuginfo(
1830 slot: &mut CollapseMacroDebuginfo,
1831 v: Option<&str>,
1832 ) -> bool {
1833 if v.is_some() {
1834 let mut bool_arg = None;
1835 if parse_opt_bool(&mut bool_arg, v) {
1836 *slot = if bool_arg.unwrap() {
1837 CollapseMacroDebuginfo::Yes
1838 } else {
1839 CollapseMacroDebuginfo::No
1840 };
1841 return true;
1842 }
1843 }
1844
1845 *slot = match v {
1846 Some("external") => CollapseMacroDebuginfo::External,
1847 _ => return false,
1848 };
1849 true
1850 }
1851
1852 pub(crate) fn parse_proc_macro_execution_strategy(
1853 slot: &mut ProcMacroExecutionStrategy,
1854 v: Option<&str>,
1855 ) -> bool {
1856 *slot = match v {
1857 Some("same-thread") => ProcMacroExecutionStrategy::SameThread,
1858 Some("cross-thread") => ProcMacroExecutionStrategy::CrossThread,
1859 _ => return false,
1860 };
1861 true
1862 }
1863
1864 pub(crate) fn parse_inlining_threshold(slot: &mut InliningThreshold, v: Option<&str>) -> bool {
1865 match v {
1866 Some("always" | "yes") => {
1867 *slot = InliningThreshold::Always;
1868 }
1869 Some("never") => {
1870 *slot = InliningThreshold::Never;
1871 }
1872 Some(v) => {
1873 if let Ok(threshold) = v.parse() {
1874 *slot = InliningThreshold::Sometimes(threshold);
1875 } else {
1876 return false;
1877 }
1878 }
1879 None => return false,
1880 }
1881 true
1882 }
1883
1884 pub(crate) fn parse_llvm_module_flag(
1885 slot: &mut Vec<(String, u32, String)>,
1886 v: Option<&str>,
1887 ) -> bool {
1888 let elements = v.unwrap_or_default().split(':').collect::<Vec<_>>();
1889 let [key, md_type, value, behavior] = elements.as_slice() else {
1890 return false;
1891 };
1892 if *md_type != "u32" {
1893 return false;
1896 }
1897 let Ok(value) = value.parse::<u32>() else {
1898 return false;
1899 };
1900 let behavior = behavior.to_lowercase();
1901 let all_behaviors =
1902 ["error", "warning", "require", "override", "append", "appendunique", "max", "min"];
1903 if !all_behaviors.contains(&behavior.as_str()) {
1904 return false;
1905 }
1906
1907 slot.push((key.to_string(), value, behavior));
1908 true
1909 }
1910
1911 pub(crate) fn parse_function_return(slot: &mut FunctionReturn, v: Option<&str>) -> bool {
1912 match v {
1913 Some("keep") => *slot = FunctionReturn::Keep,
1914 Some("thunk-extern") => *slot = FunctionReturn::ThunkExtern,
1915 _ => return false,
1916 }
1917 true
1918 }
1919
1920 pub(crate) fn parse_wasm_c_abi(_slot: &mut (), v: Option<&str>) -> bool {
1921 v == Some("spec")
1922 }
1923
1924 pub(crate) fn parse_mir_include_spans(slot: &mut MirIncludeSpans, v: Option<&str>) -> bool {
1925 *slot = match v {
1926 Some("on" | "yes" | "y" | "true") | None => MirIncludeSpans::On,
1927 Some("off" | "no" | "n" | "false") => MirIncludeSpans::Off,
1928 Some("nll") => MirIncludeSpans::Nll,
1929 _ => return false,
1930 };
1931
1932 true
1933 }
1934
1935 pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
1936 let mut bytes = 0u64;
1937 if !parse_number(&mut bytes, v) {
1938 return false;
1939 }
1940
1941 let Ok(align) = Align::from_bytes(bytes) else {
1942 return false;
1943 };
1944
1945 *slot = Some(align);
1946
1947 true
1948 }
1949}
1950
1951options! {
1952 CodegenOptions, CodegenOptionsTargetModifiers, CG_OPTIONS, cgopts, "C", "codegen",
1953
1954 #[rustc_lint_opt_deny_field_access("documented to do nothing")]
1960 ar: String = (String::new(), parse_string, [UNTRACKED],
1961 "this option is deprecated and does nothing",
1962 deprecated_do_nothing: true),
1963 #[rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field")]
1964 code_model: Option<CodeModel> = (None, parse_code_model, [TRACKED],
1965 "choose the code model to use (`rustc --print code-models` for details)"),
1966 codegen_units: Option<usize> = (None, parse_opt_number, [UNTRACKED],
1967 "divide crate into N units to optimize in parallel"),
1968 collapse_macro_debuginfo: CollapseMacroDebuginfo = (CollapseMacroDebuginfo::Unspecified,
1969 parse_collapse_macro_debuginfo, [TRACKED],
1970 "set option to collapse debuginfo for macros"),
1971 control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED],
1972 "use Windows Control Flow Guard (default: no)"),
1973 debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
1974 "explicitly enable the `cfg(debug_assertions)` directive"),
1975 debuginfo: DebugInfo = (DebugInfo::None, parse_debuginfo, [TRACKED],
1976 "debug info emission level (0-2, none, line-directives-only, \
1977 line-tables-only, limited, or full; default: 0)"),
1978 default_linker_libraries: bool = (false, parse_bool, [UNTRACKED],
1979 "allow the linker to link its default libraries (default: no)"),
1980 dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
1981 "import library generation tool (ignored except when targeting windows-gnu)"),
1982 #[rustc_lint_opt_deny_field_access("use `Session::dwarf_version` instead of this field")]
1983 dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
1984 "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
1985 embed_bitcode: bool = (true, parse_bool, [TRACKED],
1986 "emit bitcode in rlibs (default: yes)"),
1987 extra_filename: String = (String::new(), parse_string, [UNTRACKED],
1988 "extra data to put in each output filename"),
1989 force_frame_pointers: FramePointer = (FramePointer::MayOmit, parse_frame_pointer, [TRACKED],
1990 "force use of the frame pointers"),
1991 #[rustc_lint_opt_deny_field_access("use `Session::must_emit_unwind_tables` instead of this field")]
1992 force_unwind_tables: Option<bool> = (None, parse_opt_bool, [TRACKED],
1993 "force use of unwind tables"),
1994 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1995 "enable incremental compilation"),
1996 #[rustc_lint_opt_deny_field_access("documented to do nothing")]
1997 inline_threshold: Option<u32> = (None, parse_opt_number, [UNTRACKED],
1998 "this option is deprecated and does nothing \
1999 (consider using `-Cllvm-args=--inline-threshold=...`)",
2000 deprecated_do_nothing: true),
2001 #[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")]
2002 instrument_coverage: InstrumentCoverage = (InstrumentCoverage::No, parse_instrument_coverage, [TRACKED],
2003 "instrument the generated code to support LLVM source-based code coverage reports \
2004 (note, the compiler build config must include `profiler = true`); \
2005 implies `-C symbol-mangling-version=v0`"),
2006 link_arg: () = ((), parse_string_push, [UNTRACKED],
2007 "a single extra argument to append to the linker invocation (can be used several times)"),
2008 link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
2009 "extra arguments to append to the linker invocation (space separated)"),
2010 #[rustc_lint_opt_deny_field_access("use `Session::link_dead_code` instead of this field")]
2011 link_dead_code: Option<bool> = (None, parse_opt_bool, [TRACKED],
2012 "try to generate and link dead code (default: no)"),
2013 link_self_contained: LinkSelfContained = (LinkSelfContained::default(), parse_link_self_contained, [UNTRACKED],
2014 "control whether to link Rust provided C objects/libraries or rely \
2015 on a C toolchain or linker installed in the system"),
2016 linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
2017 "system linker to link outputs with"),
2018 linker_flavor: Option<LinkerFlavorCli> = (None, parse_linker_flavor, [UNTRACKED],
2019 "linker flavor"),
2020 linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
2021 parse_linker_plugin_lto, [TRACKED],
2022 "generate build artifacts that are compatible with linker-based LTO"),
2023 llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
2024 "a list of arguments to pass to LLVM (space separated)"),
2025 #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
2026 lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
2027 "perform LLVM link-time optimizations"),
2028 metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
2029 "metadata to mangle symbol names with"),
2030 no_prepopulate_passes: bool = (false, parse_no_value, [TRACKED],
2031 "give an empty list of passes to the pass manager"),
2032 no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
2033 "disable the use of the redzone"),
2034 #[rustc_lint_opt_deny_field_access("documented to do nothing")]
2035 no_stack_check: bool = (false, parse_no_value, [UNTRACKED],
2036 "this option is deprecated and does nothing",
2037 deprecated_do_nothing: true),
2038 no_vectorize_loops: bool = (false, parse_no_value, [TRACKED],
2039 "disable loop vectorization optimization passes"),
2040 no_vectorize_slp: bool = (false, parse_no_value, [TRACKED],
2041 "disable LLVM's SLP vectorization pass"),
2042 opt_level: String = ("0".to_string(), parse_string, [TRACKED],
2043 "optimization level (0-3, s, or z; default: 0)"),
2044 #[rustc_lint_opt_deny_field_access("use `Session::overflow_checks` instead of this field")]
2045 overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
2046 "use overflow checks for integer arithmetic"),
2047 #[rustc_lint_opt_deny_field_access("use `Session::panic_strategy` instead of this field")]
2048 panic: Option<PanicStrategy> = (None, parse_opt_panic_strategy, [TRACKED],
2049 "panic strategy to compile crate with"),
2050 passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
2051 "a list of extra LLVM passes to run (space separated)"),
2052 prefer_dynamic: bool = (false, parse_bool, [TRACKED],
2053 "prefer dynamic linking to static linking (default: no)"),
2054 profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
2055 parse_switch_with_opt_path, [TRACKED],
2056 "compile the program with profiling instrumentation"),
2057 profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
2058 "use the given `.profdata` file for profile-guided optimization"),
2059 #[rustc_lint_opt_deny_field_access("use `Session::relocation_model` instead of this field")]
2060 relocation_model: Option<RelocModel> = (None, parse_relocation_model, [TRACKED],
2061 "control generation of position-independent code (PIC) \
2062 (`rustc --print relocation-models` for details)"),
2063 relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
2064 "choose which RELRO level to use"),
2065 remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
2066 "output remarks for these optimization passes (space separated, or \"all\")"),
2067 rpath: bool = (false, parse_bool, [UNTRACKED],
2068 "set rpath values in libs/exes (default: no)"),
2069 save_temps: bool = (false, parse_bool, [UNTRACKED],
2070 "save all temporary output files during compilation (default: no)"),
2071 soft_float: bool = (false, parse_bool, [TRACKED],
2072 "deprecated option: use soft float ABI (*eabihf targets only) (default: no)"),
2073 #[rustc_lint_opt_deny_field_access("use `Session::split_debuginfo` instead of this field")]
2074 split_debuginfo: Option<SplitDebuginfo> = (None, parse_split_debuginfo, [TRACKED],
2075 "how to handle split-debuginfo, a platform-specific option"),
2076 strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
2077 "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
2078 symbol_mangling_version: Option<SymbolManglingVersion> = (None,
2079 parse_symbol_mangling_version, [TRACKED],
2080 "which mangling version to use for symbol names ('legacy' (default), 'v0', or 'hashed')"),
2081 target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
2082 "select target processor (`rustc --print target-cpus` for details)"),
2083 target_feature: String = (String::new(), parse_target_feature, [TRACKED],
2084 "target specific attributes. (`rustc --print target-features` for details). \
2085 This feature is unsafe."),
2086 unsafe_allow_abi_mismatch: Vec<String> = (Vec::new(), parse_comma_list, [UNTRACKED],
2087 "Allow incompatible target modifiers in dependency crates (comma separated list)"),
2088 }
2094
2095options! {
2096 UnstableOptions, UnstableOptionsTargetModifiers, Z_OPTIONS, dbopts, "Z", "unstable",
2097
2098 allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
2104 "only allow the listed language features to be enabled in code (comma separated)"),
2105 always_encode_mir: bool = (false, parse_bool, [TRACKED],
2106 "encode MIR of all functions into the crate metadata (default: no)"),
2107 assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED],
2108 "assert that the incremental cache is in given state: \
2109 either `loaded` or `not-loaded`."),
2110 assume_incomplete_release: bool = (false, parse_bool, [TRACKED],
2111 "make cfg(version) treat the current version as incomplete (default: no)"),
2112 autodiff: Vec<crate::config::AutoDiff> = (Vec::new(), parse_autodiff, [TRACKED],
2113 "a list of autodiff flags to enable
2114 Mandatory setting:
2115 `=Enable`
2116 Optional extra settings:
2117 `=PrintTA`
2118 `=PrintAA`
2119 `=PrintPerf`
2120 `=PrintSteps`
2121 `=PrintModBefore`
2122 `=PrintModAfter`
2123 `=PrintModFinal`
2124 `=PrintPasses`,
2125 `=NoPostopt`
2126 `=LooseTypes`
2127 `=Inline`
2128 Multiple options can be combined with commas."),
2129 #[rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field")]
2130 binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
2131 "include artifacts (sysroot, crate dependencies) used during compilation in dep-info \
2132 (default: no)"),
2133 box_noalias: bool = (true, parse_bool, [TRACKED],
2134 "emit noalias metadata for box (default: yes)"),
2135 branch_protection: Option<BranchProtection> = (None, parse_branch_protection, [TRACKED],
2136 "set options for branch target identification and pointer authentication on AArch64"),
2137 build_sdylib_interface: bool = (false, parse_bool, [UNTRACKED],
2138 "whether the stable interface is being built"),
2139 cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED],
2140 "instrument control-flow architecture protection"),
2141 check_cfg_all_expected: bool = (false, parse_bool, [UNTRACKED],
2142 "show all expected values in check-cfg diagnostics (default: no)"),
2143 checksum_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_cargo_src_file_hash, [TRACKED],
2144 "hash algorithm of source files used to check freshness in cargo (`blake3` or `sha256`)"),
2145 codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
2146 "the backend to use"),
2147 combine_cgu: bool = (false, parse_bool, [TRACKED],
2148 "combine CGUs into a single one"),
2149 contract_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
2150 "emit runtime checks for contract pre- and post-conditions (default: no)"),
2151 coverage_options: CoverageOptions = (CoverageOptions::default(), parse_coverage_options, [TRACKED],
2152 "control details of coverage instrumentation"),
2153 crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
2154 "inject the given attribute in the crate"),
2155 cross_crate_inline_threshold: InliningThreshold = (InliningThreshold::Sometimes(100), parse_inlining_threshold, [TRACKED],
2156 "threshold to allow cross crate inlining of functions"),
2157 debug_info_for_profiling: bool = (false, parse_bool, [TRACKED],
2158 "emit discriminators and other data necessary for AutoFDO"),
2159 debug_info_type_line_numbers: bool = (false, parse_bool, [TRACKED],
2160 "emit type and line information for additional data types (default: no)"),
2161 debuginfo_compression: DebugInfoCompression = (DebugInfoCompression::None, parse_debuginfo_compression, [TRACKED],
2162 "compress debug info sections (none, zlib, zstd, default: none)"),
2163 deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED],
2164 "deduplicate identical diagnostics (default: yes)"),
2165 default_visibility: Option<SymbolVisibility> = (None, parse_opt_symbol_visibility, [TRACKED],
2166 "overrides the `default_visibility` setting of the target"),
2167 dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
2168 "in dep-info output, omit targets for tracking dependencies of the dep-info files \
2169 themselves (default: no)"),
2170 direct_access_external_data: Option<bool> = (None, parse_opt_bool, [TRACKED],
2171 "Direct or use GOT indirect to reference external data symbols"),
2172 dual_proc_macros: bool = (false, parse_bool, [TRACKED],
2173 "load proc macros for both target and host, but only link to the target (default: no)"),
2174 dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
2175 "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) \
2176 (default: no)"),
2177 dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
2178 "dump MIR state to file.
2179 `val` is used to select which passes and functions to dump. For example:
2180 `all` matches all passes and functions,
2181 `foo` matches all passes for functions whose name contains 'foo',
2182 `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
2183 `foo | bar` all passes for function names containing 'foo' or 'bar'."),
2184 dump_mir_dataflow: bool = (false, parse_bool, [UNTRACKED],
2185 "in addition to `.mir` files, create graphviz `.dot` files with dataflow results \
2186 (default: no)"),
2187 dump_mir_dir: String = ("mir_dump".to_string(), parse_string, [UNTRACKED],
2188 "the directory the MIR is dumped into (default: `mir_dump`)"),
2189 dump_mir_exclude_alloc_bytes: bool = (false, parse_bool, [UNTRACKED],
2190 "exclude the raw bytes of allocations when dumping MIR (used in tests) (default: no)"),
2191 dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
2192 "exclude the pass number when dumping MIR (used in tests) (default: no)"),
2193 dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
2194 "in addition to `.mir` files, create graphviz `.dot` files (default: no)"),
2195 dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
2196 parse_switch_with_opt_path, [UNTRACKED],
2197 "output statistics about monomorphization collection"),
2198 dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED],
2199 "the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"),
2200 #[rustc_lint_opt_deny_field_access("use `Session::dwarf_version` instead of this field")]
2201 dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
2202 "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
2203 dylib_lto: bool = (false, parse_bool, [UNTRACKED],
2204 "enables LTO for dylib crate type"),
2205 eagerly_emit_delayed_bugs: bool = (false, parse_bool, [UNTRACKED],
2206 "emit delayed bugs eagerly as errors instead of stashing them and emitting \
2207 them only if an error has not been emitted"),
2208 ehcont_guard: bool = (false, parse_bool, [TRACKED],
2209 "generate Windows EHCont Guard tables"),
2210 embed_metadata: bool = (true, parse_bool, [TRACKED],
2211 "embed metadata in rlibs and dylibs (default: yes)"),
2212 embed_source: bool = (false, parse_bool, [TRACKED],
2213 "embed source text in DWARF debug sections (default: no)"),
2214 emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
2215 "emit a section containing stack size metadata (default: no)"),
2216 emit_thin_lto: bool = (true, parse_bool, [TRACKED],
2217 "emit the bc module with thin LTO info (default: yes)"),
2218 emscripten_wasm_eh: bool = (false, parse_bool, [TRACKED],
2219 "Use WebAssembly error handling for wasm32-unknown-emscripten"),
2220 enforce_type_length_limit: bool = (false, parse_bool, [TRACKED],
2221 "enforce the type length limit when monomorphizing instances in codegen"),
2222 experimental_default_bounds: bool = (false, parse_bool, [TRACKED],
2223 "enable default bounds for experimental group of auto traits"),
2224 export_executable_symbols: bool = (false, parse_bool, [TRACKED],
2225 "export symbols from executables, as if they were dynamic libraries"),
2226 external_clangrt: bool = (false, parse_bool, [UNTRACKED],
2227 "rely on user specified linker commands to find clangrt"),
2228 extra_const_ub_checks: bool = (false, parse_bool, [TRACKED],
2229 "turns on more checks to detect const UB, which can be slow (default: no)"),
2230 #[rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field")]
2231 fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
2232 "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
2233 (default: no)"),
2234 fixed_x18: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
2235 "make the x18 register reserved on AArch64 (default: no)"),
2236 flatten_format_args: bool = (true, parse_bool, [TRACKED],
2237 "flatten nested format_args!() and literals into a simplified format_args!() call \
2238 (default: yes)"),
2239 fmt_debug: FmtDebug = (FmtDebug::Full, parse_fmt_debug, [TRACKED],
2240 "how detailed `#[derive(Debug)]` should be. `full` prints types recursively, \
2241 `shallow` prints only type names, `none` prints nothing and disables `{:?}`. (default: `full`)"),
2242 force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
2243 "force all crates to be `rustc_private` unstable (default: no)"),
2244 function_return: FunctionReturn = (FunctionReturn::default(), parse_function_return, [TRACKED],
2245 "replace returns with jumps to `__x86_return_thunk` (default: `keep`)"),
2246 function_sections: Option<bool> = (None, parse_opt_bool, [TRACKED],
2247 "whether each function should go in its own section"),
2248 future_incompat_test: bool = (false, parse_bool, [UNTRACKED],
2249 "forces all lints to be future incompatible, used for internal testing (default: no)"),
2250 graphviz_dark_mode: bool = (false, parse_bool, [UNTRACKED],
2251 "use dark-themed colors in graphviz output (default: no)"),
2252 graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED],
2253 "use the given `fontname` in graphviz output; can be overridden by setting \
2254 environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"),
2255 has_thread_local: Option<bool> = (None, parse_opt_bool, [TRACKED],
2256 "explicitly enable the `cfg(target_thread_local)` directive"),
2257 hint_mostly_unused: bool = (false, parse_bool, [TRACKED],
2258 "hint that most of this crate will go unused, to minimize work for uncalled functions"),
2259 human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
2260 "generate human-readable, predictable names for codegen units (default: no)"),
2261 identify_regions: bool = (false, parse_bool, [UNTRACKED],
2262 "display unnamed regions as `'<id>`, using a non-ident unique id (default: no)"),
2263 ignore_directory_in_diagnostics_source_blocks: Vec<String> = (Vec::new(), parse_string_push, [UNTRACKED],
2264 "do not display the source code block in diagnostics for files in the directory"),
2265 incremental_ignore_spans: bool = (false, parse_bool, [TRACKED],
2266 "ignore spans during ICH computation -- used for testing (default: no)"),
2267 incremental_info: bool = (false, parse_bool, [UNTRACKED],
2268 "print high-level information about incremental reuse (or the lack thereof) \
2269 (default: no)"),
2270 incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
2271 "verify extended properties for incr. comp. (default: no):
2272 - hashes of green query instances
2273 - hash collisions of query keys
2274 - hash collisions when creating dep-nodes"),
2275 inline_llvm: bool = (true, parse_bool, [TRACKED],
2276 "enable LLVM inlining (default: yes)"),
2277 inline_mir: Option<bool> = (None, parse_opt_bool, [TRACKED],
2278 "enable MIR inlining (default: no)"),
2279 inline_mir_forwarder_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
2280 "inlining threshold when the caller is a simple forwarding function (default: 30)"),
2281 inline_mir_hint_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
2282 "inlining threshold for functions with inline hint (default: 100)"),
2283 inline_mir_preserve_debug: Option<bool> = (None, parse_opt_bool, [TRACKED],
2284 "when MIR inlining, whether to preserve debug info for callee variables \
2285 (default: preserve for debuginfo != None, otherwise remove)"),
2286 inline_mir_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
2287 "a default MIR inlining threshold (default: 50)"),
2288 input_stats: bool = (false, parse_bool, [UNTRACKED],
2289 "print some statistics about AST and HIR (default: no)"),
2290 instrument_mcount: bool = (false, parse_bool, [TRACKED],
2291 "insert function instrument code for mcount-based tracing (default: no)"),
2292 instrument_xray: Option<InstrumentXRay> = (None, parse_instrument_xray, [TRACKED],
2293 "insert function instrument code for XRay-based tracing (default: no)
2294 Optional extra settings:
2295 `=always`
2296 `=never`
2297 `=ignore-loops`
2298 `=instruction-threshold=N`
2299 `=skip-entry`
2300 `=skip-exit`
2301 Multiple options can be combined with commas."),
2302 layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED],
2303 "seed layout randomization"),
2304 link_directives: bool = (true, parse_bool, [TRACKED],
2305 "honor #[link] directives in the compiled crate (default: yes)"),
2306 link_native_libraries: bool = (true, parse_bool, [UNTRACKED],
2307 "link native libraries in the linker invocation (default: yes)"),
2308 link_only: bool = (false, parse_bool, [TRACKED],
2309 "link the `.rlink` file generated by `-Z no-link` (default: no)"),
2310 linker_features: LinkerFeaturesCli = (LinkerFeaturesCli::default(), parse_linker_features, [UNTRACKED],
2311 "a comma-separated list of linker features to enable (+) or disable (-): `lld`"),
2312 lint_llvm_ir: bool = (false, parse_bool, [TRACKED],
2313 "lint LLVM IR (default: no)"),
2314 lint_mir: bool = (false, parse_bool, [UNTRACKED],
2315 "lint MIR before and after each transformation"),
2316 llvm_module_flag: Vec<(String, u32, String)> = (Vec::new(), parse_llvm_module_flag, [TRACKED],
2317 "a list of module flags to pass to LLVM (space separated)"),
2318 llvm_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
2319 "a list LLVM plugins to enable (space separated)"),
2320 llvm_time_trace: bool = (false, parse_bool, [UNTRACKED],
2321 "generate JSON tracing data file from LLVM data (default: no)"),
2322 location_detail: LocationDetail = (LocationDetail::all(), parse_location_detail, [TRACKED],
2323 "what location details should be tracked when using caller_location, either \
2324 `none`, or a comma separated list of location details, for which \
2325 valid options are `file`, `line`, and `column` (default: `file,line,column`)"),
2326 ls: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
2327 "decode and print various parts of the crate metadata for a library crate \
2328 (space separated)"),
2329 macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
2330 "show macro backtraces (default: no)"),
2331 macro_stats: bool = (false, parse_bool, [UNTRACKED],
2332 "print some statistics about macro expansions (default: no)"),
2333 maximal_hir_to_mir_coverage: bool = (false, parse_bool, [TRACKED],
2334 "save as much information as possible about the correspondence between MIR and HIR \
2335 as source scopes (default: no)"),
2336 merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
2337 "control the operation of the MergeFunctions LLVM pass, taking \
2338 the same values as the target option of the same name"),
2339 meta_stats: bool = (false, parse_bool, [UNTRACKED],
2340 "gather metadata statistics (default: no)"),
2341 metrics_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
2342 "the directory metrics emitted by rustc are dumped into (implicitly enables default set of metrics)"),
2343 min_function_alignment: Option<Align> = (None, parse_align, [TRACKED],
2344 "align all functions to at least this many bytes. Must be a power of 2"),
2345 mir_emit_retag: bool = (false, parse_bool, [TRACKED],
2346 "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
2347 (default: no)"),
2348 mir_enable_passes: Vec<(String, bool)> = (Vec::new(), parse_list_with_polarity, [TRACKED],
2349 "use like `-Zmir-enable-passes=+DestinationPropagation,-InstSimplify`. Forces the \
2350 specified passes to be enabled, overriding all other checks. In particular, this will \
2351 enable unsound (known-buggy and hence usually disabled) passes without further warning! \
2352 Passes that are not specified are enabled or disabled by other flags as usual."),
2353 mir_include_spans: MirIncludeSpans = (MirIncludeSpans::default(), parse_mir_include_spans, [UNTRACKED],
2354 "include extra comments in mir pretty printing, like line numbers and statement indices, \
2355 details about types, etc. (boolean for all passes, 'nll' to enable in NLL MIR only, default: 'nll')"),
2356 #[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")]
2357 mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
2358 "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
2359 mir_preserve_ub: bool = (false, parse_bool, [TRACKED],
2360 "keep place mention statements and reads in trivial SwitchInt terminators, which are interpreted \
2361 e.g., by miri; implies -Zmir-opt-level=0 (default: no)"),
2362 mir_strip_debuginfo: MirStripDebugInfo = (MirStripDebugInfo::None, parse_mir_strip_debuginfo, [TRACKED],
2363 "Whether to remove some of the MIR debug info from methods. Default: None"),
2364 move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
2365 "the size at which the `large_assignments` lint starts to be emitted"),
2366 mutable_noalias: bool = (true, parse_bool, [TRACKED],
2367 "emit noalias metadata for mutable references (default: yes)"),
2368 namespaced_crates: bool = (false, parse_bool, [TRACKED],
2369 "allow crates to be namespaced by other crates (default: no)"),
2370 next_solver: NextSolverConfig = (NextSolverConfig::default(), parse_next_solver_config, [TRACKED],
2371 "enable and configure the next generation trait solver used by rustc"),
2372 nll_facts: bool = (false, parse_bool, [UNTRACKED],
2373 "dump facts from NLL analysis into side files (default: no)"),
2374 nll_facts_dir: String = ("nll-facts".to_string(), parse_string, [UNTRACKED],
2375 "the directory the NLL facts are dumped into (default: `nll-facts`)"),
2376 no_analysis: bool = (false, parse_no_value, [UNTRACKED],
2377 "parse and expand the source, but run no analysis"),
2378 no_codegen: bool = (false, parse_no_value, [TRACKED_NO_CRATE_HASH],
2379 "run all passes except codegen; no output"),
2380 no_generate_arange_section: bool = (false, parse_no_value, [TRACKED],
2381 "omit DWARF address ranges that give faster lookups"),
2382 no_implied_bounds_compat: bool = (false, parse_bool, [TRACKED],
2383 "disable the compatibility version of the `implied_bounds_ty` query"),
2384 no_jump_tables: bool = (false, parse_no_value, [TRACKED],
2385 "disable the jump tables and lookup tables that can be generated from a switch case lowering"),
2386 no_leak_check: bool = (false, parse_no_value, [UNTRACKED],
2387 "disable the 'leak check' for subtyping; unsound, but useful for tests"),
2388 no_link: bool = (false, parse_no_value, [TRACKED],
2389 "compile without linking"),
2390 no_parallel_backend: bool = (false, parse_no_value, [UNTRACKED],
2391 "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
2392 no_profiler_runtime: bool = (false, parse_no_value, [TRACKED],
2393 "prevent automatic injection of the profiler_builtins crate"),
2394 no_steal_thir: bool = (false, parse_bool, [UNTRACKED],
2395 "don't steal the THIR when we're done with it; useful for rustc drivers (default: no)"),
2396 no_trait_vptr: bool = (false, parse_no_value, [TRACKED],
2397 "disable generation of trait vptr in vtable for upcasting"),
2398 no_unique_section_names: bool = (false, parse_bool, [TRACKED],
2399 "do not use unique names for text and data sections when -Z function-sections is used"),
2400 normalize_docs: bool = (false, parse_bool, [TRACKED],
2401 "normalize associated items in rustdoc when generating documentation"),
2402 on_broken_pipe: OnBrokenPipe = (OnBrokenPipe::Default, parse_on_broken_pipe, [TRACKED],
2403 "behavior of std::io::ErrorKind::BrokenPipe (SIGPIPE)"),
2404 oom: OomStrategy = (OomStrategy::Abort, parse_oom_strategy, [TRACKED],
2405 "panic strategy for out-of-memory handling"),
2406 osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
2407 "pass `-install_name @rpath/...` to the macOS linker (default: no)"),
2408 packed_bundled_libs: bool = (false, parse_bool, [TRACKED],
2409 "change rlib format to store native libraries as archives"),
2410 panic_abort_tests: bool = (false, parse_bool, [TRACKED],
2411 "support compiling tests with panic=abort (default: no)"),
2412 panic_in_drop: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, [TRACKED],
2413 "panic strategy for panics in drops"),
2414 parse_crate_root_only: bool = (false, parse_bool, [UNTRACKED],
2415 "parse the crate root file only; do not parse other files, compile, assemble, or link \
2416 (default: no)"),
2417 patchable_function_entry: PatchableFunctionEntry = (PatchableFunctionEntry::default(), parse_patchable_function_entry, [TRACKED],
2418 "nop padding at function entry"),
2419 plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
2420 "whether to use the PLT when calling into shared libraries;
2421 only has effect for PIC code on systems with ELF binaries
2422 (default: PLT is disabled if full relro is enabled on x86_64)"),
2423 polonius: Polonius = (Polonius::default(), parse_polonius, [TRACKED],
2424 "enable polonius-based borrow-checker (default: no)"),
2425 pre_link_arg: () = ((), parse_string_push, [UNTRACKED],
2426 "a single extra argument to prepend the linker invocation (can be used several times)"),
2427 pre_link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
2428 "extra arguments to prepend to the linker invocation (space separated)"),
2429 precise_enum_drop_elaboration: bool = (true, parse_bool, [TRACKED],
2430 "use a more precise version of drop elaboration for matches on enums (default: yes). \
2431 This results in better codegen, but has caused miscompilations on some tier 2 platforms. \
2432 See #77382 and #74551."),
2433 #[rustc_lint_opt_deny_field_access("use `Session::print_codegen_stats` instead of this field")]
2434 print_codegen_stats: bool = (false, parse_bool, [UNTRACKED],
2435 "print codegen statistics (default: no)"),
2436 print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
2437 "print the LLVM optimization passes being run (default: no)"),
2438 print_mono_items: bool = (false, parse_bool, [UNTRACKED],
2439 "print the result of the monomorphization collection pass (default: no)"),
2440 print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
2441 "print layout information for each type encountered (default: no)"),
2442 proc_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
2443 "show backtraces for panics during proc-macro execution (default: no)"),
2444 proc_macro_execution_strategy: ProcMacroExecutionStrategy = (ProcMacroExecutionStrategy::SameThread,
2445 parse_proc_macro_execution_strategy, [UNTRACKED],
2446 "how to run proc-macro code (default: same-thread)"),
2447 profile_closures: bool = (false, parse_no_value, [UNTRACKED],
2448 "profile size of closures"),
2449 profile_sample_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
2450 "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"),
2451 profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED],
2452 "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"),
2453 query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
2454 "enable queries of the dependency graph for regression testing (default: no)"),
2455 randomize_layout: bool = (false, parse_bool, [TRACKED],
2456 "randomize the layout of types (default: no)"),
2457 reg_struct_return: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
2458 "On x86-32 targets, it overrides the default ABI to return small structs in registers.
2459 It is UNSOUND to link together crates that use different values for this flag!"),
2460 regparm: Option<u32> = (None, parse_opt_number, [TRACKED TARGET_MODIFIER],
2461 "On x86-32 targets, setting this to N causes the compiler to pass N arguments \
2462 in registers EAX, EDX, and ECX instead of on the stack for\
2463 \"C\", \"cdecl\", and \"stdcall\" fn.\
2464 It is UNSOUND to link together crates that use different values for this flag!"),
2465 relax_elf_relocations: Option<bool> = (None, parse_opt_bool, [TRACKED],
2466 "whether ELF relocations can be relaxed"),
2467 remap_cwd_prefix: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
2468 "remap paths under the current working directory to this path prefix"),
2469 remap_path_scope: RemapPathScopeComponents = (RemapPathScopeComponents::all(), parse_remap_path_scope, [TRACKED],
2470 "remap path scope (default: all)"),
2471 remark_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
2472 "directory into which to write optimization remarks (if not specified, they will be \
2473written to standard error output)"),
2474 retpoline: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
2475 "enables retpoline-indirect-branches and retpoline-indirect-calls target features (default: no)"),
2476 retpoline_external_thunk: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
2477 "enables retpoline-external-thunk, retpoline-indirect-branches and retpoline-indirect-calls \
2478 target features (default: no)"),
2479 sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
2480 "use a sanitizer"),
2481 sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],
2482 "enable canonical jump tables (default: yes)"),
2483 sanitizer_cfi_generalize_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
2484 "enable generalizing pointer types (default: no)"),
2485 sanitizer_cfi_normalize_integers: Option<bool> = (None, parse_opt_bool, [TRACKED],
2486 "enable normalizing integer types (default: no)"),
2487 sanitizer_dataflow_abilist: Vec<String> = (Vec::new(), parse_comma_list, [TRACKED],
2488 "additional ABI list files that control how shadow parameters are passed (comma separated)"),
2489 sanitizer_kcfi_arity: Option<bool> = (None, parse_opt_bool, [TRACKED],
2490 "enable KCFI arity indicator (default: no)"),
2491 sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
2492 "enable origins tracking in MemorySanitizer"),
2493 sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
2494 "enable recovery for selected sanitizers"),
2495 saturating_float_casts: Option<bool> = (None, parse_opt_bool, [TRACKED],
2496 "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
2497 the max/min integer respectively, and NaN is mapped to 0 (default: yes)"),
2498 self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
2499 parse_switch_with_opt_path, [UNTRACKED],
2500 "run the self profiler and output the raw event data"),
2501 self_profile_counter: String = ("wall-time".to_string(), parse_string, [UNTRACKED],
2502 "counter used by the self profiler (default: `wall-time`), one of:
2503 `wall-time` (monotonic clock, i.e. `std::time::Instant`)
2504 `instructions:u` (retired instructions, userspace-only)
2505 `instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)"
2506 ),
2507 self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
2509 "specify the events recorded by the self profiler;
2510 for example: `-Z self-profile-events=default,query-keys`
2511 all options: none, all, default, generic-activity, query-provider, query-cache-hit
2512 query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"),
2513 share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
2514 "make the current crate share its generic instantiations"),
2515 shell_argfiles: bool = (false, parse_bool, [UNTRACKED],
2516 "allow argument files to be specified with POSIX \"shell-style\" argument quoting"),
2517 simulate_remapped_rust_src_base: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
2518 "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \
2519 to rust's source base directory. only meant for testing purposes"),
2520 small_data_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
2521 "Set the threshold for objects to be stored in a \"small data\" section"),
2522 span_debug: bool = (false, parse_bool, [UNTRACKED],
2523 "forward proc_macro::Span's `Debug` impl to `Span`"),
2524 span_free_formats: bool = (false, parse_bool, [UNTRACKED],
2526 "exclude spans when debug-printing compiler state (default: no)"),
2527 split_dwarf_inlining: bool = (false, parse_bool, [TRACKED],
2528 "provide minimal debug info in the object/executable to facilitate online \
2529 symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
2530 split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [TRACKED],
2531 "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
2532 (default: `split`)
2533
2534 `split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
2535 file which is ignored by the linker
2536 `single`: sections which do not require relocation are written into object file but ignored
2537 by the linker"),
2538 split_lto_unit: Option<bool> = (None, parse_opt_bool, [TRACKED],
2539 "enable LTO unit splitting (default: no)"),
2540 src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
2541 "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
2542 #[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")]
2543 stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED],
2544 "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
2545 staticlib_allow_rdylib_deps: bool = (false, parse_bool, [TRACKED],
2546 "allow staticlibs to have rust dylib dependencies"),
2547 staticlib_prefer_dynamic: bool = (false, parse_bool, [TRACKED],
2548 "prefer dynamic linking to static linking for staticlibs (default: no)"),
2549 strict_init_checks: bool = (false, parse_bool, [TRACKED],
2550 "control if mem::uninitialized and mem::zeroed panic on more UB"),
2551 #[rustc_lint_opt_deny_field_access("use `Session::teach` instead of this field")]
2552 teach: bool = (false, parse_bool, [TRACKED],
2553 "show extended diagnostic help (default: no)"),
2554 temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
2555 "the directory the intermediate files are written to"),
2556 terminal_urls: TerminalUrl = (TerminalUrl::No, parse_terminal_url, [UNTRACKED],
2557 "use the OSC 8 hyperlink terminal specification to print hyperlinks in the compiler output"),
2558 #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
2559 thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
2560 "enable ThinLTO when possible"),
2561 #[rustc_lint_opt_deny_field_access("use `Session::threads` instead of this field")]
2566 threads: usize = (1, parse_threads, [UNTRACKED],
2567 "use a thread pool with N threads"),
2568 time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
2569 "measure time of each LLVM pass (default: no)"),
2570 time_passes: bool = (false, parse_bool, [UNTRACKED],
2571 "measure time of each rustc pass (default: no)"),
2572 time_passes_format: TimePassesFormat = (TimePassesFormat::Text, parse_time_passes_format, [UNTRACKED],
2573 "the format to use for -Z time-passes (`text` (default) or `json`)"),
2574 tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED],
2575 "sets a tiny, non-configurable limit for const eval; useful for compiler tests"),
2576 #[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")]
2577 tls_model: Option<TlsModel> = (None, parse_tls_model, [TRACKED],
2578 "choose the TLS model to use (`rustc --print tls-models` for details)"),
2579 trace_macros: bool = (false, parse_bool, [UNTRACKED],
2580 "for every macro invocation, print its name and arguments (default: no)"),
2581 track_diagnostics: bool = (false, parse_bool, [UNTRACKED],
2582 "tracks where in rustc a diagnostic was emitted"),
2583 translate_additional_ftl: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
2587 "additional fluent translation to preferentially use (for testing translation)"),
2588 translate_directionality_markers: bool = (false, parse_bool, [TRACKED],
2589 "emit directionality isolation markers in translated diagnostics"),
2590 translate_lang: Option<LanguageIdentifier> = (None, parse_opt_langid, [TRACKED],
2591 "language identifier for diagnostic output"),
2592 translate_remapped_path_to_local_path: bool = (true, parse_bool, [TRACKED],
2593 "translate remapped paths into local paths when possible (default: yes)"),
2594 trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
2595 "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"),
2596 treat_err_as_bug: Option<NonZero<usize>> = (None, parse_treat_err_as_bug, [TRACKED],
2597 "treat the `val`th error that occurs as bug (default if not specified: 0 - don't treat errors as bugs. \
2598 default if specified without a value: 1 - treat the first error as bug)"),
2599 trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
2600 "in diagnostics, use heuristics to shorten paths referring to items"),
2601 tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
2602 "select processor to schedule for (`rustc --print target-cpus` for details)"),
2603 #[rustc_lint_opt_deny_field_access("use `TyCtxt::use_typing_mode_borrowck` instead of this field")]
2604 typing_mode_borrowck: bool = (false, parse_bool, [TRACKED],
2605 "enable `TypingMode::Borrowck`, changing the way opaque types are handled during MIR borrowck"),
2606 #[rustc_lint_opt_deny_field_access("use `Session::ub_checks` instead of this field")]
2607 ub_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
2608 "emit runtime checks for Undefined Behavior (default: -Cdebug-assertions)"),
2609 ui_testing: bool = (false, parse_bool, [UNTRACKED],
2610 "emit compiler diagnostics in a form suitable for UI testing (default: no)"),
2611 uninit_const_chunk_threshold: usize = (16, parse_number, [TRACKED],
2612 "allow generating const initializers with mixed init/uninit chunks, \
2613 and set the maximum number of chunks for which this is allowed (default: 16)"),
2614 unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
2615 "take the brakes off const evaluation. NOTE: this is unsound (default: no)"),
2616 unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
2617 "present the input source, unstable (and less-pretty) variants;
2618 `normal`, `identified`,
2619 `expanded`, `expanded,identified`,
2620 `expanded,hygiene` (with internal representations),
2621 `ast-tree` (raw AST before expansion),
2622 `ast-tree,expanded` (raw AST after expansion),
2623 `hir` (the HIR), `hir,identified`,
2624 `hir,typed` (HIR with types for each node),
2625 `hir-tree` (dump the raw HIR),
2626 `thir-tree`, `thir-flat`,
2627 `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
2628 unsound_mir_opts: bool = (false, parse_bool, [TRACKED],
2629 "enable unsound and buggy MIR optimizations (default: no)"),
2630 #[rustc_lint_opt_deny_field_access("use `Session::unstable_options` instead of this field")]
2639 unstable_options: bool = (false, parse_no_value, [UNTRACKED],
2640 "adds unstable command line options to rustc interface (default: no)"),
2641 use_ctors_section: Option<bool> = (None, parse_opt_bool, [TRACKED],
2642 "use legacy .ctors section for initializers rather than .init_array"),
2643 use_sync_unwind: Option<bool> = (None, parse_opt_bool, [TRACKED],
2644 "Generate sync unwind tables instead of async unwind tables (default: no)"),
2645 validate_mir: bool = (false, parse_bool, [UNTRACKED],
2646 "validate MIR after each transformation"),
2647 verbose_asm: bool = (false, parse_bool, [TRACKED],
2648 "add descriptive comments from LLVM to the assembly (may change behavior) (default: no)"),
2649 #[rustc_lint_opt_deny_field_access("use `Session::verbose_internals` instead of this field")]
2650 verbose_internals: bool = (false, parse_bool, [TRACKED_NO_CRATE_HASH],
2651 "in general, enable more debug printouts (default: no)"),
2652 #[rustc_lint_opt_deny_field_access("use `Session::verify_llvm_ir` instead of this field")]
2653 verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
2654 "verify LLVM IR (default: no)"),
2655 virtual_function_elimination: bool = (false, parse_bool, [TRACKED],
2656 "enables dead virtual function elimination optimization. \
2657 Requires `-Clto[=[fat,yes]]`"),
2658 wasi_exec_model: Option<WasiExecModel> = (None, parse_wasi_exec_model, [TRACKED],
2659 "whether to build a wasi command or reactor"),
2660 wasm_c_abi: () = ((), parse_wasm_c_abi, [TRACKED],
2664 "use spec-compliant C ABI for `wasm32-unknown-unknown` (deprecated, always enabled)"),
2665 write_long_types_to_disk: bool = (true, parse_bool, [UNTRACKED],
2666 "whether long type names should be written to files instead of being printed in errors"),
2667 }