1use std::hash::Hash;
24use std::iter;
25
26use rustc_abi::Align;
27use rustc_ast::ast;
28use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
29use rustc_lint_defs::builtin::EXPLICIT_BUILTIN_CFGS_IN_FLAGS;
30use rustc_span::{Symbol, sym};
31use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, Target};
32
33use crate::config::{CrateType, FmtDebug};
34use crate::{Session, diagnostics};
35
36pub type Cfg = FxIndexSet<(Symbol, Option<Symbol>)>;
42
43#[derive(#[automatically_derived]
impl ::core::default::Default for CheckCfg {
#[inline]
fn default() -> Self {
Self {
exhaustive_names: ::core::default::Default::default(),
exhaustive_values: ::core::default::Default::default(),
expecteds: ::core::default::Default::default(),
well_known_names: ::core::default::Default::default(),
}
}
}Default)]
45pub struct CheckCfg {
46 pub exhaustive_names: bool,
48 pub exhaustive_values: bool,
50 pub expecteds: FxHashMap<Symbol, ExpectedValues<Symbol>>,
52 pub well_known_names: FxHashSet<Symbol>,
54}
55
56pub enum ExpectedValues<T> {
57 Some(FxHashSet<Option<T>>),
58 Any,
59}
60
61impl<T: Eq + Hash> ExpectedValues<T> {
62 fn insert(&mut self, value: T) -> bool {
63 match self {
64 ExpectedValues::Some(expecteds) => expecteds.insert(Some(value)),
65 ExpectedValues::Any => false,
66 }
67 }
68
69 pub fn contains(&self, value: &Option<T>) -> bool {
70 match self {
71 ExpectedValues::Some(expecteds) => expecteds.contains(value),
72 ExpectedValues::Any => false,
73 }
74 }
75}
76
77impl<T: Eq + Hash> Extend<T> for ExpectedValues<T> {
78 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
79 match self {
80 ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(Some)),
81 ExpectedValues::Any => {}
82 }
83 }
84}
85
86impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> {
87 fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
88 match self {
89 ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(|a| Some(*a))),
90 ExpectedValues::Any => {}
91 }
92 }
93}
94
95pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) {
97 let disallow = |cfg: &(Symbol, Option<Symbol>), controlled_by| {
98 let cfg_name = cfg.0;
99 let cfg = if let Some(value) = cfg.1 {
100 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}=\"{1}\"", cfg_name, value))
})format!(r#"{}="{}""#, cfg_name, value)
101 } else {
102 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}", cfg_name))
})format!("{}", cfg_name)
103 };
104 sess.psess.opt_span_buffer_lint(
105 EXPLICIT_BUILTIN_CFGS_IN_FLAGS,
106 None,
107 ast::CRATE_NODE_ID,
108 diagnostics::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.into(),
109 )
110 };
111
112 for cfg in user_cfgs {
124 match cfg {
125 (sym::overflow_checks, None) => disallow(cfg, "-C overflow-checks"),
126 (sym::debug_assertions, None) => disallow(cfg, "-C debug-assertions"),
127 (sym::ub_checks, None) => disallow(cfg, "-Z ub-checks"),
128 (sym::contract_checks, None) => disallow(cfg, "-Z contract-checks"),
129 (sym::sanitize, None | Some(_)) => disallow(cfg, "-Z sanitizer"),
130 (
131 sym::sanitizer_cfi_generalize_pointers | sym::sanitizer_cfi_normalize_integers,
132 None | Some(_),
133 ) => disallow(cfg, "-Z sanitizer=cfi"),
134 (sym::proc_macro, None) => disallow(cfg, "--crate-type proc-macro"),
135 (sym::panic, Some(sym::abort | sym::unwind | sym::immediate_abort)) => {
136 disallow(cfg, "-C panic")
137 }
138 (sym::target_feature, Some(_)) => disallow(cfg, "-C target-feature"),
139 (sym::unix, None)
140 | (sym::windows, None)
141 | (sym::relocation_model, Some(_))
142 | (sym::target_abi, None | Some(_))
143 | (sym::target_arch, Some(_))
144 | (sym::target_endian, Some(_))
145 | (sym::target_env, None | Some(_))
146 | (sym::target_family, Some(_))
147 | (sym::target_object_format, Some(_))
148 | (sym::target_os, Some(_))
149 | (sym::target_pointer_width, Some(_))
150 | (sym::target_vendor, None | Some(_))
151 | (sym::target_has_atomic, Some(_))
152 | (sym::target_has_threads, None | Some(_))
153 | (sym::target_has_atomic_primitive_alignment, Some(_))
154 | (sym::target_has_atomic_load_store, Some(_))
155 | (sym::target_has_reliable_f16, None | Some(_))
156 | (sym::target_has_reliable_f16_math, None | Some(_))
157 | (sym::target_has_reliable_f16b, None | Some(_))
158 | (sym::target_has_reliable_f128, None | Some(_))
159 | (sym::target_has_reliable_f128_math, None | Some(_))
160 | (sym::target_thread_local, None) => disallow(cfg, "--target"),
161 (sym::fmt_debug, None | Some(_)) => disallow(cfg, "-Z fmt-debug"),
162 _ => {}
163 }
164 }
165}
166
167pub(crate) fn default_configuration(sess: &Session) -> Cfg {
169 let mut ret = Cfg::default();
170
171 macro_rules! ins_none {
172 ($key:expr) => {
173 ret.insert(($key, None));
174 };
175 }
176 macro_rules! ins_str {
177 ($key:expr, $val_str:expr) => {
178 ret.insert(($key, Some(Symbol::intern($val_str))));
179 };
180 }
181 macro_rules! ins_sym {
182 ($key:expr, $val_sym:expr) => {
183 ret.insert(($key, Some($val_sym)));
184 };
185 }
186
187 if sess.opts.debug_assertions {
196 ret.insert((sym::debug_assertions, None));ins_none!(sym::debug_assertions);
197 }
198
199 if sess.is_nightly_build() {
200 match sess.opts.unstable_opts.fmt_debug {
201 FmtDebug::Full => {
202 ret.insert((sym::fmt_debug, Some(sym::full)));ins_sym!(sym::fmt_debug, sym::full);
203 }
204 FmtDebug::Shallow => {
205 ret.insert((sym::fmt_debug, Some(sym::shallow)));ins_sym!(sym::fmt_debug, sym::shallow);
206 }
207 FmtDebug::None => {
208 ret.insert((sym::fmt_debug, Some(sym::none)));ins_sym!(sym::fmt_debug, sym::none);
209 }
210 }
211 }
212
213 if sess.overflow_checks() {
214 ret.insert((sym::overflow_checks, None));ins_none!(sym::overflow_checks);
215 }
216
217 ret.insert((sym::panic, Some(sess.panic_strategy().desc_symbol())));ins_sym!(sym::panic, sess.panic_strategy().desc_symbol());
222 if sess.panic_strategy() == PanicStrategy::ImmediateAbort {
223 ret.insert((sym::panic, Some(PanicStrategy::Abort.desc_symbol())));ins_sym!(sym::panic, PanicStrategy::Abort.desc_symbol());
224 }
225
226 #[allow(rustc::bad_opt_access)]
228 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
229 ret.insert((sym::proc_macro, None));ins_none!(sym::proc_macro);
230 }
231
232 if sess.is_nightly_build() {
233 ret.insert((sym::relocation_model,
Some(sess.target.relocation_model.desc_symbol())));ins_sym!(sym::relocation_model, sess.target.relocation_model.desc_symbol());
234 }
235
236 for mut s in sess.sanitizers() {
237 if s == SanitizerSet::KERNELADDRESS {
239 s = SanitizerSet::ADDRESS;
240 }
241 if s == SanitizerSet::KERNELHWADDRESS {
243 s = SanitizerSet::HWADDRESS;
244 }
245 ret.insert((sym::sanitize, Some(Symbol::intern(&s.to_string()))));ins_str!(sym::sanitize, &s.to_string());
246 }
247
248 if sess.is_sanitizer_cfi_generalize_pointers_enabled() {
249 ret.insert((sym::sanitizer_cfi_generalize_pointers, None));ins_none!(sym::sanitizer_cfi_generalize_pointers);
250 }
251 if sess.is_sanitizer_cfi_normalize_integers_enabled() {
252 ret.insert((sym::sanitizer_cfi_normalize_integers, None));ins_none!(sym::sanitizer_cfi_normalize_integers);
253 }
254
255 ret.insert((sym::target_abi, Some(sess.target.cfg_abi.desc_symbol())));ins_sym!(sym::target_abi, sess.target.cfg_abi.desc_symbol());
256 ret.insert((sym::target_arch, Some(sess.target.arch.desc_symbol())));ins_sym!(sym::target_arch, sess.target.arch.desc_symbol());
257 ret.insert((sym::target_endian, Some(sess.target.endian.desc_symbol())));ins_sym!(sym::target_endian, sess.target.endian.desc_symbol());
258 ret.insert((sym::target_env, Some(sess.target.env.desc_symbol())));ins_sym!(sym::target_env, sess.target.env.desc_symbol());
259 ret.insert((sym::target_object_format,
Some(sess.target.options.binary_format.desc_symbol())));ins_sym!(sym::target_object_format, sess.target.options.binary_format.desc_symbol());
260
261 for family in sess.target.families.as_ref() {
262 ret.insert((sym::target_family, Some(Symbol::intern(family))));ins_str!(sym::target_family, family);
263 if family == "windows" {
264 ret.insert((sym::windows, None));ins_none!(sym::windows);
265 } else if family == "unix" {
266 ret.insert((sym::unix, None));ins_none!(sym::unix);
267 }
268 }
269
270 let layout = sess.target.parse_data_layout().unwrap_or_else(|err| {
272 sess.dcx().emit_fatal(err);
273 });
274 let mut has_atomic = false;
275 for (i, align) in [
276 (8, layout.i8_align),
277 (16, layout.i16_align),
278 (32, layout.i32_align),
279 (64, layout.i64_align),
280 (128, layout.i128_align),
281 ] {
282 if i >= sess.target.min_atomic_width() && i <= sess.target.max_atomic_width() {
283 if !has_atomic {
284 has_atomic = true;
285 if sess.is_nightly_build() {
286 if sess.target.atomic_cas {
287 ret.insert((sym::target_has_atomic, None));ins_none!(sym::target_has_atomic);
288 }
289 ret.insert((sym::target_has_atomic_load_store, None));ins_none!(sym::target_has_atomic_load_store);
290 }
291 }
292 let mut insert_atomic = |sym, align: Align| {
293 if sess.target.atomic_cas {
294 ret.insert((sym::target_has_atomic, Some(sym)));ins_sym!(sym::target_has_atomic, sym);
295 }
296 if align.bits() == i {
297 ret.insert((sym::target_has_atomic_primitive_alignment, Some(sym)));ins_sym!(sym::target_has_atomic_primitive_alignment, sym);
298 }
299 ret.insert((sym::target_has_atomic_load_store, Some(sym)));ins_sym!(sym::target_has_atomic_load_store, sym);
300 };
301 insert_atomic(sym::integer(i), align);
302 if sess.target.pointer_width as u64 == i {
303 insert_atomic(sym::ptr, layout.pointer_align().abi);
304 }
305 }
306 }
307
308 if !sess.target.singlethread(&sess.internal_target_features) {
309 ret.insert((sym::target_has_threads, None));ins_none!(sym::target_has_threads);
310 }
311
312 ret.insert((sym::target_os, Some(sess.target.os.desc_symbol())));ins_sym!(sym::target_os, sess.target.os.desc_symbol());
313 ret.insert((sym::target_pointer_width,
Some(sym::integer(sess.target.pointer_width))));ins_sym!(sym::target_pointer_width, sym::integer(sess.target.pointer_width));
314
315 if sess.opts.unstable_opts.has_thread_local.unwrap_or(sess.target.has_thread_local) {
316 ret.insert((sym::target_thread_local, None));ins_none!(sym::target_thread_local);
317 }
318
319 ret.insert((sym::target_vendor, Some(sess.target.vendor_symbol())));ins_sym!(sym::target_vendor, sess.target.vendor_symbol());
320
321 if sess.is_test_crate() {
323 ret.insert((sym::test, None));ins_none!(sym::test);
324 }
325
326 if sess.ub_checks() {
327 ret.insert((sym::ub_checks, None));ins_none!(sym::ub_checks);
328 }
329
330 if sess.contract_checks() {
331 ret.insert((sym::contract_checks, None));ins_none!(sym::contract_checks);
332 }
333
334 ret
335}
336
337impl CheckCfg {
338 pub fn fill_well_known(&mut self, current_target: &Target) {
340 if !self.exhaustive_values && !self.exhaustive_names {
341 return;
342 }
343
344 let no_values = || {
346 let mut values = FxHashSet::default();
347 values.insert(None);
348 ExpectedValues::Some(values)
349 };
350
351 let empty_values = || {
353 let values = FxHashSet::default();
354 ExpectedValues::Some(values)
355 };
356
357 macro_rules! ins {
358 ($name:expr, $values:expr) => {{
359 self.well_known_names.insert($name);
360 self.expecteds.entry($name).or_insert_with($values)
361 }};
362 }
363
364 {
self.well_known_names.insert(sym::debug_assertions);
self.expecteds.entry(sym::debug_assertions).or_insert_with(no_values)
};ins!(sym::debug_assertions, no_values);
384
385 {
self.well_known_names.insert(sym::fmt_debug);
self.expecteds.entry(sym::fmt_debug).or_insert_with(empty_values)
}ins!(sym::fmt_debug, empty_values).extend(FmtDebug::all());
386
387 {
self.well_known_names.insert(sym::clippy);
self.expecteds.entry(sym::clippy).or_insert_with(no_values)
};ins!(sym::clippy, no_values);
392 {
self.well_known_names.insert(sym::doc);
self.expecteds.entry(sym::doc).or_insert_with(no_values)
};ins!(sym::doc, no_values);
393 {
self.well_known_names.insert(sym::doctest);
self.expecteds.entry(sym::doctest).or_insert_with(no_values)
};ins!(sym::doctest, no_values);
394 {
self.well_known_names.insert(sym::miri);
self.expecteds.entry(sym::miri).or_insert_with(no_values)
};ins!(sym::miri, no_values);
395 {
self.well_known_names.insert(sym::rust_analyzer);
self.expecteds.entry(sym::rust_analyzer).or_insert_with(no_values)
};ins!(sym::rust_analyzer, no_values);
396 {
self.well_known_names.insert(sym::rustfmt);
self.expecteds.entry(sym::rustfmt).or_insert_with(no_values)
};ins!(sym::rustfmt, no_values);
397
398 {
self.well_known_names.insert(sym::overflow_checks);
self.expecteds.entry(sym::overflow_checks).or_insert_with(no_values)
};ins!(sym::overflow_checks, no_values);
399
400 {
self.well_known_names.insert(sym::panic);
self.expecteds.entry(sym::panic).or_insert_with(empty_values)
}ins!(sym::panic, empty_values)
401 .extend(PanicStrategy::ALL.iter().map(PanicStrategy::desc_symbol));
402
403 {
self.well_known_names.insert(sym::proc_macro);
self.expecteds.entry(sym::proc_macro).or_insert_with(no_values)
};ins!(sym::proc_macro, no_values);
404
405 {
self.well_known_names.insert(sym::relocation_model);
self.expecteds.entry(sym::relocation_model).or_insert_with(empty_values)
}ins!(sym::relocation_model, empty_values)
406 .extend(RelocModel::ALL.iter().map(RelocModel::desc_symbol));
407
408 let sanitize_values = SanitizerSet::all()
409 .into_iter()
410 .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
411 {
self.well_known_names.insert(sym::sanitize);
self.expecteds.entry(sym::sanitize).or_insert_with(empty_values)
}ins!(sym::sanitize, empty_values).extend(sanitize_values);
412
413 {
self.well_known_names.insert(sym::sanitizer_cfi_generalize_pointers);
self.expecteds.entry(sym::sanitizer_cfi_generalize_pointers).or_insert_with(no_values)
};ins!(sym::sanitizer_cfi_generalize_pointers, no_values);
414 {
self.well_known_names.insert(sym::sanitizer_cfi_normalize_integers);
self.expecteds.entry(sym::sanitizer_cfi_normalize_integers).or_insert_with(no_values)
};ins!(sym::sanitizer_cfi_normalize_integers, no_values);
415
416 {
self.well_known_names.insert(sym::target_feature);
self.expecteds.entry(sym::target_feature).or_insert_with(empty_values)
}ins!(sym::target_feature, empty_values).extend(
417 rustc_target::target_features::all_rust_features()
418 .filter(|(_, s)| s.in_cfg())
419 .map(|(f, _s)| f)
420 .chain(rustc_target::target_features::RUSTC_SPECIFIC_FEATURES.iter().cloned())
421 .map(Symbol::intern),
422 );
423
424 {
426 const VALUES: [&Symbol; 9] = [
427 &sym::target_abi,
428 &sym::target_arch,
429 &sym::target_endian,
430 &sym::target_env,
431 &sym::target_family,
432 &sym::target_object_format,
433 &sym::target_os,
434 &sym::target_pointer_width,
435 &sym::target_vendor,
436 ];
437
438 for &e in VALUES {
440 if !self.exhaustive_values {
441 {
self.well_known_names.insert(e);
self.expecteds.entry(e).or_insert_with(|| ExpectedValues::Any)
};ins!(e, || ExpectedValues::Any);
442 } else {
443 {
self.well_known_names.insert(e);
self.expecteds.entry(e).or_insert_with(empty_values)
};ins!(e, empty_values);
444 }
445 }
446
447 if self.exhaustive_values {
448 let [
451 Some(values_target_abi),
452 Some(values_target_arch),
453 Some(values_target_endian),
454 Some(values_target_env),
455 Some(values_target_family),
456 Some(values_target_object_format),
457 Some(values_target_os),
458 Some(values_target_pointer_width),
459 Some(values_target_vendor),
460 ] = self.expecteds.get_disjoint_mut(VALUES)
461 else {
462 {
::core::panicking::panic_fmt(format_args!("unable to get all the check-cfg values buckets"));
};panic!("unable to get all the check-cfg values buckets");
463 };
464
465 for target in Target::builtins().chain(iter::once(current_target.clone())) {
466 values_target_abi.insert(target.options.cfg_abi.desc_symbol());
467 values_target_arch.insert(target.arch.desc_symbol());
468 values_target_endian.insert(target.options.endian.desc_symbol());
469 values_target_env.insert(target.options.env.desc_symbol());
470 values_target_family.extend(
471 target.options.families.iter().map(|family| Symbol::intern(family)),
472 );
473 values_target_object_format.insert(target.options.binary_format.desc_symbol());
474 values_target_os.insert(target.options.os.desc_symbol());
475 values_target_pointer_width.insert(sym::integer(target.pointer_width));
476 values_target_vendor.insert(target.vendor_symbol());
477 }
478 }
479 }
480
481 let atomic_values = &[
482 sym::ptr,
483 sym::integer(8usize),
484 sym::integer(16usize),
485 sym::integer(32usize),
486 sym::integer(64usize),
487 sym::integer(128usize),
488 ];
489 for sym in [sym::target_has_atomic, sym::target_has_atomic_load_store] {
490 {
self.well_known_names.insert(sym);
self.expecteds.entry(sym).or_insert_with(no_values)
}ins!(sym, no_values).extend(atomic_values);
491 }
492 {
self.well_known_names.insert(sym::target_has_atomic_primitive_alignment);
self.expecteds.entry(sym::target_has_atomic_primitive_alignment).or_insert_with(empty_values)
}ins!(sym::target_has_atomic_primitive_alignment, empty_values).extend(atomic_values);
493
494 {
self.well_known_names.insert(sym::target_thread_local);
self.expecteds.entry(sym::target_thread_local).or_insert_with(no_values)
};ins!(sym::target_thread_local, no_values);
495 {
self.well_known_names.insert(sym::target_has_threads);
self.expecteds.entry(sym::target_has_threads).or_insert_with(no_values)
};ins!(sym::target_has_threads, no_values);
496
497 {
self.well_known_names.insert(sym::ub_checks);
self.expecteds.entry(sym::ub_checks).or_insert_with(no_values)
};ins!(sym::ub_checks, no_values);
498 {
self.well_known_names.insert(sym::contract_checks);
self.expecteds.entry(sym::contract_checks).or_insert_with(no_values)
};ins!(sym::contract_checks, no_values);
499
500 {
self.well_known_names.insert(sym::unix);
self.expecteds.entry(sym::unix).or_insert_with(no_values)
};ins!(sym::unix, no_values);
501 {
self.well_known_names.insert(sym::windows);
self.expecteds.entry(sym::windows).or_insert_with(no_values)
};ins!(sym::windows, no_values);
502 }
503}