Rollup merge of #94362 - Urgau:check-cfg-values, r=petrochenkov
Add well known values to `--check-cfg` implementation This pull-request adds well known values for the well known names via `--check-cfg=values()`. [RFC 3013: Checking conditional compilation at compile time](https://rust-lang.github.io/rfcs/3013-conditional-compilation-checking.html#checking-conditional-compilation-at-compile-time) doesn't define this at all, but this seems a nice improvement. The activation is done by a empty `values()` (new syntax) similar to `names()` except that `names(foo)` also activate well known names while `values(aa, "aa", "kk")` would not. As stated this use a different activation logic because well known values for the well known names are not always sufficient. In fact this is problematic for every `target_*` cfg because of non builtin targets, as the current implementation use those built-ins targets to create the list the well known values. The implementation is straight forward, first we gather (if necessary) all the values (lazily or not) and then we apply them. r? ```@petrochenkov```
This commit is contained in:
commit
afa85f0841
@ -207,6 +207,9 @@ macro_rules! error {
|
||||
"`values()` first argument must be a simple identifer"
|
||||
);
|
||||
}
|
||||
} else if args.is_empty() {
|
||||
cfg.well_known_values = true;
|
||||
continue 'specs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
use rustc_target::abi::{Align, TargetDataLayout};
|
||||
use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings};
|
||||
use rustc_target::spec::{PanicStrategy, SanitizerSet, TARGETS};
|
||||
|
||||
use rustc_serialize::json;
|
||||
|
||||
@ -1025,13 +1026,19 @@ pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig
|
||||
pub struct CheckCfg<T = String> {
|
||||
/// The set of all `names()`, if None no name checking is performed
|
||||
pub names_valid: Option<FxHashSet<T>>,
|
||||
/// Is well known values activated
|
||||
pub well_known_values: bool,
|
||||
/// The set of all `values()`
|
||||
pub values_valid: FxHashMap<T, FxHashSet<T>>,
|
||||
}
|
||||
|
||||
impl<T> Default for CheckCfg<T> {
|
||||
fn default() -> Self {
|
||||
CheckCfg { names_valid: Default::default(), values_valid: Default::default() }
|
||||
CheckCfg {
|
||||
names_valid: Default::default(),
|
||||
values_valid: Default::default(),
|
||||
well_known_values: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1047,6 +1054,7 @@ fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
|
||||
.iter()
|
||||
.map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
|
||||
.collect(),
|
||||
well_known_values: self.well_known_values,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1060,8 +1068,9 @@ pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
|
||||
|
||||
impl CrateCheckConfig {
|
||||
/// Fills a `CrateCheckConfig` with well-known configuration names.
|
||||
pub fn fill_well_known(&mut self) {
|
||||
// NOTE: This should be kept in sync with `default_configuration`
|
||||
fn fill_well_known_names(&mut self) {
|
||||
// NOTE: This should be kept in sync with `default_configuration` and
|
||||
// `fill_well_known_values`
|
||||
const WELL_KNOWN_NAMES: &[Symbol] = &[
|
||||
sym::unix,
|
||||
sym::windows,
|
||||
@ -1086,11 +1095,106 @@ pub fn fill_well_known(&mut self) {
|
||||
sym::doctest,
|
||||
sym::feature,
|
||||
];
|
||||
|
||||
// We only insert well-known names if `names()` was activated
|
||||
if let Some(names_valid) = &mut self.names_valid {
|
||||
for &name in WELL_KNOWN_NAMES {
|
||||
names_valid.insert(name);
|
||||
names_valid.extend(WELL_KNOWN_NAMES);
|
||||
}
|
||||
}
|
||||
|
||||
/// Fills a `CrateCheckConfig` with well-known configuration values.
|
||||
fn fill_well_known_values(&mut self) {
|
||||
if !self.well_known_values {
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: This should be kept in sync with `default_configuration` and
|
||||
// `fill_well_known_names`
|
||||
|
||||
let panic_values = &PanicStrategy::all();
|
||||
|
||||
let atomic_values = &[
|
||||
sym::ptr,
|
||||
sym::integer(8usize),
|
||||
sym::integer(16usize),
|
||||
sym::integer(32usize),
|
||||
sym::integer(64usize),
|
||||
sym::integer(128usize),
|
||||
];
|
||||
|
||||
let sanitize_values = SanitizerSet::all()
|
||||
.into_iter()
|
||||
.map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
|
||||
|
||||
// No-values
|
||||
for name in [
|
||||
sym::unix,
|
||||
sym::windows,
|
||||
sym::debug_assertions,
|
||||
sym::proc_macro,
|
||||
sym::test,
|
||||
sym::doc,
|
||||
sym::doctest,
|
||||
sym::target_thread_local,
|
||||
] {
|
||||
self.values_valid.entry(name).or_default();
|
||||
}
|
||||
|
||||
// Pre-defined values
|
||||
self.values_valid.entry(sym::panic).or_default().extend(panic_values);
|
||||
self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
|
||||
self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
|
||||
self.values_valid
|
||||
.entry(sym::target_has_atomic_load_store)
|
||||
.or_default()
|
||||
.extend(atomic_values);
|
||||
self.values_valid
|
||||
.entry(sym::target_has_atomic_equal_alignment)
|
||||
.or_default()
|
||||
.extend(atomic_values);
|
||||
|
||||
// Target specific values
|
||||
for target in
|
||||
TARGETS.iter().map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
|
||||
{
|
||||
self.values_valid
|
||||
.entry(sym::target_os)
|
||||
.or_default()
|
||||
.insert(Symbol::intern(&target.options.os));
|
||||
self.values_valid
|
||||
.entry(sym::target_family)
|
||||
.or_default()
|
||||
.extend(target.options.families.iter().map(|family| Symbol::intern(family)));
|
||||
self.values_valid
|
||||
.entry(sym::target_arch)
|
||||
.or_default()
|
||||
.insert(Symbol::intern(&target.arch));
|
||||
self.values_valid
|
||||
.entry(sym::target_endian)
|
||||
.or_default()
|
||||
.insert(Symbol::intern(&target.options.endian.as_str()));
|
||||
self.values_valid
|
||||
.entry(sym::target_env)
|
||||
.or_default()
|
||||
.insert(Symbol::intern(&target.options.env));
|
||||
self.values_valid
|
||||
.entry(sym::target_abi)
|
||||
.or_default()
|
||||
.insert(Symbol::intern(&target.options.abi));
|
||||
self.values_valid
|
||||
.entry(sym::target_vendor)
|
||||
.or_default()
|
||||
.insert(Symbol::intern(&target.options.vendor));
|
||||
self.values_valid
|
||||
.entry(sym::target_pointer_width)
|
||||
.or_default()
|
||||
.insert(sym::integer(target.pointer_width));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fill_well_known(&mut self) {
|
||||
self.fill_well_known_names();
|
||||
self.fill_well_known_values();
|
||||
}
|
||||
|
||||
/// Fills a `CrateCheckConfig` with configuration names and values that are actually active.
|
||||
|
@ -1063,6 +1063,7 @@
|
||||
proc_macro_path_invoc,
|
||||
profiler_builtins,
|
||||
profiler_runtime,
|
||||
ptr,
|
||||
ptr_guaranteed_eq,
|
||||
ptr_guaranteed_ne,
|
||||
ptr_null,
|
||||
|
@ -186,12 +186,16 @@ pub fn desc(&self) -> &str {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn desc_symbol(&self) -> Symbol {
|
||||
pub const fn desc_symbol(&self) -> Symbol {
|
||||
match *self {
|
||||
PanicStrategy::Unwind => sym::unwind,
|
||||
PanicStrategy::Abort => sym::abort,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn all() -> [Symbol; 2] {
|
||||
[Self::Abort.desc_symbol(), Self::Unwind.desc_symbol()]
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for PanicStrategy {
|
||||
@ -614,7 +618,7 @@ impl SanitizerSet {
|
||||
/// Return sanitizer's name
|
||||
///
|
||||
/// Returns none if the flags is a set of sanitizers numbering not exactly one.
|
||||
fn as_str(self) -> Option<&'static str> {
|
||||
pub fn as_str(self) -> Option<&'static str> {
|
||||
Some(match self {
|
||||
SanitizerSet::ADDRESS => "address",
|
||||
SanitizerSet::CFI => "cfi",
|
||||
@ -2137,6 +2141,18 @@ macro_rules! key {
|
||||
))
|
||||
}
|
||||
|
||||
/// Load a built-in target
|
||||
pub fn expect_builtin(target_triple: &TargetTriple) -> Target {
|
||||
match *target_triple {
|
||||
TargetTriple::TargetTriple(ref target_triple) => {
|
||||
load_builtin(target_triple).expect("built-in target")
|
||||
}
|
||||
TargetTriple::TargetPath(..) => {
|
||||
panic!("built-in targets doens't support target-paths")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Search for a JSON file specifying the given target triple.
|
||||
///
|
||||
/// If none is found in `$RUST_TARGET_PATH`, look for a file called `target.json` inside the
|
||||
|
@ -1,6 +1,10 @@
|
||||
// Check that a an empty values() is rejected
|
||||
// Check warning for unexpected cfg value
|
||||
//
|
||||
// check-fail
|
||||
// check-pass
|
||||
// compile-flags: --check-cfg=values() -Z unstable-options
|
||||
|
||||
#[cfg(test = "value")]
|
||||
//~^ WARNING unexpected `cfg` condition value
|
||||
pub fn f() {}
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,2 +1,11 @@
|
||||
error: invalid `--check-cfg` argument: `values()` (expected `names(name1, name2, ... nameN)` or `values(name, "value1", "value2", ... "valueN")`)
|
||||
warning: unexpected `cfg` condition value
|
||||
--> $DIR/empty-values.rs:6:7
|
||||
|
|
||||
LL | #[cfg(test = "value")]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(unexpected_cfgs)]` on by default
|
||||
= note: no expected value for `test`
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
|
28
src/test/ui/check-cfg/well-known-values.rs
Normal file
28
src/test/ui/check-cfg/well-known-values.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// This test check that we lint on non well known values and that we don't lint on well known
|
||||
// values
|
||||
//
|
||||
// check-pass
|
||||
// compile-flags: --check-cfg=values() -Z unstable-options
|
||||
|
||||
#[cfg(target_os = "linuz")]
|
||||
//~^ WARNING unexpected `cfg` condition value
|
||||
fn target_os_linux_misspell() {}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn target_os_linux() {}
|
||||
|
||||
#[cfg(target_has_atomic = "0")]
|
||||
//~^ WARNING unexpected `cfg` condition value
|
||||
fn target_has_atomic_invalid() {}
|
||||
|
||||
#[cfg(target_has_atomic = "8")]
|
||||
fn target_has_atomic() {}
|
||||
|
||||
#[cfg(unix = "aa")]
|
||||
//~^ WARNING unexpected `cfg` condition value
|
||||
fn unix_with_value() {}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn unix() {}
|
||||
|
||||
fn main() {}
|
31
src/test/ui/check-cfg/well-known-values.stderr
Normal file
31
src/test/ui/check-cfg/well-known-values.stderr
Normal file
@ -0,0 +1,31 @@
|
||||
warning: unexpected `cfg` condition value
|
||||
--> $DIR/well-known-values.rs:7:7
|
||||
|
|
||||
LL | #[cfg(target_os = "linuz")]
|
||||
| ^^^^^^^^^^^^-------
|
||||
| |
|
||||
| help: did you mean: `"linux"`
|
||||
|
|
||||
= note: `#[warn(unexpected_cfgs)]` on by default
|
||||
= note: expected values for `target_os` are: android, cuda, dragonfly, emscripten, espidf, freebsd, fuchsia, haiku, hermit, horizon, illumos, ios, l4re, linux, macos, netbsd, none, openbsd, psp, redox, solaris, solid_asp3, tvos, uefi, unknown, vxworks, wasi, windows
|
||||
|
||||
warning: unexpected `cfg` condition value
|
||||
--> $DIR/well-known-values.rs:14:7
|
||||
|
|
||||
LL | #[cfg(target_has_atomic = "0")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^---
|
||||
| |
|
||||
| help: did you mean: `"8"`
|
||||
|
|
||||
= note: expected values for `target_has_atomic` are: 128, 16, 32, 64, 8, ptr
|
||||
|
||||
warning: unexpected `cfg` condition value
|
||||
--> $DIR/well-known-values.rs:21:7
|
||||
|
|
||||
LL | #[cfg(unix = "aa")]
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= note: no expected value for `unix`
|
||||
|
||||
warning: 3 warnings emitted
|
||||
|
Loading…
Reference in New Issue
Block a user