diff options
| author | bors <bors@rust-lang.org> | 2024-01-09 14:50:14 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-01-09 14:50:14 +0000 |
| commit | 5876c8cdfd3df742c334d6447d44d760c77103b6 (patch) | |
| tree | b2437656721ba0a5f4068566975525a9bab87974 /src | |
| parent | be00c5a9b89161b7f45ba80340f709e8e41122f9 (diff) | |
| parent | f41d7739880e72743a74722ae6fcc1be9f7b4e5c (diff) | |
| download | rust-5876c8cdfd3df742c334d6447d44d760c77103b6.tar.gz rust-5876c8cdfd3df742c334d6447d44d760c77103b6.zip | |
Auto merge of #119767 - GuillaumeGomez:rollup-fbp26yb, r=GuillaumeGomez
Rollup of 9 pull requests Successful merges: - #117556 (Disallow reference to `static mut` and adding `static_mut_ref` lint) - #118748 (std: getrandom simplification for freebsd.) - #119282 (Rework and improve the unstable documentation of check-cfg) - #119527 (don't reexport atomic::ordering via rustc_data_structures, use std import) - #119668 (Simplify implementation of MIR promotion) - #119699 (Merge dead bb pruning and unreachable bb deduplication.) - #119723 (Remove `-Zdont-buffer-diagnostics`.) - #119756 (rustdoc-search: reuse individual types in function signatures) - #119758 (GNU/Hurd: unconditionally use inline stack probes) r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'src')
| -rw-r--r-- | src/doc/unstable-book/src/compiler-flags/check-cfg.md | 224 | ||||
| -rw-r--r-- | src/librustdoc/html/static/js/search.js | 111 | ||||
| -rw-r--r-- | src/tools/lint-docs/src/groups.rs | 1 | ||||
| -rw-r--r-- | src/tools/miri/tests/fail/tls/tls_static_dealloc.rs | 2 | ||||
| -rw-r--r-- | src/tools/miri/tests/pass/static_mut.rs | 3 | ||||
| -rw-r--r-- | src/tools/miri/tests/pass/tls/tls_static.rs | 2 |
6 files changed, 222 insertions, 121 deletions
diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md index 8ab6e83d99e..e8fc2fe986e 100644 --- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md @@ -4,18 +4,16 @@ The tracking issue for this feature is: [#82450](https://github.com/rust-lang/ru ------------------------ -This feature allows you to enable complete or partial checking of configuration. +This feature enables checking of conditional configuration. `rustc` accepts the `--check-cfg` option, which specifies whether to check conditions and how to -check them. The `--check-cfg` option takes a value, called the _check cfg specification_. The -check cfg specification is parsed using the Rust metadata syntax, just as the `--cfg` option is. +check them. The `--check-cfg` option takes a value, called the _check cfg specification_. +This specification has one form: -`--check-cfg` option take one form: +1. `--check-cfg cfg(...)` mark a configuration and it's expected values as expected. -1. `--check-cfg cfg(...)` enables checking the values within list-valued conditions. - -NOTE: No implicit expectation is added when using `--cfg` for both forms. Users are expected to -pass all expected names and values using `cfg(...)`. +*No implicit expectation is added when using `--cfg`. Users are expected to +pass all expected names and values using the _check cfg specification_.* ## The `cfg(...)` form @@ -23,7 +21,7 @@ The `cfg(...)` form enables checking the values within list-valued conditions. I basic form: ```bash -rustc --check-cfg 'cfg(name1, ..., nameN, values("value1", "value2", ... "valueN"))' +rustc --check-cfg 'cfg(name, values("value1", "value2", ... "valueN"))' ``` where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal @@ -31,162 +29,186 @@ string. `name` specifies the name of the condition, such as `feature` or `my_cfg When the `cfg(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]` attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]` -and `cfg!(name = "value")` call. It will check that the `"value"` specified is present in the -list of expected values. If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs` -lint diagnostic. The default diagnostic level for this lint is `Warn`. +attribute and `cfg!(name = "value")` macro call. It will check that the `"value"` specified is +present in the list of expected values. If `"value"` is not in it, then `rustc` will report an +`unexpected_cfgs` lint diagnostic. The default diagnostic level for this lint is `Warn`. -The command line `--cfg` arguments are currently *NOT* checked but may very well be checked in -the future. +*The command line `--cfg` arguments are currently *NOT* checked but may very well be checked in +the future.* -To enable checking of values, but to provide an empty set of expected values, use these forms: +To enable checking of values, but to provide an *none*/empty set of expected values +(ie. expect `#[cfg(name)]`), use these forms: ```bash -rustc --check-cfg 'cfg(name1, ..., nameN)' -rustc --check-cfg 'cfg(name1, ..., nameN, values())' +rustc --check-cfg 'cfg(name)' +rustc --check-cfg 'cfg(name, values())' ``` To enable checking of name but not values (i.e. unknown expected values), use this form: ```bash -rustc --check-cfg 'cfg(name1, ..., nameN, values(any()))' +rustc --check-cfg 'cfg(name, values(any()))' +``` + +To avoid repeating the same set of values, use this form: + +```bash +rustc --check-cfg 'cfg(name1, ..., nameN, values("value1", "value2", ... "valueN"))' ``` The `--check-cfg cfg(...)` option can be repeated, both for the same condition name and for different names. If it is repeated for the same condition name, then the sets of values for that -condition are merged together (presedence is given to `any()`). +condition are merged together (precedence is given to `values(any())`). ## Well known names and values `rustc` has a internal list of well known names and their corresponding values. Those well known names and values follows the same stability as what they refer to. -Well known values checking is always enabled as long as a `--check-cfg` argument is present. +Well known names and values checking is always enabled as long as at least one +`--check-cfg` argument is present. + +As of `2024-01-09T`, the list of known names is as follows: + +<!--- See CheckCfg::fill_well_known in compiler/rustc_session/src/config.rs --> + + - `debug_assertions` + - `doc` + - `doctest` + - `miri` + - `overflow_checks` + - `panic` + - `proc_macro` + - `relocation_model` + - `sanitize` + - `sanitizer_cfi_generalize_pointers` + - `sanitizer_cfi_normalize_integers` + - `target_abi` + - `target_arch` + - `target_endian` + - `target_env` + - `target_family` + - `target_feature` + - `target_has_atomic` + - `target_has_atomic_equal_alignment` + - `target_has_atomic_load_store` + - `target_os` + - `target_pointer_width` + - `target_thread_local` + - `target_vendor` + - `test` + - `unix` + - `windows` + +Like with `values(any())`, well known names checking can be disabled by passing `cfg(any())` +as argument to `--check-cfg`. -Well known names checking is always enable as long as a `--check-cfg` argument is present -**unless** any `cfg(any())` argument is passed. +## Examples -To disable checking of well known names, use this form: +### Equivalence table -```bash -rustc --check-cfg 'cfg(any())' -``` +This table describe the equivalence of a `--cfg` argument to a `--check-cfg` argument. -NOTE: If one want to enable values and names checking without having any cfg to declare, one -can use an empty `cfg()` argument. +| `--cfg` | `--check-cfg` | +|-----------------------------|----------------------------------------------------------| +| *nothing* | *nothing* or `--check-cfg=cfg()` (to enable the checking) | +| `--cfg foo` | `--check-cfg=cfg(foo) or --check-cfg=cfg(foo, values())` | +| `--cfg foo=""` | `--check-cfg=cfg(foo, values(""))` | +| `--cfg foo="bar"` | `--check-cfg=cfg(foo, values("bar"))` | +| `--cfg foo="1" --cfg foo="2"` | `--check-cfg=cfg(foo, values("1", "2"))` | +| `--cfg foo="1" --cfg bar="2"` | `--check-cfg=cfg(foo, values("1")) --check-cfg=cfg(bar, values("2"))` | +| `--cfg foo --cfg foo="bar"` | `--check-cfg=cfg(foo) --check-cfg=cfg(foo, values("bar"))` | -## Examples +NOTE: There is (currently) no way to express that a condition name is expected but no (!= none) +values are expected. Passing an empty `values()` means *(none)* in the sense of `#[cfg(foo)]` +with no value. Users are expected to NOT pass a `--check-cfg` with that condition name. + +### Example: Cargo-like `feature` example Consider this command line: ```bash rustc --check-cfg 'cfg(feature, values("lion", "zebra"))' \ - --cfg 'feature="lion"' -Z unstable-options \ - example.rs + --cfg 'feature="lion"' -Z unstable-options example.rs ``` This command line indicates that this crate has two features: `lion` and `zebra`. The `lion` -feature is enabled, while the `zebra` feature is disabled. Exhaustive checking of names and -values are enabled by default. Consider compiling this code: +feature is enabled, while the `zebra` feature is disabled. +Given the `--check-cfg` arguments, exhaustive checking of names and +values are enabled. +`example.rs`: ```rust -// This is expected, and tame_lion() will be compiled -#[cfg(feature = "lion")] +#[cfg(feature = "lion")] // This condition is expected, as "lion" is an expected value of `feature` fn tame_lion(lion: Lion) {} -// This is expected, and ride_zebra() will NOT be compiled. -#[cfg(feature = "zebra")] -fn ride_zebra(zebra: Zebra) {} +#[cfg(feature = "zebra")] // This condition is expected, as "zebra" is an expected value of `feature` + // but the condition will still evaluate to false + // since only --cfg feature="lion" was passed +fn ride_zebra(z: Zebra) {} -// This is UNEXPECTED, and will cause a compiler warning (by default). -#[cfg(feature = "platypus")] +#[cfg(feature = "platypus")] // This condition is UNEXPECTED, as "platypus" is NOT an expected value of + // `feature` and will cause a compiler warning (by default). fn poke_platypus() {} -// This is UNEXPECTED, because 'feechure' is not a known condition name, -// and will cause a compiler warning (by default). -#[cfg(feechure = "lion")] +#[cfg(feechure = "lion")] // This condition is UNEXPECTED, as 'feechure' is NOT a expected condition + // name, no `cfg(feechure, ...)` was passed in `--check-cfg` fn tame_lion() {} -// This is UNEXPECTED, because 'windows' is a well known condition name, -// and because 'windows' doesn't take any values, -// and will cause a compiler warning (by default). -#[cfg(windows = "unix")] +#[cfg(windows = "unix")] // This condition is UNEXPECTED, as while 'windows' is a well known + // condition name, it doens't expect any values fn tame_windows() {} ``` -### Example: Checking condition names, but not values +### Example: Multiple names and values ```bash -# This turns on checking for condition names, but not values, such as 'feature' values. -rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \ - --cfg has_feathers -Z unstable-options +rustc --check-cfg 'cfg(is_embedded, has_feathers)' \ + --check-cfg 'cfg(feature, values("zapping", "lasers"))' \ + --cfg has_feathers --cfg 'feature="zapping"' -Z unstable-options ``` ```rust -#[cfg(is_embedded)] // This is expected as "is_embedded" was provided in cfg() -fn do_embedded() {} // and because names exhaustiveness was not disabled - -#[cfg(has_feathers)] // This is expected as "has_feathers" was provided in cfg() -fn do_features() {} // and because names exhaustiveness was not disabled +#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was provided in --check-cfg +fn do_embedded() {} // and doesn't take any value -#[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in cfg() - // and because no value checking was enable for "has_feathers" - // no warning is emitted for the value "zapping" -fn do_zapping() {} +#[cfg(has_feathers)] // This condition is expected, as 'has_feathers' was provided in --check-cfg +fn do_features() {} // and doesn't take any value -#[cfg(has_mumble_frotz)] // This is UNEXPECTED because names checking is enable and - // "has_mumble_frotz" was not provided in cfg() +#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' was NEVER provided + // in any --check-cfg arguments fn do_mumble_frotz() {} -``` - -### Example: Checking feature values, but not condition names -```bash -# This turns on checking for feature values, but not for condition names. -rustc --check-cfg 'cfg(feature, values("zapping", "lasers"))' \ - --check-cfg 'cfg(any())' \ - --cfg 'feature="zapping"' -Z unstable-options -``` - -```rust -#[cfg(is_embedded)] // This is doesn't raise a warning, because names checking was - // disabled by 'cfg(any())' -fn do_embedded() {} - -#[cfg(has_feathers)] // Same as above, 'cfg(any())' was provided so no name - // checking is performed -fn do_features() {} - -#[cfg(feature = "lasers")] // This is expected, "lasers" is in the cfg(feature) list +#[cfg(feature = "lasers")] // This condition is expected, as "lasers" is an expected value of `feature` fn shoot_lasers() {} -#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in the - // cfg(feature) list +#[cfg(feature = "monkeys")] // This condition is UNEXPECTED, as "monkeys" is NOT an expected value of + // `feature` fn write_shakespeare() {} ``` -### Example: Checking both condition names and feature values +### Example: Condition names without values ```bash -# This turns on checking for feature values and for condition names. -rustc --check-cfg 'cfg(is_embedded, has_feathers)' \ - --check-cfg 'cfg(feature, values("zapping", "lasers"))' \ - --cfg has_feathers --cfg 'feature="zapping"' -Z unstable-options +rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \ + --cfg has_feathers -Z unstable-options ``` ```rust -#[cfg(is_embedded)] // This is expected because "is_embedded" was provided in cfg() -fn do_embedded() {} // and doesn't take any value - -#[cfg(has_feathers)] // This is expected because "has_feathers" was provided in cfg() -fn do_features() {} // and deosn't take any value +#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was provided in --check-cfg + // as condition name +fn do_embedded() {} -#[cfg(has_mumble_frotz)] // This is UNEXPECTED, because "has_mumble_frotz" was never provided -fn do_mumble_frotz() {} +#[cfg(has_feathers)] // This condition is expected, as "has_feathers" was provided in --check-cfg + // as condition name +fn do_features() {} -#[cfg(feature = "lasers")] // This is expected, "lasers" is in the cfg(feature) list -fn shoot_lasers() {} +#[cfg(has_feathers = "zapping")] // This condition is expected, as "has_feathers" was provided in + // and because *any* values is expected for 'has_feathers' no + // warning is emitted for the value "zapping" +fn do_zapping() {} -#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in - // the cfg(feature) list -fn write_shakespeare() {} +#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' was not provided + // in any --check-cfg arguments +fn do_mumble_frotz() {} ``` diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index a5e2bc1c7af..7995a33f09f 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2717,10 +2717,34 @@ ${item.displayPath}<span class="${type}">${name}</span>\ * @return {Array<FunctionSearchType>} */ function buildItemSearchTypeAll(types, lowercasePaths) { - return types.map(type => buildItemSearchType(type, lowercasePaths)); + return types.length > 0 ? + types.map(type => buildItemSearchType(type, lowercasePaths)) : + EMPTY_GENERICS_ARRAY; } /** + * Empty, immutable map used in item search types with no bindings. + * + * @type {Map<number, Array<FunctionType>>} + */ + const EMPTY_BINDINGS_MAP = new Map(); + + /** + * Empty, immutable map used in item search types with no bindings. + * + * @type {Array<FunctionType>} + */ + const EMPTY_GENERICS_ARRAY = []; + + /** + * Object pool for function types with no bindings or generics. + * This is reset after loading the index. + * + * @type {Map<number|null, FunctionType>} + */ + let TYPES_POOL = new Map(); + + /** * Converts a single type. * * @param {RawFunctionType} type @@ -2732,15 +2756,15 @@ ${item.displayPath}<span class="${type}">${name}</span>\ let pathIndex, generics, bindings; if (typeof type === "number") { pathIndex = type; - generics = []; - bindings = new Map(); + generics = EMPTY_GENERICS_ARRAY; + bindings = EMPTY_BINDINGS_MAP; } else { pathIndex = type[PATH_INDEX_DATA]; generics = buildItemSearchTypeAll( type[GENERICS_DATA], lowercasePaths ); - if (type.length > BINDINGS_DATA) { + if (type.length > BINDINGS_DATA && type[BINDINGS_DATA].length > 0) { bindings = new Map(type[BINDINGS_DATA].map(binding => { const [assocType, constraints] = binding; // Associated type constructors are represented sloppily in rustdoc's @@ -2759,38 +2783,83 @@ ${item.displayPath}<span class="${type}">${name}</span>\ ]; })); } else { - bindings = new Map(); + bindings = EMPTY_BINDINGS_MAP; } } + /** + * @type {FunctionType} + */ + let result; if (pathIndex < 0) { // types less than 0 are generic parameters // the actual names of generic parameters aren't stored, since they aren't API - return { + result = { id: pathIndex, ty: TY_GENERIC, path: null, generics, bindings, }; - } - if (pathIndex === 0) { + } else if (pathIndex === 0) { // `0` is used as a sentinel because it's fewer bytes than `null` - return { + result = { id: null, ty: null, path: null, generics, bindings, }; + } else { + const item = lowercasePaths[pathIndex - 1]; + result = { + id: buildTypeMapIndex(item.name, isAssocType), + ty: item.ty, + path: item.path, + generics, + bindings, + }; } - const item = lowercasePaths[pathIndex - 1]; - return { - id: buildTypeMapIndex(item.name, isAssocType), - ty: item.ty, - path: item.path, - generics, - bindings, - }; + const cr = TYPES_POOL.get(result.id); + if (cr) { + // Shallow equality check. Since this function is used + // to construct every type object, this should be mostly + // equivalent to a deep equality check, except if there's + // a conflict, we don't keep the old one around, so it's + // not a fully precise implementation of hashcons. + if (cr.generics.length === result.generics.length && + cr.generics !== result.generics && + cr.generics.every((x, i) => result.generics[i] === x) + ) { + result.generics = cr.generics; + } + if (cr.bindings.size === result.bindings.size && cr.bindings !== result.bindings) { + let ok = true; + for (const [k, v] of cr.bindings.entries()) { + const v2 = result.bindings.get(v); + if (!v2) { + ok = false; + break; + } + if (v !== v2 && v.length === v2.length && v.every((x, i) => v2[i] === x)) { + result.bindings.set(k, v); + } else if (v !== v2) { + ok = false; + break; + } + } + if (ok) { + result.bindings = cr.bindings; + } + } + if (cr.ty === result.ty && cr.path === result.path + && cr.bindings === result.bindings && cr.generics === result.generics + && cr.ty === result.ty + ) { + return cr; + } + } + TYPES_POOL.set(result.id, result); + return result; } /** @@ -2801,7 +2870,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\ * object-based encoding so that the actual search code is more readable and easier to debug. * * The raw function search type format is generated using serde in - * librustdoc/html/render/mod.rs: impl Serialize for IndexItemFunctionType + * librustdoc/html/render/mod.rs: IndexItemFunctionType::write_to_string * * @param {{ * string: string, @@ -2970,8 +3039,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\ const fb = { id: null, ty: 0, - generics: [], - bindings: new Map(), + generics: EMPTY_GENERICS_ARRAY, + bindings: EMPTY_BINDINGS_MAP, }; for (const [k, v] of type.bindings.entries()) { fb.id = k; @@ -3199,6 +3268,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\ } currentIndex += itemTypes.length; } + // Drop the (rather large) hash table used for reusing function items + TYPES_POOL = new Map(); } /** diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 5be8ef7996b..c5cd30ccc34 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -15,6 +15,7 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ ("future-incompatible", "Lints that detect code that has future-compatibility problems"), ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"), ("rust-2021-compatibility", "Lints used to transition code from the 2018 edition to 2021"), + ("rust-2024-compatibility", "Lints used to transition code from the 2021 edition to 2024"), ]; type LintGroups = BTreeMap<String, BTreeSet<String>>; diff --git a/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs b/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs index d5e6d37226a..762a8d85314 100644 --- a/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs +++ b/src/tools/miri/tests/fail/tls/tls_static_dealloc.rs @@ -1,6 +1,8 @@ //! Ensure that thread-local statics get deallocated when the thread dies. #![feature(thread_local)] +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#![allow(static_mut_ref)] #[thread_local] static mut TLS: u8 = 0; diff --git a/src/tools/miri/tests/pass/static_mut.rs b/src/tools/miri/tests/pass/static_mut.rs index 218b02525bd..c1e58b70adb 100644 --- a/src/tools/miri/tests/pass/static_mut.rs +++ b/src/tools/miri/tests/pass/static_mut.rs @@ -1,4 +1,7 @@ static mut FOO: i32 = 42; + +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#[allow(static_mut_ref)] static BAR: Foo = Foo(unsafe { &FOO as *const _ }); #[allow(dead_code)] diff --git a/src/tools/miri/tests/pass/tls/tls_static.rs b/src/tools/miri/tests/pass/tls/tls_static.rs index fc4c8a283dd..9be00af47aa 100644 --- a/src/tools/miri/tests/pass/tls/tls_static.rs +++ b/src/tools/miri/tests/pass/tls/tls_static.rs @@ -8,6 +8,8 @@ //! test, we also check that thread-locals act as per-thread statics. #![feature(thread_local)] +// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_ref` lint +#![allow(static_mut_ref)] use std::thread; |
