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