1use std::str::FromStr;
5
6use serde::{Deserialize, Deserializer};
7
8use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX;
9use crate::core::config::toml::TomlConfig;
10use crate::core::config::{
11 DebuginfoLevel, Merge, ReplaceOpt, RustcLto, StringOrBool, set, threads_from_config,
12};
13use crate::flags::Warnings;
14use crate::{
15 BTreeSet, CodegenBackendKind, Config, HashSet, PathBuf, TargetSelection, define_config, exit,
16};
17
18define_config! {
19 struct Rust {
21 optimize: Option<RustOptimize> = "optimize",
22 debug: Option<bool> = "debug",
23 codegen_units: Option<u32> = "codegen-units",
24 codegen_units_std: Option<u32> = "codegen-units-std",
25 rustc_debug_assertions: Option<bool> = "debug-assertions",
26 randomize_layout: Option<bool> = "randomize-layout",
27 std_debug_assertions: Option<bool> = "debug-assertions-std",
28 tools_debug_assertions: Option<bool> = "debug-assertions-tools",
29 overflow_checks: Option<bool> = "overflow-checks",
30 overflow_checks_std: Option<bool> = "overflow-checks-std",
31 debug_logging: Option<bool> = "debug-logging",
32 debuginfo_level: Option<DebuginfoLevel> = "debuginfo-level",
33 debuginfo_level_rustc: Option<DebuginfoLevel> = "debuginfo-level-rustc",
34 debuginfo_level_std: Option<DebuginfoLevel> = "debuginfo-level-std",
35 debuginfo_level_tools: Option<DebuginfoLevel> = "debuginfo-level-tools",
36 debuginfo_level_tests: Option<DebuginfoLevel> = "debuginfo-level-tests",
37 backtrace: Option<bool> = "backtrace",
38 incremental: Option<bool> = "incremental",
39 default_linker: Option<String> = "default-linker",
40 channel: Option<String> = "channel",
41 musl_root: Option<String> = "musl-root",
42 rpath: Option<bool> = "rpath",
43 strip: Option<bool> = "strip",
44 frame_pointers: Option<bool> = "frame-pointers",
45 stack_protector: Option<String> = "stack-protector",
46 verbose_tests: Option<bool> = "verbose-tests",
47 optimize_tests: Option<bool> = "optimize-tests",
48 codegen_tests: Option<bool> = "codegen-tests",
49 omit_git_hash: Option<bool> = "omit-git-hash",
50 dist_src: Option<bool> = "dist-src",
51 save_toolstates: Option<String> = "save-toolstates",
52 codegen_backends: Option<Vec<String>> = "codegen-backends",
53 llvm_bitcode_linker: Option<bool> = "llvm-bitcode-linker",
54 lld: Option<bool> = "lld",
55 lld_mode: Option<LldMode> = "use-lld",
56 llvm_tools: Option<bool> = "llvm-tools",
57 deny_warnings: Option<bool> = "deny-warnings",
58 backtrace_on_ice: Option<bool> = "backtrace-on-ice",
59 verify_llvm_ir: Option<bool> = "verify-llvm-ir",
60 thin_lto_import_instr_limit: Option<u32> = "thin-lto-import-instr-limit",
61 remap_debuginfo: Option<bool> = "remap-debuginfo",
62 jemalloc: Option<bool> = "jemalloc",
63 test_compare_mode: Option<bool> = "test-compare-mode",
64 llvm_libunwind: Option<String> = "llvm-libunwind",
65 control_flow_guard: Option<bool> = "control-flow-guard",
66 ehcont_guard: Option<bool> = "ehcont-guard",
67 new_symbol_mangling: Option<bool> = "new-symbol-mangling",
68 profile_generate: Option<String> = "profile-generate",
69 profile_use: Option<String> = "profile-use",
70 download_rustc: Option<StringOrBool> = "download-rustc",
72 lto: Option<String> = "lto",
73 validate_mir_opts: Option<u32> = "validate-mir-opts",
74 std_features: Option<BTreeSet<String>> = "std-features",
75 }
76}
77
78#[derive(Copy, Clone, Default, Debug, PartialEq)]
90pub enum LldMode {
91 #[default]
93 Unused,
94 SelfContained,
96 External,
100}
101
102impl LldMode {
103 pub fn is_used(&self) -> bool {
104 match self {
105 LldMode::SelfContained | LldMode::External => true,
106 LldMode::Unused => false,
107 }
108 }
109}
110
111impl<'de> Deserialize<'de> for LldMode {
112 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
113 where
114 D: Deserializer<'de>,
115 {
116 struct LldModeVisitor;
117
118 impl serde::de::Visitor<'_> for LldModeVisitor {
119 type Value = LldMode;
120
121 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 formatter.write_str("one of true, 'self-contained' or 'external'")
123 }
124
125 fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
126 where
127 E: serde::de::Error,
128 {
129 Ok(if v { LldMode::External } else { LldMode::Unused })
130 }
131
132 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
133 where
134 E: serde::de::Error,
135 {
136 match v {
137 "external" => Ok(LldMode::External),
138 "self-contained" => Ok(LldMode::SelfContained),
139 _ => Err(E::custom(format!("unknown mode {v}"))),
140 }
141 }
142 }
143
144 deserializer.deserialize_any(LldModeVisitor)
145 }
146}
147
148#[derive(Clone, Debug, PartialEq, Eq)]
149pub enum RustOptimize {
150 String(String),
151 Int(u8),
152 Bool(bool),
153}
154
155impl Default for RustOptimize {
156 fn default() -> RustOptimize {
157 RustOptimize::Bool(false)
158 }
159}
160
161impl<'de> Deserialize<'de> for RustOptimize {
162 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
163 where
164 D: Deserializer<'de>,
165 {
166 deserializer.deserialize_any(OptimizeVisitor)
167 }
168}
169
170struct OptimizeVisitor;
171
172impl serde::de::Visitor<'_> for OptimizeVisitor {
173 type Value = RustOptimize;
174
175 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 formatter.write_str(r#"one of: 0, 1, 2, 3, "s", "z", true, false"#)
177 }
178
179 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
180 where
181 E: serde::de::Error,
182 {
183 if matches!(value, "s" | "z") {
184 Ok(RustOptimize::String(value.to_string()))
185 } else {
186 Err(serde::de::Error::custom(format_optimize_error_msg(value)))
187 }
188 }
189
190 fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
191 where
192 E: serde::de::Error,
193 {
194 if matches!(value, 0..=3) {
195 Ok(RustOptimize::Int(value as u8))
196 } else {
197 Err(serde::de::Error::custom(format_optimize_error_msg(value)))
198 }
199 }
200
201 fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
202 where
203 E: serde::de::Error,
204 {
205 Ok(RustOptimize::Bool(value))
206 }
207}
208
209fn format_optimize_error_msg(v: impl std::fmt::Display) -> String {
210 format!(
211 r#"unrecognized option for rust optimize: "{v}", expected one of 0, 1, 2, 3, "s", "z", true, false"#
212 )
213}
214
215impl RustOptimize {
216 pub(crate) fn is_release(&self) -> bool {
217 match &self {
218 RustOptimize::Bool(true) | RustOptimize::String(_) => true,
219 RustOptimize::Int(i) => *i > 0,
220 RustOptimize::Bool(false) => false,
221 }
222 }
223
224 pub(crate) fn get_opt_level(&self) -> Option<String> {
225 match &self {
226 RustOptimize::String(s) => Some(s.clone()),
227 RustOptimize::Int(i) => Some(i.to_string()),
228 RustOptimize::Bool(_) => None,
229 }
230 }
231}
232
233pub fn check_incompatible_options_for_ci_rustc(
236 host: TargetSelection,
237 current_config_toml: TomlConfig,
238 ci_config_toml: TomlConfig,
239) -> Result<(), String> {
240 macro_rules! err {
241 ($current:expr, $expected:expr, $config_section:expr) => {
242 if let Some(current) = &$current {
243 if Some(current) != $expected.as_ref() {
244 return Err(format!(
245 "ERROR: Setting `{}` is incompatible with `rust.download-rustc`. \
246 Current value: {:?}, Expected value(s): {}{:?}",
247 format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")),
248 $current,
249 if $expected.is_some() { "None/" } else { "" },
250 $expected,
251 ));
252 };
253 };
254 };
255 }
256
257 macro_rules! warn {
258 ($current:expr, $expected:expr, $config_section:expr) => {
259 if let Some(current) = &$current {
260 if Some(current) != $expected.as_ref() {
261 println!(
262 "WARNING: `{}` has no effect with `rust.download-rustc`. \
263 Current value: {:?}, Expected value(s): {}{:?}",
264 format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")),
265 $current,
266 if $expected.is_some() { "None/" } else { "" },
267 $expected,
268 );
269 };
270 };
271 };
272 }
273
274 let current_profiler = current_config_toml.build.as_ref().and_then(|b| b.profiler);
275 let profiler = ci_config_toml.build.as_ref().and_then(|b| b.profiler);
276 err!(current_profiler, profiler, "build");
277
278 let current_optimized_compiler_builtins =
279 current_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins);
280 let optimized_compiler_builtins =
281 ci_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins);
282 err!(current_optimized_compiler_builtins, optimized_compiler_builtins, "build");
283
284 let host_str = host.to_string();
287 if let Some(current_cfg) = current_config_toml.target.as_ref().and_then(|c| c.get(&host_str))
288 && current_cfg.profiler.is_some()
289 {
290 let ci_target_toml = ci_config_toml.target.as_ref().and_then(|c| c.get(&host_str));
291 let ci_cfg = ci_target_toml.ok_or(format!(
292 "Target specific config for '{host_str}' is not present for CI-rustc"
293 ))?;
294
295 let profiler = &ci_cfg.profiler;
296 err!(current_cfg.profiler, profiler, "build");
297
298 let optimized_compiler_builtins = &ci_cfg.optimized_compiler_builtins;
299 err!(current_cfg.optimized_compiler_builtins, optimized_compiler_builtins, "build");
300 }
301
302 let (Some(current_rust_config), Some(ci_rust_config)) =
303 (current_config_toml.rust, ci_config_toml.rust)
304 else {
305 return Ok(());
306 };
307
308 let Rust {
309 optimize,
311 randomize_layout,
312 debug_logging,
313 debuginfo_level_rustc,
314 llvm_tools,
315 llvm_bitcode_linker,
316 lto,
317 stack_protector,
318 strip,
319 lld_mode,
320 jemalloc,
321 rpath,
322 channel,
323 default_linker,
324 std_features,
325
326 incremental: _,
328 debug: _,
329 codegen_units: _,
330 codegen_units_std: _,
331 rustc_debug_assertions: _,
332 std_debug_assertions: _,
333 tools_debug_assertions: _,
334 overflow_checks: _,
335 overflow_checks_std: _,
336 debuginfo_level: _,
337 debuginfo_level_std: _,
338 debuginfo_level_tools: _,
339 debuginfo_level_tests: _,
340 backtrace: _,
341 musl_root: _,
342 verbose_tests: _,
343 optimize_tests: _,
344 codegen_tests: _,
345 omit_git_hash: _,
346 dist_src: _,
347 save_toolstates: _,
348 codegen_backends: _,
349 lld: _,
350 deny_warnings: _,
351 backtrace_on_ice: _,
352 verify_llvm_ir: _,
353 thin_lto_import_instr_limit: _,
354 remap_debuginfo: _,
355 test_compare_mode: _,
356 llvm_libunwind: _,
357 control_flow_guard: _,
358 ehcont_guard: _,
359 new_symbol_mangling: _,
360 profile_generate: _,
361 profile_use: _,
362 download_rustc: _,
363 validate_mir_opts: _,
364 frame_pointers: _,
365 } = ci_rust_config;
366
367 err!(current_rust_config.optimize, optimize, "rust");
375 err!(current_rust_config.randomize_layout, randomize_layout, "rust");
376 err!(current_rust_config.debug_logging, debug_logging, "rust");
377 err!(current_rust_config.debuginfo_level_rustc, debuginfo_level_rustc, "rust");
378 err!(current_rust_config.rpath, rpath, "rust");
379 err!(current_rust_config.strip, strip, "rust");
380 err!(current_rust_config.lld_mode, lld_mode, "rust");
381 err!(current_rust_config.llvm_tools, llvm_tools, "rust");
382 err!(current_rust_config.llvm_bitcode_linker, llvm_bitcode_linker, "rust");
383 err!(current_rust_config.jemalloc, jemalloc, "rust");
384 err!(current_rust_config.default_linker, default_linker, "rust");
385 err!(current_rust_config.stack_protector, stack_protector, "rust");
386 err!(current_rust_config.lto, lto, "rust");
387 err!(current_rust_config.std_features, std_features, "rust");
388
389 warn!(current_rust_config.channel, channel, "rust");
390
391 Ok(())
392}
393
394pub(crate) const BUILTIN_CODEGEN_BACKENDS: &[&str] = &["llvm", "cranelift", "gcc"];
395
396pub(crate) fn parse_codegen_backends(
397 backends: Vec<String>,
398 section: &str,
399) -> Vec<CodegenBackendKind> {
400 let mut found_backends = vec![];
401 for backend in &backends {
402 if let Some(stripped) = backend.strip_prefix(CODEGEN_BACKEND_PREFIX) {
403 panic!(
404 "Invalid value '{backend}' for '{section}.codegen-backends'. \
405 Codegen backends are defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \
406 Please, use '{stripped}' instead."
407 )
408 }
409 if !BUILTIN_CODEGEN_BACKENDS.contains(&backend.as_str()) {
410 println!(
411 "HELP: '{backend}' for '{section}.codegen-backends' might fail. \
412 List of known codegen backends: {BUILTIN_CODEGEN_BACKENDS:?}"
413 );
414 }
415 let backend = match backend.as_str() {
416 "llvm" => CodegenBackendKind::Llvm,
417 "cranelift" => CodegenBackendKind::Cranelift,
418 "gcc" => CodegenBackendKind::Gcc,
419 backend => CodegenBackendKind::Custom(backend.to_string()),
420 };
421 found_backends.push(backend);
422 }
423 found_backends
424}
425
426#[cfg(not(test))]
427fn default_lld_opt_in_targets() -> Vec<String> {
428 vec!["x86_64-unknown-linux-gnu".to_string()]
429}
430
431#[cfg(test)]
432thread_local! {
433 static TEST_LLD_OPT_IN_TARGETS: std::cell::RefCell<Option<Vec<String>>> = std::cell::RefCell::new(None);
434}
435
436#[cfg(test)]
437fn default_lld_opt_in_targets() -> Vec<String> {
438 TEST_LLD_OPT_IN_TARGETS.with(|cell| cell.borrow().clone()).unwrap_or_default()
439}
440
441#[cfg(test)]
442pub fn with_lld_opt_in_targets<R>(targets: Vec<String>, f: impl FnOnce() -> R) -> R {
443 TEST_LLD_OPT_IN_TARGETS.with(|cell| {
444 let prev = cell.replace(Some(targets));
445 let result = f();
446 cell.replace(prev);
447 result
448 })
449}
450
451impl Config {
452 pub fn apply_rust_config(&mut self, toml_rust: Option<Rust>, warnings: Warnings) {
453 let mut debug = None;
454 let mut rustc_debug_assertions = None;
455 let mut std_debug_assertions = None;
456 let mut tools_debug_assertions = None;
457 let mut overflow_checks = None;
458 let mut overflow_checks_std = None;
459 let mut debug_logging = None;
460 let mut debuginfo_level = None;
461 let mut debuginfo_level_rustc = None;
462 let mut debuginfo_level_std = None;
463 let mut debuginfo_level_tools = None;
464 let mut debuginfo_level_tests = None;
465 let mut optimize = None;
466 let mut lld_enabled = None;
467 let mut std_features = None;
468
469 if let Some(rust) = toml_rust {
470 let Rust {
471 optimize: optimize_toml,
472 debug: debug_toml,
473 codegen_units,
474 codegen_units_std,
475 rustc_debug_assertions: rustc_debug_assertions_toml,
476 std_debug_assertions: std_debug_assertions_toml,
477 tools_debug_assertions: tools_debug_assertions_toml,
478 overflow_checks: overflow_checks_toml,
479 overflow_checks_std: overflow_checks_std_toml,
480 debug_logging: debug_logging_toml,
481 debuginfo_level: debuginfo_level_toml,
482 debuginfo_level_rustc: debuginfo_level_rustc_toml,
483 debuginfo_level_std: debuginfo_level_std_toml,
484 debuginfo_level_tools: debuginfo_level_tools_toml,
485 debuginfo_level_tests: debuginfo_level_tests_toml,
486 backtrace,
487 incremental,
488 randomize_layout,
489 default_linker,
490 channel: _, musl_root,
492 rpath,
493 verbose_tests,
494 optimize_tests,
495 codegen_tests,
496 omit_git_hash: _, dist_src,
498 save_toolstates,
499 codegen_backends,
500 lld: lld_enabled_toml,
501 llvm_tools,
502 llvm_bitcode_linker,
503 deny_warnings,
504 backtrace_on_ice,
505 verify_llvm_ir,
506 thin_lto_import_instr_limit,
507 remap_debuginfo,
508 jemalloc,
509 test_compare_mode,
510 llvm_libunwind,
511 control_flow_guard,
512 ehcont_guard,
513 new_symbol_mangling,
514 profile_generate,
515 profile_use,
516 download_rustc,
517 lto,
518 validate_mir_opts,
519 frame_pointers,
520 stack_protector,
521 strip,
522 lld_mode,
523 std_features: std_features_toml,
524 } = rust;
525
526 let debug_assertions_requested = matches!(rustc_debug_assertions_toml, Some(true))
537 || (matches!(debug_toml, Some(true))
538 && !matches!(rustc_debug_assertions_toml, Some(false)));
539
540 if debug_assertions_requested
541 && let Some(ref opt) = download_rustc
542 && opt.is_string_or_true()
543 {
544 eprintln!(
545 "WARN: currently no CI rustc builds have rustc debug assertions \
546 enabled. Please either set `rust.debug-assertions` to `false` if you \
547 want to use download CI rustc or set `rust.download-rustc` to `false`."
548 );
549 }
550
551 self.download_rustc_commit = self.download_ci_rustc_commit(
552 download_rustc,
553 debug_assertions_requested,
554 self.llvm_assertions,
555 );
556
557 debug = debug_toml;
558 rustc_debug_assertions = rustc_debug_assertions_toml;
559 std_debug_assertions = std_debug_assertions_toml;
560 tools_debug_assertions = tools_debug_assertions_toml;
561 overflow_checks = overflow_checks_toml;
562 overflow_checks_std = overflow_checks_std_toml;
563 debug_logging = debug_logging_toml;
564 debuginfo_level = debuginfo_level_toml;
565 debuginfo_level_rustc = debuginfo_level_rustc_toml;
566 debuginfo_level_std = debuginfo_level_std_toml;
567 debuginfo_level_tools = debuginfo_level_tools_toml;
568 debuginfo_level_tests = debuginfo_level_tests_toml;
569 lld_enabled = lld_enabled_toml;
570 std_features = std_features_toml;
571
572 if optimize_toml.as_ref().is_some_and(|v| matches!(v, RustOptimize::Bool(false))) {
573 eprintln!(
574 "WARNING: setting `optimize` to `false` is known to cause errors and \
575 should be considered unsupported. Refer to `bootstrap.example.toml` \
576 for more details."
577 );
578 }
579
580 optimize = optimize_toml;
581 self.rust_new_symbol_mangling = new_symbol_mangling;
582 set(&mut self.rust_optimize_tests, optimize_tests);
583 set(&mut self.codegen_tests, codegen_tests);
584 set(&mut self.rust_rpath, rpath);
585 set(&mut self.rust_strip, strip);
586 set(&mut self.rust_frame_pointers, frame_pointers);
587 self.rust_stack_protector = stack_protector;
588 set(&mut self.jemalloc, jemalloc);
589 set(&mut self.test_compare_mode, test_compare_mode);
590 set(&mut self.backtrace, backtrace);
591 set(&mut self.rust_dist_src, dist_src);
592 set(&mut self.verbose_tests, verbose_tests);
593 if let Some(true) = incremental {
595 self.incremental = true;
596 }
597 set(&mut self.lld_mode, lld_mode);
598 set(&mut self.llvm_bitcode_linker_enabled, llvm_bitcode_linker);
599
600 self.rust_randomize_layout = randomize_layout.unwrap_or_default();
601 self.llvm_tools_enabled = llvm_tools.unwrap_or(true);
602
603 self.llvm_enzyme = self.channel == "dev" || self.channel == "nightly";
604 self.rustc_default_linker = default_linker;
605 self.musl_root = musl_root.map(PathBuf::from);
606 self.save_toolstates = save_toolstates.map(PathBuf::from);
607 set(
608 &mut self.deny_warnings,
609 match warnings {
610 Warnings::Deny => Some(true),
611 Warnings::Warn => Some(false),
612 Warnings::Default => deny_warnings,
613 },
614 );
615 set(&mut self.backtrace_on_ice, backtrace_on_ice);
616 set(&mut self.rust_verify_llvm_ir, verify_llvm_ir);
617 self.rust_thin_lto_import_instr_limit = thin_lto_import_instr_limit;
618 set(&mut self.rust_remap_debuginfo, remap_debuginfo);
619 set(&mut self.control_flow_guard, control_flow_guard);
620 set(&mut self.ehcont_guard, ehcont_guard);
621 self.llvm_libunwind_default =
622 llvm_libunwind.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind"));
623 set(
624 &mut self.rust_codegen_backends,
625 codegen_backends.map(|backends| parse_codegen_backends(backends, "rust")),
626 );
627
628 self.rust_codegen_units = codegen_units.map(threads_from_config);
629 self.rust_codegen_units_std = codegen_units_std.map(threads_from_config);
630
631 if self.rust_profile_use.is_none() {
632 self.rust_profile_use = profile_use;
633 }
634
635 if self.rust_profile_generate.is_none() {
636 self.rust_profile_generate = profile_generate;
637 }
638
639 self.rust_lto =
640 lto.as_deref().map(|value| RustcLto::from_str(value).unwrap()).unwrap_or_default();
641 self.rust_validate_mir_opts = validate_mir_opts;
642 }
643
644 self.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true));
645
646 if default_lld_opt_in_targets().contains(&self.host_target.triple.to_string())
659 && self.hosts == [self.host_target]
660 {
661 let no_llvm_config = self
662 .target_config
663 .get(&self.host_target)
664 .is_none_or(|target_config| target_config.llvm_config.is_none());
665 let enable_lld = self.llvm_from_ci || no_llvm_config;
666 self.lld_enabled = lld_enabled.unwrap_or(enable_lld);
668 } else {
669 set(&mut self.lld_enabled, lld_enabled);
670 }
671
672 let default_std_features = BTreeSet::from([String::from("panic-unwind")]);
673 self.rust_std_features = std_features.unwrap_or(default_std_features);
674
675 let default = debug == Some(true);
676 self.rustc_debug_assertions = rustc_debug_assertions.unwrap_or(default);
677 self.std_debug_assertions = std_debug_assertions.unwrap_or(self.rustc_debug_assertions);
678 self.tools_debug_assertions = tools_debug_assertions.unwrap_or(self.rustc_debug_assertions);
679 self.rust_overflow_checks = overflow_checks.unwrap_or(default);
680 self.rust_overflow_checks_std = overflow_checks_std.unwrap_or(self.rust_overflow_checks);
681
682 self.rust_debug_logging = debug_logging.unwrap_or(self.rustc_debug_assertions);
683
684 let with_defaults = |debuginfo_level_specific: Option<_>| {
685 debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) {
686 DebuginfoLevel::Limited
687 } else {
688 DebuginfoLevel::None
689 })
690 };
691 self.rust_debuginfo_level_rustc = with_defaults(debuginfo_level_rustc);
692 self.rust_debuginfo_level_std = with_defaults(debuginfo_level_std);
693 self.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools);
694 self.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(DebuginfoLevel::None);
695 }
696}