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