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_offload: &str = "a comma separated list of settings: `Enable`";
730 pub(crate) const parse_comma_list: &str = "a comma-separated list of strings";
731 pub(crate) const parse_opt_comma_list: &str = parse_comma_list;
732 pub(crate) const parse_number: &str = "a number";
733 pub(crate) const parse_opt_number: &str = parse_number;
734 pub(crate) const parse_frame_pointer: &str = "one of `true`/`yes`/`on`, `false`/`no`/`off`, or (with -Zunstable-options) `non-leaf` or `always`";
735 pub(crate) const parse_threads: &str = parse_number;
736 pub(crate) const parse_time_passes_format: &str = "`text` (default) or `json`";
737 pub(crate) const parse_passes: &str = "a space-separated list of passes, or `all`";
738 pub(crate) const parse_panic_strategy: &str = "either `unwind` or `abort`";
739 pub(crate) const parse_on_broken_pipe: &str = "either `kill`, `error`, or `inherit`";
740 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)";
741 pub(crate) const parse_opt_panic_strategy: &str = parse_panic_strategy;
742 pub(crate) const parse_oom_strategy: &str = "either `panic` or `abort`";
743 pub(crate) const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
744 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`";
745 pub(crate) const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
746 pub(crate) const parse_cfguard: &str =
747 "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
748 pub(crate) const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)";
749 pub(crate) const parse_debuginfo: &str = "either an integer (0, 1, 2), `none`, `line-directives-only`, `line-tables-only`, `limited`, or `full`";
750 pub(crate) const parse_debuginfo_compression: &str = "one of `none`, `zlib`, or `zstd`";
751 pub(crate) const parse_mir_strip_debuginfo: &str =
752 "one of `none`, `locals-in-tiny-functions`, or `all-locals`";
753 pub(crate) const parse_collapse_macro_debuginfo: &str = "one of `no`, `external`, or `yes`";
754 pub(crate) const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
755 pub(crate) const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
756 pub(crate) const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
757 pub(crate) const parse_instrument_coverage: &str = parse_bool;
758 pub(crate) const parse_coverage_options: &str =
759 "`block` | `branch` | `condition` | `mcdc` | `no-mir-spans`";
760 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`";
761 pub(crate) const parse_unpretty: &str = "`string` or `string=string`";
762 pub(crate) const parse_treat_err_as_bug: &str = "either no value or a non-negative number";
763 pub(crate) const parse_next_solver_config: &str =
764 "either `globally` (when used without an argument), `coherence` (default) or `no`";
765 pub(crate) const parse_lto: &str =
766 "either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted";
767 pub(crate) const parse_linker_plugin_lto: &str =
768 "either a boolean (`yes`, `no`, `on`, `off`, etc), or the path to the linker plugin";
769 pub(crate) const parse_location_detail: &str = "either `none`, or a comma separated list of location details to track: `file`, `line`, or `column`";
770 pub(crate) const parse_fmt_debug: &str = "either `full`, `shallow`, or `none`";
771 pub(crate) const parse_switch_with_opt_path: &str =
772 "an optional path to the profiling data output directory";
773 pub(crate) const parse_merge_functions: &str =
774 "one of: `disabled`, `trampolines`, or `aliases`";
775 pub(crate) const parse_symbol_mangling_version: &str =
776 "one of: `legacy`, `v0` (RFC 2603), or `hashed`";
777 pub(crate) const parse_opt_symbol_visibility: &str =
778 "one of: `hidden`, `protected`, or `interposable`";
779 pub(crate) const parse_cargo_src_file_hash: &str =
780 "one of `blake3`, `md5`, `sha1`, or `sha256`";
781 pub(crate) const parse_src_file_hash: &str = "one of `md5`, `sha1`, or `sha256`";
782 pub(crate) const parse_relocation_model: &str =
783 "one of supported relocation models (`rustc --print relocation-models`)";
784 pub(crate) const parse_code_model: &str =
785 "one of supported code models (`rustc --print code-models`)";
786 pub(crate) const parse_tls_model: &str =
787 "one of supported TLS models (`rustc --print tls-models`)";
788 pub(crate) const parse_target_feature: &str = parse_string;
789 pub(crate) const parse_terminal_url: &str =
790 "either a boolean (`yes`, `no`, `on`, `off`, etc), or `auto`";
791 pub(crate) const parse_wasi_exec_model: &str = "either `command` or `reactor`";
792 pub(crate) const parse_split_debuginfo: &str =
793 "one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
794 pub(crate) const parse_split_dwarf_kind: &str =
795 "one of supported split dwarf modes (`split` or `single`)";
796 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) \
797 components: `crto`, `libc`, `unwind`, `linker`, `sanitizers`, `mingw`";
798 pub(crate) const parse_linker_features: &str =
799 "a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld`";
800 pub(crate) const parse_polonius: &str = "either no value or `legacy` (the default), or `next`";
801 pub(crate) const parse_stack_protector: &str =
802 "one of (`none` (default), `basic`, `strong`, or `all`)";
803 pub(crate) const parse_branch_protection: &str = "a `,` separated combination of `bti`, `pac-ret`, followed by a combination of `pc`, `b-key`, or `leaf`";
804 pub(crate) const parse_proc_macro_execution_strategy: &str =
805 "one of supported execution strategies (`same-thread`, or `cross-thread`)";
806 pub(crate) const parse_remap_path_scope: &str =
807 "comma separated list of scopes: `macro`, `diagnostics`, `debuginfo`, `object`, `all`";
808 pub(crate) const parse_inlining_threshold: &str =
809 "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number";
810 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`)";
811 pub(crate) const parse_function_return: &str = "`keep` or `thunk-extern`";
812 pub(crate) const parse_wasm_c_abi: &str = "`spec`";
813 pub(crate) const parse_mir_include_spans: &str =
814 "either a boolean (`yes`, `no`, `on`, `off`, etc), or `nll` (default: `nll`)";
815 pub(crate) const parse_align: &str = "a number that is a power of 2 between 1 and 2^29";
816}
817
818pub mod parse {
819 use std::str::FromStr;
820
821 pub(crate) use super::*;
822 pub(crate) const MAX_THREADS_CAP: usize = 256;
823
824 pub(crate) fn parse_no_value(slot: &mut bool, v: Option<&str>) -> bool {
830 match v {
831 None => {
832 *slot = true;
833 true
834 }
835 Some(_) => false,
837 }
838 }
839
840 pub(crate) fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
842 match v {
843 Some("y") | Some("yes") | Some("on") | Some("true") | None => {
844 *slot = true;
845 true
846 }
847 Some("n") | Some("no") | Some("off") | Some("false") => {
848 *slot = false;
849 true
850 }
851 _ => false,
852 }
853 }
854
855 pub(crate) fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
859 match v {
860 Some("y") | Some("yes") | Some("on") | Some("true") | None => {
861 *slot = Some(true);
862 true
863 }
864 Some("n") | Some("no") | Some("off") | Some("false") => {
865 *slot = Some(false);
866 true
867 }
868 _ => false,
869 }
870 }
871
872 pub(crate) fn parse_polonius(slot: &mut Polonius, v: Option<&str>) -> bool {
874 match v {
875 Some("legacy") | None => {
876 *slot = Polonius::Legacy;
877 true
878 }
879 Some("next") => {
880 *slot = Polonius::Next;
881 true
882 }
883 _ => false,
884 }
885 }
886
887 pub(crate) fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
889 match v {
890 Some(s) => {
891 *slot = s.to_string();
892 true
893 }
894 None => false,
895 }
896 }
897
898 pub(crate) fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
900 match v {
901 Some(s) => {
902 *slot = Some(s.to_string());
903 true
904 }
905 None => false,
906 }
907 }
908
909 pub(crate) fn parse_opt_langid(slot: &mut Option<LanguageIdentifier>, v: Option<&str>) -> bool {
911 match v {
912 Some(s) => {
913 *slot = rustc_errors::LanguageIdentifier::from_str(s).ok();
914 true
915 }
916 None => false,
917 }
918 }
919
920 pub(crate) fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
921 match v {
922 Some(s) => {
923 *slot = Some(PathBuf::from(s));
924 true
925 }
926 None => false,
927 }
928 }
929
930 pub(crate) fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
931 match v {
932 Some(s) => {
933 slot.push(s.to_string());
934 true
935 }
936 None => false,
937 }
938 }
939
940 pub(crate) fn parse_list(slot: &mut Vec<String>, v: Option<&str>) -> bool {
941 match v {
942 Some(s) => {
943 slot.extend(s.split_whitespace().map(|s| s.to_string()));
944 true
945 }
946 None => false,
947 }
948 }
949
950 pub(crate) fn parse_list_with_polarity(
951 slot: &mut Vec<(String, bool)>,
952 v: Option<&str>,
953 ) -> bool {
954 match v {
955 Some(s) => {
956 for s in s.split(',') {
957 let Some(pass_name) = s.strip_prefix(&['+', '-'][..]) else { return false };
958 slot.push((pass_name.to_string(), &s[..1] == "+"));
959 }
960 true
961 }
962 None => false,
963 }
964 }
965
966 pub(crate) fn parse_fmt_debug(opt: &mut FmtDebug, v: Option<&str>) -> bool {
967 *opt = match v {
968 Some("full") => FmtDebug::Full,
969 Some("shallow") => FmtDebug::Shallow,
970 Some("none") => FmtDebug::None,
971 _ => return false,
972 };
973 true
974 }
975
976 pub(crate) fn parse_location_detail(ld: &mut LocationDetail, v: Option<&str>) -> bool {
977 if let Some(v) = v {
978 ld.line = false;
979 ld.file = false;
980 ld.column = false;
981 if v == "none" {
982 return true;
983 }
984 for s in v.split(',') {
985 match s {
986 "file" => ld.file = true,
987 "line" => ld.line = true,
988 "column" => ld.column = true,
989 _ => return false,
990 }
991 }
992 true
993 } else {
994 false
995 }
996 }
997
998 pub(crate) fn parse_comma_list(slot: &mut Vec<String>, v: Option<&str>) -> bool {
999 match v {
1000 Some(s) => {
1001 let mut v: Vec<_> = s.split(',').map(|s| s.to_string()).collect();
1002 v.sort_unstable();
1003 *slot = v;
1004 true
1005 }
1006 None => false,
1007 }
1008 }
1009
1010 pub(crate) fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
1011 match v {
1012 Some(s) => {
1013 let mut v: Vec<_> = s.split(',').map(|s| s.to_string()).collect();
1014 v.sort_unstable();
1015 *slot = Some(v);
1016 true
1017 }
1018 None => false,
1019 }
1020 }
1021
1022 pub(crate) fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
1023 let ret = match v.and_then(|s| s.parse().ok()) {
1024 Some(0) => {
1025 *slot = std::thread::available_parallelism().map_or(1, NonZero::<usize>::get);
1026 true
1027 }
1028 Some(i) => {
1029 *slot = i;
1030 true
1031 }
1032 None => false,
1033 };
1034 *slot = slot.clone().min(MAX_THREADS_CAP);
1037 ret
1038 }
1039
1040 pub(crate) fn parse_number<T: Copy + FromStr>(slot: &mut T, v: Option<&str>) -> bool {
1042 match v.and_then(|s| s.parse().ok()) {
1043 Some(i) => {
1044 *slot = i;
1045 true
1046 }
1047 None => false,
1048 }
1049 }
1050
1051 pub(crate) fn parse_opt_number<T: Copy + FromStr>(
1053 slot: &mut Option<T>,
1054 v: Option<&str>,
1055 ) -> bool {
1056 match v {
1057 Some(s) => {
1058 *slot = s.parse().ok();
1059 slot.is_some()
1060 }
1061 None => false,
1062 }
1063 }
1064
1065 pub(crate) fn parse_frame_pointer(slot: &mut FramePointer, v: Option<&str>) -> bool {
1066 let mut yes = false;
1067 match v {
1068 _ if parse_bool(&mut yes, v) && yes => slot.ratchet(FramePointer::Always),
1069 _ if parse_bool(&mut yes, v) => slot.ratchet(FramePointer::MayOmit),
1070 Some("always") => slot.ratchet(FramePointer::Always),
1071 Some("non-leaf") => slot.ratchet(FramePointer::NonLeaf),
1072 _ => return false,
1073 };
1074 true
1075 }
1076
1077 pub(crate) fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
1078 match v {
1079 Some("all") => {
1080 *slot = Passes::All;
1081 true
1082 }
1083 v => {
1084 let mut passes = vec![];
1085 if parse_list(&mut passes, v) {
1086 slot.extend(passes);
1087 true
1088 } else {
1089 false
1090 }
1091 }
1092 }
1093 }
1094
1095 pub(crate) fn parse_opt_panic_strategy(
1096 slot: &mut Option<PanicStrategy>,
1097 v: Option<&str>,
1098 ) -> bool {
1099 match v {
1100 Some("unwind") => *slot = Some(PanicStrategy::Unwind),
1101 Some("abort") => *slot = Some(PanicStrategy::Abort),
1102 _ => return false,
1103 }
1104 true
1105 }
1106
1107 pub(crate) fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
1108 match v {
1109 Some("unwind") => *slot = PanicStrategy::Unwind,
1110 Some("abort") => *slot = PanicStrategy::Abort,
1111 _ => return false,
1112 }
1113 true
1114 }
1115
1116 pub(crate) fn parse_on_broken_pipe(slot: &mut OnBrokenPipe, v: Option<&str>) -> bool {
1117 match v {
1118 Some("kill") => *slot = OnBrokenPipe::Kill,
1120 Some("error") => *slot = OnBrokenPipe::Error,
1121 Some("inherit") => *slot = OnBrokenPipe::Inherit,
1122 _ => return false,
1123 }
1124 true
1125 }
1126
1127 pub(crate) fn parse_patchable_function_entry(
1128 slot: &mut PatchableFunctionEntry,
1129 v: Option<&str>,
1130 ) -> bool {
1131 let mut total_nops = 0;
1132 let mut prefix_nops = 0;
1133
1134 if !parse_number(&mut total_nops, v) {
1135 let parts = v.and_then(|v| v.split_once(',')).unzip();
1136 if !parse_number(&mut total_nops, parts.0) {
1137 return false;
1138 }
1139 if !parse_number(&mut prefix_nops, parts.1) {
1140 return false;
1141 }
1142 }
1143
1144 if let Some(pfe) =
1145 PatchableFunctionEntry::from_total_and_prefix_nops(total_nops, prefix_nops)
1146 {
1147 *slot = pfe;
1148 return true;
1149 }
1150 false
1151 }
1152
1153 pub(crate) fn parse_oom_strategy(slot: &mut OomStrategy, v: Option<&str>) -> bool {
1154 match v {
1155 Some("panic") => *slot = OomStrategy::Panic,
1156 Some("abort") => *slot = OomStrategy::Abort,
1157 _ => return false,
1158 }
1159 true
1160 }
1161
1162 pub(crate) fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
1163 match v {
1164 Some(s) => match s.parse::<RelroLevel>() {
1165 Ok(level) => *slot = Some(level),
1166 _ => return false,
1167 },
1168 _ => return false,
1169 }
1170 true
1171 }
1172
1173 pub(crate) fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
1174 if let Some(v) = v {
1175 for s in v.split(',') {
1176 *slot |= match s {
1177 "address" => SanitizerSet::ADDRESS,
1178 "cfi" => SanitizerSet::CFI,
1179 "dataflow" => SanitizerSet::DATAFLOW,
1180 "kcfi" => SanitizerSet::KCFI,
1181 "kernel-address" => SanitizerSet::KERNELADDRESS,
1182 "leak" => SanitizerSet::LEAK,
1183 "memory" => SanitizerSet::MEMORY,
1184 "memtag" => SanitizerSet::MEMTAG,
1185 "shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
1186 "thread" => SanitizerSet::THREAD,
1187 "hwaddress" => SanitizerSet::HWADDRESS,
1188 "safestack" => SanitizerSet::SAFESTACK,
1189 _ => return false,
1190 }
1191 }
1192 true
1193 } else {
1194 false
1195 }
1196 }
1197
1198 pub(crate) fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool {
1199 match v {
1200 Some("2") | None => {
1201 *slot = 2;
1202 true
1203 }
1204 Some("1") => {
1205 *slot = 1;
1206 true
1207 }
1208 Some("0") => {
1209 *slot = 0;
1210 true
1211 }
1212 Some(_) => false,
1213 }
1214 }
1215
1216 pub(crate) fn parse_strip(slot: &mut Strip, v: Option<&str>) -> bool {
1217 match v {
1218 Some("none") => *slot = Strip::None,
1219 Some("debuginfo") => *slot = Strip::Debuginfo,
1220 Some("symbols") => *slot = Strip::Symbols,
1221 _ => return false,
1222 }
1223 true
1224 }
1225
1226 pub(crate) fn parse_cfguard(slot: &mut CFGuard, v: Option<&str>) -> bool {
1227 if v.is_some() {
1228 let mut bool_arg = None;
1229 if parse_opt_bool(&mut bool_arg, v) {
1230 *slot = if bool_arg.unwrap() { CFGuard::Checks } else { CFGuard::Disabled };
1231 return true;
1232 }
1233 }
1234
1235 *slot = match v {
1236 None => CFGuard::Checks,
1237 Some("checks") => CFGuard::Checks,
1238 Some("nochecks") => CFGuard::NoChecks,
1239 Some(_) => return false,
1240 };
1241 true
1242 }
1243
1244 pub(crate) fn parse_cfprotection(slot: &mut CFProtection, v: Option<&str>) -> bool {
1245 if v.is_some() {
1246 let mut bool_arg = None;
1247 if parse_opt_bool(&mut bool_arg, v) {
1248 *slot = if bool_arg.unwrap() { CFProtection::Full } else { CFProtection::None };
1249 return true;
1250 }
1251 }
1252
1253 *slot = match v {
1254 None | Some("none") => CFProtection::None,
1255 Some("branch") => CFProtection::Branch,
1256 Some("return") => CFProtection::Return,
1257 Some("full") => CFProtection::Full,
1258 Some(_) => return false,
1259 };
1260 true
1261 }
1262
1263 pub(crate) fn parse_debuginfo(slot: &mut DebugInfo, v: Option<&str>) -> bool {
1264 match v {
1265 Some("0") | Some("none") => *slot = DebugInfo::None,
1266 Some("line-directives-only") => *slot = DebugInfo::LineDirectivesOnly,
1267 Some("line-tables-only") => *slot = DebugInfo::LineTablesOnly,
1268 Some("1") | Some("limited") => *slot = DebugInfo::Limited,
1269 Some("2") | Some("full") => *slot = DebugInfo::Full,
1270 _ => return false,
1271 }
1272 true
1273 }
1274
1275 pub(crate) fn parse_debuginfo_compression(
1276 slot: &mut DebugInfoCompression,
1277 v: Option<&str>,
1278 ) -> bool {
1279 match v {
1280 Some("none") => *slot = DebugInfoCompression::None,
1281 Some("zlib") => *slot = DebugInfoCompression::Zlib,
1282 Some("zstd") => *slot = DebugInfoCompression::Zstd,
1283 _ => return false,
1284 };
1285 true
1286 }
1287
1288 pub(crate) fn parse_mir_strip_debuginfo(slot: &mut MirStripDebugInfo, v: Option<&str>) -> bool {
1289 match v {
1290 Some("none") => *slot = MirStripDebugInfo::None,
1291 Some("locals-in-tiny-functions") => *slot = MirStripDebugInfo::LocalsInTinyFunctions,
1292 Some("all-locals") => *slot = MirStripDebugInfo::AllLocals,
1293 _ => return false,
1294 };
1295 true
1296 }
1297
1298 pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavorCli>, v: Option<&str>) -> bool {
1299 match v.and_then(|v| LinkerFlavorCli::from_str(v).ok()) {
1300 Some(lf) => *slot = Some(lf),
1301 _ => return false,
1302 }
1303 true
1304 }
1305
1306 pub(crate) fn parse_opt_symbol_visibility(
1307 slot: &mut Option<SymbolVisibility>,
1308 v: Option<&str>,
1309 ) -> bool {
1310 if let Some(v) = v {
1311 if let Ok(vis) = SymbolVisibility::from_str(v) {
1312 *slot = Some(vis);
1313 } else {
1314 return false;
1315 }
1316 }
1317 true
1318 }
1319
1320 pub(crate) fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
1321 match v {
1322 None => false,
1323 Some(s) if s.split('=').count() <= 2 => {
1324 *slot = Some(s.to_string());
1325 true
1326 }
1327 _ => false,
1328 }
1329 }
1330
1331 pub(crate) fn parse_time_passes_format(slot: &mut TimePassesFormat, v: Option<&str>) -> bool {
1332 match v {
1333 None => true,
1334 Some("json") => {
1335 *slot = TimePassesFormat::Json;
1336 true
1337 }
1338 Some("text") => {
1339 *slot = TimePassesFormat::Text;
1340 true
1341 }
1342 Some(_) => false,
1343 }
1344 }
1345
1346 pub(crate) fn parse_dump_mono_stats(slot: &mut DumpMonoStatsFormat, v: Option<&str>) -> bool {
1347 match v {
1348 None => true,
1349 Some("json") => {
1350 *slot = DumpMonoStatsFormat::Json;
1351 true
1352 }
1353 Some("markdown") => {
1354 *slot = DumpMonoStatsFormat::Markdown;
1355 true
1356 }
1357 Some(_) => false,
1358 }
1359 }
1360
1361 pub(crate) fn parse_offload(slot: &mut Vec<Offload>, v: Option<&str>) -> bool {
1362 let Some(v) = v else {
1363 *slot = vec![];
1364 return true;
1365 };
1366 let mut v: Vec<&str> = v.split(",").collect();
1367 v.sort_unstable();
1368 for &val in v.iter() {
1369 let variant = match val {
1370 "Enable" => Offload::Enable,
1371 _ => {
1372 return false;
1374 }
1375 };
1376 slot.push(variant);
1377 }
1378
1379 true
1380 }
1381
1382 pub(crate) fn parse_autodiff(slot: &mut Vec<AutoDiff>, v: Option<&str>) -> bool {
1383 let Some(v) = v else {
1384 *slot = vec![];
1385 return true;
1386 };
1387 let mut v: Vec<&str> = v.split(",").collect();
1388 v.sort_unstable();
1389 for &val in v.iter() {
1390 let (key, arg) = match val.split_once('=') {
1392 Some((k, a)) => (k, Some(a)),
1393 None => (val, None),
1394 };
1395
1396 let variant = match key {
1397 "Enable" => AutoDiff::Enable,
1398 "PrintTA" => AutoDiff::PrintTA,
1399 "PrintTAFn" => {
1400 if let Some(fun) = arg {
1401 AutoDiff::PrintTAFn(fun.to_string())
1402 } else {
1403 return false;
1404 }
1405 }
1406 "PrintAA" => AutoDiff::PrintAA,
1407 "PrintPerf" => AutoDiff::PrintPerf,
1408 "PrintSteps" => AutoDiff::PrintSteps,
1409 "PrintModBefore" => AutoDiff::PrintModBefore,
1410 "PrintModAfter" => AutoDiff::PrintModAfter,
1411 "PrintModFinal" => AutoDiff::PrintModFinal,
1412 "NoPostopt" => AutoDiff::NoPostopt,
1413 "PrintPasses" => AutoDiff::PrintPasses,
1414 "LooseTypes" => AutoDiff::LooseTypes,
1415 "Inline" => AutoDiff::Inline,
1416 _ => {
1417 return false;
1419 }
1420 };
1421 slot.push(variant);
1422 }
1423
1424 true
1425 }
1426
1427 pub(crate) fn parse_instrument_coverage(
1428 slot: &mut InstrumentCoverage,
1429 v: Option<&str>,
1430 ) -> bool {
1431 if v.is_some() {
1432 let mut bool_arg = false;
1433 if parse_bool(&mut bool_arg, v) {
1434 *slot = if bool_arg { InstrumentCoverage::Yes } else { InstrumentCoverage::No };
1435 return true;
1436 }
1437 }
1438
1439 let Some(v) = v else {
1440 *slot = InstrumentCoverage::Yes;
1441 return true;
1442 };
1443
1444 *slot = match v {
1447 "all" => InstrumentCoverage::Yes,
1448 "0" => InstrumentCoverage::No,
1449 _ => return false,
1450 };
1451 true
1452 }
1453
1454 pub(crate) fn parse_coverage_options(slot: &mut CoverageOptions, v: Option<&str>) -> bool {
1455 let Some(v) = v else { return true };
1456
1457 for option in v.split(',') {
1458 match option {
1459 "block" => slot.level = CoverageLevel::Block,
1460 "branch" => slot.level = CoverageLevel::Branch,
1461 "condition" => slot.level = CoverageLevel::Condition,
1462 "mcdc" => slot.level = CoverageLevel::Mcdc,
1463 "no-mir-spans" => slot.no_mir_spans = true,
1464 "discard-all-spans-in-codegen" => slot.discard_all_spans_in_codegen = true,
1465 _ => return false,
1466 }
1467 }
1468 true
1469 }
1470
1471 pub(crate) fn parse_instrument_xray(
1472 slot: &mut Option<InstrumentXRay>,
1473 v: Option<&str>,
1474 ) -> bool {
1475 if v.is_some() {
1476 let mut bool_arg = None;
1477 if parse_opt_bool(&mut bool_arg, v) {
1478 *slot = if bool_arg.unwrap() { Some(InstrumentXRay::default()) } else { None };
1479 return true;
1480 }
1481 }
1482
1483 let options = slot.get_or_insert_default();
1484 let mut seen_always = false;
1485 let mut seen_never = false;
1486 let mut seen_ignore_loops = false;
1487 let mut seen_instruction_threshold = false;
1488 let mut seen_skip_entry = false;
1489 let mut seen_skip_exit = false;
1490 for option in v.into_iter().flat_map(|v| v.split(',')) {
1491 match option {
1492 "always" if !seen_always && !seen_never => {
1493 options.always = true;
1494 options.never = false;
1495 seen_always = true;
1496 }
1497 "never" if !seen_never && !seen_always => {
1498 options.never = true;
1499 options.always = false;
1500 seen_never = true;
1501 }
1502 "ignore-loops" if !seen_ignore_loops => {
1503 options.ignore_loops = true;
1504 seen_ignore_loops = true;
1505 }
1506 option
1507 if option.starts_with("instruction-threshold")
1508 && !seen_instruction_threshold =>
1509 {
1510 let Some(("instruction-threshold", n)) = option.split_once('=') else {
1511 return false;
1512 };
1513 match n.parse() {
1514 Ok(n) => options.instruction_threshold = Some(n),
1515 Err(_) => return false,
1516 }
1517 seen_instruction_threshold = true;
1518 }
1519 "skip-entry" if !seen_skip_entry => {
1520 options.skip_entry = true;
1521 seen_skip_entry = true;
1522 }
1523 "skip-exit" if !seen_skip_exit => {
1524 options.skip_exit = true;
1525 seen_skip_exit = true;
1526 }
1527 _ => return false,
1528 }
1529 }
1530 true
1531 }
1532
1533 pub(crate) fn parse_treat_err_as_bug(
1534 slot: &mut Option<NonZero<usize>>,
1535 v: Option<&str>,
1536 ) -> bool {
1537 match v {
1538 Some(s) => match s.parse() {
1539 Ok(val) => {
1540 *slot = Some(val);
1541 true
1542 }
1543 Err(e) => {
1544 *slot = None;
1545 e.kind() == &IntErrorKind::Zero
1546 }
1547 },
1548 None => {
1549 *slot = NonZero::new(1);
1550 true
1551 }
1552 }
1553 }
1554
1555 pub(crate) fn parse_next_solver_config(slot: &mut NextSolverConfig, v: Option<&str>) -> bool {
1556 if let Some(config) = v {
1557 *slot = match config {
1558 "no" => NextSolverConfig { coherence: false, globally: false },
1559 "coherence" => NextSolverConfig { coherence: true, globally: false },
1560 "globally" => NextSolverConfig { coherence: true, globally: true },
1561 _ => return false,
1562 };
1563 } else {
1564 *slot = NextSolverConfig { coherence: true, globally: true };
1565 }
1566
1567 true
1568 }
1569
1570 pub(crate) fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
1571 if v.is_some() {
1572 let mut bool_arg = None;
1573 if parse_opt_bool(&mut bool_arg, v) {
1574 *slot = if bool_arg.unwrap() { LtoCli::Yes } else { LtoCli::No };
1575 return true;
1576 }
1577 }
1578
1579 *slot = match v {
1580 None => LtoCli::NoParam,
1581 Some("thin") => LtoCli::Thin,
1582 Some("fat") => LtoCli::Fat,
1583 Some(_) => return false,
1584 };
1585 true
1586 }
1587
1588 pub(crate) fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
1589 if v.is_some() {
1590 let mut bool_arg = None;
1591 if parse_opt_bool(&mut bool_arg, v) {
1592 *slot = if bool_arg.unwrap() {
1593 LinkerPluginLto::LinkerPluginAuto
1594 } else {
1595 LinkerPluginLto::Disabled
1596 };
1597 return true;
1598 }
1599 }
1600
1601 *slot = match v {
1602 None => LinkerPluginLto::LinkerPluginAuto,
1603 Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
1604 };
1605 true
1606 }
1607
1608 pub(crate) fn parse_switch_with_opt_path(
1609 slot: &mut SwitchWithOptPath,
1610 v: Option<&str>,
1611 ) -> bool {
1612 *slot = match v {
1613 None => SwitchWithOptPath::Enabled(None),
1614 Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
1615 };
1616 true
1617 }
1618
1619 pub(crate) fn parse_merge_functions(
1620 slot: &mut Option<MergeFunctions>,
1621 v: Option<&str>,
1622 ) -> bool {
1623 match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
1624 Some(mergefunc) => *slot = Some(mergefunc),
1625 _ => return false,
1626 }
1627 true
1628 }
1629
1630 pub(crate) fn parse_remap_path_scope(
1631 slot: &mut RemapPathScopeComponents,
1632 v: Option<&str>,
1633 ) -> bool {
1634 if let Some(v) = v {
1635 *slot = RemapPathScopeComponents::empty();
1636 for s in v.split(',') {
1637 *slot |= match s {
1638 "macro" => RemapPathScopeComponents::MACRO,
1639 "diagnostics" => RemapPathScopeComponents::DIAGNOSTICS,
1640 "debuginfo" => RemapPathScopeComponents::DEBUGINFO,
1641 "object" => RemapPathScopeComponents::OBJECT,
1642 "all" => RemapPathScopeComponents::all(),
1643 _ => return false,
1644 }
1645 }
1646 true
1647 } else {
1648 false
1649 }
1650 }
1651
1652 pub(crate) fn parse_relocation_model(slot: &mut Option<RelocModel>, v: Option<&str>) -> bool {
1653 match v.and_then(|s| RelocModel::from_str(s).ok()) {
1654 Some(relocation_model) => *slot = Some(relocation_model),
1655 None if v == Some("default") => *slot = None,
1656 _ => return false,
1657 }
1658 true
1659 }
1660
1661 pub(crate) fn parse_code_model(slot: &mut Option<CodeModel>, v: Option<&str>) -> bool {
1662 match v.and_then(|s| CodeModel::from_str(s).ok()) {
1663 Some(code_model) => *slot = Some(code_model),
1664 _ => return false,
1665 }
1666 true
1667 }
1668
1669 pub(crate) fn parse_tls_model(slot: &mut Option<TlsModel>, v: Option<&str>) -> bool {
1670 match v.and_then(|s| TlsModel::from_str(s).ok()) {
1671 Some(tls_model) => *slot = Some(tls_model),
1672 _ => return false,
1673 }
1674 true
1675 }
1676
1677 pub(crate) fn parse_terminal_url(slot: &mut TerminalUrl, v: Option<&str>) -> bool {
1678 *slot = match v {
1679 Some("on" | "" | "yes" | "y") | None => TerminalUrl::Yes,
1680 Some("off" | "no" | "n") => TerminalUrl::No,
1681 Some("auto") => TerminalUrl::Auto,
1682 _ => return false,
1683 };
1684 true
1685 }
1686
1687 pub(crate) fn parse_symbol_mangling_version(
1688 slot: &mut Option<SymbolManglingVersion>,
1689 v: Option<&str>,
1690 ) -> bool {
1691 *slot = match v {
1692 Some("legacy") => Some(SymbolManglingVersion::Legacy),
1693 Some("v0") => Some(SymbolManglingVersion::V0),
1694 Some("hashed") => Some(SymbolManglingVersion::Hashed),
1695 _ => return false,
1696 };
1697 true
1698 }
1699
1700 pub(crate) fn parse_src_file_hash(
1701 slot: &mut Option<SourceFileHashAlgorithm>,
1702 v: Option<&str>,
1703 ) -> bool {
1704 match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) {
1705 Some(hash_kind) => *slot = Some(hash_kind),
1706 _ => return false,
1707 }
1708 true
1709 }
1710
1711 pub(crate) fn parse_cargo_src_file_hash(
1712 slot: &mut Option<SourceFileHashAlgorithm>,
1713 v: Option<&str>,
1714 ) -> bool {
1715 match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) {
1716 Some(hash_kind) => {
1717 *slot = Some(hash_kind);
1718 }
1719 _ => return false,
1720 }
1721 true
1722 }
1723
1724 pub(crate) fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
1725 match v {
1726 Some(s) => {
1727 if !slot.is_empty() {
1728 slot.push(',');
1729 }
1730 slot.push_str(s);
1731 true
1732 }
1733 None => false,
1734 }
1735 }
1736
1737 pub(crate) fn parse_link_self_contained(slot: &mut LinkSelfContained, v: Option<&str>) -> bool {
1738 let s = v.unwrap_or("y");
1743 match s {
1744 "y" | "yes" | "on" => {
1745 slot.set_all_explicitly(true);
1746 return true;
1747 }
1748 "n" | "no" | "off" => {
1749 slot.set_all_explicitly(false);
1750 return true;
1751 }
1752 _ => {}
1753 }
1754
1755 for comp in s.split(',') {
1757 if slot.handle_cli_component(comp).is_none() {
1758 return false;
1759 }
1760 }
1761
1762 true
1763 }
1764
1765 pub(crate) fn parse_linker_features(slot: &mut LinkerFeaturesCli, v: Option<&str>) -> bool {
1767 match v {
1768 Some(s) => {
1769 for feature in s.split(',') {
1770 if slot.handle_cli_feature(feature).is_none() {
1771 return false;
1772 }
1773 }
1774
1775 true
1776 }
1777 None => false,
1778 }
1779 }
1780
1781 pub(crate) fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool {
1782 match v {
1783 Some("command") => *slot = Some(WasiExecModel::Command),
1784 Some("reactor") => *slot = Some(WasiExecModel::Reactor),
1785 _ => return false,
1786 }
1787 true
1788 }
1789
1790 pub(crate) fn parse_split_debuginfo(
1791 slot: &mut Option<SplitDebuginfo>,
1792 v: Option<&str>,
1793 ) -> bool {
1794 match v.and_then(|s| SplitDebuginfo::from_str(s).ok()) {
1795 Some(e) => *slot = Some(e),
1796 _ => return false,
1797 }
1798 true
1799 }
1800
1801 pub(crate) fn parse_split_dwarf_kind(slot: &mut SplitDwarfKind, v: Option<&str>) -> bool {
1802 match v.and_then(|s| SplitDwarfKind::from_str(s).ok()) {
1803 Some(e) => *slot = e,
1804 _ => return false,
1805 }
1806 true
1807 }
1808
1809 pub(crate) fn parse_stack_protector(slot: &mut StackProtector, v: Option<&str>) -> bool {
1810 match v.and_then(|s| StackProtector::from_str(s).ok()) {
1811 Some(ssp) => *slot = ssp,
1812 _ => return false,
1813 }
1814 true
1815 }
1816
1817 pub(crate) fn parse_branch_protection(
1818 slot: &mut Option<BranchProtection>,
1819 v: Option<&str>,
1820 ) -> bool {
1821 match v {
1822 Some(s) => {
1823 let slot = slot.get_or_insert_default();
1824 for opt in s.split(',') {
1825 match opt {
1826 "bti" => slot.bti = true,
1827 "pac-ret" if slot.pac_ret.is_none() => {
1828 slot.pac_ret = Some(PacRet { leaf: false, pc: false, key: PAuthKey::A })
1829 }
1830 "leaf" => match slot.pac_ret.as_mut() {
1831 Some(pac) => pac.leaf = true,
1832 _ => return false,
1833 },
1834 "b-key" => match slot.pac_ret.as_mut() {
1835 Some(pac) => pac.key = PAuthKey::B,
1836 _ => return false,
1837 },
1838 "pc" => match slot.pac_ret.as_mut() {
1839 Some(pac) => pac.pc = true,
1840 _ => return false,
1841 },
1842 _ => return false,
1843 };
1844 }
1845 }
1846 _ => return false,
1847 }
1848 true
1849 }
1850
1851 pub(crate) fn parse_collapse_macro_debuginfo(
1852 slot: &mut CollapseMacroDebuginfo,
1853 v: Option<&str>,
1854 ) -> bool {
1855 if v.is_some() {
1856 let mut bool_arg = None;
1857 if parse_opt_bool(&mut bool_arg, v) {
1858 *slot = if bool_arg.unwrap() {
1859 CollapseMacroDebuginfo::Yes
1860 } else {
1861 CollapseMacroDebuginfo::No
1862 };
1863 return true;
1864 }
1865 }
1866
1867 *slot = match v {
1868 Some("external") => CollapseMacroDebuginfo::External,
1869 _ => return false,
1870 };
1871 true
1872 }
1873
1874 pub(crate) fn parse_proc_macro_execution_strategy(
1875 slot: &mut ProcMacroExecutionStrategy,
1876 v: Option<&str>,
1877 ) -> bool {
1878 *slot = match v {
1879 Some("same-thread") => ProcMacroExecutionStrategy::SameThread,
1880 Some("cross-thread") => ProcMacroExecutionStrategy::CrossThread,
1881 _ => return false,
1882 };
1883 true
1884 }
1885
1886 pub(crate) fn parse_inlining_threshold(slot: &mut InliningThreshold, v: Option<&str>) -> bool {
1887 match v {
1888 Some("always" | "yes") => {
1889 *slot = InliningThreshold::Always;
1890 }
1891 Some("never") => {
1892 *slot = InliningThreshold::Never;
1893 }
1894 Some(v) => {
1895 if let Ok(threshold) = v.parse() {
1896 *slot = InliningThreshold::Sometimes(threshold);
1897 } else {
1898 return false;
1899 }
1900 }
1901 None => return false,
1902 }
1903 true
1904 }
1905
1906 pub(crate) fn parse_llvm_module_flag(
1907 slot: &mut Vec<(String, u32, String)>,
1908 v: Option<&str>,
1909 ) -> bool {
1910 let elements = v.unwrap_or_default().split(':').collect::<Vec<_>>();
1911 let [key, md_type, value, behavior] = elements.as_slice() else {
1912 return false;
1913 };
1914 if *md_type != "u32" {
1915 return false;
1918 }
1919 let Ok(value) = value.parse::<u32>() else {
1920 return false;
1921 };
1922 let behavior = behavior.to_lowercase();
1923 let all_behaviors =
1924 ["error", "warning", "require", "override", "append", "appendunique", "max", "min"];
1925 if !all_behaviors.contains(&behavior.as_str()) {
1926 return false;
1927 }
1928
1929 slot.push((key.to_string(), value, behavior));
1930 true
1931 }
1932
1933 pub(crate) fn parse_function_return(slot: &mut FunctionReturn, v: Option<&str>) -> bool {
1934 match v {
1935 Some("keep") => *slot = FunctionReturn::Keep,
1936 Some("thunk-extern") => *slot = FunctionReturn::ThunkExtern,
1937 _ => return false,
1938 }
1939 true
1940 }
1941
1942 pub(crate) fn parse_wasm_c_abi(_slot: &mut (), v: Option<&str>) -> bool {
1943 v == Some("spec")
1944 }
1945
1946 pub(crate) fn parse_mir_include_spans(slot: &mut MirIncludeSpans, v: Option<&str>) -> bool {
1947 *slot = match v {
1948 Some("on" | "yes" | "y" | "true") | None => MirIncludeSpans::On,
1949 Some("off" | "no" | "n" | "false") => MirIncludeSpans::Off,
1950 Some("nll") => MirIncludeSpans::Nll,
1951 _ => return false,
1952 };
1953
1954 true
1955 }
1956
1957 pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
1958 let mut bytes = 0u64;
1959 if !parse_number(&mut bytes, v) {
1960 return false;
1961 }
1962
1963 let Ok(align) = Align::from_bytes(bytes) else {
1964 return false;
1965 };
1966
1967 *slot = Some(align);
1968
1969 true
1970 }
1971}
1972
1973options! {
1974 CodegenOptions, CodegenOptionsTargetModifiers, CG_OPTIONS, cgopts, "C", "codegen",
1975
1976 #[rustc_lint_opt_deny_field_access("documented to do nothing")]
1982 ar: String = (String::new(), parse_string, [UNTRACKED],
1983 "this option is deprecated and does nothing",
1984 deprecated_do_nothing: true),
1985 #[rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field")]
1986 code_model: Option<CodeModel> = (None, parse_code_model, [TRACKED],
1987 "choose the code model to use (`rustc --print code-models` for details)"),
1988 codegen_units: Option<usize> = (None, parse_opt_number, [UNTRACKED],
1989 "divide crate into N units to optimize in parallel"),
1990 collapse_macro_debuginfo: CollapseMacroDebuginfo = (CollapseMacroDebuginfo::Unspecified,
1991 parse_collapse_macro_debuginfo, [TRACKED],
1992 "set option to collapse debuginfo for macros"),
1993 control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED],
1994 "use Windows Control Flow Guard (default: no)"),
1995 debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
1996 "explicitly enable the `cfg(debug_assertions)` directive"),
1997 debuginfo: DebugInfo = (DebugInfo::None, parse_debuginfo, [TRACKED],
1998 "debug info emission level (0-2, none, line-directives-only, \
1999 line-tables-only, limited, or full; default: 0)"),
2000 default_linker_libraries: bool = (false, parse_bool, [UNTRACKED],
2001 "allow the linker to link its default libraries (default: no)"),
2002 dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
2003 "import library generation tool (ignored except when targeting windows-gnu)"),
2004 #[rustc_lint_opt_deny_field_access("use `Session::dwarf_version` instead of this field")]
2005 dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
2006 "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
2007 embed_bitcode: bool = (true, parse_bool, [TRACKED],
2008 "emit bitcode in rlibs (default: yes)"),
2009 extra_filename: String = (String::new(), parse_string, [UNTRACKED],
2010 "extra data to put in each output filename"),
2011 force_frame_pointers: FramePointer = (FramePointer::MayOmit, parse_frame_pointer, [TRACKED],
2012 "force use of the frame pointers"),
2013 #[rustc_lint_opt_deny_field_access("use `Session::must_emit_unwind_tables` instead of this field")]
2014 force_unwind_tables: Option<bool> = (None, parse_opt_bool, [TRACKED],
2015 "force use of unwind tables"),
2016 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
2017 "enable incremental compilation"),
2018 #[rustc_lint_opt_deny_field_access("documented to do nothing")]
2019 inline_threshold: Option<u32> = (None, parse_opt_number, [UNTRACKED],
2020 "this option is deprecated and does nothing \
2021 (consider using `-Cllvm-args=--inline-threshold=...`)",
2022 deprecated_do_nothing: true),
2023 #[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")]
2024 instrument_coverage: InstrumentCoverage = (InstrumentCoverage::No, parse_instrument_coverage, [TRACKED],
2025 "instrument the generated code to support LLVM source-based code coverage reports \
2026 (note, the compiler build config must include `profiler = true`); \
2027 implies `-C symbol-mangling-version=v0`"),
2028 link_arg: () = ((), parse_string_push, [UNTRACKED],
2029 "a single extra argument to append to the linker invocation (can be used several times)"),
2030 link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
2031 "extra arguments to append to the linker invocation (space separated)"),
2032 #[rustc_lint_opt_deny_field_access("use `Session::link_dead_code` instead of this field")]
2033 link_dead_code: Option<bool> = (None, parse_opt_bool, [TRACKED],
2034 "try to generate and link dead code (default: no)"),
2035 link_self_contained: LinkSelfContained = (LinkSelfContained::default(), parse_link_self_contained, [UNTRACKED],
2036 "control whether to link Rust provided C objects/libraries or rely \
2037 on a C toolchain or linker installed in the system"),
2038 linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
2039 "system linker to link outputs with"),
2040 linker_features: LinkerFeaturesCli = (LinkerFeaturesCli::default(), parse_linker_features, [UNTRACKED],
2041 "a comma-separated list of linker features to enable (+) or disable (-): `lld`"),
2042 linker_flavor: Option<LinkerFlavorCli> = (None, parse_linker_flavor, [UNTRACKED],
2043 "linker flavor"),
2044 linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
2045 parse_linker_plugin_lto, [TRACKED],
2046 "generate build artifacts that are compatible with linker-based LTO"),
2047 llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
2048 "a list of arguments to pass to LLVM (space separated)"),
2049 #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
2050 lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
2051 "perform LLVM link-time optimizations"),
2052 metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
2053 "metadata to mangle symbol names with"),
2054 no_prepopulate_passes: bool = (false, parse_no_value, [TRACKED],
2055 "give an empty list of passes to the pass manager"),
2056 no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
2057 "disable the use of the redzone"),
2058 #[rustc_lint_opt_deny_field_access("documented to do nothing")]
2059 no_stack_check: bool = (false, parse_no_value, [UNTRACKED],
2060 "this option is deprecated and does nothing",
2061 deprecated_do_nothing: true),
2062 no_vectorize_loops: bool = (false, parse_no_value, [TRACKED],
2063 "disable loop vectorization optimization passes"),
2064 no_vectorize_slp: bool = (false, parse_no_value, [TRACKED],
2065 "disable LLVM's SLP vectorization pass"),
2066 opt_level: String = ("0".to_string(), parse_string, [TRACKED],
2067 "optimization level (0-3, s, or z; default: 0)"),
2068 #[rustc_lint_opt_deny_field_access("use `Session::overflow_checks` instead of this field")]
2069 overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
2070 "use overflow checks for integer arithmetic"),
2071 #[rustc_lint_opt_deny_field_access("use `Session::panic_strategy` instead of this field")]
2072 panic: Option<PanicStrategy> = (None, parse_opt_panic_strategy, [TRACKED],
2073 "panic strategy to compile crate with"),
2074 passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
2075 "a list of extra LLVM passes to run (space separated)"),
2076 prefer_dynamic: bool = (false, parse_bool, [TRACKED],
2077 "prefer dynamic linking to static linking (default: no)"),
2078 profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
2079 parse_switch_with_opt_path, [TRACKED],
2080 "compile the program with profiling instrumentation"),
2081 profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
2082 "use the given `.profdata` file for profile-guided optimization"),
2083 #[rustc_lint_opt_deny_field_access("use `Session::relocation_model` instead of this field")]
2084 relocation_model: Option<RelocModel> = (None, parse_relocation_model, [TRACKED],
2085 "control generation of position-independent code (PIC) \
2086 (`rustc --print relocation-models` for details)"),
2087 relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
2088 "choose which RELRO level to use"),
2089 remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
2090 "output remarks for these optimization passes (space separated, or \"all\")"),
2091 rpath: bool = (false, parse_bool, [UNTRACKED],
2092 "set rpath values in libs/exes (default: no)"),
2093 save_temps: bool = (false, parse_bool, [UNTRACKED],
2094 "save all temporary output files during compilation (default: no)"),
2095 soft_float: bool = (false, parse_bool, [TRACKED],
2096 "deprecated option: use soft float ABI (*eabihf targets only) (default: no)"),
2097 #[rustc_lint_opt_deny_field_access("use `Session::split_debuginfo` instead of this field")]
2098 split_debuginfo: Option<SplitDebuginfo> = (None, parse_split_debuginfo, [TRACKED],
2099 "how to handle split-debuginfo, a platform-specific option"),
2100 strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
2101 "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
2102 symbol_mangling_version: Option<SymbolManglingVersion> = (None,
2103 parse_symbol_mangling_version, [TRACKED],
2104 "which mangling version to use for symbol names ('legacy' (default), 'v0', or 'hashed')"),
2105 target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
2106 "select target processor (`rustc --print target-cpus` for details)"),
2107 target_feature: String = (String::new(), parse_target_feature, [TRACKED],
2108 "target specific attributes. (`rustc --print target-features` for details). \
2109 This feature is unsafe."),
2110 unsafe_allow_abi_mismatch: Vec<String> = (Vec::new(), parse_comma_list, [UNTRACKED],
2111 "Allow incompatible target modifiers in dependency crates (comma separated list)"),
2112 }
2118
2119options! {
2120 UnstableOptions, UnstableOptionsTargetModifiers, Z_OPTIONS, dbopts, "Z", "unstable",
2121
2122 allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
2128 "only allow the listed language features to be enabled in code (comma separated)"),
2129 always_encode_mir: bool = (false, parse_bool, [TRACKED],
2130 "encode MIR of all functions into the crate metadata (default: no)"),
2131 assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED],
2132 "assert that the incremental cache is in given state: \
2133 either `loaded` or `not-loaded`."),
2134 assume_incomplete_release: bool = (false, parse_bool, [TRACKED],
2135 "make cfg(version) treat the current version as incomplete (default: no)"),
2136 autodiff: Vec<crate::config::AutoDiff> = (Vec::new(), parse_autodiff, [TRACKED],
2137 "a list of autodiff flags to enable
2138 Mandatory setting:
2139 `=Enable`
2140 Optional extra settings:
2141 `=PrintTA`
2142 `=PrintAA`
2143 `=PrintPerf`
2144 `=PrintSteps`
2145 `=PrintModBefore`
2146 `=PrintModAfter`
2147 `=PrintModFinal`
2148 `=PrintPasses`,
2149 `=NoPostopt`
2150 `=LooseTypes`
2151 `=Inline`
2152 Multiple options can be combined with commas."),
2153 #[rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field")]
2154 binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
2155 "include artifacts (sysroot, crate dependencies) used during compilation in dep-info \
2156 (default: no)"),
2157 box_noalias: bool = (true, parse_bool, [TRACKED],
2158 "emit noalias metadata for box (default: yes)"),
2159 branch_protection: Option<BranchProtection> = (None, parse_branch_protection, [TRACKED],
2160 "set options for branch target identification and pointer authentication on AArch64"),
2161 build_sdylib_interface: bool = (false, parse_bool, [UNTRACKED],
2162 "whether the stable interface is being built"),
2163 cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED],
2164 "instrument control-flow architecture protection"),
2165 check_cfg_all_expected: bool = (false, parse_bool, [UNTRACKED],
2166 "show all expected values in check-cfg diagnostics (default: no)"),
2167 checksum_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_cargo_src_file_hash, [TRACKED],
2168 "hash algorithm of source files used to check freshness in cargo (`blake3` or `sha256`)"),
2169 codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
2170 "the backend to use"),
2171 contract_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
2172 "emit runtime checks for contract pre- and post-conditions (default: no)"),
2173 coverage_options: CoverageOptions = (CoverageOptions::default(), parse_coverage_options, [TRACKED],
2174 "control details of coverage instrumentation"),
2175 crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
2176 "inject the given attribute in the crate"),
2177 cross_crate_inline_threshold: InliningThreshold = (InliningThreshold::Sometimes(100), parse_inlining_threshold, [TRACKED],
2178 "threshold to allow cross crate inlining of functions"),
2179 debug_info_for_profiling: bool = (false, parse_bool, [TRACKED],
2180 "emit discriminators and other data necessary for AutoFDO"),
2181 debug_info_type_line_numbers: bool = (false, parse_bool, [TRACKED],
2182 "emit type and line information for additional data types (default: no)"),
2183 debuginfo_compression: DebugInfoCompression = (DebugInfoCompression::None, parse_debuginfo_compression, [TRACKED],
2184 "compress debug info sections (none, zlib, zstd, default: none)"),
2185 deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED],
2186 "deduplicate identical diagnostics (default: yes)"),
2187 default_visibility: Option<SymbolVisibility> = (None, parse_opt_symbol_visibility, [TRACKED],
2188 "overrides the `default_visibility` setting of the target"),
2189 dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
2190 "in dep-info output, omit targets for tracking dependencies of the dep-info files \
2191 themselves (default: no)"),
2192 direct_access_external_data: Option<bool> = (None, parse_opt_bool, [TRACKED],
2193 "Direct or use GOT indirect to reference external data symbols"),
2194 dual_proc_macros: bool = (false, parse_bool, [TRACKED],
2195 "load proc macros for both target and host, but only link to the target (default: no)"),
2196 dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
2197 "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) \
2198 (default: no)"),
2199 dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
2200 "dump MIR state to file.
2201 `val` is used to select which passes and functions to dump. For example:
2202 `all` matches all passes and functions,
2203 `foo` matches all passes for functions whose name contains 'foo',
2204 `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
2205 `foo | bar` all passes for function names containing 'foo' or 'bar'."),
2206 dump_mir_dataflow: bool = (false, parse_bool, [UNTRACKED],
2207 "in addition to `.mir` files, create graphviz `.dot` files with dataflow results \
2208 (default: no)"),
2209 dump_mir_dir: String = ("mir_dump".to_string(), parse_string, [UNTRACKED],
2210 "the directory the MIR is dumped into (default: `mir_dump`)"),
2211 dump_mir_exclude_alloc_bytes: bool = (false, parse_bool, [UNTRACKED],
2212 "exclude the raw bytes of allocations when dumping MIR (used in tests) (default: no)"),
2213 dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
2214 "exclude the pass number when dumping MIR (used in tests) (default: no)"),
2215 dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
2216 "in addition to `.mir` files, create graphviz `.dot` files (default: no)"),
2217 dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
2218 parse_switch_with_opt_path, [UNTRACKED],
2219 "output statistics about monomorphization collection"),
2220 dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED],
2221 "the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"),
2222 #[rustc_lint_opt_deny_field_access("use `Session::dwarf_version` instead of this field")]
2223 dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
2224 "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
2225 dylib_lto: bool = (false, parse_bool, [UNTRACKED],
2226 "enables LTO for dylib crate type"),
2227 eagerly_emit_delayed_bugs: bool = (false, parse_bool, [UNTRACKED],
2228 "emit delayed bugs eagerly as errors instead of stashing them and emitting \
2229 them only if an error has not been emitted"),
2230 ehcont_guard: bool = (false, parse_bool, [TRACKED],
2231 "generate Windows EHCont Guard tables"),
2232 embed_metadata: bool = (true, parse_bool, [TRACKED],
2233 "embed metadata in rlibs and dylibs (default: yes)"),
2234 embed_source: bool = (false, parse_bool, [TRACKED],
2235 "embed source text in DWARF debug sections (default: no)"),
2236 emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
2237 "emit a section containing stack size metadata (default: no)"),
2238 emit_thin_lto: bool = (true, parse_bool, [TRACKED],
2239 "emit the bc module with thin LTO info (default: yes)"),
2240 emscripten_wasm_eh: bool = (false, parse_bool, [TRACKED],
2241 "Use WebAssembly error handling for wasm32-unknown-emscripten"),
2242 enforce_type_length_limit: bool = (false, parse_bool, [TRACKED],
2243 "enforce the type length limit when monomorphizing instances in codegen"),
2244 experimental_default_bounds: bool = (false, parse_bool, [TRACKED],
2245 "enable default bounds for experimental group of auto traits"),
2246 export_executable_symbols: bool = (false, parse_bool, [TRACKED],
2247 "export symbols from executables, as if they were dynamic libraries"),
2248 external_clangrt: bool = (false, parse_bool, [UNTRACKED],
2249 "rely on user specified linker commands to find clangrt"),
2250 extra_const_ub_checks: bool = (false, parse_bool, [TRACKED],
2251 "turns on more checks to detect const UB, which can be slow (default: no)"),
2252 #[rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field")]
2253 fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
2254 "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
2255 (default: no)"),
2256 fixed_x18: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
2257 "make the x18 register reserved on AArch64 (default: no)"),
2258 flatten_format_args: bool = (true, parse_bool, [TRACKED],
2259 "flatten nested format_args!() and literals into a simplified format_args!() call \
2260 (default: yes)"),
2261 fmt_debug: FmtDebug = (FmtDebug::Full, parse_fmt_debug, [TRACKED],
2262 "how detailed `#[derive(Debug)]` should be. `full` prints types recursively, \
2263 `shallow` prints only type names, `none` prints nothing and disables `{:?}`. (default: `full`)"),
2264 force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
2265 "force all crates to be `rustc_private` unstable (default: no)"),
2266 function_return: FunctionReturn = (FunctionReturn::default(), parse_function_return, [TRACKED],
2267 "replace returns with jumps to `__x86_return_thunk` (default: `keep`)"),
2268 function_sections: Option<bool> = (None, parse_opt_bool, [TRACKED],
2269 "whether each function should go in its own section"),
2270 future_incompat_test: bool = (false, parse_bool, [UNTRACKED],
2271 "forces all lints to be future incompatible, used for internal testing (default: no)"),
2272 graphviz_dark_mode: bool = (false, parse_bool, [UNTRACKED],
2273 "use dark-themed colors in graphviz output (default: no)"),
2274 graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED],
2275 "use the given `fontname` in graphviz output; can be overridden by setting \
2276 environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"),
2277 has_thread_local: Option<bool> = (None, parse_opt_bool, [TRACKED],
2278 "explicitly enable the `cfg(target_thread_local)` directive"),
2279 higher_ranked_assumptions: bool = (false, parse_bool, [TRACKED],
2280 "allow deducing higher-ranked outlives assumptions from coroutines when proving auto traits"),
2281 hint_mostly_unused: bool = (false, parse_bool, [TRACKED],
2282 "hint that most of this crate will go unused, to minimize work for uncalled functions"),
2283 human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
2284 "generate human-readable, predictable names for codegen units (default: no)"),
2285 identify_regions: bool = (false, parse_bool, [UNTRACKED],
2286 "display unnamed regions as `'<id>`, using a non-ident unique id (default: no)"),
2287 ignore_directory_in_diagnostics_source_blocks: Vec<String> = (Vec::new(), parse_string_push, [UNTRACKED],
2288 "do not display the source code block in diagnostics for files in the directory"),
2289 incremental_ignore_spans: bool = (false, parse_bool, [TRACKED],
2290 "ignore spans during ICH computation -- used for testing (default: no)"),
2291 incremental_info: bool = (false, parse_bool, [UNTRACKED],
2292 "print high-level information about incremental reuse (or the lack thereof) \
2293 (default: no)"),
2294 incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
2295 "verify extended properties for incr. comp. (default: no):
2296 - hashes of green query instances
2297 - hash collisions of query keys
2298 - hash collisions when creating dep-nodes"),
2299 inline_llvm: bool = (true, parse_bool, [TRACKED],
2300 "enable LLVM inlining (default: yes)"),
2301 inline_mir: Option<bool> = (None, parse_opt_bool, [TRACKED],
2302 "enable MIR inlining (default: no)"),
2303 inline_mir_forwarder_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
2304 "inlining threshold when the caller is a simple forwarding function (default: 30)"),
2305 inline_mir_hint_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
2306 "inlining threshold for functions with inline hint (default: 100)"),
2307 inline_mir_preserve_debug: Option<bool> = (None, parse_opt_bool, [TRACKED],
2308 "when MIR inlining, whether to preserve debug info for callee variables \
2309 (default: preserve for debuginfo != None, otherwise remove)"),
2310 inline_mir_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
2311 "a default MIR inlining threshold (default: 50)"),
2312 input_stats: bool = (false, parse_bool, [UNTRACKED],
2313 "print some statistics about AST and HIR (default: no)"),
2314 instrument_mcount: bool = (false, parse_bool, [TRACKED],
2315 "insert function instrument code for mcount-based tracing (default: no)"),
2316 instrument_xray: Option<InstrumentXRay> = (None, parse_instrument_xray, [TRACKED],
2317 "insert function instrument code for XRay-based tracing (default: no)
2318 Optional extra settings:
2319 `=always`
2320 `=never`
2321 `=ignore-loops`
2322 `=instruction-threshold=N`
2323 `=skip-entry`
2324 `=skip-exit`
2325 Multiple options can be combined with commas."),
2326 layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED],
2327 "seed layout randomization"),
2328 link_directives: bool = (true, parse_bool, [TRACKED],
2329 "honor #[link] directives in the compiled crate (default: yes)"),
2330 link_native_libraries: bool = (true, parse_bool, [UNTRACKED],
2331 "link native libraries in the linker invocation (default: yes)"),
2332 link_only: bool = (false, parse_bool, [TRACKED],
2333 "link the `.rlink` file generated by `-Z no-link` (default: no)"),
2334 lint_llvm_ir: bool = (false, parse_bool, [TRACKED],
2335 "lint LLVM IR (default: no)"),
2336 lint_mir: bool = (false, parse_bool, [UNTRACKED],
2337 "lint MIR before and after each transformation"),
2338 llvm_module_flag: Vec<(String, u32, String)> = (Vec::new(), parse_llvm_module_flag, [TRACKED],
2339 "a list of module flags to pass to LLVM (space separated)"),
2340 llvm_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
2341 "a list LLVM plugins to enable (space separated)"),
2342 llvm_time_trace: bool = (false, parse_bool, [UNTRACKED],
2343 "generate JSON tracing data file from LLVM data (default: no)"),
2344 location_detail: LocationDetail = (LocationDetail::all(), parse_location_detail, [TRACKED],
2345 "what location details should be tracked when using caller_location, either \
2346 `none`, or a comma separated list of location details, for which \
2347 valid options are `file`, `line`, and `column` (default: `file,line,column`)"),
2348 ls: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
2349 "decode and print various parts of the crate metadata for a library crate \
2350 (space separated)"),
2351 macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
2352 "show macro backtraces (default: no)"),
2353 macro_stats: bool = (false, parse_bool, [UNTRACKED],
2354 "print some statistics about macro expansions (default: no)"),
2355 maximal_hir_to_mir_coverage: bool = (false, parse_bool, [TRACKED],
2356 "save as much information as possible about the correspondence between MIR and HIR \
2357 as source scopes (default: no)"),
2358 merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
2359 "control the operation of the MergeFunctions LLVM pass, taking \
2360 the same values as the target option of the same name"),
2361 meta_stats: bool = (false, parse_bool, [UNTRACKED],
2362 "gather metadata statistics (default: no)"),
2363 metrics_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
2364 "the directory metrics emitted by rustc are dumped into (implicitly enables default set of metrics)"),
2365 min_function_alignment: Option<Align> = (None, parse_align, [TRACKED],
2366 "align all functions to at least this many bytes. Must be a power of 2"),
2367 mir_emit_retag: bool = (false, parse_bool, [TRACKED],
2368 "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
2369 (default: no)"),
2370 mir_enable_passes: Vec<(String, bool)> = (Vec::new(), parse_list_with_polarity, [TRACKED],
2371 "use like `-Zmir-enable-passes=+DestinationPropagation,-InstSimplify`. Forces the \
2372 specified passes to be enabled, overriding all other checks. In particular, this will \
2373 enable unsound (known-buggy and hence usually disabled) passes without further warning! \
2374 Passes that are not specified are enabled or disabled by other flags as usual."),
2375 mir_include_spans: MirIncludeSpans = (MirIncludeSpans::default(), parse_mir_include_spans, [UNTRACKED],
2376 "include extra comments in mir pretty printing, like line numbers and statement indices, \
2377 details about types, etc. (boolean for all passes, 'nll' to enable in NLL MIR only, default: 'nll')"),
2378 #[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")]
2379 mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
2380 "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
2381 mir_preserve_ub: bool = (false, parse_bool, [TRACKED],
2382 "keep place mention statements and reads in trivial SwitchInt terminators, which are interpreted \
2383 e.g., by miri; implies -Zmir-opt-level=0 (default: no)"),
2384 mir_strip_debuginfo: MirStripDebugInfo = (MirStripDebugInfo::None, parse_mir_strip_debuginfo, [TRACKED],
2385 "Whether to remove some of the MIR debug info from methods. Default: None"),
2386 move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
2387 "the size at which the `large_assignments` lint starts to be emitted"),
2388 mutable_noalias: bool = (true, parse_bool, [TRACKED],
2389 "emit noalias metadata for mutable references (default: yes)"),
2390 namespaced_crates: bool = (false, parse_bool, [TRACKED],
2391 "allow crates to be namespaced by other crates (default: no)"),
2392 next_solver: NextSolverConfig = (NextSolverConfig::default(), parse_next_solver_config, [TRACKED],
2393 "enable and configure the next generation trait solver used by rustc"),
2394 nll_facts: bool = (false, parse_bool, [UNTRACKED],
2395 "dump facts from NLL analysis into side files (default: no)"),
2396 nll_facts_dir: String = ("nll-facts".to_string(), parse_string, [UNTRACKED],
2397 "the directory the NLL facts are dumped into (default: `nll-facts`)"),
2398 no_analysis: bool = (false, parse_no_value, [UNTRACKED],
2399 "parse and expand the source, but run no analysis"),
2400 no_codegen: bool = (false, parse_no_value, [TRACKED_NO_CRATE_HASH],
2401 "run all passes except codegen; no output"),
2402 no_generate_arange_section: bool = (false, parse_no_value, [TRACKED],
2403 "omit DWARF address ranges that give faster lookups"),
2404 no_implied_bounds_compat: bool = (false, parse_bool, [TRACKED],
2405 "disable the compatibility version of the `implied_bounds_ty` query"),
2406 no_jump_tables: bool = (false, parse_no_value, [TRACKED],
2407 "disable the jump tables and lookup tables that can be generated from a switch case lowering"),
2408 no_leak_check: bool = (false, parse_no_value, [UNTRACKED],
2409 "disable the 'leak check' for subtyping; unsound, but useful for tests"),
2410 no_link: bool = (false, parse_no_value, [TRACKED],
2411 "compile without linking"),
2412 no_parallel_backend: bool = (false, parse_no_value, [UNTRACKED],
2413 "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
2414 no_profiler_runtime: bool = (false, parse_no_value, [TRACKED],
2415 "prevent automatic injection of the profiler_builtins crate"),
2416 no_steal_thir: bool = (false, parse_bool, [UNTRACKED],
2417 "don't steal the THIR when we're done with it; useful for rustc drivers (default: no)"),
2418 no_trait_vptr: bool = (false, parse_no_value, [TRACKED],
2419 "disable generation of trait vptr in vtable for upcasting"),
2420 no_unique_section_names: bool = (false, parse_bool, [TRACKED],
2421 "do not use unique names for text and data sections when -Z function-sections is used"),
2422 normalize_docs: bool = (false, parse_bool, [TRACKED],
2423 "normalize associated items in rustdoc when generating documentation"),
2424 offload: Vec<crate::config::Offload> = (Vec::new(), parse_offload, [TRACKED],
2425 "a list of offload flags to enable
2426 Mandatory setting:
2427 `=Enable`
2428 Currently the only option available"),
2429 on_broken_pipe: OnBrokenPipe = (OnBrokenPipe::Default, parse_on_broken_pipe, [TRACKED],
2430 "behavior of std::io::ErrorKind::BrokenPipe (SIGPIPE)"),
2431 oom: OomStrategy = (OomStrategy::Abort, parse_oom_strategy, [TRACKED],
2432 "panic strategy for out-of-memory handling"),
2433 osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
2434 "pass `-install_name @rpath/...` to the macOS linker (default: no)"),
2435 packed_bundled_libs: bool = (false, parse_bool, [TRACKED],
2436 "change rlib format to store native libraries as archives"),
2437 panic_abort_tests: bool = (false, parse_bool, [TRACKED],
2438 "support compiling tests with panic=abort (default: no)"),
2439 panic_in_drop: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, [TRACKED],
2440 "panic strategy for panics in drops"),
2441 parse_crate_root_only: bool = (false, parse_bool, [UNTRACKED],
2442 "parse the crate root file only; do not parse other files, compile, assemble, or link \
2443 (default: no)"),
2444 patchable_function_entry: PatchableFunctionEntry = (PatchableFunctionEntry::default(), parse_patchable_function_entry, [TRACKED],
2445 "nop padding at function entry"),
2446 plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
2447 "whether to use the PLT when calling into shared libraries;
2448 only has effect for PIC code on systems with ELF binaries
2449 (default: PLT is disabled if full relro is enabled on x86_64)"),
2450 polonius: Polonius = (Polonius::default(), parse_polonius, [TRACKED],
2451 "enable polonius-based borrow-checker (default: no)"),
2452 pre_link_arg: () = ((), parse_string_push, [UNTRACKED],
2453 "a single extra argument to prepend the linker invocation (can be used several times)"),
2454 pre_link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
2455 "extra arguments to prepend to the linker invocation (space separated)"),
2456 precise_enum_drop_elaboration: bool = (true, parse_bool, [TRACKED],
2457 "use a more precise version of drop elaboration for matches on enums (default: yes). \
2458 This results in better codegen, but has caused miscompilations on some tier 2 platforms. \
2459 See #77382 and #74551."),
2460 #[rustc_lint_opt_deny_field_access("use `Session::print_codegen_stats` instead of this field")]
2461 print_codegen_stats: bool = (false, parse_bool, [UNTRACKED],
2462 "print codegen statistics (default: no)"),
2463 print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
2464 "print the LLVM optimization passes being run (default: no)"),
2465 print_mono_items: bool = (false, parse_bool, [UNTRACKED],
2466 "print the result of the monomorphization collection pass (default: no)"),
2467 print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
2468 "print layout information for each type encountered (default: no)"),
2469 proc_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
2470 "show backtraces for panics during proc-macro execution (default: no)"),
2471 proc_macro_execution_strategy: ProcMacroExecutionStrategy = (ProcMacroExecutionStrategy::SameThread,
2472 parse_proc_macro_execution_strategy, [UNTRACKED],
2473 "how to run proc-macro code (default: same-thread)"),
2474 profile_closures: bool = (false, parse_no_value, [UNTRACKED],
2475 "profile size of closures"),
2476 profile_sample_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
2477 "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"),
2478 profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED],
2479 "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"),
2480 query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
2481 "enable queries of the dependency graph for regression testing (default: no)"),
2482 randomize_layout: bool = (false, parse_bool, [TRACKED],
2483 "randomize the layout of types (default: no)"),
2484 reg_struct_return: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
2485 "On x86-32 targets, it overrides the default ABI to return small structs in registers.
2486 It is UNSOUND to link together crates that use different values for this flag!"),
2487 regparm: Option<u32> = (None, parse_opt_number, [TRACKED TARGET_MODIFIER],
2488 "On x86-32 targets, setting this to N causes the compiler to pass N arguments \
2489 in registers EAX, EDX, and ECX instead of on the stack for\
2490 \"C\", \"cdecl\", and \"stdcall\" fn.\
2491 It is UNSOUND to link together crates that use different values for this flag!"),
2492 relax_elf_relocations: Option<bool> = (None, parse_opt_bool, [TRACKED],
2493 "whether ELF relocations can be relaxed"),
2494 remap_cwd_prefix: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
2495 "remap paths under the current working directory to this path prefix"),
2496 remap_path_scope: RemapPathScopeComponents = (RemapPathScopeComponents::all(), parse_remap_path_scope, [TRACKED],
2497 "remap path scope (default: all)"),
2498 remark_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
2499 "directory into which to write optimization remarks (if not specified, they will be \
2500written to standard error output)"),
2501 retpoline: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
2502 "enables retpoline-indirect-branches and retpoline-indirect-calls target features (default: no)"),
2503 retpoline_external_thunk: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
2504 "enables retpoline-external-thunk, retpoline-indirect-branches and retpoline-indirect-calls \
2505 target features (default: no)"),
2506 sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
2507 "use a sanitizer"),
2508 sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],
2509 "enable canonical jump tables (default: yes)"),
2510 sanitizer_cfi_generalize_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
2511 "enable generalizing pointer types (default: no)"),
2512 sanitizer_cfi_normalize_integers: Option<bool> = (None, parse_opt_bool, [TRACKED],
2513 "enable normalizing integer types (default: no)"),
2514 sanitizer_dataflow_abilist: Vec<String> = (Vec::new(), parse_comma_list, [TRACKED],
2515 "additional ABI list files that control how shadow parameters are passed (comma separated)"),
2516 sanitizer_kcfi_arity: Option<bool> = (None, parse_opt_bool, [TRACKED],
2517 "enable KCFI arity indicator (default: no)"),
2518 sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
2519 "enable origins tracking in MemorySanitizer"),
2520 sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
2521 "enable recovery for selected sanitizers"),
2522 saturating_float_casts: Option<bool> = (None, parse_opt_bool, [TRACKED],
2523 "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
2524 the max/min integer respectively, and NaN is mapped to 0 (default: yes)"),
2525 self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
2526 parse_switch_with_opt_path, [UNTRACKED],
2527 "run the self profiler and output the raw event data"),
2528 self_profile_counter: String = ("wall-time".to_string(), parse_string, [UNTRACKED],
2529 "counter used by the self profiler (default: `wall-time`), one of:
2530 `wall-time` (monotonic clock, i.e. `std::time::Instant`)
2531 `instructions:u` (retired instructions, userspace-only)
2532 `instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)"
2533 ),
2534 self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
2536 "specify the events recorded by the self profiler;
2537 for example: `-Z self-profile-events=default,query-keys`
2538 all options: none, all, default, generic-activity, query-provider, query-cache-hit
2539 query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"),
2540 share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
2541 "make the current crate share its generic instantiations"),
2542 shell_argfiles: bool = (false, parse_bool, [UNTRACKED],
2543 "allow argument files to be specified with POSIX \"shell-style\" argument quoting"),
2544 simulate_remapped_rust_src_base: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
2545 "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \
2546 to rust's source base directory. only meant for testing purposes"),
2547 small_data_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
2548 "Set the threshold for objects to be stored in a \"small data\" section"),
2549 span_debug: bool = (false, parse_bool, [UNTRACKED],
2550 "forward proc_macro::Span's `Debug` impl to `Span`"),
2551 span_free_formats: bool = (false, parse_bool, [UNTRACKED],
2553 "exclude spans when debug-printing compiler state (default: no)"),
2554 split_dwarf_inlining: bool = (false, parse_bool, [TRACKED],
2555 "provide minimal debug info in the object/executable to facilitate online \
2556 symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
2557 split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [TRACKED],
2558 "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
2559 (default: `split`)
2560
2561 `split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
2562 file which is ignored by the linker
2563 `single`: sections which do not require relocation are written into object file but ignored
2564 by the linker"),
2565 split_lto_unit: Option<bool> = (None, parse_opt_bool, [TRACKED],
2566 "enable LTO unit splitting (default: no)"),
2567 src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
2568 "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
2569 #[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")]
2570 stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED],
2571 "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
2572 staticlib_allow_rdylib_deps: bool = (false, parse_bool, [TRACKED],
2573 "allow staticlibs to have rust dylib dependencies"),
2574 staticlib_prefer_dynamic: bool = (false, parse_bool, [TRACKED],
2575 "prefer dynamic linking to static linking for staticlibs (default: no)"),
2576 strict_init_checks: bool = (false, parse_bool, [TRACKED],
2577 "control if mem::uninitialized and mem::zeroed panic on more UB"),
2578 #[rustc_lint_opt_deny_field_access("use `Session::teach` instead of this field")]
2579 teach: bool = (false, parse_bool, [TRACKED],
2580 "show extended diagnostic help (default: no)"),
2581 temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
2582 "the directory the intermediate files are written to"),
2583 terminal_urls: TerminalUrl = (TerminalUrl::No, parse_terminal_url, [UNTRACKED],
2584 "use the OSC 8 hyperlink terminal specification to print hyperlinks in the compiler output"),
2585 #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
2586 thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
2587 "enable ThinLTO when possible"),
2588 #[rustc_lint_opt_deny_field_access("use `Session::threads` instead of this field")]
2593 threads: usize = (1, parse_threads, [UNTRACKED],
2594 "use a thread pool with N threads"),
2595 time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
2596 "measure time of each LLVM pass (default: no)"),
2597 time_passes: bool = (false, parse_bool, [UNTRACKED],
2598 "measure time of each rustc pass (default: no)"),
2599 time_passes_format: TimePassesFormat = (TimePassesFormat::Text, parse_time_passes_format, [UNTRACKED],
2600 "the format to use for -Z time-passes (`text` (default) or `json`)"),
2601 tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED],
2602 "sets a tiny, non-configurable limit for const eval; useful for compiler tests"),
2603 #[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")]
2604 tls_model: Option<TlsModel> = (None, parse_tls_model, [TRACKED],
2605 "choose the TLS model to use (`rustc --print tls-models` for details)"),
2606 trace_macros: bool = (false, parse_bool, [UNTRACKED],
2607 "for every macro invocation, print its name and arguments (default: no)"),
2608 track_diagnostics: bool = (false, parse_bool, [UNTRACKED],
2609 "tracks where in rustc a diagnostic was emitted"),
2610 translate_additional_ftl: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
2614 "additional fluent translation to preferentially use (for testing translation)"),
2615 translate_directionality_markers: bool = (false, parse_bool, [TRACKED],
2616 "emit directionality isolation markers in translated diagnostics"),
2617 translate_lang: Option<LanguageIdentifier> = (None, parse_opt_langid, [TRACKED],
2618 "language identifier for diagnostic output"),
2619 translate_remapped_path_to_local_path: bool = (true, parse_bool, [TRACKED],
2620 "translate remapped paths into local paths when possible (default: yes)"),
2621 trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
2622 "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"),
2623 treat_err_as_bug: Option<NonZero<usize>> = (None, parse_treat_err_as_bug, [TRACKED],
2624 "treat the `val`th error that occurs as bug (default if not specified: 0 - don't treat errors as bugs. \
2625 default if specified without a value: 1 - treat the first error as bug)"),
2626 trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
2627 "in diagnostics, use heuristics to shorten paths referring to items"),
2628 tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
2629 "select processor to schedule for (`rustc --print target-cpus` for details)"),
2630 #[rustc_lint_opt_deny_field_access("use `TyCtxt::use_typing_mode_borrowck` instead of this field")]
2631 typing_mode_borrowck: bool = (false, parse_bool, [TRACKED],
2632 "enable `TypingMode::Borrowck`, changing the way opaque types are handled during MIR borrowck"),
2633 #[rustc_lint_opt_deny_field_access("use `Session::ub_checks` instead of this field")]
2634 ub_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
2635 "emit runtime checks for Undefined Behavior (default: -Cdebug-assertions)"),
2636 ui_testing: bool = (false, parse_bool, [UNTRACKED],
2637 "emit compiler diagnostics in a form suitable for UI testing (default: no)"),
2638 uninit_const_chunk_threshold: usize = (16, parse_number, [TRACKED],
2639 "allow generating const initializers with mixed init/uninit chunks, \
2640 and set the maximum number of chunks for which this is allowed (default: 16)"),
2641 unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
2642 "take the brakes off const evaluation. NOTE: this is unsound (default: no)"),
2643 unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
2644 "present the input source, unstable (and less-pretty) variants;
2645 `normal`, `identified`,
2646 `expanded`, `expanded,identified`,
2647 `expanded,hygiene` (with internal representations),
2648 `ast-tree` (raw AST before expansion),
2649 `ast-tree,expanded` (raw AST after expansion),
2650 `hir` (the HIR), `hir,identified`,
2651 `hir,typed` (HIR with types for each node),
2652 `hir-tree` (dump the raw HIR),
2653 `thir-tree`, `thir-flat`,
2654 `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
2655 unsound_mir_opts: bool = (false, parse_bool, [TRACKED],
2656 "enable unsound and buggy MIR optimizations (default: no)"),
2657 #[rustc_lint_opt_deny_field_access("use `Session::unstable_options` instead of this field")]
2666 unstable_options: bool = (false, parse_no_value, [UNTRACKED],
2667 "adds unstable command line options to rustc interface (default: no)"),
2668 use_ctors_section: Option<bool> = (None, parse_opt_bool, [TRACKED],
2669 "use legacy .ctors section for initializers rather than .init_array"),
2670 use_sync_unwind: Option<bool> = (None, parse_opt_bool, [TRACKED],
2671 "Generate sync unwind tables instead of async unwind tables (default: no)"),
2672 validate_mir: bool = (false, parse_bool, [UNTRACKED],
2673 "validate MIR after each transformation"),
2674 verbose_asm: bool = (false, parse_bool, [TRACKED],
2675 "add descriptive comments from LLVM to the assembly (may change behavior) (default: no)"),
2676 #[rustc_lint_opt_deny_field_access("use `Session::verbose_internals` instead of this field")]
2677 verbose_internals: bool = (false, parse_bool, [TRACKED_NO_CRATE_HASH],
2678 "in general, enable more debug printouts (default: no)"),
2679 #[rustc_lint_opt_deny_field_access("use `Session::verify_llvm_ir` instead of this field")]
2680 verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
2681 "verify LLVM IR (default: no)"),
2682 virtual_function_elimination: bool = (false, parse_bool, [TRACKED],
2683 "enables dead virtual function elimination optimization. \
2684 Requires `-Clto[=[fat,yes]]`"),
2685 wasi_exec_model: Option<WasiExecModel> = (None, parse_wasi_exec_model, [TRACKED],
2686 "whether to build a wasi command or reactor"),
2687 wasm_c_abi: () = ((), parse_wasm_c_abi, [TRACKED],
2691 "use spec-compliant C ABI for `wasm32-unknown-unknown` (deprecated, always enabled)"),
2692 write_long_types_to_disk: bool = (true, parse_bool, [UNTRACKED],
2693 "whether long type names should be written to files instead of being printed in errors"),
2694 }