Skip to content

Commit

Permalink
Rollup merge of rust-lang#94362 - Urgau:check-cfg-values, r=petrochenkov
Browse files Browse the repository at this point in the history
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`
  • Loading branch information
Dylan-DPC authored Mar 4, 2022
2 parents 1b14fd3 + 4aa92af commit e11f9c8
Show file tree
Hide file tree
Showing 8 changed files with 207 additions and 11 deletions.
3 changes: 3 additions & 0 deletions compiler/rustc_interface/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
"`values()` first argument must be a simple identifer"
);
}
} else if args.is_empty() {
cfg.well_known_values = true;
continue 'specs;
}
}
}
Expand Down
116 changes: 110 additions & 6 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use rustc_data_structures::impl_stable_hash_via_hash;

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;

Expand Down Expand Up @@ -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,
}
}
}

Expand All @@ -1047,6 +1054,7 @@ impl<T> CheckCfg<T> {
.iter()
.map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
.collect(),
well_known_values: self.well_known_values,
}
}
}
Expand All @@ -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,
Expand All @@ -1086,11 +1095,106 @@ impl CrateCheckConfig {
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.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,7 @@ symbols! {
proc_macro_path_invoc,
profiler_builtins,
profiler_runtime,
ptr,
ptr_guaranteed_eq,
ptr_guaranteed_ne,
ptr_null,
Expand Down
20 changes: 18 additions & 2 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,12 +186,16 @@ impl PanicStrategy {
}
}

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 {
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -2137,6 +2141,18 @@ impl Target {
))
}

/// 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
Expand Down
8 changes: 6 additions & 2 deletions src/test/ui/check-cfg/empty-values.rs
Original file line number Diff line number Diff line change
@@ -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() {}
11 changes: 10 additions & 1 deletion src/test/ui/check-cfg/empty-values.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 28 additions & 0 deletions src/test/ui/check-cfg/well-known-values.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 31 additions & 0 deletions src/test/ui/check-cfg/well-known-values.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit e11f9c8

Please sign in to comment.