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 "inject-unused-local-file" => slot.inject_unused_local_file = true,
1417 _ => return false,
1418 }
1419 }
1420 true
1421 }
1422
1423 pub(crate) fn parse_instrument_xray(
1424 slot: &mut Option<InstrumentXRay>,
1425 v: Option<&str>,
1426 ) -> bool {
1427 if v.is_some() {
1428 let mut bool_arg = None;
1429 if parse_opt_bool(&mut bool_arg, v) {
1430 *slot = if bool_arg.unwrap() { Some(InstrumentXRay::default()) } else { None };
1431 return true;
1432 }
1433 }
1434
1435 let options = slot.get_or_insert_default();
1436 let mut seen_always = false;
1437 let mut seen_never = false;
1438 let mut seen_ignore_loops = false;
1439 let mut seen_instruction_threshold = false;
1440 let mut seen_skip_entry = false;
1441 let mut seen_skip_exit = false;
1442 for option in v.into_iter().flat_map(|v| v.split(',')) {
1443 match option {
1444 "always" if !seen_always && !seen_never => {
1445 options.always = true;
1446 options.never = false;
1447 seen_always = true;
1448 }
1449 "never" if !seen_never && !seen_always => {
1450 options.never = true;
1451 options.always = false;
1452 seen_never = true;
1453 }
1454 "ignore-loops" if !seen_ignore_loops => {
1455 options.ignore_loops = true;
1456 seen_ignore_loops = true;
1457 }
1458 option
1459 if option.starts_with("instruction-threshold")
1460 && !seen_instruction_threshold =>
1461 {
1462 let Some(("instruction-threshold", n)) = option.split_once('=') else {
1463 return false;
1464 };
1465 match n.parse() {
1466 Ok(n) => options.instruction_threshold = Some(n),
1467 Err(_) => return false,
1468 }
1469 seen_instruction_threshold = true;
1470 }
1471 "skip-entry" if !seen_skip_entry => {
1472 options.skip_entry = true;
1473 seen_skip_entry = true;
1474 }
1475 "skip-exit" if !seen_skip_exit => {
1476 options.skip_exit = true;
1477 seen_skip_exit = true;
1478 }
1479 _ => return false,
1480 }
1481 }
1482 true
1483 }
1484
1485 pub(crate) fn parse_treat_err_as_bug(
1486 slot: &mut Option<NonZero<usize>>,
1487 v: Option<&str>,
1488 ) -> bool {
1489 match v {
1490 Some(s) => match s.parse() {
1491 Ok(val) => {
1492 *slot = Some(val);
1493 true
1494 }
1495 Err(e) => {
1496 *slot = None;
1497 e.kind() == &IntErrorKind::Zero
1498 }
1499 },
1500 None => {
1501 *slot = NonZero::new(1);
1502 true
1503 }
1504 }
1505 }
1506
1507 pub(crate) fn parse_next_solver_config(slot: &mut NextSolverConfig, v: Option<&str>) -> bool {
1508 if let Some(config) = v {
1509 *slot = match config {
1510 "no" => NextSolverConfig { coherence: false, globally: false },
1511 "coherence" => NextSolverConfig { coherence: true, globally: false },
1512 "globally" => NextSolverConfig { coherence: true, globally: true },
1513 _ => return false,
1514 };
1515 } else {
1516 *slot = NextSolverConfig { coherence: true, globally: true };
1517 }
1518
1519 true
1520 }
1521
1522 pub(crate) fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
1523 if v.is_some() {
1524 let mut bool_arg = None;
1525 if parse_opt_bool(&mut bool_arg, v) {
1526 *slot = if bool_arg.unwrap() { LtoCli::Yes } else { LtoCli::No };
1527 return true;
1528 }
1529 }
1530
1531 *slot = match v {
1532 None => LtoCli::NoParam,
1533 Some("thin") => LtoCli::Thin,
1534 Some("fat") => LtoCli::Fat,
1535 Some(_) => return false,
1536 };
1537 true
1538 }
1539
1540 pub(crate) fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
1541 if v.is_some() {
1542 let mut bool_arg = None;
1543 if parse_opt_bool(&mut bool_arg, v) {
1544 *slot = if bool_arg.unwrap() {
1545 LinkerPluginLto::LinkerPluginAuto
1546 } else {
1547 LinkerPluginLto::Disabled
1548 };
1549 return true;
1550 }
1551 }
1552
1553 *slot = match v {
1554 None => LinkerPluginLto::LinkerPluginAuto,
1555 Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
1556 };
1557 true
1558 }
1559
1560 pub(crate) fn parse_switch_with_opt_path(
1561 slot: &mut SwitchWithOptPath,
1562 v: Option<&str>,
1563 ) -> bool {
1564 *slot = match v {
1565 None => SwitchWithOptPath::Enabled(None),
1566 Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
1567 };
1568 true
1569 }
1570
1571 pub(crate) fn parse_merge_functions(
1572 slot: &mut Option<MergeFunctions>,
1573 v: Option<&str>,
1574 ) -> bool {
1575 match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
1576 Some(mergefunc) => *slot = Some(mergefunc),
1577 _ => return false,
1578 }
1579 true
1580 }
1581
1582 pub(crate) fn parse_remap_path_scope(
1583 slot: &mut RemapPathScopeComponents,
1584 v: Option<&str>,
1585 ) -> bool {
1586 if let Some(v) = v {
1587 *slot = RemapPathScopeComponents::empty();
1588 for s in v.split(',') {
1589 *slot |= match s {
1590 "macro" => RemapPathScopeComponents::MACRO,
1591 "diagnostics" => RemapPathScopeComponents::DIAGNOSTICS,
1592 "debuginfo" => RemapPathScopeComponents::DEBUGINFO,
1593 "object" => RemapPathScopeComponents::OBJECT,
1594 "all" => RemapPathScopeComponents::all(),
1595 _ => return false,
1596 }
1597 }
1598 true
1599 } else {
1600 false
1601 }
1602 }
1603
1604 pub(crate) fn parse_relocation_model(slot: &mut Option<RelocModel>, v: Option<&str>) -> bool {
1605 match v.and_then(|s| RelocModel::from_str(s).ok()) {
1606 Some(relocation_model) => *slot = Some(relocation_model),
1607 None if v == Some("default") => *slot = None,
1608 _ => return false,
1609 }
1610 true
1611 }
1612
1613 pub(crate) fn parse_code_model(slot: &mut Option<CodeModel>, v: Option<&str>) -> bool {
1614 match v.and_then(|s| CodeModel::from_str(s).ok()) {
1615 Some(code_model) => *slot = Some(code_model),
1616 _ => return false,
1617 }
1618 true
1619 }
1620
1621 pub(crate) fn parse_tls_model(slot: &mut Option<TlsModel>, v: Option<&str>) -> bool {
1622 match v.and_then(|s| TlsModel::from_str(s).ok()) {
1623 Some(tls_model) => *slot = Some(tls_model),
1624 _ => return false,
1625 }
1626 true
1627 }
1628
1629 pub(crate) fn parse_terminal_url(slot: &mut TerminalUrl, v: Option<&str>) -> bool {
1630 *slot = match v {
1631 Some("on" | "" | "yes" | "y") | None => TerminalUrl::Yes,
1632 Some("off" | "no" | "n") => TerminalUrl::No,
1633 Some("auto") => TerminalUrl::Auto,
1634 _ => return false,
1635 };
1636 true
1637 }
1638
1639 pub(crate) fn parse_symbol_mangling_version(
1640 slot: &mut Option<SymbolManglingVersion>,
1641 v: Option<&str>,
1642 ) -> bool {
1643 *slot = match v {
1644 Some("legacy") => Some(SymbolManglingVersion::Legacy),
1645 Some("v0") => Some(SymbolManglingVersion::V0),
1646 Some("hashed") => Some(SymbolManglingVersion::Hashed),
1647 _ => return false,
1648 };
1649 true
1650 }
1651
1652 pub(crate) fn parse_src_file_hash(
1653 slot: &mut Option<SourceFileHashAlgorithm>,
1654 v: Option<&str>,
1655 ) -> bool {
1656 match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) {
1657 Some(hash_kind) => *slot = Some(hash_kind),
1658 _ => return false,
1659 }
1660 true
1661 }
1662
1663 pub(crate) fn parse_cargo_src_file_hash(
1664 slot: &mut Option<SourceFileHashAlgorithm>,
1665 v: Option<&str>,
1666 ) -> bool {
1667 match v.and_then(|s| SourceFileHashAlgorithm::from_str(s).ok()) {
1668 Some(hash_kind) => {
1669 *slot = Some(hash_kind);
1670 }
1671 _ => return false,
1672 }
1673 true
1674 }
1675
1676 pub(crate) fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool {
1677 match v {
1678 Some(s) => {
1679 if !slot.is_empty() {
1680 slot.push(',');
1681 }
1682 slot.push_str(s);
1683 true
1684 }
1685 None => false,
1686 }
1687 }
1688
1689 pub(crate) fn parse_link_self_contained(slot: &mut LinkSelfContained, v: Option<&str>) -> bool {
1690 let s = v.unwrap_or("y");
1695 match s {
1696 "y" | "yes" | "on" => {
1697 slot.set_all_explicitly(true);
1698 return true;
1699 }
1700 "n" | "no" | "off" => {
1701 slot.set_all_explicitly(false);
1702 return true;
1703 }
1704 _ => {}
1705 }
1706
1707 for comp in s.split(',') {
1709 if slot.handle_cli_component(comp).is_none() {
1710 return false;
1711 }
1712 }
1713
1714 true
1715 }
1716
1717 pub(crate) fn parse_linker_features(slot: &mut LinkerFeaturesCli, v: Option<&str>) -> bool {
1719 match v {
1720 Some(s) => {
1721 for feature in s.split(',') {
1722 if slot.handle_cli_feature(feature).is_none() {
1723 return false;
1724 }
1725 }
1726
1727 true
1728 }
1729 None => false,
1730 }
1731 }
1732
1733 pub(crate) fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool {
1734 match v {
1735 Some("command") => *slot = Some(WasiExecModel::Command),
1736 Some("reactor") => *slot = Some(WasiExecModel::Reactor),
1737 _ => return false,
1738 }
1739 true
1740 }
1741
1742 pub(crate) fn parse_split_debuginfo(
1743 slot: &mut Option<SplitDebuginfo>,
1744 v: Option<&str>,
1745 ) -> bool {
1746 match v.and_then(|s| SplitDebuginfo::from_str(s).ok()) {
1747 Some(e) => *slot = Some(e),
1748 _ => return false,
1749 }
1750 true
1751 }
1752
1753 pub(crate) fn parse_split_dwarf_kind(slot: &mut SplitDwarfKind, v: Option<&str>) -> bool {
1754 match v.and_then(|s| SplitDwarfKind::from_str(s).ok()) {
1755 Some(e) => *slot = e,
1756 _ => return false,
1757 }
1758 true
1759 }
1760
1761 pub(crate) fn parse_stack_protector(slot: &mut StackProtector, v: Option<&str>) -> bool {
1762 match v.and_then(|s| StackProtector::from_str(s).ok()) {
1763 Some(ssp) => *slot = ssp,
1764 _ => return false,
1765 }
1766 true
1767 }
1768
1769 pub(crate) fn parse_branch_protection(
1770 slot: &mut Option<BranchProtection>,
1771 v: Option<&str>,
1772 ) -> bool {
1773 match v {
1774 Some(s) => {
1775 let slot = slot.get_or_insert_default();
1776 for opt in s.split(',') {
1777 match opt {
1778 "bti" => slot.bti = true,
1779 "pac-ret" if slot.pac_ret.is_none() => {
1780 slot.pac_ret = Some(PacRet { leaf: false, pc: false, key: PAuthKey::A })
1781 }
1782 "leaf" => match slot.pac_ret.as_mut() {
1783 Some(pac) => pac.leaf = true,
1784 _ => return false,
1785 },
1786 "b-key" => match slot.pac_ret.as_mut() {
1787 Some(pac) => pac.key = PAuthKey::B,
1788 _ => return false,
1789 },
1790 "pc" => match slot.pac_ret.as_mut() {
1791 Some(pac) => pac.pc = true,
1792 _ => return false,
1793 },
1794 _ => return false,
1795 };
1796 }
1797 }
1798 _ => return false,
1799 }
1800 true
1801 }
1802
1803 pub(crate) fn parse_collapse_macro_debuginfo(
1804 slot: &mut CollapseMacroDebuginfo,
1805 v: Option<&str>,
1806 ) -> bool {
1807 if v.is_some() {
1808 let mut bool_arg = None;
1809 if parse_opt_bool(&mut bool_arg, v) {
1810 *slot = if bool_arg.unwrap() {
1811 CollapseMacroDebuginfo::Yes
1812 } else {
1813 CollapseMacroDebuginfo::No
1814 };
1815 return true;
1816 }
1817 }
1818
1819 *slot = match v {
1820 Some("external") => CollapseMacroDebuginfo::External,
1821 _ => return false,
1822 };
1823 true
1824 }
1825
1826 pub(crate) fn parse_proc_macro_execution_strategy(
1827 slot: &mut ProcMacroExecutionStrategy,
1828 v: Option<&str>,
1829 ) -> bool {
1830 *slot = match v {
1831 Some("same-thread") => ProcMacroExecutionStrategy::SameThread,
1832 Some("cross-thread") => ProcMacroExecutionStrategy::CrossThread,
1833 _ => return false,
1834 };
1835 true
1836 }
1837
1838 pub(crate) fn parse_inlining_threshold(slot: &mut InliningThreshold, v: Option<&str>) -> bool {
1839 match v {
1840 Some("always" | "yes") => {
1841 *slot = InliningThreshold::Always;
1842 }
1843 Some("never") => {
1844 *slot = InliningThreshold::Never;
1845 }
1846 Some(v) => {
1847 if let Ok(threshold) = v.parse() {
1848 *slot = InliningThreshold::Sometimes(threshold);
1849 } else {
1850 return false;
1851 }
1852 }
1853 None => return false,
1854 }
1855 true
1856 }
1857
1858 pub(crate) fn parse_llvm_module_flag(
1859 slot: &mut Vec<(String, u32, String)>,
1860 v: Option<&str>,
1861 ) -> bool {
1862 let elements = v.unwrap_or_default().split(':').collect::<Vec<_>>();
1863 let [key, md_type, value, behavior] = elements.as_slice() else {
1864 return false;
1865 };
1866 if *md_type != "u32" {
1867 return false;
1870 }
1871 let Ok(value) = value.parse::<u32>() else {
1872 return false;
1873 };
1874 let behavior = behavior.to_lowercase();
1875 let all_behaviors =
1876 ["error", "warning", "require", "override", "append", "appendunique", "max", "min"];
1877 if !all_behaviors.contains(&behavior.as_str()) {
1878 return false;
1879 }
1880
1881 slot.push((key.to_string(), value, behavior));
1882 true
1883 }
1884
1885 pub(crate) fn parse_function_return(slot: &mut FunctionReturn, v: Option<&str>) -> bool {
1886 match v {
1887 Some("keep") => *slot = FunctionReturn::Keep,
1888 Some("thunk-extern") => *slot = FunctionReturn::ThunkExtern,
1889 _ => return false,
1890 }
1891 true
1892 }
1893
1894 pub(crate) fn parse_wasm_c_abi(slot: &mut WasmCAbi, v: Option<&str>) -> bool {
1895 match v {
1896 Some("spec") => *slot = WasmCAbi::Spec,
1897 Some("legacy") => *slot = WasmCAbi::Legacy { with_lint: false },
1899 _ => return false,
1900 }
1901 true
1902 }
1903
1904 pub(crate) fn parse_mir_include_spans(slot: &mut MirIncludeSpans, v: Option<&str>) -> bool {
1905 *slot = match v {
1906 Some("on" | "yes" | "y" | "true") | None => MirIncludeSpans::On,
1907 Some("off" | "no" | "n" | "false") => MirIncludeSpans::Off,
1908 Some("nll") => MirIncludeSpans::Nll,
1909 _ => return false,
1910 };
1911
1912 true
1913 }
1914
1915 pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
1916 let mut bytes = 0u64;
1917 if !parse_number(&mut bytes, v) {
1918 return false;
1919 }
1920
1921 let Ok(align) = Align::from_bytes(bytes) else {
1922 return false;
1923 };
1924
1925 *slot = Some(align);
1926
1927 true
1928 }
1929}
1930
1931options! {
1932 CodegenOptions, CodegenOptionsTargetModifiers, CG_OPTIONS, cgopts, "C", "codegen",
1933
1934 #[rustc_lint_opt_deny_field_access("documented to do nothing")]
1940 ar: String = (String::new(), parse_string, [UNTRACKED],
1941 "this option is deprecated and does nothing",
1942 deprecated_do_nothing: true),
1943 #[rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field")]
1944 code_model: Option<CodeModel> = (None, parse_code_model, [TRACKED],
1945 "choose the code model to use (`rustc --print code-models` for details)"),
1946 codegen_units: Option<usize> = (None, parse_opt_number, [UNTRACKED],
1947 "divide crate into N units to optimize in parallel"),
1948 collapse_macro_debuginfo: CollapseMacroDebuginfo = (CollapseMacroDebuginfo::Unspecified,
1949 parse_collapse_macro_debuginfo, [TRACKED],
1950 "set option to collapse debuginfo for macros"),
1951 control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED],
1952 "use Windows Control Flow Guard (default: no)"),
1953 debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
1954 "explicitly enable the `cfg(debug_assertions)` directive"),
1955 debuginfo: DebugInfo = (DebugInfo::None, parse_debuginfo, [TRACKED],
1956 "debug info emission level (0-2, none, line-directives-only, \
1957 line-tables-only, limited, or full; default: 0)"),
1958 default_linker_libraries: bool = (false, parse_bool, [UNTRACKED],
1959 "allow the linker to link its default libraries (default: no)"),
1960 dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
1961 "import library generation tool (ignored except when targeting windows-gnu)"),
1962 #[rustc_lint_opt_deny_field_access("use `Session::dwarf_version` instead of this field")]
1963 dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
1964 "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
1965 embed_bitcode: bool = (true, parse_bool, [TRACKED],
1966 "emit bitcode in rlibs (default: yes)"),
1967 extra_filename: String = (String::new(), parse_string, [UNTRACKED],
1968 "extra data to put in each output filename"),
1969 force_frame_pointers: FramePointer = (FramePointer::MayOmit, parse_frame_pointer, [TRACKED],
1970 "force use of the frame pointers"),
1971 #[rustc_lint_opt_deny_field_access("use `Session::must_emit_unwind_tables` instead of this field")]
1972 force_unwind_tables: Option<bool> = (None, parse_opt_bool, [TRACKED],
1973 "force use of unwind tables"),
1974 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1975 "enable incremental compilation"),
1976 #[rustc_lint_opt_deny_field_access("documented to do nothing")]
1977 inline_threshold: Option<u32> = (None, parse_opt_number, [UNTRACKED],
1978 "this option is deprecated and does nothing \
1979 (consider using `-Cllvm-args=--inline-threshold=...`)",
1980 deprecated_do_nothing: true),
1981 #[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")]
1982 instrument_coverage: InstrumentCoverage = (InstrumentCoverage::No, parse_instrument_coverage, [TRACKED],
1983 "instrument the generated code to support LLVM source-based code coverage reports \
1984 (note, the compiler build config must include `profiler = true`); \
1985 implies `-C symbol-mangling-version=v0`"),
1986 link_arg: () = ((), parse_string_push, [UNTRACKED],
1987 "a single extra argument to append to the linker invocation (can be used several times)"),
1988 link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
1989 "extra arguments to append to the linker invocation (space separated)"),
1990 #[rustc_lint_opt_deny_field_access("use `Session::link_dead_code` instead of this field")]
1991 link_dead_code: Option<bool> = (None, parse_opt_bool, [TRACKED],
1992 "try to generate and link dead code (default: no)"),
1993 link_self_contained: LinkSelfContained = (LinkSelfContained::default(), parse_link_self_contained, [UNTRACKED],
1994 "control whether to link Rust provided C objects/libraries or rely \
1995 on a C toolchain or linker installed in the system"),
1996 linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
1997 "system linker to link outputs with"),
1998 linker_flavor: Option<LinkerFlavorCli> = (None, parse_linker_flavor, [UNTRACKED],
1999 "linker flavor"),
2000 linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
2001 parse_linker_plugin_lto, [TRACKED],
2002 "generate build artifacts that are compatible with linker-based LTO"),
2003 llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
2004 "a list of arguments to pass to LLVM (space separated)"),
2005 #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
2006 lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
2007 "perform LLVM link-time optimizations"),
2008 metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
2009 "metadata to mangle symbol names with"),
2010 no_prepopulate_passes: bool = (false, parse_no_value, [TRACKED],
2011 "give an empty list of passes to the pass manager"),
2012 no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
2013 "disable the use of the redzone"),
2014 #[rustc_lint_opt_deny_field_access("documented to do nothing")]
2015 no_stack_check: bool = (false, parse_no_value, [UNTRACKED],
2016 "this option is deprecated and does nothing",
2017 deprecated_do_nothing: true),
2018 no_vectorize_loops: bool = (false, parse_no_value, [TRACKED],
2019 "disable loop vectorization optimization passes"),
2020 no_vectorize_slp: bool = (false, parse_no_value, [TRACKED],
2021 "disable LLVM's SLP vectorization pass"),
2022 opt_level: String = ("0".to_string(), parse_string, [TRACKED],
2023 "optimization level (0-3, s, or z; default: 0)"),
2024 #[rustc_lint_opt_deny_field_access("use `Session::overflow_checks` instead of this field")]
2025 overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
2026 "use overflow checks for integer arithmetic"),
2027 #[rustc_lint_opt_deny_field_access("use `Session::panic_strategy` instead of this field")]
2028 panic: Option<PanicStrategy> = (None, parse_opt_panic_strategy, [TRACKED],
2029 "panic strategy to compile crate with"),
2030 passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
2031 "a list of extra LLVM passes to run (space separated)"),
2032 prefer_dynamic: bool = (false, parse_bool, [TRACKED],
2033 "prefer dynamic linking to static linking (default: no)"),
2034 profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
2035 parse_switch_with_opt_path, [TRACKED],
2036 "compile the program with profiling instrumentation"),
2037 profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
2038 "use the given `.profdata` file for profile-guided optimization"),
2039 #[rustc_lint_opt_deny_field_access("use `Session::relocation_model` instead of this field")]
2040 relocation_model: Option<RelocModel> = (None, parse_relocation_model, [TRACKED],
2041 "control generation of position-independent code (PIC) \
2042 (`rustc --print relocation-models` for details)"),
2043 relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
2044 "choose which RELRO level to use"),
2045 remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
2046 "output remarks for these optimization passes (space separated, or \"all\")"),
2047 rpath: bool = (false, parse_bool, [UNTRACKED],
2048 "set rpath values in libs/exes (default: no)"),
2049 save_temps: bool = (false, parse_bool, [UNTRACKED],
2050 "save all temporary output files during compilation (default: no)"),
2051 soft_float: bool = (false, parse_bool, [TRACKED],
2052 "deprecated option: use soft float ABI (*eabihf targets only) (default: no)"),
2053 #[rustc_lint_opt_deny_field_access("use `Session::split_debuginfo` instead of this field")]
2054 split_debuginfo: Option<SplitDebuginfo> = (None, parse_split_debuginfo, [TRACKED],
2055 "how to handle split-debuginfo, a platform-specific option"),
2056 strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
2057 "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
2058 symbol_mangling_version: Option<SymbolManglingVersion> = (None,
2059 parse_symbol_mangling_version, [TRACKED],
2060 "which mangling version to use for symbol names ('legacy' (default), 'v0', or 'hashed')"),
2061 target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
2062 "select target processor (`rustc --print target-cpus` for details)"),
2063 target_feature: String = (String::new(), parse_target_feature, [TRACKED],
2064 "target specific attributes. (`rustc --print target-features` for details). \
2065 This feature is unsafe."),
2066 unsafe_allow_abi_mismatch: Vec<String> = (Vec::new(), parse_comma_list, [UNTRACKED],
2067 "Allow incompatible target modifiers in dependency crates (comma separated list)"),
2068 }
2074
2075options! {
2076 UnstableOptions, UnstableOptionsTargetModifiers, Z_OPTIONS, dbopts, "Z", "unstable",
2077
2078 allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
2084 "only allow the listed language features to be enabled in code (comma separated)"),
2085 always_encode_mir: bool = (false, parse_bool, [TRACKED],
2086 "encode MIR of all functions into the crate metadata (default: no)"),
2087 assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED],
2088 "assert that the incremental cache is in given state: \
2089 either `loaded` or `not-loaded`."),
2090 assume_incomplete_release: bool = (false, parse_bool, [TRACKED],
2091 "make cfg(version) treat the current version as incomplete (default: no)"),
2092 autodiff: Vec<crate::config::AutoDiff> = (Vec::new(), parse_autodiff, [TRACKED],
2093 "a list of autodiff flags to enable
2094 Mandatory setting:
2095 `=Enable`
2096 Optional extra settings:
2097 `=PrintTA`
2098 `=PrintAA`
2099 `=PrintPerf`
2100 `=PrintSteps`
2101 `=PrintModBefore`
2102 `=PrintModAfter`
2103 `=PrintModFinal`
2104 `=PrintPasses`,
2105 `=NoPostopt`
2106 `=LooseTypes`
2107 `=Inline`
2108 Multiple options can be combined with commas."),
2109 #[rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field")]
2110 binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
2111 "include artifacts (sysroot, crate dependencies) used during compilation in dep-info \
2112 (default: no)"),
2113 box_noalias: bool = (true, parse_bool, [TRACKED],
2114 "emit noalias metadata for box (default: yes)"),
2115 branch_protection: Option<BranchProtection> = (None, parse_branch_protection, [TRACKED],
2116 "set options for branch target identification and pointer authentication on AArch64"),
2117 build_sdylib_interface: bool = (false, parse_bool, [UNTRACKED],
2118 "whether the stable interface is being built"),
2119 cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED],
2120 "instrument control-flow architecture protection"),
2121 check_cfg_all_expected: bool = (false, parse_bool, [UNTRACKED],
2122 "show all expected values in check-cfg diagnostics (default: no)"),
2123 checksum_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_cargo_src_file_hash, [TRACKED],
2124 "hash algorithm of source files used to check freshness in cargo (`blake3` or `sha256`)"),
2125 codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
2126 "the backend to use"),
2127 combine_cgu: bool = (false, parse_bool, [TRACKED],
2128 "combine CGUs into a single one"),
2129 contract_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
2130 "emit runtime checks for contract pre- and post-conditions (default: no)"),
2131 coverage_options: CoverageOptions = (CoverageOptions::default(), parse_coverage_options, [TRACKED],
2132 "control details of coverage instrumentation"),
2133 crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
2134 "inject the given attribute in the crate"),
2135 cross_crate_inline_threshold: InliningThreshold = (InliningThreshold::Sometimes(100), parse_inlining_threshold, [TRACKED],
2136 "threshold to allow cross crate inlining of functions"),
2137 debug_info_for_profiling: bool = (false, parse_bool, [TRACKED],
2138 "emit discriminators and other data necessary for AutoFDO"),
2139 debug_info_type_line_numbers: bool = (false, parse_bool, [TRACKED],
2140 "emit type and line information for additional data types (default: no)"),
2141 debuginfo_compression: DebugInfoCompression = (DebugInfoCompression::None, parse_debuginfo_compression, [TRACKED],
2142 "compress debug info sections (none, zlib, zstd, default: none)"),
2143 deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED],
2144 "deduplicate identical diagnostics (default: yes)"),
2145 default_visibility: Option<SymbolVisibility> = (None, parse_opt_symbol_visibility, [TRACKED],
2146 "overrides the `default_visibility` setting of the target"),
2147 dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
2148 "in dep-info output, omit targets for tracking dependencies of the dep-info files \
2149 themselves (default: no)"),
2150 direct_access_external_data: Option<bool> = (None, parse_opt_bool, [TRACKED],
2151 "Direct or use GOT indirect to reference external data symbols"),
2152 dual_proc_macros: bool = (false, parse_bool, [TRACKED],
2153 "load proc macros for both target and host, but only link to the target (default: no)"),
2154 dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
2155 "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) \
2156 (default: no)"),
2157 dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
2158 "dump MIR state to file.
2159 `val` is used to select which passes and functions to dump. For example:
2160 `all` matches all passes and functions,
2161 `foo` matches all passes for functions whose name contains 'foo',
2162 `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
2163 `foo | bar` all passes for function names containing 'foo' or 'bar'."),
2164 dump_mir_dataflow: bool = (false, parse_bool, [UNTRACKED],
2165 "in addition to `.mir` files, create graphviz `.dot` files with dataflow results \
2166 (default: no)"),
2167 dump_mir_dir: String = ("mir_dump".to_string(), parse_string, [UNTRACKED],
2168 "the directory the MIR is dumped into (default: `mir_dump`)"),
2169 dump_mir_exclude_alloc_bytes: bool = (false, parse_bool, [UNTRACKED],
2170 "exclude the raw bytes of allocations when dumping MIR (used in tests) (default: no)"),
2171 dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
2172 "exclude the pass number when dumping MIR (used in tests) (default: no)"),
2173 dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
2174 "in addition to `.mir` files, create graphviz `.dot` files (default: no)"),
2175 dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
2176 parse_switch_with_opt_path, [UNTRACKED],
2177 "output statistics about monomorphization collection"),
2178 dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED],
2179 "the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"),
2180 #[rustc_lint_opt_deny_field_access("use `Session::dwarf_version` instead of this field")]
2181 dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
2182 "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
2183 dylib_lto: bool = (false, parse_bool, [UNTRACKED],
2184 "enables LTO for dylib crate type"),
2185 eagerly_emit_delayed_bugs: bool = (false, parse_bool, [UNTRACKED],
2186 "emit delayed bugs eagerly as errors instead of stashing them and emitting \
2187 them only if an error has not been emitted"),
2188 ehcont_guard: bool = (false, parse_bool, [TRACKED],
2189 "generate Windows EHCont Guard tables"),
2190 embed_metadata: bool = (true, parse_bool, [TRACKED],
2191 "embed metadata in rlibs and dylibs (default: yes)"),
2192 embed_source: bool = (false, parse_bool, [TRACKED],
2193 "embed source text in DWARF debug sections (default: no)"),
2194 emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
2195 "emit a section containing stack size metadata (default: no)"),
2196 emit_thin_lto: bool = (true, parse_bool, [TRACKED],
2197 "emit the bc module with thin LTO info (default: yes)"),
2198 emscripten_wasm_eh: bool = (false, parse_bool, [TRACKED],
2199 "Use WebAssembly error handling for wasm32-unknown-emscripten"),
2200 enforce_type_length_limit: bool = (false, parse_bool, [TRACKED],
2201 "enforce the type length limit when monomorphizing instances in codegen"),
2202 experimental_default_bounds: bool = (false, parse_bool, [TRACKED],
2203 "enable default bounds for experimental group of auto traits"),
2204 export_executable_symbols: bool = (false, parse_bool, [TRACKED],
2205 "export symbols from executables, as if they were dynamic libraries"),
2206 external_clangrt: bool = (false, parse_bool, [UNTRACKED],
2207 "rely on user specified linker commands to find clangrt"),
2208 extra_const_ub_checks: bool = (false, parse_bool, [TRACKED],
2209 "turns on more checks to detect const UB, which can be slow (default: no)"),
2210 #[rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field")]
2211 fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
2212 "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
2213 (default: no)"),
2214 fixed_x18: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
2215 "make the x18 register reserved on AArch64 (default: no)"),
2216 flatten_format_args: bool = (true, parse_bool, [TRACKED],
2217 "flatten nested format_args!() and literals into a simplified format_args!() call \
2218 (default: yes)"),
2219 fmt_debug: FmtDebug = (FmtDebug::Full, parse_fmt_debug, [TRACKED],
2220 "how detailed `#[derive(Debug)]` should be. `full` prints types recursively, \
2221 `shallow` prints only type names, `none` prints nothing and disables `{:?}`. (default: `full`)"),
2222 force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
2223 "force all crates to be `rustc_private` unstable (default: no)"),
2224 function_return: FunctionReturn = (FunctionReturn::default(), parse_function_return, [TRACKED],
2225 "replace returns with jumps to `__x86_return_thunk` (default: `keep`)"),
2226 function_sections: Option<bool> = (None, parse_opt_bool, [TRACKED],
2227 "whether each function should go in its own section"),
2228 future_incompat_test: bool = (false, parse_bool, [UNTRACKED],
2229 "forces all lints to be future incompatible, used for internal testing (default: no)"),
2230 graphviz_dark_mode: bool = (false, parse_bool, [UNTRACKED],
2231 "use dark-themed colors in graphviz output (default: no)"),
2232 graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED],
2233 "use the given `fontname` in graphviz output; can be overridden by setting \
2234 environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"),
2235 has_thread_local: Option<bool> = (None, parse_opt_bool, [TRACKED],
2236 "explicitly enable the `cfg(target_thread_local)` directive"),
2237 human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
2238 "generate human-readable, predictable names for codegen units (default: no)"),
2239 identify_regions: bool = (false, parse_bool, [UNTRACKED],
2240 "display unnamed regions as `'<id>`, using a non-ident unique id (default: no)"),
2241 ignore_directory_in_diagnostics_source_blocks: Vec<String> = (Vec::new(), parse_string_push, [UNTRACKED],
2242 "do not display the source code block in diagnostics for files in the directory"),
2243 incremental_ignore_spans: bool = (false, parse_bool, [TRACKED],
2244 "ignore spans during ICH computation -- used for testing (default: no)"),
2245 incremental_info: bool = (false, parse_bool, [UNTRACKED],
2246 "print high-level information about incremental reuse (or the lack thereof) \
2247 (default: no)"),
2248 incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
2249 "verify extended properties for incr. comp. (default: no):
2250 - hashes of green query instances
2251 - hash collisions of query keys
2252 - hash collisions when creating dep-nodes"),
2253 inline_llvm: bool = (true, parse_bool, [TRACKED],
2254 "enable LLVM inlining (default: yes)"),
2255 inline_mir: Option<bool> = (None, parse_opt_bool, [TRACKED],
2256 "enable MIR inlining (default: no)"),
2257 inline_mir_forwarder_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
2258 "inlining threshold when the caller is a simple forwarding function (default: 30)"),
2259 inline_mir_hint_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
2260 "inlining threshold for functions with inline hint (default: 100)"),
2261 inline_mir_preserve_debug: Option<bool> = (None, parse_opt_bool, [TRACKED],
2262 "when MIR inlining, whether to preserve debug info for callee variables \
2263 (default: preserve for debuginfo != None, otherwise remove)"),
2264 inline_mir_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
2265 "a default MIR inlining threshold (default: 50)"),
2266 input_stats: bool = (false, parse_bool, [UNTRACKED],
2267 "print some statistics about AST and HIR (default: no)"),
2268 instrument_mcount: bool = (false, parse_bool, [TRACKED],
2269 "insert function instrument code for mcount-based tracing (default: no)"),
2270 instrument_xray: Option<InstrumentXRay> = (None, parse_instrument_xray, [TRACKED],
2271 "insert function instrument code for XRay-based tracing (default: no)
2272 Optional extra settings:
2273 `=always`
2274 `=never`
2275 `=ignore-loops`
2276 `=instruction-threshold=N`
2277 `=skip-entry`
2278 `=skip-exit`
2279 Multiple options can be combined with commas."),
2280 layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED],
2281 "seed layout randomization"),
2282 link_directives: bool = (true, parse_bool, [TRACKED],
2283 "honor #[link] directives in the compiled crate (default: yes)"),
2284 link_native_libraries: bool = (true, parse_bool, [UNTRACKED],
2285 "link native libraries in the linker invocation (default: yes)"),
2286 link_only: bool = (false, parse_bool, [TRACKED],
2287 "link the `.rlink` file generated by `-Z no-link` (default: no)"),
2288 linker_features: LinkerFeaturesCli = (LinkerFeaturesCli::default(), parse_linker_features, [UNTRACKED],
2289 "a comma-separated list of linker features to enable (+) or disable (-): `lld`"),
2290 lint_llvm_ir: bool = (false, parse_bool, [TRACKED],
2291 "lint LLVM IR (default: no)"),
2292 lint_mir: bool = (false, parse_bool, [UNTRACKED],
2293 "lint MIR before and after each transformation"),
2294 llvm_module_flag: Vec<(String, u32, String)> = (Vec::new(), parse_llvm_module_flag, [TRACKED],
2295 "a list of module flags to pass to LLVM (space separated)"),
2296 llvm_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
2297 "a list LLVM plugins to enable (space separated)"),
2298 llvm_time_trace: bool = (false, parse_bool, [UNTRACKED],
2299 "generate JSON tracing data file from LLVM data (default: no)"),
2300 location_detail: LocationDetail = (LocationDetail::all(), parse_location_detail, [TRACKED],
2301 "what location details should be tracked when using caller_location, either \
2302 `none`, or a comma separated list of location details, for which \
2303 valid options are `file`, `line`, and `column` (default: `file,line,column`)"),
2304 ls: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
2305 "decode and print various parts of the crate metadata for a library crate \
2306 (space separated)"),
2307 macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
2308 "show macro backtraces (default: no)"),
2309 maximal_hir_to_mir_coverage: bool = (false, parse_bool, [TRACKED],
2310 "save as much information as possible about the correspondence between MIR and HIR \
2311 as source scopes (default: no)"),
2312 merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
2313 "control the operation of the MergeFunctions LLVM pass, taking \
2314 the same values as the target option of the same name"),
2315 meta_stats: bool = (false, parse_bool, [UNTRACKED],
2316 "gather metadata statistics (default: no)"),
2317 metrics_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
2318 "the directory metrics emitted by rustc are dumped into (implicitly enables default set of metrics)"),
2319 min_function_alignment: Option<Align> = (None, parse_align, [TRACKED],
2320 "align all functions to at least this many bytes. Must be a power of 2"),
2321 mir_emit_retag: bool = (false, parse_bool, [TRACKED],
2322 "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
2323 (default: no)"),
2324 mir_enable_passes: Vec<(String, bool)> = (Vec::new(), parse_list_with_polarity, [TRACKED],
2325 "use like `-Zmir-enable-passes=+DestinationPropagation,-InstSimplify`. Forces the \
2326 specified passes to be enabled, overriding all other checks. In particular, this will \
2327 enable unsound (known-buggy and hence usually disabled) passes without further warning! \
2328 Passes that are not specified are enabled or disabled by other flags as usual."),
2329 mir_include_spans: MirIncludeSpans = (MirIncludeSpans::default(), parse_mir_include_spans, [UNTRACKED],
2330 "include extra comments in mir pretty printing, like line numbers and statement indices, \
2331 details about types, etc. (boolean for all passes, 'nll' to enable in NLL MIR only, default: 'nll')"),
2332 #[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")]
2333 mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
2334 "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
2335 mir_preserve_ub: bool = (false, parse_bool, [TRACKED],
2336 "keep place mention statements and reads in trivial SwitchInt terminators, which are interpreted \
2337 e.g., by miri; implies -Zmir-opt-level=0 (default: no)"),
2338 mir_strip_debuginfo: MirStripDebugInfo = (MirStripDebugInfo::None, parse_mir_strip_debuginfo, [TRACKED],
2339 "Whether to remove some of the MIR debug info from methods. Default: None"),
2340 move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
2341 "the size at which the `large_assignments` lint starts to be emitted"),
2342 mutable_noalias: bool = (true, parse_bool, [TRACKED],
2343 "emit noalias metadata for mutable references (default: yes)"),
2344 namespaced_crates: bool = (false, parse_bool, [TRACKED],
2345 "allow crates to be namespaced by other crates (default: no)"),
2346 next_solver: NextSolverConfig = (NextSolverConfig::default(), parse_next_solver_config, [TRACKED],
2347 "enable and configure the next generation trait solver used by rustc"),
2348 nll_facts: bool = (false, parse_bool, [UNTRACKED],
2349 "dump facts from NLL analysis into side files (default: no)"),
2350 nll_facts_dir: String = ("nll-facts".to_string(), parse_string, [UNTRACKED],
2351 "the directory the NLL facts are dumped into (default: `nll-facts`)"),
2352 no_analysis: bool = (false, parse_no_value, [UNTRACKED],
2353 "parse and expand the source, but run no analysis"),
2354 no_codegen: bool = (false, parse_no_value, [TRACKED_NO_CRATE_HASH],
2355 "run all passes except codegen; no output"),
2356 no_generate_arange_section: bool = (false, parse_no_value, [TRACKED],
2357 "omit DWARF address ranges that give faster lookups"),
2358 no_implied_bounds_compat: bool = (false, parse_bool, [TRACKED],
2359 "disable the compatibility version of the `implied_bounds_ty` query"),
2360 no_jump_tables: bool = (false, parse_no_value, [TRACKED],
2361 "disable the jump tables and lookup tables that can be generated from a switch case lowering"),
2362 no_leak_check: bool = (false, parse_no_value, [UNTRACKED],
2363 "disable the 'leak check' for subtyping; unsound, but useful for tests"),
2364 no_link: bool = (false, parse_no_value, [TRACKED],
2365 "compile without linking"),
2366 no_parallel_backend: bool = (false, parse_no_value, [UNTRACKED],
2367 "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
2368 no_profiler_runtime: bool = (false, parse_no_value, [TRACKED],
2369 "prevent automatic injection of the profiler_builtins crate"),
2370 no_trait_vptr: bool = (false, parse_no_value, [TRACKED],
2371 "disable generation of trait vptr in vtable for upcasting"),
2372 no_unique_section_names: bool = (false, parse_bool, [TRACKED],
2373 "do not use unique names for text and data sections when -Z function-sections is used"),
2374 normalize_docs: bool = (false, parse_bool, [TRACKED],
2375 "normalize associated items in rustdoc when generating documentation"),
2376 on_broken_pipe: OnBrokenPipe = (OnBrokenPipe::Default, parse_on_broken_pipe, [TRACKED],
2377 "behavior of std::io::ErrorKind::BrokenPipe (SIGPIPE)"),
2378 oom: OomStrategy = (OomStrategy::Abort, parse_oom_strategy, [TRACKED],
2379 "panic strategy for out-of-memory handling"),
2380 osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
2381 "pass `-install_name @rpath/...` to the macOS linker (default: no)"),
2382 packed_bundled_libs: bool = (false, parse_bool, [TRACKED],
2383 "change rlib format to store native libraries as archives"),
2384 panic_abort_tests: bool = (false, parse_bool, [TRACKED],
2385 "support compiling tests with panic=abort (default: no)"),
2386 panic_in_drop: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, [TRACKED],
2387 "panic strategy for panics in drops"),
2388 parse_crate_root_only: bool = (false, parse_bool, [UNTRACKED],
2389 "parse the crate root file only; do not parse other files, compile, assemble, or link \
2390 (default: no)"),
2391 patchable_function_entry: PatchableFunctionEntry = (PatchableFunctionEntry::default(), parse_patchable_function_entry, [TRACKED],
2392 "nop padding at function entry"),
2393 plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
2394 "whether to use the PLT when calling into shared libraries;
2395 only has effect for PIC code on systems with ELF binaries
2396 (default: PLT is disabled if full relro is enabled on x86_64)"),
2397 polonius: Polonius = (Polonius::default(), parse_polonius, [TRACKED],
2398 "enable polonius-based borrow-checker (default: no)"),
2399 pre_link_arg: () = ((), parse_string_push, [UNTRACKED],
2400 "a single extra argument to prepend the linker invocation (can be used several times)"),
2401 pre_link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
2402 "extra arguments to prepend to the linker invocation (space separated)"),
2403 precise_enum_drop_elaboration: bool = (true, parse_bool, [TRACKED],
2404 "use a more precise version of drop elaboration for matches on enums (default: yes). \
2405 This results in better codegen, but has caused miscompilations on some tier 2 platforms. \
2406 See #77382 and #74551."),
2407 #[rustc_lint_opt_deny_field_access("use `Session::print_codegen_stats` instead of this field")]
2408 print_codegen_stats: bool = (false, parse_bool, [UNTRACKED],
2409 "print codegen statistics (default: no)"),
2410 print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
2411 "print the LLVM optimization passes being run (default: no)"),
2412 print_mono_items: bool = (false, parse_bool, [UNTRACKED],
2413 "print the result of the monomorphization collection pass (default: no)"),
2414 print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
2415 "print layout information for each type encountered (default: no)"),
2416 proc_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
2417 "show backtraces for panics during proc-macro execution (default: no)"),
2418 proc_macro_execution_strategy: ProcMacroExecutionStrategy = (ProcMacroExecutionStrategy::SameThread,
2419 parse_proc_macro_execution_strategy, [UNTRACKED],
2420 "how to run proc-macro code (default: same-thread)"),
2421 profile_closures: bool = (false, parse_no_value, [UNTRACKED],
2422 "profile size of closures"),
2423 profile_sample_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
2424 "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"),
2425 profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED],
2426 "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"),
2427 query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
2428 "enable queries of the dependency graph for regression testing (default: no)"),
2429 randomize_layout: bool = (false, parse_bool, [TRACKED],
2430 "randomize the layout of types (default: no)"),
2431 reg_struct_return: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
2432 "On x86-32 targets, it overrides the default ABI to return small structs in registers.
2433 It is UNSOUND to link together crates that use different values for this flag!"),
2434 regparm: Option<u32> = (None, parse_opt_number, [TRACKED TARGET_MODIFIER],
2435 "On x86-32 targets, setting this to N causes the compiler to pass N arguments \
2436 in registers EAX, EDX, and ECX instead of on the stack for\
2437 \"C\", \"cdecl\", and \"stdcall\" fn.\
2438 It is UNSOUND to link together crates that use different values for this flag!"),
2439 relax_elf_relocations: Option<bool> = (None, parse_opt_bool, [TRACKED],
2440 "whether ELF relocations can be relaxed"),
2441 remap_cwd_prefix: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
2442 "remap paths under the current working directory to this path prefix"),
2443 remap_path_scope: RemapPathScopeComponents = (RemapPathScopeComponents::all(), parse_remap_path_scope, [TRACKED],
2444 "remap path scope (default: all)"),
2445 remark_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
2446 "directory into which to write optimization remarks (if not specified, they will be \
2447written to standard error output)"),
2448 sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
2449 "use a sanitizer"),
2450 sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],
2451 "enable canonical jump tables (default: yes)"),
2452 sanitizer_cfi_generalize_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
2453 "enable generalizing pointer types (default: no)"),
2454 sanitizer_cfi_normalize_integers: Option<bool> = (None, parse_opt_bool, [TRACKED],
2455 "enable normalizing integer types (default: no)"),
2456 sanitizer_dataflow_abilist: Vec<String> = (Vec::new(), parse_comma_list, [TRACKED],
2457 "additional ABI list files that control how shadow parameters are passed (comma separated)"),
2458 sanitizer_kcfi_arity: Option<bool> = (None, parse_opt_bool, [TRACKED],
2459 "enable KCFI arity indicator (default: no)"),
2460 sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
2461 "enable origins tracking in MemorySanitizer"),
2462 sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
2463 "enable recovery for selected sanitizers"),
2464 saturating_float_casts: Option<bool> = (None, parse_opt_bool, [TRACKED],
2465 "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
2466 the max/min integer respectively, and NaN is mapped to 0 (default: yes)"),
2467 self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
2468 parse_switch_with_opt_path, [UNTRACKED],
2469 "run the self profiler and output the raw event data"),
2470 self_profile_counter: String = ("wall-time".to_string(), parse_string, [UNTRACKED],
2471 "counter used by the self profiler (default: `wall-time`), one of:
2472 `wall-time` (monotonic clock, i.e. `std::time::Instant`)
2473 `instructions:u` (retired instructions, userspace-only)
2474 `instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)"
2475 ),
2476 self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
2478 "specify the events recorded by the self profiler;
2479 for example: `-Z self-profile-events=default,query-keys`
2480 all options: none, all, default, generic-activity, query-provider, query-cache-hit
2481 query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"),
2482 share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
2483 "make the current crate share its generic instantiations"),
2484 shell_argfiles: bool = (false, parse_bool, [UNTRACKED],
2485 "allow argument files to be specified with POSIX \"shell-style\" argument quoting"),
2486 simulate_remapped_rust_src_base: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
2487 "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \
2488 to rust's source base directory. only meant for testing purposes"),
2489 small_data_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
2490 "Set the threshold for objects to be stored in a \"small data\" section"),
2491 span_debug: bool = (false, parse_bool, [UNTRACKED],
2492 "forward proc_macro::Span's `Debug` impl to `Span`"),
2493 span_free_formats: bool = (false, parse_bool, [UNTRACKED],
2495 "exclude spans when debug-printing compiler state (default: no)"),
2496 split_dwarf_inlining: bool = (false, parse_bool, [TRACKED],
2497 "provide minimal debug info in the object/executable to facilitate online \
2498 symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
2499 split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [TRACKED],
2500 "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
2501 (default: `split`)
2502
2503 `split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
2504 file which is ignored by the linker
2505 `single`: sections which do not require relocation are written into object file but ignored
2506 by the linker"),
2507 split_lto_unit: Option<bool> = (None, parse_opt_bool, [TRACKED],
2508 "enable LTO unit splitting (default: no)"),
2509 src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
2510 "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
2511 #[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")]
2512 stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED],
2513 "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
2514 staticlib_allow_rdylib_deps: bool = (false, parse_bool, [TRACKED],
2515 "allow staticlibs to have rust dylib dependencies"),
2516 staticlib_prefer_dynamic: bool = (false, parse_bool, [TRACKED],
2517 "prefer dynamic linking to static linking for staticlibs (default: no)"),
2518 strict_init_checks: bool = (false, parse_bool, [TRACKED],
2519 "control if mem::uninitialized and mem::zeroed panic on more UB"),
2520 #[rustc_lint_opt_deny_field_access("use `Session::teach` instead of this field")]
2521 teach: bool = (false, parse_bool, [TRACKED],
2522 "show extended diagnostic help (default: no)"),
2523 temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
2524 "the directory the intermediate files are written to"),
2525 terminal_urls: TerminalUrl = (TerminalUrl::No, parse_terminal_url, [UNTRACKED],
2526 "use the OSC 8 hyperlink terminal specification to print hyperlinks in the compiler output"),
2527 #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
2528 thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
2529 "enable ThinLTO when possible"),
2530 #[rustc_lint_opt_deny_field_access("use `Session::threads` instead of this field")]
2535 threads: usize = (1, parse_threads, [UNTRACKED],
2536 "use a thread pool with N threads"),
2537 time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
2538 "measure time of each LLVM pass (default: no)"),
2539 time_passes: bool = (false, parse_bool, [UNTRACKED],
2540 "measure time of each rustc pass (default: no)"),
2541 time_passes_format: TimePassesFormat = (TimePassesFormat::Text, parse_time_passes_format, [UNTRACKED],
2542 "the format to use for -Z time-passes (`text` (default) or `json`)"),
2543 tiny_const_eval_limit: bool = (false, parse_bool, [TRACKED],
2544 "sets a tiny, non-configurable limit for const eval; useful for compiler tests"),
2545 #[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")]
2546 tls_model: Option<TlsModel> = (None, parse_tls_model, [TRACKED],
2547 "choose the TLS model to use (`rustc --print tls-models` for details)"),
2548 trace_macros: bool = (false, parse_bool, [UNTRACKED],
2549 "for every macro invocation, print its name and arguments (default: no)"),
2550 track_diagnostics: bool = (false, parse_bool, [UNTRACKED],
2551 "tracks where in rustc a diagnostic was emitted"),
2552 translate_additional_ftl: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
2556 "additional fluent translation to preferentially use (for testing translation)"),
2557 translate_directionality_markers: bool = (false, parse_bool, [TRACKED],
2558 "emit directionality isolation markers in translated diagnostics"),
2559 translate_lang: Option<LanguageIdentifier> = (None, parse_opt_langid, [TRACKED],
2560 "language identifier for diagnostic output"),
2561 translate_remapped_path_to_local_path: bool = (true, parse_bool, [TRACKED],
2562 "translate remapped paths into local paths when possible (default: yes)"),
2563 trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED],
2564 "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"),
2565 treat_err_as_bug: Option<NonZero<usize>> = (None, parse_treat_err_as_bug, [TRACKED],
2566 "treat the `val`th error that occurs as bug (default if not specified: 0 - don't treat errors as bugs. \
2567 default if specified without a value: 1 - treat the first error as bug)"),
2568 trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],
2569 "in diagnostics, use heuristics to shorten paths referring to items"),
2570 tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
2571 "select processor to schedule for (`rustc --print target-cpus` for details)"),
2572 #[rustc_lint_opt_deny_field_access("use `TyCtxt::use_typing_mode_borrowck` instead of this field")]
2573 typing_mode_borrowck: bool = (false, parse_bool, [TRACKED],
2574 "enable `TypingMode::Borrowck`, changing the way opaque types are handled during MIR borrowck"),
2575 #[rustc_lint_opt_deny_field_access("use `Session::ub_checks` instead of this field")]
2576 ub_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
2577 "emit runtime checks for Undefined Behavior (default: -Cdebug-assertions)"),
2578 ui_testing: bool = (false, parse_bool, [UNTRACKED],
2579 "emit compiler diagnostics in a form suitable for UI testing (default: no)"),
2580 uninit_const_chunk_threshold: usize = (16, parse_number, [TRACKED],
2581 "allow generating const initializers with mixed init/uninit chunks, \
2582 and set the maximum number of chunks for which this is allowed (default: 16)"),
2583 unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
2584 "take the brakes off const evaluation. NOTE: this is unsound (default: no)"),
2585 unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
2586 "present the input source, unstable (and less-pretty) variants;
2587 `normal`, `identified`,
2588 `expanded`, `expanded,identified`,
2589 `expanded,hygiene` (with internal representations),
2590 `ast-tree` (raw AST before expansion),
2591 `ast-tree,expanded` (raw AST after expansion),
2592 `hir` (the HIR), `hir,identified`,
2593 `hir,typed` (HIR with types for each node),
2594 `hir-tree` (dump the raw HIR),
2595 `thir-tree`, `thir-flat`,
2596 `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
2597 unsound_mir_opts: bool = (false, parse_bool, [TRACKED],
2598 "enable unsound and buggy MIR optimizations (default: no)"),
2599 #[rustc_lint_opt_deny_field_access("use `Session::unstable_options` instead of this field")]
2608 unstable_options: bool = (false, parse_no_value, [UNTRACKED],
2609 "adds unstable command line options to rustc interface (default: no)"),
2610 use_ctors_section: Option<bool> = (None, parse_opt_bool, [TRACKED],
2611 "use legacy .ctors section for initializers rather than .init_array"),
2612 use_sync_unwind: Option<bool> = (None, parse_opt_bool, [TRACKED],
2613 "Generate sync unwind tables instead of async unwind tables (default: no)"),
2614 validate_mir: bool = (false, parse_bool, [UNTRACKED],
2615 "validate MIR after each transformation"),
2616 verbose_asm: bool = (false, parse_bool, [TRACKED],
2617 "add descriptive comments from LLVM to the assembly (may change behavior) (default: no)"),
2618 #[rustc_lint_opt_deny_field_access("use `Session::verbose_internals` instead of this field")]
2619 verbose_internals: bool = (false, parse_bool, [TRACKED_NO_CRATE_HASH],
2620 "in general, enable more debug printouts (default: no)"),
2621 #[rustc_lint_opt_deny_field_access("use `Session::verify_llvm_ir` instead of this field")]
2622 verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
2623 "verify LLVM IR (default: no)"),
2624 virtual_function_elimination: bool = (false, parse_bool, [TRACKED],
2625 "enables dead virtual function elimination optimization. \
2626 Requires `-Clto[=[fat,yes]]`"),
2627 wasi_exec_model: Option<WasiExecModel> = (None, parse_wasi_exec_model, [TRACKED],
2628 "whether to build a wasi command or reactor"),
2629 wasm_c_abi: WasmCAbi = (WasmCAbi::Legacy { with_lint: true }, parse_wasm_c_abi, [TRACKED],
2630 "use spec-compliant C ABI for `wasm32-unknown-unknown` (default: legacy)"),
2631 write_long_types_to_disk: bool = (true, parse_bool, [UNTRACKED],
2632 "whether long type names should be written to files instead of being printed in errors"),
2633 }