From 88c0724b62a2244fa0f715ec9a70b6bc8eb5a401 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 10 Jun 2026 20:35:15 -0500 Subject: [PATCH 01/56] std: Update documentation for `LocalKey>::update` The disclaimers relevant for other `LocalKey` methods are relevant for `update`, so add them to the documentation. --- library/std/src/thread/local.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index b20dc21ac3c38..1ee763b8a4ba8 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -620,6 +620,14 @@ impl LocalKey> { /// Updates the contained value using a function. /// + /// This will lazily initialize the value if this thread has not referenced + /// this key yet. + /// + /// # Panics + /// + /// Panics if the key currently has its destructor running, + /// and it **may** panic if the destructor has previously been run for this thread. + /// /// # Examples /// /// ``` From ef5968d200b3e3af1fd9893ffc4a922ae829c678 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 10 Jun 2026 20:36:55 -0500 Subject: [PATCH 02/56] Stabilize `local_key_cell_update` Newly stable API: impl LocalKey> { pub fn update(&'static self, f: impl FnOnce(T) -> T) where T: Copy; } This matches the signature on `Cell`. Tracking issue: RUST-143989 --- library/std/src/thread/local.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 1ee763b8a4ba8..25660fc7b94a3 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -631,7 +631,6 @@ impl LocalKey> { /// # Examples /// /// ``` - /// #![feature(local_key_cell_update)] /// use std::cell::Cell; /// /// thread_local! { @@ -641,7 +640,7 @@ impl LocalKey> { /// X.update(|x| x + 1); /// assert_eq!(X.get(), 6); /// ``` - #[unstable(feature = "local_key_cell_update", issue = "143989")] + #[stable(feature = "local_key_cell_update", since = "CURRENT_RUSTC_VERSION")] pub fn update(&'static self, f: impl FnOnce(T) -> T) where T: Copy, From 66b489f42f682bddd01e8e1a5207a8337f44a79c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 20 Jun 2026 16:10:53 +0200 Subject: [PATCH 03/56] Update syntax of try build delegation in bors --- src/doc/rustc-dev-guide/src/tests/ci.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index 8f06d69d8cffe..31c6949d85d6c 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -209,7 +209,7 @@ to help make the perf comparison as fair as possible. > > 3. Run the prescribed try jobs with `@bors try`. As aforementioned, this > requires the user to either (1) have `try` permissions or (2) be delegated -> with `try` permissions by `@bors delegate=try` by someone who has `try` +> with `try` permissions by `@bors delegate try` by someone who has `try` > permissions. > > Note that this is usually easier to do than manually edit [`jobs.yml`]. From 35990d1bd15a3a10efca261cfef4d1ef00b5188c Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 22 Jun 2026 14:24:53 +0200 Subject: [PATCH 04/56] do not use title case for section names --- src/doc/rustc-dev-guide/src/compiler-debugging.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md index a07b418c64d4d..f9766706ad133 100644 --- a/src/doc/rustc-dev-guide/src/compiler-debugging.md +++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md @@ -248,7 +248,7 @@ You can then look at the PR to get more context on *why* it was changed. [bisect]: https://github.com/rust-lang/cargo-bisect-rustc [bisect-tutorial]: https://rust-lang.github.io/cargo-bisect-rustc/tutorial.html -## Downloading Artifacts from Rust's CI +## Downloading artifacts from Rust's CI The [rustup-toolchain-install-master][rtim] tool by kennytm can be used to download the artifacts produced by Rust's CI for a specific SHA1 -- this From 616c9f81997cf2e04fea6806bdc31543a8759714 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 22 Jun 2026 14:27:11 +0200 Subject: [PATCH 05/56] do not use title case for section names (part 2) --- src/doc/rustc-dev-guide/src/compiler-debugging.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md index a07b418c64d4d..2a4365ba669ef 100644 --- a/src/doc/rustc-dev-guide/src/compiler-debugging.md +++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md @@ -236,7 +236,7 @@ The compiler uses the [`tracing`] crate for logging. For details, see [the chapter on tracing](./tracing.md). -## Narrowing (Bisecting) Regressions +## Narrowing (bisecting) regressions The [cargo-bisect-rustc][bisect] tool can be used as a quick and easy way to find exactly which PR caused a change in `rustc` behavior. From 35df79520149487c33bca0c2c14aab0c0c8fd1d6 Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 22 Jun 2026 17:20:41 +0200 Subject: [PATCH 06/56] std: allocate less memory in `current_exe` for OpenBSD --- library/std/src/lib.rs | 1 + library/std/src/sys/paths/unix.rs | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index c9e884d89c85e..ed71db1209358 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -287,6 +287,7 @@ #![feature(doc_masked)] #![feature(doc_notable_trait)] #![feature(dropck_eyepatch)] +#![feature(exact_div)] #![feature(f16)] #![feature(f128)] #![feature(ffi_const)] diff --git a/library/std/src/sys/paths/unix.rs b/library/std/src/sys/paths/unix.rs index e0b1aafda6eb0..02b2890dcb90c 100644 --- a/library/std/src/sys/paths/unix.rs +++ b/library/std/src/sys/paths/unix.rs @@ -234,11 +234,20 @@ pub fn current_exe() -> io::Result { unsafe { let mut mib = [libc::CTL_KERN, libc::KERN_PROC_ARGS, libc::getpid(), libc::KERN_PROC_ARGV]; let mib = mib.as_mut_ptr(); - let mut argv_len = 0; - cvt(libc::sysctl(mib, 4, ptr::null_mut(), &mut argv_len, ptr::null_mut(), 0))?; - let mut argv = Vec::<*const libc::c_char>::with_capacity(argv_len as usize); - cvt(libc::sysctl(mib, 4, argv.as_mut_ptr() as *mut _, &mut argv_len, ptr::null_mut(), 0))?; - argv.set_len(argv_len as usize); + + // Determine the required size (in bytes) for the argument array ... + let mut argv_size = 0; + cvt(libc::sysctl(mib, 4, ptr::null_mut(), &mut argv_size, ptr::null_mut(), 0))?; + + // ... allocate a buffer for it ... + let argc = argv_size.div_exact(size_of::<*const libc::c_char>()).unwrap(); + let mut argv = Vec::<*const libc::c_char>::with_capacity(argc); + + // ... and retrieve the argument array. + cvt(libc::sysctl(mib, 4, argv.as_mut_ptr() as *mut _, &mut argv_size, ptr::null_mut(), 0))?; + let argc = argv_size.div_exact(size_of::<*const libc::c_char>()).unwrap(); + argv.set_len(argc); + if argv[0].is_null() { return Err(io::const_error!(io::ErrorKind::Uncategorized, "no current exe available")); } From db9b6a1d7d868086f3cab2afa37040a20f2bfe31 Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 25 Jun 2026 14:48:59 +0200 Subject: [PATCH 07/56] std: program names starting with a dot may not be path-like --- library/std/src/sys/paths/unix.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/paths/unix.rs b/library/std/src/sys/paths/unix.rs index 02b2890dcb90c..3f3fca5dcf8be 100644 --- a/library/std/src/sys/paths/unix.rs +++ b/library/std/src/sys/paths/unix.rs @@ -252,9 +252,13 @@ pub fn current_exe() -> io::Result { return Err(io::const_error!(io::ErrorKind::Uncategorized, "no current exe available")); } let argv0 = CStr::from_ptr(argv[0]).to_bytes(); - if argv0[0] == b'.' || argv0.iter().any(|b| *b == b'/') { + if argv0.iter().any(|b| *b == b'/') { + // The program name is path-like, so try to canonicalize it. crate::fs::canonicalize(OsStr::from_bytes(argv0)) } else { + // The program was probably found in the PATH. Instead of trying to + // find it again (which might not succeed if PATH has changed), just + // return the program name – this function is best-effort anyway. Ok(PathBuf::from(OsStr::from_bytes(argv0))) } } From 4928ea5384ba03ed9560890408938f76190199f2 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Mon, 29 Jun 2026 05:50:11 +0000 Subject: [PATCH 08/56] Prepare for merging from rust-lang/rust This updates the rust-version file to 7fb284d9037fa54f6a9b24261c82b394472cbfd7. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index a05eac34eb1e9..f930573748e28 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -8c75e93c5c7671c29f3e8c096b7acf56822ed23a +7fb284d9037fa54f6a9b24261c82b394472cbfd7 From 9af8904a21515948826ea28aa65f1421b13aa756 Mon Sep 17 00:00:00 2001 From: Fallible <118682743+fallible-algebra@users.noreply.github.com> Date: Mon, 1 Jun 2026 15:54:29 +0100 Subject: [PATCH 09/56] Add well-formedness chapter --- src/doc/rustc-dev-guide/src/SUMMARY.md | 1 + .../src/analysis/well-formed.md | 293 ++++++++++++++++++ .../rustc-dev-guide/src/appendix/glossary.md | 1 + 3 files changed, 295 insertions(+) create mode 100644 src/doc/rustc-dev-guide/src/analysis/well-formed.md diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 9a9861186011d..9b59170de4d05 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -191,6 +191,7 @@ - [Sharing the trait solver with rust-analyzer](./solve/sharing-crates-with-rust-analyzer.md) - [`Unsize` and `CoerceUnsized` traits](./traits/unsize.md) - [Having separate `Trait` and `Projection` bounds](./traits/separate-projection-bounds.md) +- [Well-Formedness](./analysis/well-formed.md) - [Variance](./variance.md) - [Coherence checking](./coherence.md) - [HIR Type checking](./hir-typeck/summary.md) diff --git a/src/doc/rustc-dev-guide/src/analysis/well-formed.md b/src/doc/rustc-dev-guide/src/analysis/well-formed.md new file mode 100644 index 0000000000000..49c9509fea466 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/analysis/well-formed.md @@ -0,0 +1,293 @@ +# Well-Formedness + +## What is Well-Formedness? + +"Well-formed" means "correctly built."[^wf-history] Something is _well-formed_ when its structure follows rules. When we use this term in the Rust compiler we are concerned with establishing some kind of _internal consistency_. + +## Well-Formedness in Rust + +To check that something is well-formed is to perform a "Well-formedness check." + +In the Rust compiler there are two different forms of well-formedness checking: + +- **Type-Level Term**[^terms][^terms-abbreviated] well-formedness check. + - Also called "Term well-formedness" or "Term well-formedness checking." + - Not a distinct analysis stage, this gets performed throughout analysis. +- **Item**[^items] well-formedness check (item-wfck.) + - "Item-wfck" will often wind up requiring Terms be well-formed, but skips some areas. + - Inner "Terms" can (incorrectly) get normalized first. + - More coherent as a stage in the compiler than "term well-formedness" (which is performed in many places.) + +See: [What Well-Formedness Isn't](#what-well-formedness-isnt). + +## Well-Formedness of Type-Level Terms + +Term well-formedness checking begins with building a list of things that need to be true for a term to be well-formed. We call these "Obligations"[^obligations]. + +Type-Level Terms are considered Well-Formed when their associated obligations are satisfied by the trait solver. + +### Obligations for Well-Formedness + +Specific obligations are things like `String: Clone`, `A: usize`, or `::Item: Debug`. + +On this page we show the split between obligations and terms/items as: + +```rust,ignore + +--- + +``` + +Here is an example of a well-formed type-level term: + +```rust,ignore +Vec +--- +// Obligations to fulfill +Vec where T: Sized +// Trait solver says `String: Sized` is true, so this is well-formed. +Vec where String: Sized +``` + +When we compute the obligations for `Vec`, we'll find that `Vec` generates the obligation `T: Sized`. We substitute `T` with `String` in `Vec`, so we find the obligation `String: Sized` which the trait solver will determine to be satisfied. + +The following **is not** well-formed: + +```rust,ignore +Vec +--- +// Obligations to fulfill +Vec where T: Sized +// Trait solver says `str: Sized` is not true, so this is not well-formed. +Vec where str: Sized +``` + +The above computes the obligation `T: Sized`, like before, but we substitute `T` for `str` in the instance of `Vec` finding the obligation `str: sized`. This obligation will be determined by the trait solver to be _unsatisfied_. + +#### Determining Obligations + +In the compiler, obligations of terms are found through the [`obligations`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/wf/fn.obligations.html) function in the [term well-formedness module](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/wf/index.html). + +#### Other Obligations + +Obligations are more than just trait and const generic bounds, but we've only mentioned these specific obligations so far as they are what we care about when we do "well-formedness checking" of terms. See: [`PredicateKind`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_type_ir/predicate_kind/enum.PredicateKind.html) and [`ClauseKind`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_type_ir/predicate_kind/enum.ClauseKind.html) for a full list of obligations. + +### We Don't Need Normalization (Yet) + +[Normalization](../normalization.md) is the process of resolving [type aliases](../normalization.md#aliases) into their underlying type. + +A type alias is considered well-formed if its where clauses are satisfied. The underlying type undergoes well-formedness checking at most definition and instantiation sites, but there are exceptions. + +### Const Generic Arguments + +Term well-formedness is responsible for getting "type checking" obligations of const generic terms[^tyck-const-generics]. Let's look at the following use of const generics: + +```rust,ignore +fn use_const_generics() { /* ... */ } +// call site +use_const_generics::<6>(); +--- +// call site wfck obligations +const 6: usize +``` + +The call site will provide us with the obligation `6: usize` during well-formedness checking. This obligation will be passed off to the trait solver just like any trait-style obligation, as the trait solver has more responsibilities than its name suggests. + +## Well-Formedness of Items + +Items are, generally speaking, "Things that get defined." Item-wfck happens at the signature level for types and functions, methods, and definitions/implementations of traits. + +```rust,ignore +// The `Vec` is checked during item wfck +fn foo(_: Vec) { + // The `Vec<[u8]>` is not handled by item wfck as it's not in the signature + let _: Vec<[u8]> +} +--- +Vec: Sized // Generated +Vec<[u8]>: Sized // Not done at item-wfck. Done elsewhere. +``` + +Item-wfck has more responsibilities than only collecting the obligations of its internal type-level terms and passing them to the trait solver. We do not talk about all of these here, but they can be found at the individual `check_*` functions in [**the item-wfck module**](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/wfcheck/index.html). + + + +### Global and Trivial Bounds + + + +Trait bounds are a common Obligation. Global and Trivial trait bounds are kinds of trait bounds where we already have enough information to determine if they are true or false. Item-wfck is responsible for finding and checking these bounds. + +- **Global bounds** are, in the old solver, post-normalization bounds that don't contain any generic parameters (likeΒ `` or `'a`) or bound variables (like `for<'b>`). +- **Trivial bounds** are bounds that do not need further normalization to determine if they're well-formed or not. + +Consider the following function definition: + +```rust,ignore +fn apartment_complex(block: T, name: String) where String: Clone { /* ... */ } +--- +String: Clone // Trivial & Global bound! There's no aliases to resolve. +// There could be bligations on T but we don't care about them here. +``` + +This produces a trait bound obligation `String: Clone` that is _Global_ (no generic parameters) and _Trivial_ (didn't require normalization to be well-formedness checked). The trait solver doesn't need to be given any additional information for it to be able to make a judgment on the well-formedness of `String: Clone`. + +False trivial bounds are simply trivial bounds that do not hold. The following is a basic example: + +```rust,ignore +fn apartment_simple(block: T, name: String) where String: Copy { /* ... */ } +--- +String: Copy // Trivial bound again, but this one is false! +``` + +Here we have a trivial bound that does not hold, because `String` is not `Copy`. + +#### Trivial Bounds Are Not Always Global + +Trivial Bounds are not a subset of Global Bounds. A trivial bound that isn't Global is `for<'a> String: Clone` (trivially true, has a bound variable) or `&'a str: Copy` (trivially false, has a generic parameter). + +#### Item-Wfck and Trivial/Global Bounds + + + +When checking items are well-formed we will check that there are no trivially false global bounds. + +## When We Don't Fully Do Well-Formedness Checking + +Well-formedness checking is not a coherent "stage" of type checking. There are many areas where well-formedness checking is performed, and some areas where we skip over well-formedness checking due to limitations in what kinds of analysis we can currently perform. Ideally, we would never skip or defer well-formedness checking. + +### We (Sometimes) Need Normalization + +There are places where normalization of an Item happens before its Terms have gone through well-formedness checking. This is considered problematic as doing so allows some terms to [bypass term well-formedness checking entirely](https://github.com/rust-lang/rust/issues/100041). + +### Trait Objects + +We do not require the where clauses of trait objects to be well-formed when determining if that trait object is well-formed. These where clauses are proven when coercing into a trait object, but this remains a hole in well-formedness checking. + +As an example, the following will compile because we don't have a point where we're constructing the trait object from a concrete type: + +```rust,ignore +trait Trait +where + for<'a> [u8]: Sized {} + +fn foo(_: &dyn Trait) {} +--- +// This doesn't end up being generated, because it happens within a trait object. +[u8]: Sized +``` + +The above should not compile because `[u8]: Sized`, but this won't be checked until actual use: + +```rust +trait Trait +where + for<'a> [u8]: Sized {} + +fn foo(_: &dyn Trait) {} + +// We still need to specify the bound here, otherwise `[u8]: Sized` _is_ +// checked as an obligation. +impl Trait for u8 where for<'a> [u8]: Sized {} + +fn main() { + // No matter what we do, this boundary between concrete type and trait + // object will produce the obligation `[u8]: Sized`, which will fail when + // handed over to the trait solver. + let object: Box = Box::new(42u8); + foo(&object); +} +``` + +This exception does not apply to Const Generic Arguments in trait objects: + +```rust,ignore +trait Trait {} +fn foo(_: &dyn Trait) {} +--- +const N: usize +const B: bool +N = B // Substitution +const B: usize + bool +``` + +The above doesn't compile, unlike the previous example we gave. We're doing _some_ well-formedness checking here when it comes to the const generic arguments. + +### Binders / Higher-Ranked Types + +Binders / Higher-Ranked Types reduce the amount well-formedness checking we do on a term, leaving well-formedness checking to when the bound is instantiated: + +```rust,ignore +let _: for<'a> fn(Vec<[&'a ()]>); +--- +// This doesn't end up being generated, because it happens within a HRB +[&'a ()]: Sized // slices aren't sized, this would fail! +``` + +Specifically, obligations involving variables from binders (`for<'a>`) are only checked when the binder is instantiated. Some things are stilled checked under the `for<'a>`, but we still skip a lot of things. + +A lot of unsoundness surrounds this behavior. See: [#25860](https://github.com/rust-lang/rust/issues/25860), [#84591](https://github.com/rust-lang/rust/issues/84591). + +Let's consider the following: + +```rust,ignore +for<'a, 'b> fn(&'a &'b ()) +``` + +The above HRB implies `'b: 'a` (a lifetime bound), rather than two completely separate lifetimes. This is normal lifetime behavior, but during well-formedness checking we cannot prove that this bound is generally true[^horrible], so we skip it. + +### Free Type Aliases + +The right-hand side of Free Type Aliases[^fta] is not fully checked to be well-formed at the definition site, only the types of const generic arguments in the RHS are checked. + +The following free type alias passes type checking, at time of writing: + +```rust,ignore +type WorksButShouldNot = Vec; +--- +// This should fail! But we skip the RHS of free type aliases +str: Sized // Not generated +``` + +This shouldn't work, as both `T: Sized`, `str: Sized` are implied by `Vec`. This "passes" item-wfck because the RHS of a free type alias doesn't go through well-formedness checking _until it's used_. Item-wfck is **deferred until use** for this specific case. + +For Const Generics we still do a small amount of well-formedness checking at the definition site of a free type alias. This is consistent with our current special-casing of const generic well-formedness checking when we skip over things like where bounds. + +This means that the following, despite being of a similar form to the above example, fails as it should: + +```rust,ignore +pub struct Consty; +type Alias = Consty<42>; +--- +// This *is* generated as an obligation, so this (correctly) fails. +42: bool // This is generated! +``` + + + +## "Well-Formed" or "Wellformed"? + +Prefer "well-formed" over "wellformed," as this is consistent with logic literature. This also gets abbreviated to WF in other parts of the dev guide / docs. + +## Informal Usage + +In conversation, contributors may refer to something as "well-formed" and not necessarily mean what we cover here because "well-formedness" is a general phrase associated with the correctness of formal structures. This isn't necessarily in error, but it should be looked out for. + +## What Well-Formedness Isn't + +Well-formedness checking is not "number of parameters" or "parameter type" checking[^kind-checking]. Neither term well-formedness checking nor item-wfck is concerned with if a type with 2 parameters has 1 or 3 types applied to it (assuming no defaults), or if a const generic parameter has a type applied to it. These kinds of problems will get handled during HIR-ty Lowering[^hir-ty-lower], not wfck. + +Well-formedness doesn't check or validate lifetimes, this is handled in [MIR](../borrow-check.md). + +Well-formedness in the Rust compiler doesn't correspond to "correct syntax" as it does in logic. The term has a history of general use in a mathematical context of "follows a given set of rules." In Rust, our original usage was closer to "this thing is internally consistent" with respect to the bounds on a type in places such as the original [clarification on projections and well-formedness RFC](https://github.com/rust-lang/rfcs/blob/master/text/1214-projections-lifetimes-and-wf.md). + +[^obligations]: These get referred to as Obligations, Requirements, or Constraints in the documentation. Preferred term is "obligations", as this matches the suffix of the type and the names of relevant functions. In future, this may be superseded by the new solver's term "Goal." +[^wf-history]: In linguistics this is "grammatically correct," in logic it is "syntactically correct," and in casual mathematician use it can be read as a more general "follows the rules we set for this domain." +[^horrible]: Instead, this bound is checked during "MIR borrowck" when the lifetimes are instantiated. +[^fta]: Type aliases not associated with anything, i.e. a module-level `type Alias = Vec;`. +[^items]: "Definition" style things in rust, See the [glossary](../appendix/glossary.md). +[^terms]: AKA Type expressions and subexpressions in the general sense, not a specific struct or enum in the rust compiler. See the [glossary](../appendix/glossary.md). +[^terms-abbreviated]: Abbreviated as "Terms" on this page in some areas. +[^kind-checking]: AKA "kind checking", as we might see in languages like Haskell. +[^hir-ty-lower]: +[^tyck-const-generics]: \ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/appendix/glossary.md b/src/doc/rustc-dev-guide/src/appendix/glossary.md index 30959f4b39e6f..527da87b7b7e1 100644 --- a/src/doc/rustc-dev-guide/src/appendix/glossary.md +++ b/src/doc/rustc-dev-guide/src/appendix/glossary.md @@ -102,6 +102,7 @@ Term | Meaning trans πŸ‘Ž | Short for _translation_, the code to translate MIR into LLVM IR. **Renamed to** [codegen](#codegen). `Ty` | The internal representation of a type. ([see more](../ty.md)) `TyCtxt` | The data structure often referred to as [`tcx`](#tcx) in code which provides access to session data and the query system. +Type-Level Term | An expression at the type level, such as a Type or Const Generic. UFCS πŸ‘Ž | Short for _universal function call syntax_, this is an unambiguous syntax for calling a method. **Term no longer in use!** Prefer _fully-qualified path / syntax_. ([see more](../hir-typeck/summary.md), [see the reference](https://doc.rust-lang.org/reference/expressions/call-expr.html#disambiguating-function-calls)) uninhabited type | A type which has _no_ values. This is not the same as a ZST, which has exactly 1 value. An example of an uninhabited type is `enum Foo {}`, which has no variants, and so, can never be created. The compiler can treat code that deals with uninhabited types as dead code, since there is no such value to be manipulated. `!` (the never type) is an uninhabited type. Uninhabited types are also called _empty types_. upvar | A variable captured by a closure from outside the closure. From 6bf1cd9b2c2ad1a0d50ed9173ad211c31013c389 Mon Sep 17 00:00:00 2001 From: Kiran Shila Date: Tue, 23 Jun 2026 12:43:41 -0700 Subject: [PATCH 10/56] update autodiff install docs for nix --- .../src/autodiff/installation.md | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/autodiff/installation.md b/src/doc/rustc-dev-guide/src/autodiff/installation.md index 7247efd46a380..4176763a7bd62 100644 --- a/src/doc/rustc-dev-guide/src/autodiff/installation.md +++ b/src/doc/rustc-dev-guide/src/autodiff/installation.md @@ -18,30 +18,30 @@ Please run: rustup +nightly component add enzyme ``` -## Installation guide for Nix user. +## Installation guide for Nix + +On [Nix], you can declare a nightly Rust toolchain with the Enzyme component using the [oxalica rust-overlay]. + +For example: + +```nix +rust-bin.selectLatestNightlyWith (toolchain: toolchain.default.override { + extensions = [ "enzyme" ]; +}) +``` + +Alternatively, you can create a [toolchain file] that declares the Enzyme component such as + +```toml +[toolchain] +channel = "nightly-2026-06-23" +components = [ "enzyme" ] +``` + +and consume it in the overlay -This setup was recommended by a nix and autodiff user. -It uses [`Overlay`]. -Please verify for yourself if you are comfortable using that repository. -In that case you might use the following nix configuration to get a rustc that supports `std::autodiff`. ```nix -{ - enzymeLib = pkgs.fetchzip { - url = "https://ci-artifacts.rust-lang.org/rustc-builds/ec818fda361ca216eb186f5cf45131bd9c776bb4/enzyme-nightly-x86_64-unknown-linux-gnu.tar.xz"; - sha256 = "sha256-Rnrop44vzS+qmYNaRoMNNMFyAc3YsMnwdNGYMXpZ5VY="; - }; - - rustToolchain = pkgs.symlinkJoin { - name = "rust-with-enzyme"; - paths = [pkgs.rust-bin.nightly.latest.default]; - nativeBuildInputs = [pkgs.makeWrapper]; - postBuild = '' - libdir=$out/lib/rustlib/x86_64-unknown-linux-gnu/lib - cp ${enzymeLib}/enzyme-preview/lib/rustlib/x86_64-unknown-linux-gnu/lib/libEnzyme-22.so $libdir/ - wrapProgram $out/bin/rustc --add-flags "--sysroot $out" - ''; - }; -} +rust-bin.fromRustupToolchainFile ./rust-toolchain.toml ``` ## Build instructions @@ -135,4 +135,6 @@ This will build Enzyme, and you can find it in `Enzyme/enzyme/build/lib/ Date: Wed, 1 Jul 2026 04:39:15 +0200 Subject: [PATCH 11/56] Fix typo in best-practices.md --- src/doc/rustc-dev-guide/src/tests/best-practices.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/best-practices.md b/src/doc/rustc-dev-guide/src/tests/best-practices.md index b6daffa6683c0..c0230c6717473 100644 --- a/src/doc/rustc-dev-guide/src/tests/best-practices.md +++ b/src/doc/rustc-dev-guide/src/tests/best-practices.md @@ -171,7 +171,7 @@ place. If a test suite can randomly spuriously fail due to flaky tests, did the whole test suite pass or did I just get lucky/unlucky? -- Flaky tests can randomly fail in full CI, wasting previous full CI resources. +- Flaky tests can randomly fail in full CI, wasting precious full CI resources. ## Compiletest directives From a4eba1dae50971b11bbdad7bbe65de3275b2a5a3 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 1 Jul 2026 09:12:53 +0200 Subject: [PATCH 12/56] make more simple --- src/doc/rustc-dev-guide/src/tests/best-practices.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/tests/best-practices.md b/src/doc/rustc-dev-guide/src/tests/best-practices.md index c0230c6717473..d1378a849a9d4 100644 --- a/src/doc/rustc-dev-guide/src/tests/best-practices.md +++ b/src/doc/rustc-dev-guide/src/tests/best-practices.md @@ -171,7 +171,7 @@ place. If a test suite can randomly spuriously fail due to flaky tests, did the whole test suite pass or did I just get lucky/unlucky? -- Flaky tests can randomly fail in full CI, wasting precious full CI resources. +- Flaky tests can randomly fail in full CI, wasting precious resources. ## Compiletest directives From 866e997d6e9929b07cb06a98608e6ce6075f0d06 Mon Sep 17 00:00:00 2001 From: danieljofficial Date: Tue, 16 Jun 2026 21:13:47 +0100 Subject: [PATCH 13/56] move a few tests out of tests/ui/issues --- .../generic-fn-items-in-array-literal.rs} | 0 .../issue-33241.rs => dst/tuple-with-unsized-tail-field.rs} | 0 .../issue-35988.rs => enum/unsized-field-in-enum-variant.rs} | 0 .../unsized-field-in-enum-variant.stderr} | 0 .../multibyte-char-in-diagnostic-source-line.rs} | 0 .../multibyte-char-in-diagnostic-source-line.stderr} | 0 .../auxiliary/unstable-crate-import-gated-in-2018-edition.rs} | 0 .../unstable-crate-import-gated-in-2018-edition.rs} | 0 .../unstable-crate-import-gated-in-2018-edition.stderr} | 0 .../issue-3556.rs => fmt/format-enum-with-recursive-variant.rs} | 0 .../issue-43431.rs => fn_traits/fn-trait-ufcs-call-in-impl.rs} | 0 .../fn-trait-ufcs-call-in-impl.stderr} | 0 .../issue-45510.rs => fn_traits/overloaded-fnonce-resolution.rs} | 0 .../parenthesized-fn-trait-in-qualified-path.rs} | 0 .../parenthesized-fn-trait-in-qualified-path.stderr} | 0 .../accept-lifetime-list-empty-or-trailing-comma.rs} | 0 16 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-43923.rs => coercion/generic-fn-items-in-array-literal.rs} (100%) rename tests/ui/{issues/issue-33241.rs => dst/tuple-with-unsized-tail-field.rs} (100%) rename tests/ui/{issues/issue-35988.rs => enum/unsized-field-in-enum-variant.rs} (100%) rename tests/ui/{issues/issue-35988.stderr => enum/unsized-field-in-enum-variant.stderr} (100%) rename tests/ui/{issues/issue-44023.rs => error-emitter/multibyte-char-in-diagnostic-source-line.rs} (100%) rename tests/ui/{issues/issue-44023.stderr => error-emitter/multibyte-char-in-diagnostic-source-line.stderr} (100%) rename tests/ui/{issues/auxiliary/issue-52489.rs => feature-gates/auxiliary/unstable-crate-import-gated-in-2018-edition.rs} (100%) rename tests/ui/{issues/issue-52489.rs => feature-gates/unstable-crate-import-gated-in-2018-edition.rs} (100%) rename tests/ui/{issues/issue-52489.stderr => feature-gates/unstable-crate-import-gated-in-2018-edition.stderr} (100%) rename tests/ui/{issues/issue-3556.rs => fmt/format-enum-with-recursive-variant.rs} (100%) rename tests/ui/{issues/issue-43431.rs => fn_traits/fn-trait-ufcs-call-in-impl.rs} (100%) rename tests/ui/{issues/issue-43431.stderr => fn_traits/fn-trait-ufcs-call-in-impl.stderr} (100%) rename tests/ui/{issues/issue-45510.rs => fn_traits/overloaded-fnonce-resolution.rs} (100%) rename tests/ui/{issues/issue-39687.rs => fn_traits/parenthesized-fn-trait-in-qualified-path.rs} (100%) rename tests/ui/{issues/issue-39687.stderr => fn_traits/parenthesized-fn-trait-in-qualified-path.stderr} (100%) rename tests/ui/{issues/issue-37733.rs => parser/accept-lifetime-list-empty-or-trailing-comma.rs} (100%) diff --git a/tests/ui/issues/issue-43923.rs b/tests/ui/coercion/generic-fn-items-in-array-literal.rs similarity index 100% rename from tests/ui/issues/issue-43923.rs rename to tests/ui/coercion/generic-fn-items-in-array-literal.rs diff --git a/tests/ui/issues/issue-33241.rs b/tests/ui/dst/tuple-with-unsized-tail-field.rs similarity index 100% rename from tests/ui/issues/issue-33241.rs rename to tests/ui/dst/tuple-with-unsized-tail-field.rs diff --git a/tests/ui/issues/issue-35988.rs b/tests/ui/enum/unsized-field-in-enum-variant.rs similarity index 100% rename from tests/ui/issues/issue-35988.rs rename to tests/ui/enum/unsized-field-in-enum-variant.rs diff --git a/tests/ui/issues/issue-35988.stderr b/tests/ui/enum/unsized-field-in-enum-variant.stderr similarity index 100% rename from tests/ui/issues/issue-35988.stderr rename to tests/ui/enum/unsized-field-in-enum-variant.stderr diff --git a/tests/ui/issues/issue-44023.rs b/tests/ui/error-emitter/multibyte-char-in-diagnostic-source-line.rs similarity index 100% rename from tests/ui/issues/issue-44023.rs rename to tests/ui/error-emitter/multibyte-char-in-diagnostic-source-line.rs diff --git a/tests/ui/issues/issue-44023.stderr b/tests/ui/error-emitter/multibyte-char-in-diagnostic-source-line.stderr similarity index 100% rename from tests/ui/issues/issue-44023.stderr rename to tests/ui/error-emitter/multibyte-char-in-diagnostic-source-line.stderr diff --git a/tests/ui/issues/auxiliary/issue-52489.rs b/tests/ui/feature-gates/auxiliary/unstable-crate-import-gated-in-2018-edition.rs similarity index 100% rename from tests/ui/issues/auxiliary/issue-52489.rs rename to tests/ui/feature-gates/auxiliary/unstable-crate-import-gated-in-2018-edition.rs diff --git a/tests/ui/issues/issue-52489.rs b/tests/ui/feature-gates/unstable-crate-import-gated-in-2018-edition.rs similarity index 100% rename from tests/ui/issues/issue-52489.rs rename to tests/ui/feature-gates/unstable-crate-import-gated-in-2018-edition.rs diff --git a/tests/ui/issues/issue-52489.stderr b/tests/ui/feature-gates/unstable-crate-import-gated-in-2018-edition.stderr similarity index 100% rename from tests/ui/issues/issue-52489.stderr rename to tests/ui/feature-gates/unstable-crate-import-gated-in-2018-edition.stderr diff --git a/tests/ui/issues/issue-3556.rs b/tests/ui/fmt/format-enum-with-recursive-variant.rs similarity index 100% rename from tests/ui/issues/issue-3556.rs rename to tests/ui/fmt/format-enum-with-recursive-variant.rs diff --git a/tests/ui/issues/issue-43431.rs b/tests/ui/fn_traits/fn-trait-ufcs-call-in-impl.rs similarity index 100% rename from tests/ui/issues/issue-43431.rs rename to tests/ui/fn_traits/fn-trait-ufcs-call-in-impl.rs diff --git a/tests/ui/issues/issue-43431.stderr b/tests/ui/fn_traits/fn-trait-ufcs-call-in-impl.stderr similarity index 100% rename from tests/ui/issues/issue-43431.stderr rename to tests/ui/fn_traits/fn-trait-ufcs-call-in-impl.stderr diff --git a/tests/ui/issues/issue-45510.rs b/tests/ui/fn_traits/overloaded-fnonce-resolution.rs similarity index 100% rename from tests/ui/issues/issue-45510.rs rename to tests/ui/fn_traits/overloaded-fnonce-resolution.rs diff --git a/tests/ui/issues/issue-39687.rs b/tests/ui/fn_traits/parenthesized-fn-trait-in-qualified-path.rs similarity index 100% rename from tests/ui/issues/issue-39687.rs rename to tests/ui/fn_traits/parenthesized-fn-trait-in-qualified-path.rs diff --git a/tests/ui/issues/issue-39687.stderr b/tests/ui/fn_traits/parenthesized-fn-trait-in-qualified-path.stderr similarity index 100% rename from tests/ui/issues/issue-39687.stderr rename to tests/ui/fn_traits/parenthesized-fn-trait-in-qualified-path.stderr diff --git a/tests/ui/issues/issue-37733.rs b/tests/ui/parser/accept-lifetime-list-empty-or-trailing-comma.rs similarity index 100% rename from tests/ui/issues/issue-37733.rs rename to tests/ui/parser/accept-lifetime-list-empty-or-trailing-comma.rs From 2c0fe5bc4204f24c75273284976ee7e1e0324d5e Mon Sep 17 00:00:00 2001 From: danieljofficial Date: Wed, 1 Jul 2026 18:31:47 +0100 Subject: [PATCH 14/56] add links and bless --- tests/ui/coercion/generic-fn-items-in-array-literal.rs | 1 + tests/ui/dst/tuple-with-unsized-tail-field.rs | 1 + tests/ui/enum/unsized-field-in-enum-variant.rs | 1 + tests/ui/enum/unsized-field-in-enum-variant.stderr | 2 +- .../multibyte-char-in-diagnostic-source-line.rs | 1 + .../multibyte-char-in-diagnostic-source-line.stderr | 2 +- .../unstable-crate-import-gated-in-2018-edition.rs | 3 ++- .../unstable-crate-import-gated-in-2018-edition.rs | 9 +++++---- .../unstable-crate-import-gated-in-2018-edition.stderr | 10 +++++----- tests/ui/fmt/format-enum-with-recursive-variant.rs | 1 + tests/ui/fn_traits/fn-trait-ufcs-call-in-impl.rs | 1 + tests/ui/fn_traits/fn-trait-ufcs-call-in-impl.stderr | 2 +- tests/ui/fn_traits/overloaded-fnonce-resolution.rs | 1 + .../parenthesized-fn-trait-in-qualified-path.rs | 1 + .../parenthesized-fn-trait-in-qualified-path.stderr | 2 +- .../accept-lifetime-list-empty-or-trailing-comma.rs | 1 + 16 files changed, 25 insertions(+), 14 deletions(-) diff --git a/tests/ui/coercion/generic-fn-items-in-array-literal.rs b/tests/ui/coercion/generic-fn-items-in-array-literal.rs index 4cd46b6ca6025..cbc5d391ed1fe 100644 --- a/tests/ui/coercion/generic-fn-items-in-array-literal.rs +++ b/tests/ui/coercion/generic-fn-items-in-array-literal.rs @@ -1,3 +1,4 @@ +//! Regression test for //@ run-pass #![allow(dead_code)] #![allow(unused_variables)] diff --git a/tests/ui/dst/tuple-with-unsized-tail-field.rs b/tests/ui/dst/tuple-with-unsized-tail-field.rs index 1c497876a90da..db81106f0422b 100644 --- a/tests/ui/dst/tuple-with-unsized-tail-field.rs +++ b/tests/ui/dst/tuple-with-unsized-tail-field.rs @@ -1,3 +1,4 @@ +//! Regression test for //@ check-pass use std::fmt; diff --git a/tests/ui/enum/unsized-field-in-enum-variant.rs b/tests/ui/enum/unsized-field-in-enum-variant.rs index 5cf2f8e5212d1..a2640e1ba5b13 100644 --- a/tests/ui/enum/unsized-field-in-enum-variant.rs +++ b/tests/ui/enum/unsized-field-in-enum-variant.rs @@ -1,3 +1,4 @@ +//! Regression test for enum E { V([Box]), //~^ ERROR the size for values of type diff --git a/tests/ui/enum/unsized-field-in-enum-variant.stderr b/tests/ui/enum/unsized-field-in-enum-variant.stderr index 4a674b010ea62..7ea40614da22d 100644 --- a/tests/ui/enum/unsized-field-in-enum-variant.stderr +++ b/tests/ui/enum/unsized-field-in-enum-variant.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `[Box]` cannot be known at compilation time - --> $DIR/issue-35988.rs:2:7 + --> $DIR/unsized-field-in-enum-variant.rs:3:7 | LL | V([Box]), | ^^^^^^^^ doesn't have a size known at compile-time diff --git a/tests/ui/error-emitter/multibyte-char-in-diagnostic-source-line.rs b/tests/ui/error-emitter/multibyte-char-in-diagnostic-source-line.rs index e4320b7dac592..4b1843bb5fb0f 100644 --- a/tests/ui/error-emitter/multibyte-char-in-diagnostic-source-line.rs +++ b/tests/ui/error-emitter/multibyte-char-in-diagnostic-source-line.rs @@ -1,3 +1,4 @@ +//! Regression test for pub fn main () {} fn αƒ‘αƒαƒ­αƒ›αƒ”αƒšαƒαƒ“_αƒ’αƒ”αƒ›αƒ αƒ˜αƒ”αƒšαƒ˜_αƒ‘αƒαƒ“αƒ˜αƒšαƒ˜ ( ) -> isize { //~ ERROR mismatched types diff --git a/tests/ui/error-emitter/multibyte-char-in-diagnostic-source-line.stderr b/tests/ui/error-emitter/multibyte-char-in-diagnostic-source-line.stderr index 8554154fba515..9ced2d882b8f6 100644 --- a/tests/ui/error-emitter/multibyte-char-in-diagnostic-source-line.stderr +++ b/tests/ui/error-emitter/multibyte-char-in-diagnostic-source-line.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-44023.rs:3:36 + --> $DIR/multibyte-char-in-diagnostic-source-line.rs:4:36 | LL | fn αƒ‘αƒαƒ­αƒ›αƒ”αƒšαƒαƒ“_αƒ’αƒ”αƒ›αƒ αƒ˜αƒ”αƒšαƒ˜_αƒ‘αƒαƒ“αƒ˜αƒšαƒ˜ ( ) -> isize { | ------------------------ ^^^^^ expected `isize`, found `()` diff --git a/tests/ui/feature-gates/auxiliary/unstable-crate-import-gated-in-2018-edition.rs b/tests/ui/feature-gates/auxiliary/unstable-crate-import-gated-in-2018-edition.rs index f53bf7db52536..f725a948d6aec 100644 --- a/tests/ui/feature-gates/auxiliary/unstable-crate-import-gated-in-2018-edition.rs +++ b/tests/ui/feature-gates/auxiliary/unstable-crate-import-gated-in-2018-edition.rs @@ -1,3 +1,4 @@ +//! Auxiliary crate for regression test of #![crate_type = "lib"] -#![unstable(feature = "issue_52489_unstable", issue = "none")] +#![unstable(feature = "unstable_crate_import_gated_in_2018_edition", issue = "none")] #![feature(staged_api)] diff --git a/tests/ui/feature-gates/unstable-crate-import-gated-in-2018-edition.rs b/tests/ui/feature-gates/unstable-crate-import-gated-in-2018-edition.rs index c1e1cb41c76d6..9e2036357ff63 100644 --- a/tests/ui/feature-gates/unstable-crate-import-gated-in-2018-edition.rs +++ b/tests/ui/feature-gates/unstable-crate-import-gated-in-2018-edition.rs @@ -1,8 +1,9 @@ +//! Regression test for //@ edition:2018 -//@ aux-build:issue-52489.rs -//@ compile-flags:--extern issue_52489 +//@ aux-build:unstable-crate-import-gated-in-2018-edition.rs +//@ compile-flags: --extern unstable_crate_import_gated_in_2018_edition -use issue_52489; -//~^ ERROR use of unstable library feature `issue_52489_unstable` +use unstable_crate_import_gated_in_2018_edition; +//~^ ERROR use of unstable library feature `unstable_crate_import_gated_in_2018_edition` fn main() {} diff --git a/tests/ui/feature-gates/unstable-crate-import-gated-in-2018-edition.stderr b/tests/ui/feature-gates/unstable-crate-import-gated-in-2018-edition.stderr index 8e5b87b7f0fd2..d9ef6c01ca0ab 100644 --- a/tests/ui/feature-gates/unstable-crate-import-gated-in-2018-edition.stderr +++ b/tests/ui/feature-gates/unstable-crate-import-gated-in-2018-edition.stderr @@ -1,10 +1,10 @@ -error[E0658]: use of unstable library feature `issue_52489_unstable` - --> $DIR/issue-52489.rs:5:5 +error[E0658]: use of unstable library feature `unstable_crate_import_gated_in_2018_edition` + --> $DIR/unstable-crate-import-gated-in-2018-edition.rs:6:5 | -LL | use issue_52489; - | ^^^^^^^^^^^ +LL | use unstable_crate_import_gated_in_2018_edition; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: add `#![feature(issue_52489_unstable)]` to the crate attributes to enable + = help: add `#![feature(unstable_crate_import_gated_in_2018_edition)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 1 previous error diff --git a/tests/ui/fmt/format-enum-with-recursive-variant.rs b/tests/ui/fmt/format-enum-with-recursive-variant.rs index 72fd46e0a4a1c..9ea7c4d91a6c2 100644 --- a/tests/ui/fmt/format-enum-with-recursive-variant.rs +++ b/tests/ui/fmt/format-enum-with-recursive-variant.rs @@ -1,3 +1,4 @@ +//! Regression test for //@ run-pass #![allow(dead_code)] diff --git a/tests/ui/fn_traits/fn-trait-ufcs-call-in-impl.rs b/tests/ui/fn_traits/fn-trait-ufcs-call-in-impl.rs index 0286336910e10..8ccf231215689 100644 --- a/tests/ui/fn_traits/fn-trait-ufcs-call-in-impl.rs +++ b/tests/ui/fn_traits/fn-trait-ufcs-call-in-impl.rs @@ -1,3 +1,4 @@ +//! Regression test for #![feature(fn_traits)] trait CallSingle { diff --git a/tests/ui/fn_traits/fn-trait-ufcs-call-in-impl.stderr b/tests/ui/fn_traits/fn-trait-ufcs-call-in-impl.stderr index 27a720408e4b7..33dbbfd7ac077 100644 --- a/tests/ui/fn_traits/fn-trait-ufcs-call-in-impl.stderr +++ b/tests/ui/fn_traits/fn-trait-ufcs-call-in-impl.stderr @@ -1,5 +1,5 @@ error[E0229]: associated item constraints are not allowed here - --> $DIR/issue-43431.rs:9:27 + --> $DIR/fn-trait-ufcs-call-in-impl.rs:10:27 | LL | B>::call(self, (a,)) | ^ associated item constraint not allowed here diff --git a/tests/ui/fn_traits/overloaded-fnonce-resolution.rs b/tests/ui/fn_traits/overloaded-fnonce-resolution.rs index d73218a385924..0f7a8649fd627 100644 --- a/tests/ui/fn_traits/overloaded-fnonce-resolution.rs +++ b/tests/ui/fn_traits/overloaded-fnonce-resolution.rs @@ -1,3 +1,4 @@ +//! Regression test for // Test overloaded resolution of fn_traits. //@ run-pass diff --git a/tests/ui/fn_traits/parenthesized-fn-trait-in-qualified-path.rs b/tests/ui/fn_traits/parenthesized-fn-trait-in-qualified-path.rs index 58f981b63d11d..479b23ac30542 100644 --- a/tests/ui/fn_traits/parenthesized-fn-trait-in-qualified-path.rs +++ b/tests/ui/fn_traits/parenthesized-fn-trait-in-qualified-path.rs @@ -1,3 +1,4 @@ +//! Regression test for #![feature(fn_traits)] fn main() { diff --git a/tests/ui/fn_traits/parenthesized-fn-trait-in-qualified-path.stderr b/tests/ui/fn_traits/parenthesized-fn-trait-in-qualified-path.stderr index 87e5fdc2d8f22..b863561f02855 100644 --- a/tests/ui/fn_traits/parenthesized-fn-trait-in-qualified-path.stderr +++ b/tests/ui/fn_traits/parenthesized-fn-trait-in-qualified-path.stderr @@ -1,5 +1,5 @@ error[E0229]: associated item constraints are not allowed here - --> $DIR/issue-39687.rs:4:14 + --> $DIR/parenthesized-fn-trait-in-qualified-path.rs:5:14 | LL | ::call; | ^^^^ associated item constraint not allowed here diff --git a/tests/ui/parser/accept-lifetime-list-empty-or-trailing-comma.rs b/tests/ui/parser/accept-lifetime-list-empty-or-trailing-comma.rs index fff42e9fc3c99..3bac134f39682 100644 --- a/tests/ui/parser/accept-lifetime-list-empty-or-trailing-comma.rs +++ b/tests/ui/parser/accept-lifetime-list-empty-or-trailing-comma.rs @@ -1,3 +1,4 @@ +//! Regression test for //@ build-pass #![allow(dead_code)] type A = for<> fn(); From fdfba6737d9718efd73cbded185265a8c4dcd9f3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 1 Jul 2026 14:38:58 +1000 Subject: [PATCH 15/56] Clarify some interning details `Interned` does pointer equality/hashing, which is valid in two cases. - The values are guaranteed to be unique (e.g. via interning, or construction). This is how `rustc_middle` uses `Interned`. - The type has "identity" and different values should be considered distinct even if they are identical. This is how `rustc_resolve` uses `Interned`. PR 137202 tried to clarify things by adding a `T: Hash` constraint to `Interned<'a, T>`. This constraint isn't actually used, because `Interned` is hashed based on pointer value, not contents. But it was intended to communicate the idea that a type stored in `Interned` is actually interned, which is likely to be done with hashing. Panicking impls of `Hash` were added for the relevant `rustc_resolve` types to work around the fact that it doesn't use hashing-based interning. In my opinion PR 137202 didn't improve things. The `T: Hash` constraint is only aimed at the interning case, and even for that case it's not quite right because you could use a `BTreeMap` to intern instead of a `HashMap`. This commit does several things. - Removes the `T: Hash` constraint and the `Hash` impls for `rustc_resolve` types added in PR 137202. - Improves the comments on `Interned` to cover the non-interning cases. - Removes the `PartialOrd`/`Ord` impls on `Interned` because (a) they're not used, and (b) their meaning is unclear for the "identity" case. - Improves the documentation in `rustc_resolve` to explain how `Interned` usage is valid there. --- compiler/rustc_data_structures/src/intern.rs | 78 +++++++------------ .../rustc_data_structures/src/intern/tests.rs | 27 +------ compiler/rustc_resolve/src/imports.rs | 19 +---- compiler/rustc_resolve/src/lib.rs | 39 +++------- 4 files changed, 44 insertions(+), 119 deletions(-) diff --git a/compiler/rustc_data_structures/src/intern.rs b/compiler/rustc_data_structures/src/intern.rs index 042cf1910adc8..382c921f198e0 100644 --- a/compiler/rustc_data_structures/src/intern.rs +++ b/compiler/rustc_data_structures/src/intern.rs @@ -1,4 +1,3 @@ -use std::cmp::Ordering; use std::fmt::{self, Debug}; use std::hash::{Hash, Hasher}; use std::ops::Deref; @@ -11,26 +10,40 @@ mod private { pub struct PrivateZst; } -/// A reference to a value that is interned, and is known to be unique. +/// This type is a reference with one special behaviour: the reference pointer (i.e. the address of +/// the value referred to) is used for equality and hashing, rather than the value's contents, as +/// would occur with a vanilla reference. There are two cases when this is useful. /// -/// Note that it is possible to have a `T` and a `Interned` that are (or -/// refer to) equal but different values. But if you have two different -/// `Interned`s, they both refer to the same value, at a single location in -/// memory. This means that equality and hashing can be done on the value's -/// address rather than the value's contents, which can improve performance. +/// - Types where uniqueness is guaranteed. This is most commonly achieved via interning -- hence +/// the name `Interned` -- though it may also be possible via other means. In this case, the use +/// of `Interned` is primarily a performance optimization, because pointer equality/hashing gives +/// the same results as value equality/hashing, but is faster. (The use of the `Interned` type +/// also provides documentation about the interned-ness.) /// -/// The `PrivateZst` field means you can pattern match with `Interned(v, _)` -/// but you can only construct a `Interned` with `new_unchecked`, and not -/// directly. +/// Note that in this case it is possible to have a `T` and a `Interned` that are (or refer +/// to) equal but different values. But if you have two different `Interned`s, they both refer +/// to the same value, at a single location in memory. +/// +/// - Types with identity, where distinct values should always be considered unequal, even if they +/// have equal values. These are rare in Rust, but do occur sometimes. In this case, the use of +/// `Interned` gives different behaviour, because pointer equality/hashing gives different result +/// to value equality/hashing, and is also faster. +/// +/// The `PrivateZst` field means you can pattern match with `Interned(v, _)` but you can only +/// construct a `Interned` with `new_unchecked`, and not directly. This means that all creation +/// points can be audited easily. #[rustc_pass_by_value] pub struct Interned<'a, T>(pub &'a T, pub private::PrivateZst); impl<'a, T> Interned<'a, T> { - /// Create a new `Interned` value. The value referred to *must* be interned - /// and thus be unique, and it *must* remain unique in the future. This - /// function has `_unchecked` in the name but is not `unsafe`, because if - /// the uniqueness condition is violated condition it will cause incorrect - /// behaviour but will not affect memory safety. + /// Create a new `Interned` value. The value referred to *must* satisfy one of the following + /// two conditions. + /// - It must be unique and it must remain unique in the future. + /// - It must be of a type with "identity" such that distinct values should always be + /// considered unequal. + /// + /// This function has `_unchecked` in the name but is not `unsafe`, because if neither of these + /// conditions is met it will cause incorrect behaviour but will not affect memory safety. #[inline] pub const fn new_unchecked(t: &'a T) -> Self { Interned(t, private::PrivateZst) @@ -64,41 +77,10 @@ impl<'a, T> PartialEq for Interned<'a, T> { impl<'a, T> Eq for Interned<'a, T> {} -impl<'a, T: PartialOrd> PartialOrd for Interned<'a, T> { - fn partial_cmp(&self, other: &Interned<'a, T>) -> Option { - // Pointer equality implies equality, due to the uniqueness constraint, - // but the contents must be compared otherwise. - if ptr::eq(self.0, other.0) { - Some(Ordering::Equal) - } else { - let res = self.0.partial_cmp(other.0); - debug_assert_ne!(res, Some(Ordering::Equal)); - res - } - } -} - -impl<'a, T: Ord> Ord for Interned<'a, T> { - fn cmp(&self, other: &Interned<'a, T>) -> Ordering { - // Pointer equality implies equality, due to the uniqueness constraint, - // but the contents must be compared otherwise. - if ptr::eq(self.0, other.0) { - Ordering::Equal - } else { - let res = self.0.cmp(other.0); - debug_assert_ne!(res, Ordering::Equal); - res - } - } -} - -impl<'a, T> Hash for Interned<'a, T> -where - T: Hash, -{ +impl<'a, T> Hash for Interned<'a, T> { #[inline] fn hash(&self, s: &mut H) { - // Pointer hashing is sufficient, due to the uniqueness constraint. + // Pointer hashing is sufficient. ptr::hash(self.0, s) } } diff --git a/compiler/rustc_data_structures/src/intern/tests.rs b/compiler/rustc_data_structures/src/intern/tests.rs index a85cd480a09f6..8b814bff1301a 100644 --- a/compiler/rustc_data_structures/src/intern/tests.rs +++ b/compiler/rustc_data_structures/src/intern/tests.rs @@ -1,5 +1,6 @@ use super::*; +#[allow(unused)] #[derive(Debug)] struct S(u32); @@ -11,22 +12,6 @@ impl PartialEq for S { impl Eq for S {} -impl PartialOrd for S { - fn partial_cmp(&self, other: &S) -> Option { - // The `==` case should be handled by `Interned`. - assert_ne!(self.0, other.0); - self.0.partial_cmp(&other.0) - } -} - -impl Ord for S { - fn cmp(&self, other: &S) -> Ordering { - // The `==` case should be handled by `Interned`. - assert_ne!(self.0, other.0); - self.0.cmp(&other.0) - } -} - #[test] fn test_uniq() { let s1 = S(1); @@ -45,14 +30,4 @@ fn test_uniq() { assert_eq!(v1, v1); assert_eq!(v3a, v3b); assert_ne!(v1, v4); // same content but different addresses: not equal - - assert_eq!(v1.cmp(&v2), Ordering::Less); - assert_eq!(v3a.cmp(&v2), Ordering::Greater); - assert_eq!(v1.cmp(&v1), Ordering::Equal); // only uses Interned::eq, not S::cmp - assert_eq!(v3a.cmp(&v3b), Ordering::Equal); // only uses Interned::eq, not S::cmp - - assert_eq!(v1.partial_cmp(&v2), Some(Ordering::Less)); - assert_eq!(v3a.partial_cmp(&v2), Some(Ordering::Greater)); - assert_eq!(v1.partial_cmp(&v1), Some(Ordering::Equal)); // only uses Interned::eq, not S::cmp - assert_eq!(v3a.partial_cmp(&v3b), Some(Ordering::Equal)); // only uses Interned::eq, not S::cmp } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index c4d668edefa32..379ae992c9a6e 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -210,23 +210,10 @@ pub(crate) struct ImportData<'ra> { pub on_unknown_attr: Option, } -/// All imports are unique and allocated on a same arena, -/// so we can use referential equality to compare them. +/// `Interned` is used because values of this type have "identity" and compare as unequal even if +/// they have the same contents. pub(crate) type Import<'ra> = Interned<'ra, ImportData<'ra>>; -// Allows us to use Interned without actually enforcing (via Hash/PartialEq/...) uniqueness of the -// contained data. -// FIXME: We may wish to actually have at least debug-level assertions that Interned's guarantees -// are upheld. -impl std::hash::Hash for ImportData<'_> { - fn hash(&self, _: &mut H) - where - H: std::hash::Hasher, - { - unreachable!() - } -} - impl<'ra> ImportData<'ra> { pub(crate) fn is_glob(&self) -> bool { matches!(self.kind, ImportKind::Glob { .. }) @@ -291,6 +278,8 @@ pub(crate) struct NameResolution<'ra> { pub orig_ident_span: Span, } +/// `Interned` is used because values of this type have "identity" and compare as unequal even if +/// they have the same contents. pub(crate) type NameResolutionRef<'ra> = Interned<'ra, CmRefCell>>; impl<'ra> NameResolution<'ra> { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 3b93f2d1fd130..2ceec78bd300b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -682,8 +682,8 @@ struct ModuleData<'ra> { self_decl: Option>, } -/// All modules are unique and allocated on a same arena, -/// so we can use referential equality to compare them. +/// `Interned` is used because values of this type have "identity" and compare as unequal even if +/// they have the same contents. #[derive(Clone, Copy, PartialEq, Eq, Hash)] #[rustc_pass_by_value] struct Module<'ra>(Interned<'ra, ModuleData<'ra>>); @@ -698,19 +698,6 @@ struct LocalModule<'ra>(Interned<'ra, ModuleData<'ra>>); #[rustc_pass_by_value] struct ExternModule<'ra>(Interned<'ra, ModuleData<'ra>>); -// Allows us to use Interned without actually enforcing (via Hash/PartialEq/...) uniqueness of the -// contained data. -// FIXME: We may wish to actually have at least debug-level assertions that Interned's guarantees -// are upheld. -impl std::hash::Hash for ModuleData<'_> { - fn hash(&self, _: &mut H) - where - H: std::hash::Hasher, - { - unreachable!() - } -} - impl<'ra> ModuleData<'ra> { fn new( parent: Option>, @@ -915,6 +902,7 @@ impl<'ra> LocalModule<'ra> { assert!(kind.is_local()); let parent = parent.map(|m| m.to_module()); let data = ModuleData::new(parent, kind, expn_id, span, no_implicit_prelude, vis, arenas); + // SAFETY: `Interned` is valid because values of this type have "identity". LocalModule(Interned::new_unchecked(arenas.modules.alloc(data))) } @@ -936,6 +924,7 @@ impl<'ra> ExternModule<'ra> { assert!(!kind.is_local()); let parent = parent.map(|m| m.to_module()); let data = ModuleData::new(parent, kind, expn_id, span, no_implicit_prelude, vis, arenas); + // SAFETY: `Interned` is valid because values of this type have "identity". ExternModule(Interned::new_unchecked(arenas.modules.alloc(data))) } @@ -1000,23 +989,10 @@ struct DeclData<'ra> { parent_module: Option>, } -/// All name declarations are unique and allocated on a same arena, -/// so we can use referential equality to compare them. +/// `Interned` is used because values of this type have "identity" and compare as unequal even if +/// they have the same contents. type Decl<'ra> = Interned<'ra, DeclData<'ra>>; -// Allows us to use Interned without actually enforcing (via Hash/PartialEq/...) uniqueness of the -// contained data. -// FIXME: We may wish to actually have at least debug-level assertions that Interned's guarantees -// are upheld. -impl std::hash::Hash for DeclData<'_> { - fn hash(&self, _: &mut H) - where - H: std::hash::Hasher, - { - unreachable!() - } -} - /// Name declaration kind. #[derive(Debug)] enum DeclKind<'ra> { @@ -1584,12 +1560,15 @@ impl<'ra> ResolverArenas<'ra> { } fn alloc_decl(&'ra self, data: DeclData<'ra>) -> Decl<'ra> { + // SAFETY: `Interned` is valid because values of this type have "identity". Interned::new_unchecked(self.dropless.alloc(data)) } fn alloc_import(&'ra self, import: ImportData<'ra>) -> Import<'ra> { + // SAFETY: `Interned` is valid because values of this type have "identity". Interned::new_unchecked(self.imports.alloc(import)) } fn alloc_name_resolution(&'ra self, orig_ident_span: Span) -> NameResolutionRef<'ra> { + // SAFETY: `Interned` is valid because values of this type have "identity". Interned::new_unchecked( self.name_resolutions.alloc(CmRefCell::new(NameResolution::new(orig_ident_span))), ) From febe5a5482737f4213956fd9b628956148873823 Mon Sep 17 00:00:00 2001 From: Roland Xu Date: Tue, 23 Jun 2026 23:17:05 +0800 Subject: [PATCH 16/56] Remove unexpected usage of Unambig in non-infer variants --- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_hir/src/intravisit.rs | 2 +- .../min_adt_const_params/tuple_with_infer_arg.rs | 10 ++++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 tests/ui/const-generics/min_adt_const_params/tuple_with_infer_arg.rs diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 2a10245d3d2e8..7207fc2923062 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -499,7 +499,7 @@ impl<'hir, Unambig> ConstArg<'hir, Unambig> { #[derive(Clone, Copy, Debug, StableHash)] #[repr(u8, C)] pub enum ConstArgKind<'hir, Unambig = ()> { - Tup(&'hir [&'hir ConstArg<'hir, Unambig>]), + Tup(&'hir [&'hir ConstArg<'hir>]), /// **Note:** Currently this is only used for bare const params /// (`N` where `fn foo(...)`), /// not paths to any const (`N` where `const N: usize = ...`). diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 9e0eaef596420..0dcc41ce17641 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1088,7 +1088,7 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( try_visit!(visitor.visit_id(*hir_id)); match kind { ConstArgKind::Tup(exprs) => { - walk_list!(visitor, visit_const_arg, *exprs); + walk_list!(visitor, visit_const_arg_unambig, *exprs); V::Result::output() } ConstArgKind::Struct(qpath, field_exprs) => { diff --git a/tests/ui/const-generics/min_adt_const_params/tuple_with_infer_arg.rs b/tests/ui/const-generics/min_adt_const_params/tuple_with_infer_arg.rs new file mode 100644 index 0000000000000..4ce1d08249b56 --- /dev/null +++ b/tests/ui/const-generics/min_adt_const_params/tuple_with_infer_arg.rs @@ -0,0 +1,10 @@ +//@ check-pass + +#![feature(min_adt_const_params)] +#![feature(min_generic_const_args)] + +struct S; + +fn main() { + let _: S<{ (1, _) }> = S::<{ (1, 2) }>; +} From 34df03318044542c2b3c45b6d706bdb567c92136 Mon Sep 17 00:00:00 2001 From: Obei Sideg Date: Fri, 3 Jul 2026 14:54:45 +0300 Subject: [PATCH 17/56] Update `FIXME(static_mut_refs)` comments update `FIXME(static_mut_refs)` comment to say: use raw pointers instead of references. --- library/std/src/sync/mod.rs | 2 +- library/std/src/sys/alloc/vexos.rs | 2 +- library/std/src/sys/alloc/xous.rs | 2 +- library/std/tests/thread_local/tests.rs | 2 +- src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed | 2 +- src/tools/clippy/tests/ui/redundant_static_lifetimes.rs | 2 +- src/tools/clippy/tests/ui/useless_conversion.fixed | 2 +- src/tools/clippy/tests/ui/useless_conversion.rs | 2 +- src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs | 2 +- .../miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs | 2 +- src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs | 2 +- src/tools/miri/tests/pass-dep/libc/libc-pipe.rs | 2 +- src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs | 2 +- src/tools/miri/tests/pass/atomic.rs | 2 +- src/tools/miri/tests/pass/static_memory_modification.rs | 2 +- src/tools/miri/tests/pass/static_mut.rs | 2 +- src/tools/miri/tests/pass/tls/tls_static.rs | 2 +- tests/ui/abi/statics/static-mut-foreign.rs | 2 +- tests/ui/array-slice-vec/slice-panic-1.rs | 2 +- tests/ui/array-slice-vec/slice-panic-2.rs | 2 +- tests/ui/array-slice-vec/slice.rs | 2 +- tests/ui/async-await/issues/issue-67611-static-mut-refs.rs | 2 +- tests/ui/binding/order-drop-with-match.rs | 2 +- tests/ui/binding/ref-pattern-drop-behavior-8860.rs | 2 +- tests/ui/consts/static-mut-refs.rs | 2 +- tests/ui/coroutine/static-mut-reference-across-yield.rs | 2 +- tests/ui/drop/conditional-drop-10734.rs | 2 +- tests/ui/drop/destructor-run-for-expression-4734.rs | 2 +- tests/ui/drop/destructor-run-for-let-ignore-6892.rs | 2 +- tests/ui/drop/drop-count-assertion-16151.rs | 2 +- tests/ui/drop/drop-struct-as-object.rs | 2 +- tests/ui/drop/generic-drop-trait-bound-15858.rs | 2 +- tests/ui/drop/issue-23338-ensure-param-drop-order.rs | 2 +- tests/ui/drop/issue-23611-enum-swap-in-drop.rs | 2 +- tests/ui/drop/issue-48962.rs | 2 +- tests/ui/drop/repeat-drop.rs | 2 +- tests/ui/drop/same-alloca-reassigned-match-binding-16151.rs | 2 +- tests/ui/drop/static-issue-17302.rs | 2 +- tests/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs | 2 +- .../functional-struct-update-respects-privacy.rs | 2 +- tests/ui/linkage-attr/link-section-placement.rs | 2 +- tests/ui/linkage-attr/linkage-attr-mutable-static.rs | 2 +- tests/ui/lto/lto-still-runs-thread-dtors.rs | 2 +- tests/ui/methods/method-self-arg-trait.rs | 2 +- tests/ui/methods/method-self-arg.rs | 2 +- tests/ui/mir/mir_early_return_scope.rs | 2 +- tests/ui/nll/issue-69114-static-mut-ty.rs | 2 +- tests/ui/numbers-arithmetic/shift-near-oflo.rs | 2 +- tests/ui/self/where-for-self.rs | 2 +- tests/ui/thread-local/thread-local-issue-37508.rs | 2 +- tests/ui/traits/impl.rs | 2 +- tests/ui/union/union-drop-assign.rs | 2 +- tests/ui/union/union-drop.rs | 2 +- 53 files changed, 53 insertions(+), 53 deletions(-) diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 439b5b09a5ac0..1c3b6d01ed9d8 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -9,7 +9,7 @@ //! Consider the following code, operating on some global static variables: //! //! ```rust -//! // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +//! // FIXME(static_mut_refs): use raw pointers instead of references //! #![allow(static_mut_refs)] //! //! static mut A: u32 = 0; diff --git a/library/std/src/sys/alloc/vexos.rs b/library/std/src/sys/alloc/vexos.rs index c1fb6896a89ae..5ccf6625ed626 100644 --- a/library/std/src/sys/alloc/vexos.rs +++ b/library/std/src/sys/alloc/vexos.rs @@ -1,4 +1,4 @@ -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use crate::alloc::{GlobalAlloc, Layout, System}; diff --git a/library/std/src/sys/alloc/xous.rs b/library/std/src/sys/alloc/xous.rs index c7f973b802791..af2dcabc1a23b 100644 --- a/library/std/src/sys/alloc/xous.rs +++ b/library/std/src/sys/alloc/xous.rs @@ -1,4 +1,4 @@ -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use crate::alloc::{GlobalAlloc, Layout, System}; diff --git a/library/std/tests/thread_local/tests.rs b/library/std/tests/thread_local/tests.rs index 633bab38eb4db..1a25d91e43bc0 100644 --- a/library/std/tests/thread_local/tests.rs +++ b/library/std/tests/thread_local/tests.rs @@ -110,7 +110,7 @@ fn smoke_dtor() { #[test] fn circular() { - // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint + // FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] struct S1(&'static LocalKey>>, &'static LocalKey>>); diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed b/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed index 86c6ca17eb20e..0a898032459f6 100644 --- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed +++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed @@ -1,5 +1,5 @@ #![allow(unused)] -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] #[derive(Debug)] diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs b/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs index 6fefe6c232d2f..fa45eff0f2626 100644 --- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs +++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs @@ -1,5 +1,5 @@ #![allow(unused)] -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] #[derive(Debug)] diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed index a22df7013f988..d74ea54354fdd 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.fixed +++ b/src/tools/clippy/tests/ui/useless_conversion.fixed @@ -1,7 +1,7 @@ #![deny(clippy::useless_conversion)] #![allow(clippy::into_iter_on_ref)] #![allow(clippy::needless_ifs, clippy::unnecessary_wraps, unused)] -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use std::ops::ControlFlow; diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs index 1f170cf87ac58..5d7d180635771 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.rs +++ b/src/tools/clippy/tests/ui/useless_conversion.rs @@ -1,7 +1,7 @@ #![deny(clippy::useless_conversion)] #![allow(clippy::into_iter_on_ref)] #![allow(clippy::needless_ifs, clippy::unnecessary_wraps, unused)] -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use std::ops::ControlFlow; diff --git a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs index 5b7a2b7039d80..2e45af9e28880 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/linux-futex.rs @@ -1,7 +1,7 @@ //@only-target: linux android //@compile-flags: -Zmiri-disable-isolation -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use std::mem::MaybeUninit; diff --git a/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs b/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs index df42780021610..6ec4b6e48bc3f 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs @@ -5,7 +5,7 @@ //! the fallback path in `guard::key::enable`, which uses a *single* pthread_key //! to manage a thread-local list of dtors to call. -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use std::{mem, ptr}; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs index e753983344bd4..d84ce42922886 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs @@ -3,7 +3,7 @@ //@compile-flags: -Zmiri-deterministic-concurrency //@run-native -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use std::{io, thread}; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs index 12b5ae5666cfd..de278c190b589 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs @@ -69,7 +69,7 @@ fn test_pipe_threaded() { thread2.join().unwrap(); } -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #[allow(static_mut_refs)] fn test_race() { static mut VAL: u8 = 0; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs index f994dc28a9349..bcfa52211dd9b 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs @@ -3,7 +3,7 @@ //@compile-flags: -Zmiri-deterministic-concurrency //@run-native -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use std::thread; diff --git a/src/tools/miri/tests/pass/atomic.rs b/src/tools/miri/tests/pass/atomic.rs index 842f036b0615a..0b7fff69d8ce2 100644 --- a/src/tools/miri/tests/pass/atomic.rs +++ b/src/tools/miri/tests/pass/atomic.rs @@ -3,7 +3,7 @@ //@[tree]compile-flags: -Zmiri-tree-borrows //@compile-flags: -Zmiri-strict-provenance -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use std::sync::atomic::Ordering::*; diff --git a/src/tools/miri/tests/pass/static_memory_modification.rs b/src/tools/miri/tests/pass/static_memory_modification.rs index 1900250bf4f8f..f55f2a251930e 100644 --- a/src/tools/miri/tests/pass/static_memory_modification.rs +++ b/src/tools/miri/tests/pass/static_memory_modification.rs @@ -1,4 +1,4 @@ -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/src/tools/miri/tests/pass/static_mut.rs b/src/tools/miri/tests/pass/static_mut.rs index f88c7a16e6dd7..005ec5f9dfcb4 100644 --- a/src/tools/miri/tests/pass/static_mut.rs +++ b/src/tools/miri/tests/pass/static_mut.rs @@ -1,4 +1,4 @@ -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use std::ptr::addr_of; diff --git a/src/tools/miri/tests/pass/tls/tls_static.rs b/src/tools/miri/tests/pass/tls/tls_static.rs index 600ecea334e13..dfc13720b4c8d 100644 --- a/src/tools/miri/tests/pass/tls/tls_static.rs +++ b/src/tools/miri/tests/pass/tls/tls_static.rs @@ -8,7 +8,7 @@ //! dereferencing the pointer on `t2` resolves to `t1`'s thread-local. In this //! test, we also check that thread-locals act as per-thread statics. -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] #![feature(thread_local)] diff --git a/tests/ui/abi/statics/static-mut-foreign.rs b/tests/ui/abi/statics/static-mut-foreign.rs index 40cd57637e6cd..f79400e7a6df8 100644 --- a/tests/ui/abi/statics/static-mut-foreign.rs +++ b/tests/ui/abi/statics/static-mut-foreign.rs @@ -3,7 +3,7 @@ // statics cannot. This ensures that there's some form of error if this is // attempted. -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use std::ffi::c_int; diff --git a/tests/ui/array-slice-vec/slice-panic-1.rs b/tests/ui/array-slice-vec/slice-panic-1.rs index d7c1098fa2bda..60680c367a671 100644 --- a/tests/ui/array-slice-vec/slice-panic-1.rs +++ b/tests/ui/array-slice-vec/slice-panic-1.rs @@ -5,7 +5,7 @@ // Test that if a slicing expr[..] fails, the correct cleanups happen. -// FIXME(static_mut_refs): this could use an atomic +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use std::thread; diff --git a/tests/ui/array-slice-vec/slice-panic-2.rs b/tests/ui/array-slice-vec/slice-panic-2.rs index 157e716a95d49..e5ba045248da2 100644 --- a/tests/ui/array-slice-vec/slice-panic-2.rs +++ b/tests/ui/array-slice-vec/slice-panic-2.rs @@ -5,7 +5,7 @@ // Test that if a slicing expr[..] fails, the correct cleanups happen. -// FIXME(static_mut_refs): this could use an atomic +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use std::thread; diff --git a/tests/ui/array-slice-vec/slice.rs b/tests/ui/array-slice-vec/slice.rs index ad5db7a2102b4..b94a8e029f778 100644 --- a/tests/ui/array-slice-vec/slice.rs +++ b/tests/ui/array-slice-vec/slice.rs @@ -3,7 +3,7 @@ // Test slicing sugar. -// FIXME(static_mut_refs): this could use an atomic +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] extern crate core; diff --git a/tests/ui/async-await/issues/issue-67611-static-mut-refs.rs b/tests/ui/async-await/issues/issue-67611-static-mut-refs.rs index 04958352d3f2e..9f0869a3a0b43 100644 --- a/tests/ui/async-await/issues/issue-67611-static-mut-refs.rs +++ b/tests/ui/async-await/issues/issue-67611-static-mut-refs.rs @@ -1,7 +1,7 @@ //@ build-pass //@ edition:2018 -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] static mut A: [i32; 5] = [1, 2, 3, 4, 5]; diff --git a/tests/ui/binding/order-drop-with-match.rs b/tests/ui/binding/order-drop-with-match.rs index cd0ff73cf12da..db91ead4e0f85 100644 --- a/tests/ui/binding/order-drop-with-match.rs +++ b/tests/ui/binding/order-drop-with-match.rs @@ -5,7 +5,7 @@ // in ORDER matching up to when it ran. // Correct order is: matched, inner, outer -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] static mut ORDER: [usize; 3] = [0, 0, 0]; diff --git a/tests/ui/binding/ref-pattern-drop-behavior-8860.rs b/tests/ui/binding/ref-pattern-drop-behavior-8860.rs index 1a67caf021cf7..bcb3ca2800396 100644 --- a/tests/ui/binding/ref-pattern-drop-behavior-8860.rs +++ b/tests/ui/binding/ref-pattern-drop-behavior-8860.rs @@ -1,6 +1,6 @@ // https://github.com/rust-lang/rust/issues/8860 //@ run-pass -// FIXME(static_mut_refs): this could use an atomic +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] #![allow(dead_code)] diff --git a/tests/ui/consts/static-mut-refs.rs b/tests/ui/consts/static-mut-refs.rs index c0d0bb613325c..8eab90d0673e3 100644 --- a/tests/ui/consts/static-mut-refs.rs +++ b/tests/ui/consts/static-mut-refs.rs @@ -1,7 +1,7 @@ //@ run-pass #![allow(dead_code)] -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] // Checks that mutable static items can have mutable slices and other references diff --git a/tests/ui/coroutine/static-mut-reference-across-yield.rs b/tests/ui/coroutine/static-mut-reference-across-yield.rs index d45d6e6428b9c..b7a77e4b95b69 100644 --- a/tests/ui/coroutine/static-mut-reference-across-yield.rs +++ b/tests/ui/coroutine/static-mut-reference-across-yield.rs @@ -1,7 +1,7 @@ //@ build-pass #![feature(coroutines, stmt_expr_attributes)] -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] static mut A: [i32; 5] = [1, 2, 3, 4, 5]; diff --git a/tests/ui/drop/conditional-drop-10734.rs b/tests/ui/drop/conditional-drop-10734.rs index 25f492bf9e087..3ac9239fe20fd 100644 --- a/tests/ui/drop/conditional-drop-10734.rs +++ b/tests/ui/drop/conditional-drop-10734.rs @@ -3,7 +3,7 @@ //@ run-pass #![allow(non_upper_case_globals)] -// FIXME(static_mut_refs): this could use an atomic +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] static mut drop_count: usize = 0; diff --git a/tests/ui/drop/destructor-run-for-expression-4734.rs b/tests/ui/drop/destructor-run-for-expression-4734.rs index 57971ee5ef76e..15d676409738e 100644 --- a/tests/ui/drop/destructor-run-for-expression-4734.rs +++ b/tests/ui/drop/destructor-run-for-expression-4734.rs @@ -4,7 +4,7 @@ // Ensures that destructors are run for expressions of the form "e;" where // `e` is a type which requires a destructor. -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] #![allow(path_statements)] diff --git a/tests/ui/drop/destructor-run-for-let-ignore-6892.rs b/tests/ui/drop/destructor-run-for-let-ignore-6892.rs index 0fcf133c2b188..643eac466845a 100644 --- a/tests/ui/drop/destructor-run-for-let-ignore-6892.rs +++ b/tests/ui/drop/destructor-run-for-let-ignore-6892.rs @@ -4,7 +4,7 @@ // Ensures that destructors are run for expressions of the form "let _ = e;" // where `e` is a type which requires a destructor. -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] struct Foo; diff --git a/tests/ui/drop/drop-count-assertion-16151.rs b/tests/ui/drop/drop-count-assertion-16151.rs index ede6bc23e733a..0e49708609ba7 100644 --- a/tests/ui/drop/drop-count-assertion-16151.rs +++ b/tests/ui/drop/drop-count-assertion-16151.rs @@ -1,7 +1,7 @@ // https://github.com/rust-lang/rust/issues/16151 //@ run-pass -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use std::mem; diff --git a/tests/ui/drop/drop-struct-as-object.rs b/tests/ui/drop/drop-struct-as-object.rs index 46633bd70751f..0f407e4fffb04 100644 --- a/tests/ui/drop/drop-struct-as-object.rs +++ b/tests/ui/drop/drop-struct-as-object.rs @@ -5,7 +5,7 @@ // Test that destructor on a struct runs successfully after the struct // is boxed and converted to an object. -// FIXME(static_mut_refs): this could use an atomic +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] static mut value: usize = 0; diff --git a/tests/ui/drop/generic-drop-trait-bound-15858.rs b/tests/ui/drop/generic-drop-trait-bound-15858.rs index 682604d17d864..237cef50ef55d 100644 --- a/tests/ui/drop/generic-drop-trait-bound-15858.rs +++ b/tests/ui/drop/generic-drop-trait-bound-15858.rs @@ -1,7 +1,7 @@ //! Regression test for https://github.com/rust-lang/rust/issues/15858 //@ run-pass -// FIXME(static_mut_refs): this could use an atomic +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] static mut DROP_RAN: bool = false; diff --git a/tests/ui/drop/issue-23338-ensure-param-drop-order.rs b/tests/ui/drop/issue-23338-ensure-param-drop-order.rs index 54a9d3324b9e6..cdfc3ee889eae 100644 --- a/tests/ui/drop/issue-23338-ensure-param-drop-order.rs +++ b/tests/ui/drop/issue-23338-ensure-param-drop-order.rs @@ -1,6 +1,6 @@ //@ run-pass #![allow(non_upper_case_globals)] -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] // This test is ensuring that parameters are indeed dropped after diff --git a/tests/ui/drop/issue-23611-enum-swap-in-drop.rs b/tests/ui/drop/issue-23611-enum-swap-in-drop.rs index 208c6e2ada3d0..253c3c3c7f98a 100644 --- a/tests/ui/drop/issue-23611-enum-swap-in-drop.rs +++ b/tests/ui/drop/issue-23611-enum-swap-in-drop.rs @@ -1,6 +1,6 @@ //@ run-pass #![allow(non_upper_case_globals)] -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] // Issue 23611: this test is ensuring that, for an instance `X` of the diff --git a/tests/ui/drop/issue-48962.rs b/tests/ui/drop/issue-48962.rs index 98d3af49ac1ec..5ecc54c5a27b1 100644 --- a/tests/ui/drop/issue-48962.rs +++ b/tests/ui/drop/issue-48962.rs @@ -1,7 +1,7 @@ //@ run-pass #![allow(unused_must_use)] // Test that we are able to reinitialize box with moved referent -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] static mut ORDER: [usize; 3] = [0, 0, 0]; diff --git a/tests/ui/drop/repeat-drop.rs b/tests/ui/drop/repeat-drop.rs index 7488d9113b0af..1b10e6e553b80 100644 --- a/tests/ui/drop/repeat-drop.rs +++ b/tests/ui/drop/repeat-drop.rs @@ -3,7 +3,7 @@ #![allow(dropping_references, dropping_copy_types)] -// FIXME(static_mut_refs): this could use an atomic +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] static mut CHECK: usize = 0; diff --git a/tests/ui/drop/same-alloca-reassigned-match-binding-16151.rs b/tests/ui/drop/same-alloca-reassigned-match-binding-16151.rs index ecc862ec7be6b..449a4728963d9 100644 --- a/tests/ui/drop/same-alloca-reassigned-match-binding-16151.rs +++ b/tests/ui/drop/same-alloca-reassigned-match-binding-16151.rs @@ -2,7 +2,7 @@ //@ run-pass -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use std::mem; diff --git a/tests/ui/drop/static-issue-17302.rs b/tests/ui/drop/static-issue-17302.rs index 060f5564efdae..ef13da6ec6547 100644 --- a/tests/ui/drop/static-issue-17302.rs +++ b/tests/ui/drop/static-issue-17302.rs @@ -1,6 +1,6 @@ //@ run-pass -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] static mut DROPPED: [bool; 2] = [false, false]; diff --git a/tests/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs b/tests/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs index 57e8b2286497c..ac6eb209a9211 100644 --- a/tests/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs +++ b/tests/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs @@ -2,7 +2,7 @@ // This test verifies that temporaries created for `while`'s and `if` // conditions are dropped after the condition is evaluated. -// FIXME(static_mut_refs): this could use an atomic +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] struct Temporary; diff --git a/tests/ui/functional-struct-update/functional-struct-update-respects-privacy.rs b/tests/ui/functional-struct-update/functional-struct-update-respects-privacy.rs index a05d20ffbd280..e90cf3f9e4cc1 100644 --- a/tests/ui/functional-struct-update/functional-struct-update-respects-privacy.rs +++ b/tests/ui/functional-struct-update/functional-struct-update-respects-privacy.rs @@ -3,7 +3,7 @@ // The `foo` module attempts to maintains an invariant that each `S` // has a unique `u64` id. -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use self::foo::S; diff --git a/tests/ui/linkage-attr/link-section-placement.rs b/tests/ui/linkage-attr/link-section-placement.rs index 299ad31d82d0d..b1b88e911861f 100644 --- a/tests/ui/linkage-attr/link-section-placement.rs +++ b/tests/ui/linkage-attr/link-section-placement.rs @@ -3,7 +3,7 @@ //@ run-pass #![feature(cfg_target_object_format)] -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] #![allow(non_upper_case_globals)] diff --git a/tests/ui/linkage-attr/linkage-attr-mutable-static.rs b/tests/ui/linkage-attr/linkage-attr-mutable-static.rs index cc93f61e28f37..09f7d65f97e4d 100644 --- a/tests/ui/linkage-attr/linkage-attr-mutable-static.rs +++ b/tests/ui/linkage-attr/linkage-attr-mutable-static.rs @@ -2,7 +2,7 @@ //! them at runtime, so deny mutable statics with #[linkage]. #![feature(linkage)] -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] fn main() { diff --git a/tests/ui/lto/lto-still-runs-thread-dtors.rs b/tests/ui/lto/lto-still-runs-thread-dtors.rs index 9a97677773cca..780e8eb844faf 100644 --- a/tests/ui/lto/lto-still-runs-thread-dtors.rs +++ b/tests/ui/lto/lto-still-runs-thread-dtors.rs @@ -4,7 +4,7 @@ //@ needs-threads //@ ignore-backends: gcc -// FIXME(static_mut_refs): this could use an atomic +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use std::thread; diff --git a/tests/ui/methods/method-self-arg-trait.rs b/tests/ui/methods/method-self-arg-trait.rs index ccffe02328bbf..7b945fc3c38a4 100644 --- a/tests/ui/methods/method-self-arg-trait.rs +++ b/tests/ui/methods/method-self-arg-trait.rs @@ -1,7 +1,7 @@ //@ run-pass // Test method calls with self as an argument -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] static mut COUNT: u64 = 1; diff --git a/tests/ui/methods/method-self-arg.rs b/tests/ui/methods/method-self-arg.rs index 2e058ee1077c6..e54b47b3b645f 100644 --- a/tests/ui/methods/method-self-arg.rs +++ b/tests/ui/methods/method-self-arg.rs @@ -1,7 +1,7 @@ //@ run-pass // Test method calls with self as an argument -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] static mut COUNT: usize = 1; diff --git a/tests/ui/mir/mir_early_return_scope.rs b/tests/ui/mir/mir_early_return_scope.rs index 42f1cc50d15da..7e550c3ef5dff 100644 --- a/tests/ui/mir/mir_early_return_scope.rs +++ b/tests/ui/mir/mir_early_return_scope.rs @@ -1,6 +1,6 @@ //@ run-pass #![allow(unused_variables)] -// FIXME(static_mut_refs): this could use an atomic +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] static mut DROP: bool = false; diff --git a/tests/ui/nll/issue-69114-static-mut-ty.rs b/tests/ui/nll/issue-69114-static-mut-ty.rs index 95c787488c08e..dd5fe3c6ff26b 100644 --- a/tests/ui/nll/issue-69114-static-mut-ty.rs +++ b/tests/ui/nll/issue-69114-static-mut-ty.rs @@ -1,6 +1,6 @@ // Check that borrowck ensures that `static mut` items have the expected type. -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] static FOO: u8 = 42; diff --git a/tests/ui/numbers-arithmetic/shift-near-oflo.rs b/tests/ui/numbers-arithmetic/shift-near-oflo.rs index 97227bd843f07..714ff6e86fd5a 100644 --- a/tests/ui/numbers-arithmetic/shift-near-oflo.rs +++ b/tests/ui/numbers-arithmetic/shift-near-oflo.rs @@ -1,7 +1,7 @@ //@ run-pass //@ compile-flags: -C debug-assertions -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] // Check that we do *not* overflow on a number of edge cases. diff --git a/tests/ui/self/where-for-self.rs b/tests/ui/self/where-for-self.rs index d31bb1f22c4ce..d874cbd5bcdde 100644 --- a/tests/ui/self/where-for-self.rs +++ b/tests/ui/self/where-for-self.rs @@ -2,7 +2,7 @@ // Test that we can quantify lifetimes outside a constraint (i.e., including // the self type) in a where clause. -// FIXME(static_mut_refs): this could use an atomic +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] static mut COUNT: u32 = 1; diff --git a/tests/ui/thread-local/thread-local-issue-37508.rs b/tests/ui/thread-local/thread-local-issue-37508.rs index 34c3945345184..ef7670af3d384 100644 --- a/tests/ui/thread-local/thread-local-issue-37508.rs +++ b/tests/ui/thread-local/thread-local-issue-37508.rs @@ -4,7 +4,7 @@ // // Regression test for issue #37508 -// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] #![no_main] diff --git a/tests/ui/traits/impl.rs b/tests/ui/traits/impl.rs index b45935fd86a41..8858db8fad26e 100644 --- a/tests/ui/traits/impl.rs +++ b/tests/ui/traits/impl.rs @@ -3,7 +3,7 @@ //@ aux-build:traitimpl.rs -// FIXME(static_mut_refs): this could use an atomic +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] extern crate traitimpl; diff --git a/tests/ui/union/union-drop-assign.rs b/tests/ui/union/union-drop-assign.rs index 451fb14eddf93..710a6f6205e01 100644 --- a/tests/ui/union/union-drop-assign.rs +++ b/tests/ui/union/union-drop-assign.rs @@ -3,7 +3,7 @@ // Drop works for union itself. -// FIXME(static_mut_refs): this could use an atomic +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] use std::mem::ManuallyDrop; diff --git a/tests/ui/union/union-drop.rs b/tests/ui/union/union-drop.rs index 6f6d5c1416534..9a2911599dfe2 100644 --- a/tests/ui/union/union-drop.rs +++ b/tests/ui/union/union-drop.rs @@ -2,7 +2,7 @@ #![allow(dead_code)] #![allow(unused_variables)] -// FIXME(static_mut_refs): this could use an atomic +// FIXME(static_mut_refs): use raw pointers instead of references #![allow(static_mut_refs)] // Drop works for union itself. From 1e7c81b2d9a20ad6cae8b938a4d8fb1b34c83808 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 3 Jul 2026 17:44:58 +0000 Subject: [PATCH 18/56] Look for cdb location in the registry first This is more robust then assuming it's in Program Files. We still fallback to Program Files as a last resort. --- src/bootstrap/Cargo.lock | 12 +++++++++ src/bootstrap/Cargo.toml | 3 +++ src/bootstrap/src/core/debuggers/cdb.rs | 35 ++++++++++++++++--------- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 7c890e3f2004c..f988d207529b6 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -71,6 +71,7 @@ dependencies = [ "tracing-subscriber", "walkdir", "windows 0.61.1", + "windows-registry", "xz2", ] @@ -1095,6 +1096,17 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + [[package]] name = "windows-result" version = "0.3.2" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 60e52102dc46b..b2e8c42adf48b 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -66,6 +66,9 @@ tracing = { version = "0.1", optional = true, features = ["attributes"] } tracing-chrome = { version = "0.7", optional = true } tracing-subscriber = { version = "0.3", optional = true, features = ["env-filter", "fmt", "registry", "std"] } +[target.'cfg(windows)'.dependencies.windows-registry] +version = "0.6" + [target.'cfg(windows)'.dependencies.junction] version = "1.3.0" diff --git a/src/bootstrap/src/core/debuggers/cdb.rs b/src/bootstrap/src/core/debuggers/cdb.rs index a19b70477ecfe..7f835f3618724 100644 --- a/src/bootstrap/src/core/debuggers/cdb.rs +++ b/src/bootstrap/src/core/debuggers/cdb.rs @@ -7,15 +7,12 @@ pub(crate) struct Cdb { pub(crate) cdb: PathBuf, } -/// FIXME: This CDB discovery code was very questionable when it was in -/// compiletest, and it's just as questionable now that it's in bootstrap. +/// We consult the registry to find the installed cdb.exe and try "Program Files" if that fails. pub(crate) fn discover_cdb(target: TargetSelection) -> Option { if !cfg!(windows) || !target.ends_with("-pc-windows-msvc") { return None; } - let pf86 = - PathBuf::from(env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?); let cdb_arch = if cfg!(target_arch = "x86") { "x86" } else if cfg!(target_arch = "x86_64") { @@ -28,14 +25,28 @@ pub(crate) fn discover_cdb(target: TargetSelection) -> Option { return None; // No compatible CDB.exe in the Windows 10 SDK }; - let mut path = pf86; - path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too? - path.push(cdb_arch); - path.push(r"cdb.exe"); + let path = discover_cdb_registry(cdb_arch).or_else(|| discover_cdb_program_files(cdb_arch))?; + Some(Cdb { cdb: path }) +} - if !path.exists() { - return None; - } +#[cfg(windows)] +fn discover_cdb_registry(cdb_arch: &'static str) -> Option { + use windows_registry::LOCAL_MACHINE; + let roots = LOCAL_MACHINE.open(r"SOFTWARE\Microsoft\Windows Kits\Installed Roots").ok()?; + // "KitsRoot10" is used by both the Windows 10 and 11 SDKs. + let mut path: PathBuf = roots.get_string("KitsRoot10").ok()?.into(); + path.extend([r"Debuggers", cdb_arch, r"cdb.exe"]); + path.exists().then_some(path) +} - Some(Cdb { cdb: path }) +#[cfg(not(windows))] +fn discover_cdb_registry(_cdb_arch: &'static str) -> Option { + None +} + +fn discover_cdb_program_files(cdb_arch: &'static str) -> Option { + let mut path = + PathBuf::from(env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?); + path.extend([r"Windows Kits\10\Debuggers", cdb_arch, r"cdb.exe"]); + path.exists().then_some(path) } From 9016189942ef529c95622d9fad909577a3936386 Mon Sep 17 00:00:00 2001 From: zedddie Date: Fri, 3 Jul 2026 23:37:02 +0200 Subject: [PATCH 19/56] move batch --- .../unconstrained-lifetime-in-projection.rs} | 0 .../unconstrained-lifetime-in-projection.stderr} | 0 .../index-self-with-arithmetic-on-self-item.rs} | 0 .../issue-2989.rs => codegen/bitvec-to-bools-opt-miscompile.rs} | 0 .../bitvec-to-bools-opt-miscompile.stderr} | 0 .../issue-30081.rs => codegen/box-deref-segfault-misopt.rs} | 0 .../issue-29948.rs => drop/move-closure-drop-on-unwind.rs} | 0 .../issue-30018-panic.rs => drop/panic-during-slice-init.rs} | 0 .../issue-29668.rs => privacy/fn-returns-unnameable-type.rs} | 0 .../issue-3021-b.rs => resolve/impl-method-cant-capture-env.rs} | 0 .../impl-method-cant-capture-env.stderr} | 0 .../{issue-3021.rs => impl-trait-for-type-cant-capture-env.rs} | 0 ...ue-3021.stderr => impl-trait-for-type-cant-capture-env.stderr} | 0 .../resolve/{issue-3021-c.rs => outer-generic-in-trait-method.rs} | 0 .../{issue-3021-c.stderr => outer-generic-in-trait-method.stderr} | 0 .../issue-3021-d.rs => resolve/trait-impl-cant-capture-env.rs} | 0 .../trait-impl-cant-capture-env.stderr} | 0 17 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-29861.rs => associated-types/unconstrained-lifetime-in-projection.rs} (100%) rename tests/ui/{issues/issue-29861.stderr => associated-types/unconstrained-lifetime-in-projection.stderr} (100%) rename tests/ui/{issues/issue-29743.rs => borrowck/index-self-with-arithmetic-on-self-item.rs} (100%) rename tests/ui/{issues/issue-2989.rs => codegen/bitvec-to-bools-opt-miscompile.rs} (100%) rename tests/ui/{issues/issue-2989.stderr => codegen/bitvec-to-bools-opt-miscompile.stderr} (100%) rename tests/ui/{issues/issue-30081.rs => codegen/box-deref-segfault-misopt.rs} (100%) rename tests/ui/{issues/issue-29948.rs => drop/move-closure-drop-on-unwind.rs} (100%) rename tests/ui/{issues/issue-30018-panic.rs => drop/panic-during-slice-init.rs} (100%) rename tests/ui/{issues/issue-29668.rs => privacy/fn-returns-unnameable-type.rs} (100%) rename tests/ui/{issues/issue-3021-b.rs => resolve/impl-method-cant-capture-env.rs} (100%) rename tests/ui/{issues/issue-3021-b.stderr => resolve/impl-method-cant-capture-env.stderr} (100%) rename tests/ui/resolve/{issue-3021.rs => impl-trait-for-type-cant-capture-env.rs} (100%) rename tests/ui/resolve/{issue-3021.stderr => impl-trait-for-type-cant-capture-env.stderr} (100%) rename tests/ui/resolve/{issue-3021-c.rs => outer-generic-in-trait-method.rs} (100%) rename tests/ui/resolve/{issue-3021-c.stderr => outer-generic-in-trait-method.stderr} (100%) rename tests/ui/{issues/issue-3021-d.rs => resolve/trait-impl-cant-capture-env.rs} (100%) rename tests/ui/{issues/issue-3021-d.stderr => resolve/trait-impl-cant-capture-env.stderr} (100%) diff --git a/tests/ui/issues/issue-29861.rs b/tests/ui/associated-types/unconstrained-lifetime-in-projection.rs similarity index 100% rename from tests/ui/issues/issue-29861.rs rename to tests/ui/associated-types/unconstrained-lifetime-in-projection.rs diff --git a/tests/ui/issues/issue-29861.stderr b/tests/ui/associated-types/unconstrained-lifetime-in-projection.stderr similarity index 100% rename from tests/ui/issues/issue-29861.stderr rename to tests/ui/associated-types/unconstrained-lifetime-in-projection.stderr diff --git a/tests/ui/issues/issue-29743.rs b/tests/ui/borrowck/index-self-with-arithmetic-on-self-item.rs similarity index 100% rename from tests/ui/issues/issue-29743.rs rename to tests/ui/borrowck/index-self-with-arithmetic-on-self-item.rs diff --git a/tests/ui/issues/issue-2989.rs b/tests/ui/codegen/bitvec-to-bools-opt-miscompile.rs similarity index 100% rename from tests/ui/issues/issue-2989.rs rename to tests/ui/codegen/bitvec-to-bools-opt-miscompile.rs diff --git a/tests/ui/issues/issue-2989.stderr b/tests/ui/codegen/bitvec-to-bools-opt-miscompile.stderr similarity index 100% rename from tests/ui/issues/issue-2989.stderr rename to tests/ui/codegen/bitvec-to-bools-opt-miscompile.stderr diff --git a/tests/ui/issues/issue-30081.rs b/tests/ui/codegen/box-deref-segfault-misopt.rs similarity index 100% rename from tests/ui/issues/issue-30081.rs rename to tests/ui/codegen/box-deref-segfault-misopt.rs diff --git a/tests/ui/issues/issue-29948.rs b/tests/ui/drop/move-closure-drop-on-unwind.rs similarity index 100% rename from tests/ui/issues/issue-29948.rs rename to tests/ui/drop/move-closure-drop-on-unwind.rs diff --git a/tests/ui/issues/issue-30018-panic.rs b/tests/ui/drop/panic-during-slice-init.rs similarity index 100% rename from tests/ui/issues/issue-30018-panic.rs rename to tests/ui/drop/panic-during-slice-init.rs diff --git a/tests/ui/issues/issue-29668.rs b/tests/ui/privacy/fn-returns-unnameable-type.rs similarity index 100% rename from tests/ui/issues/issue-29668.rs rename to tests/ui/privacy/fn-returns-unnameable-type.rs diff --git a/tests/ui/issues/issue-3021-b.rs b/tests/ui/resolve/impl-method-cant-capture-env.rs similarity index 100% rename from tests/ui/issues/issue-3021-b.rs rename to tests/ui/resolve/impl-method-cant-capture-env.rs diff --git a/tests/ui/issues/issue-3021-b.stderr b/tests/ui/resolve/impl-method-cant-capture-env.stderr similarity index 100% rename from tests/ui/issues/issue-3021-b.stderr rename to tests/ui/resolve/impl-method-cant-capture-env.stderr diff --git a/tests/ui/resolve/issue-3021.rs b/tests/ui/resolve/impl-trait-for-type-cant-capture-env.rs similarity index 100% rename from tests/ui/resolve/issue-3021.rs rename to tests/ui/resolve/impl-trait-for-type-cant-capture-env.rs diff --git a/tests/ui/resolve/issue-3021.stderr b/tests/ui/resolve/impl-trait-for-type-cant-capture-env.stderr similarity index 100% rename from tests/ui/resolve/issue-3021.stderr rename to tests/ui/resolve/impl-trait-for-type-cant-capture-env.stderr diff --git a/tests/ui/resolve/issue-3021-c.rs b/tests/ui/resolve/outer-generic-in-trait-method.rs similarity index 100% rename from tests/ui/resolve/issue-3021-c.rs rename to tests/ui/resolve/outer-generic-in-trait-method.rs diff --git a/tests/ui/resolve/issue-3021-c.stderr b/tests/ui/resolve/outer-generic-in-trait-method.stderr similarity index 100% rename from tests/ui/resolve/issue-3021-c.stderr rename to tests/ui/resolve/outer-generic-in-trait-method.stderr diff --git a/tests/ui/issues/issue-3021-d.rs b/tests/ui/resolve/trait-impl-cant-capture-env.rs similarity index 100% rename from tests/ui/issues/issue-3021-d.rs rename to tests/ui/resolve/trait-impl-cant-capture-env.rs diff --git a/tests/ui/issues/issue-3021-d.stderr b/tests/ui/resolve/trait-impl-cant-capture-env.stderr similarity index 100% rename from tests/ui/issues/issue-3021-d.stderr rename to tests/ui/resolve/trait-impl-cant-capture-env.stderr From 0c42d9225a4bb7e33289a2cdad69eb7ac9f9b7d5 Mon Sep 17 00:00:00 2001 From: zedddie Date: Fri, 3 Jul 2026 23:37:29 +0200 Subject: [PATCH 20/56] bless batch --- src/tools/tidy/src/issues.txt | 2 -- .../unconstrained-lifetime-in-projection.rs | 4 ++++ .../unconstrained-lifetime-in-projection.stderr | 4 ++-- .../index-self-with-arithmetic-on-self-item.rs | 3 +++ tests/ui/codegen/bitvec-to-bools-opt-miscompile.rs | 2 ++ tests/ui/codegen/bitvec-to-bools-opt-miscompile.stderr | 2 +- tests/ui/codegen/box-deref-segfault-misopt.rs | 3 ++- tests/ui/drop/move-closure-drop-on-unwind.rs | 4 ++++ tests/ui/drop/panic-during-slice-init.rs | 10 +++++----- tests/ui/privacy/fn-returns-unnameable-type.rs | 3 ++- tests/ui/resolve/impl-method-cant-capture-env.rs | 3 +++ tests/ui/resolve/impl-method-cant-capture-env.stderr | 2 +- .../ui/resolve/impl-trait-for-type-cant-capture-env.rs | 3 +++ .../impl-trait-for-type-cant-capture-env.stderr | 2 +- tests/ui/resolve/outer-generic-in-trait-method.rs | 3 +++ tests/ui/resolve/outer-generic-in-trait-method.stderr | 4 ++-- tests/ui/resolve/trait-impl-cant-capture-env.rs | 3 +++ tests/ui/resolve/trait-impl-cant-capture-env.stderr | 4 ++-- 18 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index db6008da59b34..bb251a6823ac6 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2324,8 +2324,6 @@ ui/resolve/issue-2356.rs ui/resolve/issue-23716.rs ui/resolve/issue-24968.rs ui/resolve/issue-26545.rs -ui/resolve/issue-3021-c.rs -ui/resolve/issue-3021.rs ui/resolve/issue-30535.rs ui/resolve/issue-3099-a.rs ui/resolve/issue-3099-b.rs diff --git a/tests/ui/associated-types/unconstrained-lifetime-in-projection.rs b/tests/ui/associated-types/unconstrained-lifetime-in-projection.rs index 875c168185feb..bee7d521c30f8 100644 --- a/tests/ui/associated-types/unconstrained-lifetime-in-projection.rs +++ b/tests/ui/associated-types/unconstrained-lifetime-in-projection.rs @@ -1,3 +1,7 @@ +//! Regression test for . +//! Unconstrained lifetimes in associated type were wrongly allowed when +//! occurred in projection. + pub trait MakeRef<'a> { type Ref; } diff --git a/tests/ui/associated-types/unconstrained-lifetime-in-projection.stderr b/tests/ui/associated-types/unconstrained-lifetime-in-projection.stderr index a25cbf0515d84..0847fa652c55a 100644 --- a/tests/ui/associated-types/unconstrained-lifetime-in-projection.stderr +++ b/tests/ui/associated-types/unconstrained-lifetime-in-projection.stderr @@ -1,11 +1,11 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates - --> $DIR/issue-29861.rs:11:6 + --> $DIR/unconstrained-lifetime-in-projection.rs:15:6 | LL | impl<'a, T: 'a> MakeRef2 for T { | ^^ unconstrained lifetime parameter error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-29861.rs:16:43 + --> $DIR/unconstrained-lifetime-in-projection.rs:20:43 | LL | fn foo() -> ::Ref2 { &String::from("foo") } | ^^^^^^^^^^^^^^^^^^^ -- borrow later used here diff --git a/tests/ui/borrowck/index-self-with-arithmetic-on-self-item.rs b/tests/ui/borrowck/index-self-with-arithmetic-on-self-item.rs index 8e522a7482190..3987e782af27b 100644 --- a/tests/ui/borrowck/index-self-with-arithmetic-on-self-item.rs +++ b/tests/ui/borrowck/index-self-with-arithmetic-on-self-item.rs @@ -1,3 +1,6 @@ +//! Regression test for . +//! Test borrowck doesn't complain about using arithmetic with self item +//! as index. //@ check-pass fn main() { diff --git a/tests/ui/codegen/bitvec-to-bools-opt-miscompile.rs b/tests/ui/codegen/bitvec-to-bools-opt-miscompile.rs index fc35d1906368f..9611cd5485b60 100644 --- a/tests/ui/codegen/bitvec-to-bools-opt-miscompile.rs +++ b/tests/ui/codegen/bitvec-to-bools-opt-miscompile.rs @@ -1,4 +1,6 @@ +//! Regression test for . //@ run-pass + #![allow(non_camel_case_types)] trait methods { //~ WARN trait `methods` is never used diff --git a/tests/ui/codegen/bitvec-to-bools-opt-miscompile.stderr b/tests/ui/codegen/bitvec-to-bools-opt-miscompile.stderr index 500ace8f2753e..3eb03d3740fcd 100644 --- a/tests/ui/codegen/bitvec-to-bools-opt-miscompile.stderr +++ b/tests/ui/codegen/bitvec-to-bools-opt-miscompile.stderr @@ -1,5 +1,5 @@ warning: trait `methods` is never used - --> $DIR/issue-2989.rs:4:7 + --> $DIR/bitvec-to-bools-opt-miscompile.rs:6:7 | LL | trait methods { | ^^^^^^^ diff --git a/tests/ui/codegen/box-deref-segfault-misopt.rs b/tests/ui/codegen/box-deref-segfault-misopt.rs index 538e89f224697..f764db35e8c29 100644 --- a/tests/ui/codegen/box-deref-segfault-misopt.rs +++ b/tests/ui/codegen/box-deref-segfault-misopt.rs @@ -1,5 +1,6 @@ +//! Regression test for . +//! Misoptimization caused this to segfault. //@ run-pass -// This used to segfault #30081 pub enum Instruction { Increment(i8), diff --git a/tests/ui/drop/move-closure-drop-on-unwind.rs b/tests/ui/drop/move-closure-drop-on-unwind.rs index 77a3885da042a..ad110c1de01c8 100644 --- a/tests/ui/drop/move-closure-drop-on-unwind.rs +++ b/tests/ui/drop/move-closure-drop-on-unwind.rs @@ -1,3 +1,7 @@ +//! Regression test for . +//! Test `FnOnce` impl closure's value gets properly dropped +//! (during unwind as well). + //@ run-pass //@ needs-unwind //@ ignore-backends: gcc diff --git a/tests/ui/drop/panic-during-slice-init.rs b/tests/ui/drop/panic-during-slice-init.rs index 09b832bb59d02..ddf1e01dd8e7a 100644 --- a/tests/ui/drop/panic-during-slice-init.rs +++ b/tests/ui/drop/panic-during-slice-init.rs @@ -1,9 +1,9 @@ -//@ run-pass -// Regression test for Issue #30018. This is very similar to the -// original reported test, except that the panic is wrapped in a -// spawned thread to isolate the expected error result from the -// SIGTRAP injected by the drop-flag consistency checking. +//! Regression test for . +//! This is very similar to the original reported test, except that the +//! panic is wrapped in a spawned thread to isolate the expected error +//! result from the SIGTRAP injected by the drop-flag consistency checking. +//@ run-pass //@ needs-unwind //@ needs-threads //@ ignore-backends: gcc diff --git a/tests/ui/privacy/fn-returns-unnameable-type.rs b/tests/ui/privacy/fn-returns-unnameable-type.rs index 76b9429329631..1e4474cfafefa 100644 --- a/tests/ui/privacy/fn-returns-unnameable-type.rs +++ b/tests/ui/privacy/fn-returns-unnameable-type.rs @@ -1,5 +1,6 @@ +//! Regression test for . +//! Test functions can return unnameable types. //@ run-pass -// Functions can return unnameable types mod m1 { mod m2 { diff --git a/tests/ui/resolve/impl-method-cant-capture-env.rs b/tests/ui/resolve/impl-method-cant-capture-env.rs index f1630afe1730e..57ef5b83e2ccb 100644 --- a/tests/ui/resolve/impl-method-cant-capture-env.rs +++ b/tests/ui/resolve/impl-method-cant-capture-env.rs @@ -1,3 +1,6 @@ +//! Regression test for . +//! Ensure upvars from fn cannot be used in impl method block body. + fn siphash(k0 : u64) { struct SipHash { diff --git a/tests/ui/resolve/impl-method-cant-capture-env.stderr b/tests/ui/resolve/impl-method-cant-capture-env.stderr index 48777fec0a3ff..360598dee5827 100644 --- a/tests/ui/resolve/impl-method-cant-capture-env.stderr +++ b/tests/ui/resolve/impl-method-cant-capture-env.stderr @@ -1,5 +1,5 @@ error[E0434]: can't capture dynamic environment in a fn item - --> $DIR/issue-3021-b.rs:9:22 + --> $DIR/impl-method-cant-capture-env.rs:12:22 | LL | self.v0 = k0 ^ 0x736f6d6570736575; | ^^ diff --git a/tests/ui/resolve/impl-trait-for-type-cant-capture-env.rs b/tests/ui/resolve/impl-trait-for-type-cant-capture-env.rs index a672261f8d681..29c4ca07c22f2 100644 --- a/tests/ui/resolve/impl-trait-for-type-cant-capture-env.rs +++ b/tests/ui/resolve/impl-trait-for-type-cant-capture-env.rs @@ -1,3 +1,6 @@ +//! Regression test for . +//! Test accessing upvars in impl trait for type method is forbidden. + trait SipHash { fn reset(&self); } diff --git a/tests/ui/resolve/impl-trait-for-type-cant-capture-env.stderr b/tests/ui/resolve/impl-trait-for-type-cant-capture-env.stderr index 5dc4f9542fee5..2c25f6b1b8954 100644 --- a/tests/ui/resolve/impl-trait-for-type-cant-capture-env.stderr +++ b/tests/ui/resolve/impl-trait-for-type-cant-capture-env.stderr @@ -1,5 +1,5 @@ error[E0434]: can't capture dynamic environment in a fn item - --> $DIR/issue-3021.rs:12:22 + --> $DIR/impl-trait-for-type-cant-capture-env.rs:15:22 | LL | self.v0 = k0 ^ 0x736f6d6570736575; | ^^ diff --git a/tests/ui/resolve/outer-generic-in-trait-method.rs b/tests/ui/resolve/outer-generic-in-trait-method.rs index bd21d1244235d..a31062f480463 100644 --- a/tests/ui/resolve/outer-generic-in-trait-method.rs +++ b/tests/ui/resolve/outer-generic-in-trait-method.rs @@ -1,3 +1,6 @@ +//! Regression test for . +//! Test we can't use outer generic param in trait method defined in fn body. + fn siphash() { trait U { diff --git a/tests/ui/resolve/outer-generic-in-trait-method.stderr b/tests/ui/resolve/outer-generic-in-trait-method.stderr index d521d4f4a73ae..f85b9623a52f3 100644 --- a/tests/ui/resolve/outer-generic-in-trait-method.stderr +++ b/tests/ui/resolve/outer-generic-in-trait-method.stderr @@ -1,5 +1,5 @@ error[E0401]: can't use generic parameters from outer item - --> $DIR/issue-3021-c.rs:4:24 + --> $DIR/outer-generic-in-trait-method.rs:7:24 | LL | fn siphash() { | - type parameter from outer item @@ -16,7 +16,7 @@ LL | trait U { | +++ error[E0401]: can't use generic parameters from outer item - --> $DIR/issue-3021-c.rs:4:30 + --> $DIR/outer-generic-in-trait-method.rs:7:30 | LL | fn siphash() { | - type parameter from outer item diff --git a/tests/ui/resolve/trait-impl-cant-capture-env.rs b/tests/ui/resolve/trait-impl-cant-capture-env.rs index 1fb0002b2fc73..751e49f9863c9 100644 --- a/tests/ui/resolve/trait-impl-cant-capture-env.rs +++ b/tests/ui/resolve/trait-impl-cant-capture-env.rs @@ -1,3 +1,6 @@ +//! Regression test for . +//! Ensure upvars from fn cannot be used in impl method block body. + trait SipHash { fn result(&self) -> u64; fn reset(&self); diff --git a/tests/ui/resolve/trait-impl-cant-capture-env.stderr b/tests/ui/resolve/trait-impl-cant-capture-env.stderr index 39e6e8c43e944..3c80960a235cb 100644 --- a/tests/ui/resolve/trait-impl-cant-capture-env.stderr +++ b/tests/ui/resolve/trait-impl-cant-capture-env.stderr @@ -1,5 +1,5 @@ error[E0434]: can't capture dynamic environment in a fn item - --> $DIR/issue-3021-d.rs:21:23 + --> $DIR/trait-impl-cant-capture-env.rs:24:23 | LL | self.v0 = k0 ^ 0x736f6d6570736575; | ^^ @@ -7,7 +7,7 @@ LL | self.v0 = k0 ^ 0x736f6d6570736575; = help: use the `|| { ... }` closure form instead error[E0434]: can't capture dynamic environment in a fn item - --> $DIR/issue-3021-d.rs:22:23 + --> $DIR/trait-impl-cant-capture-env.rs:25:23 | LL | self.v1 = k1 ^ 0x646f72616e646f6d; | ^^ From ba53d1b1cca6ea33ac96e3f99ab15f5de8580cf4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 3 Jul 2026 13:36:47 +1000 Subject: [PATCH 21/56] Add some more AST size assertions --- compiler/rustc_ast/src/ast.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index bd5ce5d18b839..8a2a707b5ad2f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -4391,27 +4391,37 @@ mod size_asserts { // tidy-alphabetical-start static_assert_size!(AssocItem, 80); static_assert_size!(AssocItemKind, 16); + static_assert_size!(AttrKind, 16); static_assert_size!(Attribute, 32); static_assert_size!(Block, 32); static_assert_size!(Expr, 72); static_assert_size!(ExprKind, 40); static_assert_size!(Fn, 192); + static_assert_size!(FnDecl, 24); + static_assert_size!(FnHeader, 76); + static_assert_size!(FnSig, 96); static_assert_size!(ForeignItem, 80); static_assert_size!(ForeignItemKind, 16); static_assert_size!(GenericArg, 24); + static_assert_size!(GenericArgs, 40); static_assert_size!(GenericBound, 88); + static_assert_size!(GenericParam, 96); static_assert_size!(Generics, 40); static_assert_size!(Impl, 80); static_assert_size!(Item, 152); static_assert_size!(ItemKind, 88); + static_assert_size!(Lifetime, 16); static_assert_size!(LitKind, 24); static_assert_size!(Local, 96); + static_assert_size!(MetaItem, 88); + static_assert_size!(MetaItemKind, 40); static_assert_size!(MetaItemLit, 40); static_assert_size!(Param, 40); static_assert_size!(Pat, 80); static_assert_size!(PatKind, 56); static_assert_size!(Path, 24); static_assert_size!(PathSegment, 24); + static_assert_size!(QSelf, 24); static_assert_size!(Stmt, 32); static_assert_size!(StmtKind, 16); static_assert_size!(TraitImplHeader, 72); From b14e429dfb352c04e5e328315a9056c429d7540a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 3 Jul 2026 13:07:47 +1000 Subject: [PATCH 22/56] Use `ThinVec` in `Expr::OffsetOf` Because we use `ThinVec` rather than `Vec` almost everywhere else in the AST. --- compiler/rustc_ast/src/ast.rs | 2 +- compiler/rustc_ast/src/visit.rs | 1 + compiler/rustc_parse/src/parser/expr.rs | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 8a2a707b5ad2f..fff4d8e7ea799 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1868,7 +1868,7 @@ pub enum ExprKind { /// /// Usually not written directly in user code but /// indirectly via the macro `core::mem::offset_of!(...)`. - OffsetOf(Box, Vec), + OffsetOf(Box, ThinVec), /// A macro invocation; pre-expansion. MacCall(Box), diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 1e96d1d52f7eb..8b96bbde82215 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -386,6 +386,7 @@ macro_rules! common_visitor_and_walkers { impl_visitable_list!(<$($lt)? $($mut)?> ThinVec, ThinVec, + ThinVec, ThinVec<(Ident, Option)>, ThinVec<(NodeId, Path)>, ThinVec, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 60a94345c5325..df1877b82cb93 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1154,8 +1154,8 @@ impl<'a> Parser<'a> { /// Parse the field access used in offset_of, matched by `$(e:expr)+`. /// Currently returns a list of idents. However, it should be possible in /// future to also do array indices, which might be arbitrary expressions. - pub(crate) fn parse_floating_field_access(&mut self) -> PResult<'a, Vec> { - let mut fields = Vec::new(); + pub(crate) fn parse_floating_field_access(&mut self) -> PResult<'a, ThinVec> { + let mut fields = ThinVec::new(); let mut trailing_dot = None; loop { From 3a0a97727d174905858f88d06eba9d651a46f8eb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 3 Jul 2026 13:24:25 +1000 Subject: [PATCH 23/56] Use `ThinVec` in `GenericBounds` Because we use `ThinVec` rather than `Vec` almost everywhere else in the AST. --- compiler/rustc_ast/src/ast.rs | 6 +++--- compiler/rustc_ast/src/visit.rs | 1 + compiler/rustc_builtin_macros/src/deriving/debug.rs | 2 +- .../rustc_builtin_macros/src/deriving/generic/mod.rs | 6 +++--- compiler/rustc_parse/src/parser/generics.rs | 12 ++++++------ compiler/rustc_parse/src/parser/item.rs | 5 +++-- compiler/rustc_parse/src/parser/ty.rs | 8 ++++---- compiler/rustc_resolve/src/late/diagnostics.rs | 4 ++-- tests/ui/stats/input-stats.stderr | 8 ++++---- 9 files changed, 27 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index fff4d8e7ea799..3e1fff594040e 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -407,7 +407,7 @@ impl GenericBound { } } -pub type GenericBounds = Vec; +pub type GenericBounds = ThinVec; /// Specifies the enforced ordering for generic parameters. In the future, /// if we wanted to relax this order, we could override `PartialEq` and @@ -1534,7 +1534,7 @@ impl Expr { let (Some(lhs), Some(rhs)) = (lhs.to_bound(), rhs.to_bound()) else { return None; }; - TyKind::TraitObject(vec![lhs, rhs], TraitObjectSyntax::None) + TyKind::TraitObject(thin_vec![lhs, rhs], TraitObjectSyntax::None) } ExprKind::Underscore => TyKind::Infer, @@ -4405,7 +4405,7 @@ mod size_asserts { static_assert_size!(GenericArg, 24); static_assert_size!(GenericArgs, 40); static_assert_size!(GenericBound, 88); - static_assert_size!(GenericParam, 96); + static_assert_size!(GenericParam, 80); static_assert_size!(Generics, 40); static_assert_size!(Impl, 80); static_assert_size!(Item, 152); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 8b96bbde82215..fb4e76321d150 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -386,6 +386,7 @@ macro_rules! common_visitor_and_walkers { impl_visitable_list!(<$($lt)? $($mut)?> ThinVec, ThinVec, + ThinVec, ThinVec, ThinVec<(Ident, Option)>, ThinVec<(NodeId, Path)>, diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs index 004b13bcc333d..2436800d0099d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -167,7 +167,7 @@ fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> let ty_dyn_debug = cx.ty( span, ast::TyKind::TraitObject( - vec![cx.trait_bound(path_debug, false)], + thin_vec![cx.trait_bound(path_debug, false)], ast::TraitObjectSyntax::Dyn, ), ); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index ff6b15b173ed1..1577db640502c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -617,7 +617,7 @@ impl<'a> TraitDef<'a> { ident, generics: Generics::default(), after_where_clause: ast::WhereClause::default(), - bounds: Vec::new(), + bounds: ThinVec::new(), ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)), })), tokens: None, @@ -639,7 +639,7 @@ impl<'a> TraitDef<'a> { // Extra restrictions on the generics parameters to the // type being derived upon. let span = param.ident.span.with_ctxt(ctxt); - let bounds: Vec<_> = self + let bounds: ThinVec<_> = self .additional_bounds .iter() .map(|p| { @@ -723,7 +723,7 @@ impl<'a> TraitDef<'a> { { continue; } - let mut bounds: Vec<_> = self + let mut bounds: ThinVec<_> = self .additional_bounds .iter() .map(|p| { diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index e2df607fd0f86..506607f57191d 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -26,7 +26,7 @@ impl<'a> Parser<'a> { /// BOUND = LT_BOUND (e.g., `'a`) /// ``` fn parse_lt_param_bounds(&mut self) -> GenericBounds { - let mut lifetimes = Vec::new(); + let mut lifetimes = ThinVec::new(); while self.check_lifetime() { lifetimes.push(ast::GenericBound::Outlives(self.expect_lifetime())); @@ -86,7 +86,7 @@ impl<'a> Parser<'a> { } self.parse_generic_bounds()? } else { - Vec::new() + ThinVec::new() }; let default = if self.eat(exp!(Eq)) { Some(self.parse_ty()?) } else { None }; @@ -125,7 +125,7 @@ impl<'a> Parser<'a> { ident, id: ast::DUMMY_NODE_ID, attrs: preceding_attrs, - bounds: Vec::new(), + bounds: ThinVec::new(), kind: GenericParamKind::Const { ty, span, default: None }, is_placeholder: false, colon_span: None, @@ -148,7 +148,7 @@ impl<'a> Parser<'a> { ident, id: ast::DUMMY_NODE_ID, attrs: preceding_attrs, - bounds: Vec::new(), + bounds: ThinVec::new(), kind: GenericParamKind::Const { ty, span, default }, is_placeholder: false, colon_span: None, @@ -189,7 +189,7 @@ impl<'a> Parser<'a> { ident, id: ast::DUMMY_NODE_ID, attrs: preceding_attrs, - bounds: Vec::new(), + bounds: ThinVec::new(), kind: GenericParamKind::Const { ty, span, default }, is_placeholder: false, colon_span: None, @@ -225,7 +225,7 @@ impl<'a> Parser<'a> { let (colon_span, bounds) = if this.eat(exp!(Colon)) { (Some(this.prev_token.span), this.parse_lt_param_bounds()) } else { - (None, Vec::new()) + (None, ThinVec::new()) }; if this.check_noexpect(&token::Eq) && this.look_ahead(1, |t| t.is_lifetime()) { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 16fed9c6c273b..6f5c4c874d83b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1135,7 +1135,7 @@ impl<'a> Parser<'a> { // Parse optional colon and supertrait bounds. let had_colon = self.eat(exp!(Colon)); let span_at_colon = self.prev_token.span; - let bounds = if had_colon { self.parse_generic_bounds()? } else { Vec::new() }; + let bounds = if had_colon { self.parse_generic_bounds()? } else { ThinVec::new() }; let span_before_eq = self.prev_token.span; if self.eat(exp!(Eq)) { @@ -1253,7 +1253,8 @@ impl<'a> Parser<'a> { let mut generics = self.parse_generics()?; // Parse optional colon and param bounds. - let bounds = if self.eat(exp!(Colon)) { self.parse_generic_bounds()? } else { Vec::new() }; + let bounds = + if self.eat(exp!(Colon)) { self.parse_generic_bounds()? } else { ThinVec::new() }; generics.where_clause = self.parse_where_clause()?; let ty = if self.eat(exp!(Eq)) { Some(self.parse_ty()?) } else { None }; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 8a881c6f8b568..9c873711e2f87 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -576,7 +576,7 @@ impl<'a> Parser<'a> { lo.to(self.prev_token.span), parens, ); - let bounds = vec![GenericBound::Trait(poly_trait_ref)]; + let bounds = thin_vec![GenericBound::Trait(poly_trait_ref)]; self.parse_remaining_bounds(bounds, parse_plus) } @@ -1080,7 +1080,7 @@ impl<'a> Parser<'a> { /// Only if `allow_plus` this parses a `+`-separated list of bounds (trailing `+` is admitted). /// Otherwise, this only parses a single bound or none. fn parse_generic_bounds_common(&mut self, allow_plus: AllowPlus) -> PResult<'a, GenericBounds> { - let mut bounds = Vec::new(); + let mut bounds = ThinVec::new(); // In addition to looping while we find generic bounds: // We continue even if we find a keyword. This is necessary for error recovery on, @@ -1432,7 +1432,7 @@ impl<'a> Parser<'a> { // Someone has written something like `&dyn (Trait + Other)`. The correct code // would be `&(dyn Trait + Other)` if self.token.is_like_plus() && leading_token.is_keyword(kw::Dyn) { - let bounds = vec![]; + let bounds = thin_vec![]; self.parse_remaining_bounds(bounds, true)?; self.expect(exp!(CloseParen))?; self.dcx().emit_err(errors::IncorrectParensTraitBounds { @@ -1617,7 +1617,7 @@ impl<'a> Parser<'a> { id: lt.id, ident: lt.ident, attrs: ast::AttrVec::new(), - bounds: Vec::new(), + bounds: ThinVec::new(), is_placeholder: false, kind: ast::GenericParamKind::Lifetime, colon_span: None, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 8c5c7f5b2d76d..668278f13d9cf 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -28,7 +28,7 @@ use rustc_session::{Session, lint}; use rustc_span::edit_distance::{edit_distance, find_best_match_for_name}; use rustc_span::edition::Edition; use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym}; -use thin_vec::ThinVec; +use thin_vec::{ThinVec, thin_vec}; use tracing::debug; use super::NoConstantGenericsReason; @@ -4522,7 +4522,7 @@ fn mk_where_bound_predicate( let new_where_bound_predicate = ast::WhereBoundPredicate { bound_generic_params: ThinVec::new(), bounded_ty: Box::new(ty.clone()), - bounds: vec![ast::GenericBound::Trait(ast::PolyTraitRef { + bounds: thin_vec![ast::GenericBound::Trait(ast::PolyTraitRef { bound_generic_params: ThinVec::new(), modifiers: ast::TraitBoundModifiers::NONE, trait_ref: ast::TraitRef { diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index b4d8277a46c00..f4c6808431687 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -27,7 +27,7 @@ ast-stats Pat 560 (NN.N%) 7 80 ast-stats - Struct 80 (NN.N%) 1 ast-stats - Wild 80 (NN.N%) 1 ast-stats - Ident 400 (NN.N%) 5 -ast-stats GenericParam 480 (NN.N%) 5 96 +ast-stats GenericParam 400 (NN.N%) 5 80 ast-stats GenericBound 352 (NN.N%) 4 88 ast-stats - Trait 352 (NN.N%) 4 ast-stats AssocItem 320 (NN.N%) 4 80 @@ -50,14 +50,14 @@ ast-stats Local 96 (NN.N%) 1 96 ast-stats Arm 96 (NN.N%) 2 48 ast-stats ForeignItem 80 (NN.N%) 1 80 ast-stats - Fn 80 (NN.N%) 1 -ast-stats WherePredicate 72 (NN.N%) 1 72 -ast-stats - BoundPredicate 72 (NN.N%) 1 +ast-stats WherePredicate 56 (NN.N%) 1 56 +ast-stats - BoundPredicate 56 (NN.N%) 1 ast-stats ExprField 48 (NN.N%) 1 48 ast-stats GenericArgs 40 (NN.N%) 1 40 ast-stats - AngleBracketed 40 (NN.N%) 1 ast-stats Crate 40 (NN.N%) 1 40 ast-stats ---------------------------------------------------------------- -ast-stats Total 7_624 127 +ast-stats Total 7_528 127 ast-stats ================================================================ hir-stats ================================================================ hir-stats HIR STATS: input_stats From 27935a6a54a417dfea0c6b2f79c28ea255c67df0 Mon Sep 17 00:00:00 2001 From: Sylvester Kpei Date: Fri, 3 Jul 2026 19:47:41 -0700 Subject: [PATCH 24/56] Fix incorrect tracking issue link for read_le/read_be The unstable attribute on Read::read_le and Read::read_be pointed to the implementation PR rather than the tracking issue, so the docs on doc.rust-lang.org linked to the wrong page. --- library/std/src/io/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index dc623a3e82c2c..6396be588c0ff 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1294,7 +1294,7 @@ pub trait Read { /// Ok(()) /// } /// ``` - #[unstable(feature = "read_le", issue = "156983")] + #[unstable(feature = "read_le", issue = "156984")] #[inline] fn read_le(&mut self) -> Result where @@ -1327,7 +1327,7 @@ pub trait Read { /// Ok(()) /// } /// ``` - #[unstable(feature = "read_le", issue = "156983")] + #[unstable(feature = "read_le", issue = "156984")] #[inline] fn read_be(&mut self) -> Result where From 4c7acb4cf835e84f1fb486d3d865f565d3722884 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 4 Jul 2026 14:40:58 +0900 Subject: [PATCH 25/56] add rustdoc-ui regression for non-ident doc auto_cfg values --- tests/rustdoc-ui/doc-auto-cfg-values-non-ident.rs | 7 +++++++ tests/rustdoc-ui/doc-auto-cfg-values-non-ident.stderr | 11 +++++++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/rustdoc-ui/doc-auto-cfg-values-non-ident.rs create mode 100644 tests/rustdoc-ui/doc-auto-cfg-values-non-ident.stderr diff --git a/tests/rustdoc-ui/doc-auto-cfg-values-non-ident.rs b/tests/rustdoc-ui/doc-auto-cfg-values-non-ident.rs new file mode 100644 index 0000000000000..213a804b8b63e --- /dev/null +++ b/tests/rustdoc-ui/doc-auto-cfg-values-non-ident.rs @@ -0,0 +1,7 @@ +// Regression test for https://github.com/rust-lang/rust/issues/158744. + +#![feature(doc_cfg)] + +#[doc(auto_cfg(hide(a, values(::b))))] +//~^ ERROR malformed `doc` attribute input +fn f() {} diff --git a/tests/rustdoc-ui/doc-auto-cfg-values-non-ident.stderr b/tests/rustdoc-ui/doc-auto-cfg-values-non-ident.stderr new file mode 100644 index 0000000000000..8c08c5ed4226d --- /dev/null +++ b/tests/rustdoc-ui/doc-auto-cfg-values-non-ident.stderr @@ -0,0 +1,11 @@ +error[E0565]: malformed `doc` attribute input + --> $DIR/doc-auto-cfg-values-non-ident.rs:5:1 + | +LL | #[doc(auto_cfg(hide(a, values(::b))))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^^^^ + | | + | expected a valid identifier here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0565`. From 86960f5e13eb93f3793c39a523dbdfe76d32f849 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 4 Jul 2026 14:41:21 +0900 Subject: [PATCH 26/56] handle non-ident doc auto_cfg values without panicking --- compiler/rustc_attr_parsing/src/attributes/doc.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 23eef6334ccee..9b03792057b33 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -348,8 +348,11 @@ impl DocParser { // If it's a list, then only `any()` and `none()` are allowed and they must not // contain any item. MetaItemOrLitParser::MetaItemParser(sub_item) => { - if let Some(ident) = sub_item.ident() - && [sym::any, sym::none].contains(&ident.name) + let Some(ident) = sub_item.ident() else { + cx.adcx().expected_identifier(sub_item.path().span()); + continue; + }; + if [sym::any, sym::none].contains(&ident.name) && let ArgParser::List(list) = sub_item.args() && list.mixed().count() == 0 { @@ -371,9 +374,7 @@ impl DocParser { } else { cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - DocAutoCfgHideShowUnexpectedItem { - attr_name: sub_item.ident().unwrap().name, - }, + DocAutoCfgHideShowUnexpectedItem { attr_name: ident.name }, sub_item.span(), ); } From c341ff552bdc30be78db9603e0519819561865bc Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Jul 2026 10:59:05 +0200 Subject: [PATCH 27/56] sembr src/analysis/well-formed.md --- .../src/analysis/well-formed.md | 88 +++++++++++++------ 1 file changed, 59 insertions(+), 29 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/analysis/well-formed.md b/src/doc/rustc-dev-guide/src/analysis/well-formed.md index 49c9509fea466..464ffce817369 100644 --- a/src/doc/rustc-dev-guide/src/analysis/well-formed.md +++ b/src/doc/rustc-dev-guide/src/analysis/well-formed.md @@ -2,7 +2,8 @@ ## What is Well-Formedness? -"Well-formed" means "correctly built."[^wf-history] Something is _well-formed_ when its structure follows rules. When we use this term in the Rust compiler we are concerned with establishing some kind of _internal consistency_. +"Well-formed" means "correctly built."[^wf-history] Something is _well-formed_ when its structure follows rules. +When we use this term in the Rust compiler we are concerned with establishing some kind of _internal consistency_. ## Well-Formedness in Rust @@ -12,7 +13,7 @@ In the Rust compiler there are two different forms of well-formedness checking: - **Type-Level Term**[^terms][^terms-abbreviated] well-formedness check. - Also called "Term well-formedness" or "Term well-formedness checking." - - Not a distinct analysis stage, this gets performed throughout analysis. + - Not a distinct analysis stage, this gets performed throughout analysis. - **Item**[^items] well-formedness check (item-wfck.) - "Item-wfck" will often wind up requiring Terms be well-formed, but skips some areas. - Inner "Terms" can (incorrectly) get normalized first. @@ -22,7 +23,8 @@ See: [What Well-Formedness Isn't](#what-well-formedness-isnt). ## Well-Formedness of Type-Level Terms -Term well-formedness checking begins with building a list of things that need to be true for a term to be well-formed. We call these "Obligations"[^obligations]. +Term well-formedness checking begins with building a list of things that need to be true for a term to be well-formed. +We call these "Obligations"[^obligations]. Type-Level Terms are considered Well-Formed when their associated obligations are satisfied by the trait solver. @@ -49,7 +51,8 @@ Vec where T: Sized Vec where String: Sized ``` -When we compute the obligations for `Vec`, we'll find that `Vec` generates the obligation `T: Sized`. We substitute `T` with `String` in `Vec`, so we find the obligation `String: Sized` which the trait solver will determine to be satisfied. +When we compute the obligations for `Vec`, we'll find that `Vec` generates the obligation `T: Sized`. +We substitute `T` with `String` in `Vec`, so we find the obligation `String: Sized` which the trait solver will determine to be satisfied. The following **is not** well-formed: @@ -62,7 +65,8 @@ Vec where T: Sized Vec where str: Sized ``` -The above computes the obligation `T: Sized`, like before, but we substitute `T` for `str` in the instance of `Vec` finding the obligation `str: sized`. This obligation will be determined by the trait solver to be _unsatisfied_. +The above computes the obligation `T: Sized`, like before, but we substitute `T` for `str` in the instance of `Vec` finding the obligation `str: sized`. +This obligation will be determined by the trait solver to be _unsatisfied_. #### Determining Obligations @@ -70,17 +74,20 @@ In the compiler, obligations of terms are found through the [`obligations`](http #### Other Obligations -Obligations are more than just trait and const generic bounds, but we've only mentioned these specific obligations so far as they are what we care about when we do "well-formedness checking" of terms. See: [`PredicateKind`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_type_ir/predicate_kind/enum.PredicateKind.html) and [`ClauseKind`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_type_ir/predicate_kind/enum.ClauseKind.html) for a full list of obligations. +Obligations are more than just trait and const generic bounds, but we've only mentioned these specific obligations so far as they are what we care about when we do "well-formedness checking" of terms. +See: [`PredicateKind`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_type_ir/predicate_kind/enum.PredicateKind.html) and [`ClauseKind`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_type_ir/predicate_kind/enum.ClauseKind.html) for a full list of obligations. ### We Don't Need Normalization (Yet) -[Normalization](../normalization.md) is the process of resolving [type aliases](../normalization.md#aliases) into their underlying type. +[Normalization](../normalization.md) is the process of resolving [type aliases](../normalization.md#aliases) into their underlying type. -A type alias is considered well-formed if its where clauses are satisfied. The underlying type undergoes well-formedness checking at most definition and instantiation sites, but there are exceptions. +A type alias is considered well-formed if its where clauses are satisfied. +The underlying type undergoes well-formedness checking at most definition and instantiation sites, but there are exceptions. ### Const Generic Arguments -Term well-formedness is responsible for getting "type checking" obligations of const generic terms[^tyck-const-generics]. Let's look at the following use of const generics: +Term well-formedness is responsible for getting "type checking" obligations of const generic terms[^tyck-const-generics]. +Let's look at the following use of const generics: ```rust,ignore fn use_const_generics() { /* ... */ } @@ -91,7 +98,8 @@ use_const_generics::<6>(); const 6: usize ``` -The call site will provide us with the obligation `6: usize` during well-formedness checking. This obligation will be passed off to the trait solver just like any trait-style obligation, as the trait solver has more responsibilities than its name suggests. +The call site will provide us with the obligation `6: usize` during well-formedness checking. +This obligation will be passed off to the trait solver just like any trait-style obligation, as the trait solver has more responsibilities than its name suggests. ## Well-Formedness of Items @@ -108,7 +116,8 @@ Vec: Sized // Generated Vec<[u8]>: Sized // Not done at item-wfck. Done elsewhere. ``` -Item-wfck has more responsibilities than only collecting the obligations of its internal type-level terms and passing them to the trait solver. We do not talk about all of these here, but they can be found at the individual `check_*` functions in [**the item-wfck module**](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/wfcheck/index.html). +Item-wfck has more responsibilities than only collecting the obligations of its internal type-level terms and passing them to the trait solver. +We do not talk about all of these here, but they can be found at the individual `check_*` functions in [**the item-wfck module**](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/wfcheck/index.html). @@ -116,7 +125,9 @@ Item-wfck has more responsibilities than only collecting the obligations of its -Trait bounds are a common Obligation. Global and Trivial trait bounds are kinds of trait bounds where we already have enough information to determine if they are true or false. Item-wfck is responsible for finding and checking these bounds. +Trait bounds are a common Obligation. +Global and Trivial trait bounds are kinds of trait bounds where we already have enough information to determine if they are true or false. +Item-wfck is responsible for finding and checking these bounds. - **Global bounds** are, in the old solver, post-normalization bounds that don't contain any generic parameters (likeΒ `` or `'a`) or bound variables (like `for<'b>`). - **Trivial bounds** are bounds that do not need further normalization to determine if they're well-formed or not. @@ -130,9 +141,11 @@ String: Clone // Trivial & Global bound! There's no aliases to resolve. // There could be bligations on T but we don't care about them here. ``` -This produces a trait bound obligation `String: Clone` that is _Global_ (no generic parameters) and _Trivial_ (didn't require normalization to be well-formedness checked). The trait solver doesn't need to be given any additional information for it to be able to make a judgment on the well-formedness of `String: Clone`. +This produces a trait bound obligation `String: Clone` that is _Global_ (no generic parameters) and _Trivial_ (didn't require normalization to be well-formedness checked). +The trait solver doesn't need to be given any additional information for it to be able to make a judgment on the well-formedness of `String: Clone`. -False trivial bounds are simply trivial bounds that do not hold. The following is a basic example: +False trivial bounds are simply trivial bounds that do not hold. +The following is a basic example: ```rust,ignore fn apartment_simple(block: T, name: String) where String: Copy { /* ... */ } @@ -144,7 +157,8 @@ Here we have a trivial bound that does not hold, because `String` is not `Copy`. #### Trivial Bounds Are Not Always Global -Trivial Bounds are not a subset of Global Bounds. A trivial bound that isn't Global is `for<'a> String: Clone` (trivially true, has a bound variable) or `&'a str: Copy` (trivially false, has a generic parameter). +Trivial Bounds are not a subset of Global Bounds. +A trivial bound that isn't Global is `for<'a> String: Clone` (trivially true, has a bound variable) or `&'a str: Copy` (trivially false, has a generic parameter). #### Item-Wfck and Trivial/Global Bounds @@ -154,15 +168,19 @@ When checking items are well-formed we will check that there are no trivially fa ## When We Don't Fully Do Well-Formedness Checking -Well-formedness checking is not a coherent "stage" of type checking. There are many areas where well-formedness checking is performed, and some areas where we skip over well-formedness checking due to limitations in what kinds of analysis we can currently perform. Ideally, we would never skip or defer well-formedness checking. +Well-formedness checking is not a coherent "stage" of type checking. +There are many areas where well-formedness checking is performed, and some areas where we skip over well-formedness checking due to limitations in what kinds of analysis we can currently perform. +Ideally, we would never skip or defer well-formedness checking. ### We (Sometimes) Need Normalization -There are places where normalization of an Item happens before its Terms have gone through well-formedness checking. This is considered problematic as doing so allows some terms to [bypass term well-formedness checking entirely](https://github.com/rust-lang/rust/issues/100041). +There are places where normalization of an Item happens before its Terms have gone through well-formedness checking. +This is considered problematic as doing so allows some terms to [bypass term well-formedness checking entirely](https://github.com/rust-lang/rust/issues/100041). ### Trait Objects -We do not require the where clauses of trait objects to be well-formed when determining if that trait object is well-formed. These where clauses are proven when coercing into a trait object, but this remains a hole in well-formedness checking. +We do not require the where clauses of trait objects to be well-formed when determining if that trait object is well-formed. +These where clauses are proven when coercing into a trait object, but this remains a hole in well-formedness checking. As an example, the following will compile because we don't have a point where we're constructing the trait object from a concrete type: @@ -211,7 +229,8 @@ N = B // Substitution const B: usize + bool ``` -The above doesn't compile, unlike the previous example we gave. We're doing _some_ well-formedness checking here when it comes to the const generic arguments. +The above doesn't compile, unlike the previous example we gave. +We're doing _some_ well-formedness checking here when it comes to the const generic arguments. ### Binders / Higher-Ranked Types @@ -224,9 +243,11 @@ let _: for<'a> fn(Vec<[&'a ()]>); [&'a ()]: Sized // slices aren't sized, this would fail! ``` -Specifically, obligations involving variables from binders (`for<'a>`) are only checked when the binder is instantiated. Some things are stilled checked under the `for<'a>`, but we still skip a lot of things. +Specifically, obligations involving variables from binders (`for<'a>`) are only checked when the binder is instantiated. +Some things are stilled checked under the `for<'a>`, but we still skip a lot of things. -A lot of unsoundness surrounds this behavior. See: [#25860](https://github.com/rust-lang/rust/issues/25860), [#84591](https://github.com/rust-lang/rust/issues/84591). +A lot of unsoundness surrounds this behavior. +See: [#25860](https://github.com/rust-lang/rust/issues/25860), [#84591](https://github.com/rust-lang/rust/issues/84591). Let's consider the following: @@ -234,7 +255,8 @@ Let's consider the following: for<'a, 'b> fn(&'a &'b ()) ``` -The above HRB implies `'b: 'a` (a lifetime bound), rather than two completely separate lifetimes. This is normal lifetime behavior, but during well-formedness checking we cannot prove that this bound is generally true[^horrible], so we skip it. +The above HRB implies `'b: 'a` (a lifetime bound), rather than two completely separate lifetimes. +This is normal lifetime behavior, but during well-formedness checking we cannot prove that this bound is generally true[^horrible], so we skip it. ### Free Type Aliases @@ -249,9 +271,12 @@ type WorksButShouldNot = Vec; str: Sized // Not generated ``` -This shouldn't work, as both `T: Sized`, `str: Sized` are implied by `Vec`. This "passes" item-wfck because the RHS of a free type alias doesn't go through well-formedness checking _until it's used_. Item-wfck is **deferred until use** for this specific case. +This shouldn't work, as both `T: Sized`, `str: Sized` are implied by `Vec`. +This "passes" item-wfck because the RHS of a free type alias doesn't go through well-formedness checking _until it's used_. +Item-wfck is **deferred until use** for this specific case. -For Const Generics we still do a small amount of well-formedness checking at the definition site of a free type alias. This is consistent with our current special-casing of const generic well-formedness checking when we skip over things like where bounds. +For Const Generics we still do a small amount of well-formedness checking at the definition site of a free type alias. +This is consistent with our current special-casing of const generic well-formedness checking when we skip over things like where bounds. This means that the following, despite being of a similar form to the above example, fails as it should: @@ -267,19 +292,24 @@ type Alias = Consty<42>; ## "Well-Formed" or "Wellformed"? -Prefer "well-formed" over "wellformed," as this is consistent with logic literature. This also gets abbreviated to WF in other parts of the dev guide / docs. +Prefer "well-formed" over "wellformed," as this is consistent with logic literature. +This also gets abbreviated to WF in other parts of the dev guide / docs. ## Informal Usage -In conversation, contributors may refer to something as "well-formed" and not necessarily mean what we cover here because "well-formedness" is a general phrase associated with the correctness of formal structures. This isn't necessarily in error, but it should be looked out for. +In conversation, contributors may refer to something as "well-formed" and not necessarily mean what we cover here because "well-formedness" is a general phrase associated with the correctness of formal structures. +This isn't necessarily in error, but it should be looked out for. ## What Well-Formedness Isn't -Well-formedness checking is not "number of parameters" or "parameter type" checking[^kind-checking]. Neither term well-formedness checking nor item-wfck is concerned with if a type with 2 parameters has 1 or 3 types applied to it (assuming no defaults), or if a const generic parameter has a type applied to it. These kinds of problems will get handled during HIR-ty Lowering[^hir-ty-lower], not wfck. +Well-formedness checking is not "number of parameters" or "parameter type" checking[^kind-checking]. +Neither term well-formedness checking nor item-wfck is concerned with if a type with 2 parameters has 1 or 3 types applied to it (assuming no defaults), or if a const generic parameter has a type applied to it. +These kinds of problems will get handled during HIR-ty Lowering[^hir-ty-lower], not wfck. Well-formedness doesn't check or validate lifetimes, this is handled in [MIR](../borrow-check.md). -Well-formedness in the Rust compiler doesn't correspond to "correct syntax" as it does in logic. The term has a history of general use in a mathematical context of "follows a given set of rules." In Rust, our original usage was closer to "this thing is internally consistent" with respect to the bounds on a type in places such as the original [clarification on projections and well-formedness RFC](https://github.com/rust-lang/rfcs/blob/master/text/1214-projections-lifetimes-and-wf.md). +Well-formedness in the Rust compiler doesn't correspond to "correct syntax" as it does in logic. +The term has a history of general use in a mathematical context of "follows a given set of rules." In Rust, our original usage was closer to "this thing is internally consistent" with respect to the bounds on a type in places such as the original [clarification on projections and well-formedness RFC](https://github.com/rust-lang/rfcs/blob/master/text/1214-projections-lifetimes-and-wf.md). [^obligations]: These get referred to as Obligations, Requirements, or Constraints in the documentation. Preferred term is "obligations", as this matches the suffix of the type and the names of relevant functions. In future, this may be superseded by the new solver's term "Goal." [^wf-history]: In linguistics this is "grammatically correct," in logic it is "syntactically correct," and in casual mathematician use it can be read as a more general "follows the rules we set for this domain." @@ -290,4 +320,4 @@ Well-formedness in the Rust compiler doesn't correspond to "correct syntax" as i [^terms-abbreviated]: Abbreviated as "Terms" on this page in some areas. [^kind-checking]: AKA "kind checking", as we might see in languages like Haskell. [^hir-ty-lower]: -[^tyck-const-generics]: \ No newline at end of file +[^tyck-const-generics]: From ccec2e040b53fb9e84e7604095e97a4c3ac397df Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Jul 2026 11:07:58 +0200 Subject: [PATCH 28/56] fix misplaced quotes --- .../src/analysis/well-formed.md | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/analysis/well-formed.md b/src/doc/rustc-dev-guide/src/analysis/well-formed.md index 464ffce817369..b50063072d71a 100644 --- a/src/doc/rustc-dev-guide/src/analysis/well-formed.md +++ b/src/doc/rustc-dev-guide/src/analysis/well-formed.md @@ -2,17 +2,17 @@ ## What is Well-Formedness? -"Well-formed" means "correctly built."[^wf-history] Something is _well-formed_ when its structure follows rules. +"Well-formed" means "correctly built"[^wf-history]. Something is _well-formed_ when its structure follows rules. When we use this term in the Rust compiler we are concerned with establishing some kind of _internal consistency_. ## Well-Formedness in Rust -To check that something is well-formed is to perform a "Well-formedness check." +To check that something is well-formed is to perform a "Well-formedness check". In the Rust compiler there are two different forms of well-formedness checking: - **Type-Level Term**[^terms][^terms-abbreviated] well-formedness check. - - Also called "Term well-formedness" or "Term well-formedness checking." + - Also called "Term well-formedness" or "Term well-formedness checking". - Not a distinct analysis stage, this gets performed throughout analysis. - **Item**[^items] well-formedness check (item-wfck.) - "Item-wfck" will often wind up requiring Terms be well-formed, but skips some areas. @@ -103,7 +103,7 @@ This obligation will be passed off to the trait solver just like any trait-style ## Well-Formedness of Items -Items are, generally speaking, "Things that get defined." Item-wfck happens at the signature level for types and functions, methods, and definitions/implementations of traits. +Items are, generally speaking, "Things that get defined". Item-wfck happens at the signature level for types and functions, methods, and definitions/implementations of traits. ```rust,ignore // The `Vec` is checked during item wfck @@ -186,7 +186,7 @@ As an example, the following will compile because we don't have a point where we ```rust,ignore trait Trait -where +where for<'a> [u8]: Sized {} fn foo(_: &dyn Trait) {} @@ -199,13 +199,13 @@ The above should not compile because `[u8]: Sized`, but this won't be checked un ```rust trait Trait -where +where for<'a> [u8]: Sized {} - + fn foo(_: &dyn Trait) {} // We still need to specify the bound here, otherwise `[u8]: Sized` _is_ -// checked as an obligation. +// checked as an obligation. impl Trait for u8 where for<'a> [u8]: Sized {} fn main() { @@ -226,7 +226,7 @@ fn foo(_: &dyn Trait) {} const N: usize const B: bool N = B // Substitution -const B: usize + bool +const B: usize + bool ``` The above doesn't compile, unlike the previous example we gave. @@ -292,7 +292,7 @@ type Alias = Consty<42>; ## "Well-Formed" or "Wellformed"? -Prefer "well-formed" over "wellformed," as this is consistent with logic literature. +Prefer "well-formed" over "wellformed", as this is consistent with logic literature. This also gets abbreviated to WF in other parts of the dev guide / docs. ## Informal Usage @@ -309,10 +309,10 @@ These kinds of problems will get handled during HIR-ty Lowering[^hir-ty-lower], Well-formedness doesn't check or validate lifetimes, this is handled in [MIR](../borrow-check.md). Well-formedness in the Rust compiler doesn't correspond to "correct syntax" as it does in logic. -The term has a history of general use in a mathematical context of "follows a given set of rules." In Rust, our original usage was closer to "this thing is internally consistent" with respect to the bounds on a type in places such as the original [clarification on projections and well-formedness RFC](https://github.com/rust-lang/rfcs/blob/master/text/1214-projections-lifetimes-and-wf.md). +The term has a history of general use in a mathematical context of "follows a given set of rules". In Rust, our original usage was closer to "this thing is internally consistent" with respect to the bounds on a type in places such as the original [clarification on projections and well-formedness RFC](https://github.com/rust-lang/rfcs/blob/master/text/1214-projections-lifetimes-and-wf.md). -[^obligations]: These get referred to as Obligations, Requirements, or Constraints in the documentation. Preferred term is "obligations", as this matches the suffix of the type and the names of relevant functions. In future, this may be superseded by the new solver's term "Goal." -[^wf-history]: In linguistics this is "grammatically correct," in logic it is "syntactically correct," and in casual mathematician use it can be read as a more general "follows the rules we set for this domain." +[^obligations]: These get referred to as Obligations, Requirements, or Constraints in the documentation. Preferred term is "obligations", as this matches the suffix of the type and the names of relevant functions. In future, this may be superseded by the new solver's term "Goal". +[^wf-history]: In linguistics this is "grammatically correct", in logic it is "syntactically correct", and in casual mathematician use it can be read as a more general "follows the rules we set for this domain". [^horrible]: Instead, this bound is checked during "MIR borrowck" when the lifetimes are instantiated. [^fta]: Type aliases not associated with anything, i.e. a module-level `type Alias = Vec;`. [^items]: "Definition" style things in rust, See the [glossary](../appendix/glossary.md). From eefd538c162aed470cf456a8d3e51c5d900a0ca7 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Jul 2026 11:08:08 +0200 Subject: [PATCH 29/56] sembr src/analysis/well-formed.md --- src/doc/rustc-dev-guide/src/analysis/well-formed.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/analysis/well-formed.md b/src/doc/rustc-dev-guide/src/analysis/well-formed.md index b50063072d71a..dc938f22fbe01 100644 --- a/src/doc/rustc-dev-guide/src/analysis/well-formed.md +++ b/src/doc/rustc-dev-guide/src/analysis/well-formed.md @@ -2,7 +2,8 @@ ## What is Well-Formedness? -"Well-formed" means "correctly built"[^wf-history]. Something is _well-formed_ when its structure follows rules. +"Well-formed" means "correctly built"[^wf-history]. +Something is _well-formed_ when its structure follows rules. When we use this term in the Rust compiler we are concerned with establishing some kind of _internal consistency_. ## Well-Formedness in Rust @@ -103,7 +104,8 @@ This obligation will be passed off to the trait solver just like any trait-style ## Well-Formedness of Items -Items are, generally speaking, "Things that get defined". Item-wfck happens at the signature level for types and functions, methods, and definitions/implementations of traits. +Items are, generally speaking, "Things that get defined". +Item-wfck happens at the signature level for types and functions, methods, and definitions/implementations of traits. ```rust,ignore // The `Vec` is checked during item wfck @@ -309,7 +311,8 @@ These kinds of problems will get handled during HIR-ty Lowering[^hir-ty-lower], Well-formedness doesn't check or validate lifetimes, this is handled in [MIR](../borrow-check.md). Well-formedness in the Rust compiler doesn't correspond to "correct syntax" as it does in logic. -The term has a history of general use in a mathematical context of "follows a given set of rules". In Rust, our original usage was closer to "this thing is internally consistent" with respect to the bounds on a type in places such as the original [clarification on projections and well-formedness RFC](https://github.com/rust-lang/rfcs/blob/master/text/1214-projections-lifetimes-and-wf.md). +The term has a history of general use in a mathematical context of "follows a given set of rules". +In Rust, our original usage was closer to "this thing is internally consistent" with respect to the bounds on a type in places such as the original [clarification on projections and well-formedness RFC](https://github.com/rust-lang/rfcs/blob/master/text/1214-projections-lifetimes-and-wf.md). [^obligations]: These get referred to as Obligations, Requirements, or Constraints in the documentation. Preferred term is "obligations", as this matches the suffix of the type and the names of relevant functions. In future, this may be superseded by the new solver's term "Goal". [^wf-history]: In linguistics this is "grammatically correct", in logic it is "syntactically correct", and in casual mathematician use it can be read as a more general "follows the rules we set for this domain". From 6b77786795d9e0d6c37c95e83ec3d76a448351f9 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Jul 2026 11:23:00 +0200 Subject: [PATCH 30/56] use sentence case --- src/doc/rustc-dev-guide/src/SUMMARY.md | 2 +- .../src/analysis/well-formed.md | 44 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 6b17426e165ef..bf2de84575d69 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -193,7 +193,7 @@ - [Sharing the trait solver with rust-analyzer](./solve/sharing-crates-with-rust-analyzer.md) - [`Unsize` and `CoerceUnsized` traits](./traits/unsize.md) - [Having separate `Trait` and `Projection` bounds](./traits/separate-projection-bounds.md) -- [Well-Formedness](./analysis/well-formed.md) +- [Well-formedness](./analysis/well-formed.md) - [Variance](./variance.md) - [Coherence checking](./coherence.md) - [HIR Type checking](./hir-typeck/summary.md) diff --git a/src/doc/rustc-dev-guide/src/analysis/well-formed.md b/src/doc/rustc-dev-guide/src/analysis/well-formed.md index dc938f22fbe01..df60aa2ec59b7 100644 --- a/src/doc/rustc-dev-guide/src/analysis/well-formed.md +++ b/src/doc/rustc-dev-guide/src/analysis/well-formed.md @@ -1,12 +1,12 @@ -# Well-Formedness +# Well-formedness -## What is Well-Formedness? +## What is well-formedness? "Well-formed" means "correctly built"[^wf-history]. Something is _well-formed_ when its structure follows rules. When we use this term in the Rust compiler we are concerned with establishing some kind of _internal consistency_. -## Well-Formedness in Rust +## Well-formedness in Rust To check that something is well-formed is to perform a "Well-formedness check". @@ -22,14 +22,14 @@ In the Rust compiler there are two different forms of well-formedness checking: See: [What Well-Formedness Isn't](#what-well-formedness-isnt). -## Well-Formedness of Type-Level Terms +## Well-formedness of type-level terms Term well-formedness checking begins with building a list of things that need to be true for a term to be well-formed. We call these "Obligations"[^obligations]. -Type-Level Terms are considered Well-Formed when their associated obligations are satisfied by the trait solver. +Type-Level Terms are considered well-formed when their associated obligations are satisfied by the trait solver. -### Obligations for Well-Formedness +### Obligations for well-formedness Specific obligations are things like `String: Clone`, `A: usize`, or `::Item: Debug`. @@ -69,23 +69,23 @@ Vec where str: Sized The above computes the obligation `T: Sized`, like before, but we substitute `T` for `str` in the instance of `Vec` finding the obligation `str: sized`. This obligation will be determined by the trait solver to be _unsatisfied_. -#### Determining Obligations +#### Determining obligations In the compiler, obligations of terms are found through the [`obligations`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/wf/fn.obligations.html) function in the [term well-formedness module](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/wf/index.html). -#### Other Obligations +#### Other obligations Obligations are more than just trait and const generic bounds, but we've only mentioned these specific obligations so far as they are what we care about when we do "well-formedness checking" of terms. See: [`PredicateKind`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_type_ir/predicate_kind/enum.PredicateKind.html) and [`ClauseKind`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_type_ir/predicate_kind/enum.ClauseKind.html) for a full list of obligations. -### We Don't Need Normalization (Yet) +### We don't need normalization (yet) [Normalization](../normalization.md) is the process of resolving [type aliases](../normalization.md#aliases) into their underlying type. A type alias is considered well-formed if its where clauses are satisfied. The underlying type undergoes well-formedness checking at most definition and instantiation sites, but there are exceptions. -### Const Generic Arguments +### Const generic arguments Term well-formedness is responsible for getting "type checking" obligations of const generic terms[^tyck-const-generics]. Let's look at the following use of const generics: @@ -102,7 +102,7 @@ const 6: usize The call site will provide us with the obligation `6: usize` during well-formedness checking. This obligation will be passed off to the trait solver just like any trait-style obligation, as the trait solver has more responsibilities than its name suggests. -## Well-Formedness of Items +## Well-formedness of items Items are, generally speaking, "Things that get defined". Item-wfck happens at the signature level for types and functions, methods, and definitions/implementations of traits. @@ -123,7 +123,7 @@ We do not talk about all of these here, but they can be found at the individual -### Global and Trivial Bounds +### Global and trivial bounds @@ -157,29 +157,29 @@ String: Copy // Trivial bound again, but this one is false! Here we have a trivial bound that does not hold, because `String` is not `Copy`. -#### Trivial Bounds Are Not Always Global +#### Trivial bounds are not always global Trivial Bounds are not a subset of Global Bounds. A trivial bound that isn't Global is `for<'a> String: Clone` (trivially true, has a bound variable) or `&'a str: Copy` (trivially false, has a generic parameter). -#### Item-Wfck and Trivial/Global Bounds +#### Item-wfck and trivial/global bounds When checking items are well-formed we will check that there are no trivially false global bounds. -## When We Don't Fully Do Well-Formedness Checking +## When we don't fully do well-formedness checking Well-formedness checking is not a coherent "stage" of type checking. There are many areas where well-formedness checking is performed, and some areas where we skip over well-formedness checking due to limitations in what kinds of analysis we can currently perform. Ideally, we would never skip or defer well-formedness checking. -### We (Sometimes) Need Normalization +### We (sometimes) need normalization There are places where normalization of an Item happens before its Terms have gone through well-formedness checking. This is considered problematic as doing so allows some terms to [bypass term well-formedness checking entirely](https://github.com/rust-lang/rust/issues/100041). -### Trait Objects +### Trait objects We do not require the where clauses of trait objects to be well-formed when determining if that trait object is well-formed. These where clauses are proven when coercing into a trait object, but this remains a hole in well-formedness checking. @@ -234,7 +234,7 @@ const B: usize + bool The above doesn't compile, unlike the previous example we gave. We're doing _some_ well-formedness checking here when it comes to the const generic arguments. -### Binders / Higher-Ranked Types +### Binders / higher-ranked types Binders / Higher-Ranked Types reduce the amount well-formedness checking we do on a term, leaving well-formedness checking to when the bound is instantiated: @@ -260,7 +260,7 @@ for<'a, 'b> fn(&'a &'b ()) The above HRB implies `'b: 'a` (a lifetime bound), rather than two completely separate lifetimes. This is normal lifetime behavior, but during well-formedness checking we cannot prove that this bound is generally true[^horrible], so we skip it. -### Free Type Aliases +### Free type aliases The right-hand side of Free Type Aliases[^fta] is not fully checked to be well-formed at the definition site, only the types of const generic arguments in the RHS are checked. @@ -292,17 +292,17 @@ type Alias = Consty<42>; -## "Well-Formed" or "Wellformed"? +## "well-formed" or "wellformed"? Prefer "well-formed" over "wellformed", as this is consistent with logic literature. This also gets abbreviated to WF in other parts of the dev guide / docs. -## Informal Usage +## Informal usage In conversation, contributors may refer to something as "well-formed" and not necessarily mean what we cover here because "well-formedness" is a general phrase associated with the correctness of formal structures. This isn't necessarily in error, but it should be looked out for. -## What Well-Formedness Isn't +## What well-formedness isn't Well-formedness checking is not "number of parameters" or "parameter type" checking[^kind-checking]. Neither term well-formedness checking nor item-wfck is concerned with if a type with 2 parameters has 1 or 3 types applied to it (assuming no defaults), or if a const generic parameter has a type applied to it. From 2452d9d8f0224787c8408727581c7794906be7f2 Mon Sep 17 00:00:00 2001 From: krishna3554 Date: Sat, 4 Jul 2026 00:11:25 +0530 Subject: [PATCH 31/56] Update date-check markers for July 2026 --- src/doc/rustc-dev-guide/src/contributing.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 4e292c5476d1c..0c1feb3f48b3f 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -444,20 +444,20 @@ Just a few things to keep in mind: For the action to pick the date, add a special annotation before specifying the date: ```md - Nov 2025 + Jul 2026 ``` Example: ```md - As of Nov 2025, the foo did the bar. + As of Jul 2026, the foo did the bar. ``` For cases where the date should not be part of the visible rendered output, use the following instead: ```md - + ``` - A link to a relevant WG, tracking issue, `rustc` rustdoc page, or similar, that may provide From 5ba2f10884f4874043d98d8300fc9bc4eb394aa4 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Jul 2026 11:59:13 +0200 Subject: [PATCH 32/56] less words --- src/doc/rustc-dev-guide/src/contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 4e292c5476d1c..0bfacb017f27c 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -425,7 +425,7 @@ Just a few things to keep in mind: - When contributing text to the guide, please contextualize the information with some time period and/or a reason so that the reader knows how much to trust the information. - Aim to provide a reasonable amount of context, possibly including but not limited to: + Aim to provide a reasonable amount of context, and consider including: - A reason for why the text may be out of date other than "change", as change is a constant across the project. From bae7fbab10e0e7dfba0c9ab8648d395a582fd471 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Jul 2026 12:10:34 +0200 Subject: [PATCH 33/56] new mdbook now gives this for free Should of been in 6f0ae3e918b9d6bb09761e7d9f4119f387f14675 --- src/doc/rustc-dev-guide/src/contributing.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index 0bfacb017f27c..be0b76af34159 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -464,10 +464,6 @@ Just a few things to keep in mind: further explanation for the change process or a way to verify that the information is not outdated. -- If a text grows rather long (more than a few page scrolls) or complicated (more than four - subsections), it might benefit from having a Table of Contents at the beginning, - which you can auto-generate by including the `` marker at the top. - #### ⚠️ Note: Where to contribute `rustc-dev-guide` changes For detailed information about where to contribute rustc-dev-guide changes and the benefits of doing so, From 769c5bd5a6afd6b4317c5762bb5d6f0e2d821e30 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Jul 2026 12:20:16 +0200 Subject: [PATCH 34/56] document accepted practice --- src/doc/rustc-dev-guide/src/contributing.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index be0b76af34159..c0d44518e9013 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -464,6 +464,10 @@ Just a few things to keep in mind: further explanation for the change process or a way to verify that the information is not outdated. +- Use sentence case for chapter and sections titles. + +- Use dashes (`-`) to separate words file names. + #### ⚠️ Note: Where to contribute `rustc-dev-guide` changes For detailed information about where to contribute rustc-dev-guide changes and the benefits of doing so, From dd200bae9258960d720d19316505cae30fefd6d3 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Jul 2026 12:39:56 +0200 Subject: [PATCH 35/56] use local --- src/doc/rustc-dev-guide/src/analysis/well-formed.md | 2 +- src/doc/rustc-dev-guide/src/contributing.md | 2 +- src/doc/rustc-dev-guide/src/offload/installation.md | 2 +- .../rustc-dev-guide/src/traits/separate-projection-bounds.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/analysis/well-formed.md b/src/doc/rustc-dev-guide/src/analysis/well-formed.md index df60aa2ec59b7..4a2450a480ed2 100644 --- a/src/doc/rustc-dev-guide/src/analysis/well-formed.md +++ b/src/doc/rustc-dev-guide/src/analysis/well-formed.md @@ -323,4 +323,4 @@ In Rust, our original usage was closer to "this thing is internally consistent" [^terms-abbreviated]: Abbreviated as "Terms" on this page in some areas. [^kind-checking]: AKA "kind checking", as we might see in languages like Haskell. [^hir-ty-lower]: -[^tyck-const-generics]: +[^tyck-const-generics]: #checking-types-of-const-arguments diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md index c0d44518e9013..546ce55bda2e5 100644 --- a/src/doc/rustc-dev-guide/src/contributing.md +++ b/src/doc/rustc-dev-guide/src/contributing.md @@ -257,7 +257,7 @@ In particular, we don't recommend running the full `./x test` suite locally, since it takes a very long time to execute. See the [Testing with CI] chapter for using Rust's CI to test your changes. -[Testing with CI]: https://rustc-dev-guide.rust-lang.org/tests/ci.html#testing-with-ci +[Testing with CI]: tests/ci.md#testing-with-ci ### r+ diff --git a/src/doc/rustc-dev-guide/src/offload/installation.md b/src/doc/rustc-dev-guide/src/offload/installation.md index 4b67f31cd3c28..ab8e7984d5b4a 100644 --- a/src/doc/rustc-dev-guide/src/offload/installation.md +++ b/src/doc/rustc-dev-guide/src/offload/installation.md @@ -44,7 +44,7 @@ Run this test script for offload-specific tests: ./x test --stage 1 tests/codegen-llvm/gpu_offload ``` -For testing the CI locally, you may use the commands outlined in [Testing with Docker](https://rustc-dev-guide.rust-lang.org/tests/docker.html): +For testing the CI locally, you may use the commands outlined in [Testing with Docker](../tests/docker.md): ```console cargo run --manifest-path src/ci/citool/Cargo.toml run-local dist-x86_64-linux ``` diff --git a/src/doc/rustc-dev-guide/src/traits/separate-projection-bounds.md b/src/doc/rustc-dev-guide/src/traits/separate-projection-bounds.md index 144e27316cbb4..94a0d752c945b 100644 --- a/src/doc/rustc-dev-guide/src/traits/separate-projection-bounds.md +++ b/src/doc/rustc-dev-guide/src/traits/separate-projection-bounds.md @@ -8,7 +8,7 @@ The way we prove `Projection` bounds directly relies on proving the correspondin It feels like it might make more sense to just have a single implementation which checks whether a trait is implemented and returns (a way to compute) its associated types. This is unfortunately quite difficult, as we may use a different candidate for norm than for the corresponding trait bound. -See [alias-bound vs where-bound](https://rustc-dev-guide.rust-lang.org/solve/candidate-preference.html#we-always-consider-aliasbound-candidates) and [global where-bound vs impl](https://rustc-dev-guide.rust-lang.org/solve/candidate-preference.html#we-prefer-global-where-bounds-over-impls). +See [alias-bound vs where-bound](../solve/candidate-preference.md#we-always-consider-aliasbound-candidates) and [global where-bound vs impl](../solve/candidate-preference.md#we-prefer-global-where-bounds-over-impls). There are also some other subtle reasons for why we can't do so. The most stupid is that for rigid aliases; From 4132d73e54b2f6894d2d12f9f4e6752706b5719e Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Jul 2026 12:47:55 +0200 Subject: [PATCH 36/56] sembr src/building/bootstrapping/debugging-bootstrap.md --- .../bootstrapping/debugging-bootstrap.md | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md index 93b11c0690a92..da7c07cb23c52 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md @@ -1,12 +1,15 @@ # Debugging bootstrap -There are two main ways of debugging (and profiling bootstrap). The first is through println logging, and the second is through the `tracing` feature. +There are two main ways of debugging (and profiling bootstrap). +The first is through println logging, and the second is through the `tracing` feature. ## `println` logging -Bootstrap has extensive unstructured logging. Most of it is gated behind the `--verbose` flag (pass `-vv` for even more detail). +Bootstrap has extensive unstructured logging. +Most of it is gated behind the `--verbose` flag (pass `-vv` for even more detail). -If you want to see verbose output of executed Cargo commands and other kinds of detailed logs, pass `-v` or `-vv` when invoking bootstrap. Note that the logs are unstructured and may be overwhelming. +If you want to see verbose output of executed Cargo commands and other kinds of detailed logs, pass `-v` or `-vv` when invoking bootstrap. +Note that the logs are unstructured and may be overwhelming. ``` $ ./x dist rustc --dry-run -vv @@ -27,7 +30,8 @@ Bootstrap has a conditional `tracing` feature, which provides the following feat - It generates a command execution summary, which shows which commands were executed, how many of their executions were cached, and what commands were the slowest to run. - The generated `command-stats.txt` file is in a simple human-readable format. -The structured logs will be written to standard error output (`stderr`), while the other outputs will be stored in files in the `/bootstrap-trace/` directory. For convenience, bootstrap will also create a symlink to the latest generated trace output directory at `/bootstrap-trace/latest`. +The structured logs will be written to standard error output (`stderr`), while the other outputs will be stored in files in the `/bootstrap-trace/` directory. +For convenience, bootstrap will also create a symlink to the latest generated trace output directory at `/bootstrap-trace/latest`. > Note that if you execute bootstrap with `--dry-run`, the tracing output directory might change. Bootstrap will always print a path where the tracing output files were stored at the end of its execution. @@ -73,18 +77,24 @@ Build completed successfully in 0:00:00 #### Controlling tracing output -The environment variable `BOOTSTRAP_TRACING` accepts a [`tracing_subscriber` filter][tracing-env-filter]. If you set `BOOTSTRAP_TRACING=trace`, you will enable all logs, but that can be overwhelming. You can thus use the filter to reduce the amount of data logged. +The environment variable `BOOTSTRAP_TRACING` accepts a [`tracing_subscriber` filter][tracing-env-filter]. +If you set `BOOTSTRAP_TRACING=trace`, you will enable all logs, but that can be overwhelming. +You can thus use the filter to reduce the amount of data logged. There are two orthogonal ways to control which kind of tracing logs you want: 1. You can specify the log **level**, e.g. `debug` or `trace`. - If you select a level, all events/spans with an equal or higher priority level will be shown. 2. You can also control the log **target**, e.g. `bootstrap` or `bootstrap::core::config` or a custom target like `CONFIG_HANDLING` or `STEP`. - - Custom targets are used to limit what kinds of spans you are interested in, as the `BOOTSTRAP_TRACING=trace` output can be quite verbose. Currently, you can use the following custom targets: + - Custom targets are used to limit what kinds of spans you are interested in, as the `BOOTSTRAP_TRACING=trace` output can be quite verbose. + Currently, you can use the following custom targets: - `CONFIG_HANDLING`: show spans related to config handling. - - `STEP`: show all executed steps. Executed commands have `info` event level. - - `COMMAND`: show all executed commands. Executed commands have `trace` event level. - - `IO`: show performed I/O operations. Executed commands have `trace` event level. + - `STEP`: show all executed steps. + Executed commands have `info` event level. + - `COMMAND`: show all executed commands. + Executed commands have `trace` event level. + - `IO`: show performed I/O operations. + Executed commands have `trace` event level. - Note that many I/O are currently not being traced. You can of course combine them (custom target logs are typically gated behind `TRACE` log level additionally): @@ -100,14 +110,15 @@ Note that the level that you specify using `BOOTSTRAP_TRACING` also has an effec ##### FIXME(#96176): specific tracing for `compiler()` vs `compiler_for()` The additional targets `COMPILER` and `COMPILER_FOR` are used to help trace what -`builder.compiler()` and `builder.compiler_for()` does. They should be removed -if [#96176][cleanup-compiler-for] is resolved. +`builder.compiler()` and `builder.compiler_for()` does. +They should be removed if [#96176][cleanup-compiler-for] is resolved. [cleanup-compiler-for]: https://github.com/rust-lang/rust/issues/96176 ### Using `tracing` in bootstrap -Both `tracing::*` macros and the `tracing::instrument` proc-macro attribute need to be gated behind `tracing` feature. Examples: +Both `tracing::*` macros and the `tracing::instrument` proc-macro attribute need to be gated behind `tracing` feature. +Examples: ```rs #[cfg(feature = "tracing")] From d8954e6586b989beaa49a715d0144366e27b2139 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Jul 2026 12:49:45 +0200 Subject: [PATCH 37/56] sembr src/building/bootstrapping/intro.md --- .../src/building/bootstrapping/intro.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md index 7f53097824cc9..307455595d4ba 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md @@ -1,14 +1,13 @@ # Bootstrapping the compiler [*Bootstrapping*][boot] is the process of using a compiler to compile itself. -More accurately, it means using an older compiler to compile a newer version -of the same compiler. +More accurately, it means using an older compiler to compile a newer version of the same compiler. This raises a chicken-and-egg paradox: where did the first compiler come from? -It must have been written in a different language. In Rust's case it was -[written in OCaml][ocaml-compiler]. However, it was abandoned long ago, and the -only way to build a modern version of rustc is with a slightly less modern -version. +It must have been written in a different language. +In Rust's case it was [written in OCaml][ocaml-compiler]. +However, it was abandoned long ago, and the +only way to build a modern version of rustc is with a slightly less modern version. This is exactly how `x.py` works: it downloads the current beta release of rustc, then uses it to compile the new compiler. @@ -17,8 +16,7 @@ In this section, we give a high-level overview of [what Bootstrap does](./what-bootstrapping-does.md), followed by a high-level introduction to [how Bootstrap does it](./how-bootstrap-does-it.md). -Additionally, see [debugging bootstrap](./debugging-bootstrap.md) to learn -about debugging methods. +Additionally, see [debugging bootstrap](./debugging-bootstrap.md) to learn about debugging methods. [boot]: https://en.wikipedia.org/wiki/Bootstrapping_(compilers) [ocaml-compiler]: https://github.com/rust-lang/rust/tree/ef75860a0a72f79f97216f8aaa5b388d98da6480/src/boot From 3b40dd01db62d03ea5420b8036c3714635b33ad6 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Jul 2026 12:52:42 +0200 Subject: [PATCH 38/56] indirection --- .../rustc-dev-guide/src/building/bootstrapping/intro.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md index 307455595d4ba..e4704a10e0a78 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/intro.md @@ -1,11 +1,11 @@ # Bootstrapping the compiler -[*Bootstrapping*][boot] is the process of using a compiler to compile itself. +[*Bootstrapping*] is the process of using a compiler to compile itself. More accurately, it means using an older compiler to compile a newer version of the same compiler. This raises a chicken-and-egg paradox: where did the first compiler come from? It must have been written in a different language. -In Rust's case it was [written in OCaml][ocaml-compiler]. +In Rust's case it was [written in OCaml]. However, it was abandoned long ago, and the only way to build a modern version of rustc is with a slightly less modern version. @@ -18,5 +18,5 @@ introduction to [how Bootstrap does it](./how-bootstrap-does-it.md). Additionally, see [debugging bootstrap](./debugging-bootstrap.md) to learn about debugging methods. -[boot]: https://en.wikipedia.org/wiki/Bootstrapping_(compilers) -[ocaml-compiler]: https://github.com/rust-lang/rust/tree/ef75860a0a72f79f97216f8aaa5b388d98da6480/src/boot +[*Bootstrapping*]: https://en.wikipedia.org/wiki/Bootstrapping_(compilers) +[written in OCaml]: https://github.com/rust-lang/rust/tree/ef75860a0a72f79f97216f8aaa5b388d98da6480/src/boot From 02b4d2bbec5d1434abcaf242764048527b5e786b Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Jul 2026 12:53:16 +0200 Subject: [PATCH 39/56] sembr src/building/bootstrapping/how-bootstrap-does-it.md --- .../bootstrapping/how-bootstrap-does-it.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/how-bootstrap-does-it.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/how-bootstrap-does-it.md index 4d301b3abae1a..63c154d25d22f 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/how-bootstrap-does-it.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/how-bootstrap-does-it.md @@ -1,14 +1,16 @@ # How Bootstrap does it The core concept in Bootstrap is a build [`Step`], which are chained together -by [`Builder::ensure`]. [`Builder::ensure`] takes a [`Step`] as input, and runs -the [`Step`] if and only if it has not already been run. Let's take a closer -look at [`Step`]. +by [`Builder::ensure`]. +[`Builder::ensure`] takes a [`Step`] as input, and runs +the [`Step`] if and only if it has not already been run. +Let's take a closer look at [`Step`]. ## Synopsis of [`Step`] A [`Step`] represents a granular collection of actions involved in the process -of producing some artifact. It can be thought of like a rule in Makefiles. +of producing some artifact. +It can be thought of like a rule in Makefiles. The [`Step`] trait is defined as: ```rs,no_run @@ -30,8 +32,8 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { - `run` is the function that is responsible for doing the work. [`Builder::ensure`] invokes `run`. - `should_run` is the command-line interface, which determines if an invocation - such as `x build foo` should run a given [`Step`]. In a "default" context - where no paths are provided, then `make_run` is called directly. + such as `x build foo` should run a given [`Step`]. + In a "default" context where no paths are provided, then `make_run` is called directly. - `make_run` is invoked only for things directly asked via the CLI and not for steps which are dependencies of other steps. From 3ca83eba7aa278fb504629e02fbea02f3c17dcc7 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Jul 2026 12:54:06 +0200 Subject: [PATCH 40/56] sembr src/building/bootstrapping/bootstrap-in-dependencies.md --- .../src/building/bootstrapping/bootstrap-in-dependencies.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md index 68c5c2386bd5e..03772f4a580df 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md @@ -1,6 +1,7 @@ # `cfg(bootstrap)` in compiler dependencies -The rust compiler uses some external crates that can run into cyclic dependencies with the compiler itself: the compiler needs an updated crate to build, but the crate needs an updated compiler. This page describes how `#[cfg(bootstrap)]` can be used to break this cycle. +The rust compiler uses some external crates that can run into cyclic dependencies with the compiler itself: the compiler needs an updated crate to build, but the crate needs an updated compiler. +This page describes how `#[cfg(bootstrap)]` can be used to break this cycle. ## Enabling `#[cfg(bootstrap)]` @@ -50,4 +51,5 @@ For `compiler-builtins` this meant a version bump, in other cases it may be a gi ### Step 4: remove the old behavior from the compiler ([#139753](https://github.com/rust-lang/rust/pull/139753)) -The updated crate can now be used. In this example that meant that the old behavior could be removed. +The updated crate can now be used. +In this example that meant that the old behavior could be removed. From ecb36ae3834cf06e6f0ebd501a5875885e472789 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Jul 2026 12:54:59 +0200 Subject: [PATCH 41/56] capitalise --- .../src/building/bootstrapping/bootstrap-in-dependencies.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md index 03772f4a580df..35a0d5d9302bc 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md @@ -1,6 +1,6 @@ # `cfg(bootstrap)` in compiler dependencies -The rust compiler uses some external crates that can run into cyclic dependencies with the compiler itself: the compiler needs an updated crate to build, but the crate needs an updated compiler. +The Rust compiler uses some external crates that can run into cyclic dependencies with the compiler itself: the compiler needs an updated crate to build, but the crate needs an updated compiler. This page describes how `#[cfg(bootstrap)]` can be used to break this cycle. ## Enabling `#[cfg(bootstrap)]` From 41462bbdd202e04019131f47c7b3409b68f1b6b6 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Jul 2026 12:55:16 +0200 Subject: [PATCH 42/56] overlong --- .../src/building/bootstrapping/bootstrap-in-dependencies.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md index 35a0d5d9302bc..2780fc36709e6 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md @@ -1,6 +1,7 @@ # `cfg(bootstrap)` in compiler dependencies -The Rust compiler uses some external crates that can run into cyclic dependencies with the compiler itself: the compiler needs an updated crate to build, but the crate needs an updated compiler. +The Rust compiler uses some external crates that can run into cyclic dependencies with the compiler itself: +the compiler needs an updated crate to build, but the crate needs an updated compiler. This page describes how `#[cfg(bootstrap)]` can be used to break this cycle. ## Enabling `#[cfg(bootstrap)]` From b593a46b0eaa48c30a642adf9a69101a83476f03 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Sat, 4 Jul 2026 12:55:46 +0200 Subject: [PATCH 43/56] missing pause --- .../src/building/bootstrapping/bootstrap-in-dependencies.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md index 2780fc36709e6..33697e1690f21 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md @@ -40,7 +40,7 @@ As a concrete example we'll use a change where the `#[naked]` attribute was made ### Step 1: accept the new behavior in the compiler ([#139797](https://github.com/rust-lang/rust/pull/139797)) -In this example it is possible to accept both the old and new behavior at the same time by disabling an error. +In this example, it is possible to accept both the old and new behavior at the same time by disabling an error. ### Step 2: update the crate ([#821](https://github.com/rust-lang/compiler-builtins/pull/821)) From 99b3d11ca82ee34592df68d8a0ec6575db800418 Mon Sep 17 00:00:00 2001 From: ArshLabs Date: Sat, 4 Jul 2026 17:02:49 +0530 Subject: [PATCH 44/56] library: expand HashSet extract_if coverage --- library/std/src/collections/hash/set/tests.rs | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs index d7bbc7bdc6a5b..5dfc02935c112 100644 --- a/library/std/src/collections/hash/set/tests.rs +++ b/library/std/src/collections/hash/set/tests.rs @@ -418,14 +418,32 @@ fn test_retain() { } #[test] -fn test_extract_if() { - let mut x: HashSet<_> = [1].iter().copied().collect(); - let mut y: HashSet<_> = [1].iter().copied().collect(); - - x.extract_if(|_| true).for_each(drop); - y.extract_if(|_| false).for_each(drop); - assert_eq!(x.len(), 0); - assert_eq!(y.len(), 1); +fn test_extract_if_empty() { + let mut set: HashSet = HashSet::new(); + let extracted: Vec<_> = + set.extract_if(|_| unreachable!("there's nothing to decide on")).collect(); + + assert!(extracted.is_empty()); + assert!(set.is_empty()); +} + +#[test] +fn test_extract_if_consuming_nothing() { + let mut set: HashSet<_> = (0..3).collect(); + let extracted: Vec<_> = set.extract_if(|_| false).collect(); + + assert!(extracted.is_empty()); + assert_eq!(set, HashSet::from([0, 1, 2])); +} + +#[test] +fn test_extract_if_consuming_all() { + let mut set: HashSet<_> = (0..3).collect(); + let mut extracted: Vec<_> = set.extract_if(|_| true).collect(); + extracted.sort_unstable(); + + assert_eq!(extracted, vec![0, 1, 2]); + assert!(set.is_empty()); } #[test] From d0c3225dc776dc3d94da0942ccf94d30742a87de Mon Sep 17 00:00:00 2001 From: Valentyn Kit Date: Sat, 4 Jul 2026 16:15:08 +0300 Subject: [PATCH 45/56] bootstrap: only encode RUSTFLAGS when a flag contains a space Bootstrap now passes rustc and rustdoc flags via CARGO_ENCODED_RUSTFLAGS and CARGO_ENCODED_RUSTDOCFLAGS, whose values use \x1f to separate flags. That control character renders as \u{1f} when a failing command is debug-printed, so the printed command can't be copy-pasted. Prefer the plain, space-separated RUSTFLAGS/RUSTDOCFLAGS form, which is equivalent whenever no flag value contains a space, and only fall back to the encoded form when a flag value does contain a space. --- src/bootstrap/src/core/builder/cargo.rs | 44 +++++++++++++++++++------ src/bootstrap/src/core/builder/tests.rs | 23 +++++++++++++ 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 72094373b5719..87fe911715fce 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -78,6 +78,26 @@ impl Rustflags { } } +/// Picks the environment variable and value to pass a set of [`Rustflags`] to cargo. +/// +/// `flags` is the `\x1f`-separated string built by [`Rustflags`]. We prefer the plain, +/// space-separated form (`RUSTFLAGS`/`RUSTDOCFLAGS`) so the command stays readable and +/// copy-pasteable in bootstrap's debug output, and only fall back to the `CARGO_ENCODED_*` form +/// (which keeps the `\x1f` separators) when a flag value contains a space that the plain, +/// whitespace-split form can't represent. See . +pub(super) fn flags_env( + plain: &'static str, + encoded: &'static str, + flags: &str, +) -> (&'static str, String) { + // A space can only appear inside a flag value, since the separators are `\x1f`. + if flags.contains(' ') { + (encoded, flags.to_string()) + } else { + (plain, flags.replace('\x1f', " ")) + } +} + /// Flags that are passed to the `rustc` shim binary. These flags will only be applied when /// compiling host code, i.e. when `--target` is unset. #[derive(Debug, Default)] @@ -465,21 +485,25 @@ impl From for BootstrapCommand { cargo.command.args(cargo.args); - // Always unset the plain RUSTFLAGS/RUSTDOCFLAGS so that downstream - // tools (e.g. build.rs scripts) see only the encoded form. Any flags - // from the caller's environment have already been folded into the - // Rustflags struct via `propagate_cargo_env`. + // Unset any inherited flag variables (plain and encoded) so cargo uses only the flags + // bootstrap sets below. Flags from the caller's environment have already been folded into + // the Rustflags struct via `propagate_cargo_env`. This also matters because we may set the + // plain form below, which cargo ignores when `CARGO_ENCODED_RUSTFLAGS` is also present. cargo.command.env_remove("RUSTFLAGS"); + cargo.command.env_remove("CARGO_ENCODED_RUSTFLAGS"); cargo.command.env_remove("RUSTDOCFLAGS"); + cargo.command.env_remove("CARGO_ENCODED_RUSTDOCFLAGS"); - let rustflags = &cargo.rustflags.0; - if !rustflags.is_empty() { - cargo.command.env("CARGO_ENCODED_RUSTFLAGS", rustflags); + if !cargo.rustflags.0.is_empty() { + let (var, value) = + flags_env("RUSTFLAGS", "CARGO_ENCODED_RUSTFLAGS", &cargo.rustflags.0); + cargo.command.env(var, value); } - let rustdocflags = &cargo.rustdocflags.0; - if !rustdocflags.is_empty() { - cargo.command.env("CARGO_ENCODED_RUSTDOCFLAGS", rustdocflags); + if !cargo.rustdocflags.0.is_empty() { + let (var, value) = + flags_env("RUSTDOCFLAGS", "CARGO_ENCODED_RUSTDOCFLAGS", &cargo.rustdocflags.0); + cargo.command.env(var, value); } let encoded_hostflags = cargo.hostflags.encode(); diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 176a61b15c988..62ba7d79b13df 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -3349,3 +3349,26 @@ fn render_compiler(compiler: Compiler, config: &RenderConfig) -> String { fn host_target() -> String { get_host_target().to_string() } + +#[test] +fn flags_env_prefers_plain_form_without_spaces() { + use super::cargo::flags_env; + + // No flag value contains a space, so use the readable, copy-pasteable plain form + // rather than the `\x1f`-separated encoded form (rust-lang/rust#158749). + assert_eq!( + flags_env("RUSTFLAGS", "CARGO_ENCODED_RUSTFLAGS", "--cfg=foo\u{1f}-Cdebuginfo=0"), + ("RUSTFLAGS", "--cfg=foo -Cdebuginfo=0".to_string()), + ); + + // A flag value contains a space (e.g. an `-L` path), which the whitespace-split plain + // form can't represent, so keep the encoded form. + assert_eq!( + flags_env( + "RUSTFLAGS", + "CARGO_ENCODED_RUSTFLAGS", + "-Clink-arg=-L/opt/my libs\u{1f}--cfg=foo" + ), + ("CARGO_ENCODED_RUSTFLAGS", "-Clink-arg=-L/opt/my libs\u{1f}--cfg=foo".to_string()), + ); +} From 835045eeeb56422c0e9258f80944a335bb773e4e Mon Sep 17 00:00:00 2001 From: xonx <119700621+xonx4l@users.noreply.github.com> Date: Sat, 4 Jul 2026 18:17:23 +0000 Subject: [PATCH 46/56] hook intrinsic-test into aarch64-gnu --- src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile index 87bfc0766fbd9..220dbaeebd430 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile @@ -26,4 +26,5 @@ ENV RUST_CONFIGURE_ARGS="--build=aarch64-unknown-linux-gnu \ --enable-profiler \ --enable-compiler-docs" ENV SCRIPT="python3 ../x.py --stage 2 test && \ - python3 ../x.py --stage 2 test src/tools/cargo" + python3 ../x.py --stage 2 test src/tools/cargo && \ + python3 ../x.py --stage 2 test library/stdarch/crates/intrinsic-test" From 6ef22dec2caf9f726b728c81a49e161d1d8f9560 Mon Sep 17 00:00:00 2001 From: Amirhossein Akhlaghpour Date: Sat, 4 Jul 2026 18:44:47 +0330 Subject: [PATCH 47/56] fix: emit diagnostic for AVR target without target-cpu Signed-off-by: Amirhossein Akhlaghpour --- .../rustc_codegen_ssa/src/back/metadata.rs | 3 +- .../avr-custom-missing-cpu.json | 33 +++++++++++++++++++ .../avr-custom-target-missing-cpu/foo.rs | 13 ++++++++ .../avr-custom-target-missing-cpu/rmake.rs | 16 +++++++++ 4 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 tests/run-make/avr-custom-target-missing-cpu/avr-custom-missing-cpu.json create mode 100644 tests/run-make/avr-custom-target-missing-cpu/foo.rs create mode 100644 tests/run-make/avr-custom-target-missing-cpu/rmake.rs diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 55a85547ef99f..6f526879f7766 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -24,6 +24,7 @@ use rustc_target::spec::{CfgAbi, LlvmAbi, Os, RelocModel, Target, ef_avr_arch}; use tracing::debug; use super::apple; +use crate::errors; /// The default metadata loader. This is used by cg_llvm and cg_clif. /// @@ -370,7 +371,7 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { if let Some(ref cpu) = sess.opts.cg.target_cpu { ef_avr_arch(cpu) } else { - bug!("AVR CPU not explicitly specified") + sess.dcx().emit_fatal(errors::CpuRequired) } } Architecture::Csky => { diff --git a/tests/run-make/avr-custom-target-missing-cpu/avr-custom-missing-cpu.json b/tests/run-make/avr-custom-target-missing-cpu/avr-custom-missing-cpu.json new file mode 100644 index 0000000000000..b93fdc186ef3e --- /dev/null +++ b/tests/run-make/avr-custom-target-missing-cpu/avr-custom-missing-cpu.json @@ -0,0 +1,33 @@ +{ + "arch": "avr", + "atomic-cas": false, + "crt-objects-fallback": "false", + "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8:16-a:8", + "eh-frame-header": false, + "exe-suffix": ".elf", + "late-link-args": { + "gnu-cc": [ + "-lgcc" + ], + "gnu-lld-cc": [ + "-lgcc" + ] + }, + "linker": "avr-gcc", + "linker-flavor": "gnu-cc", + "llvm-target": "avr-unknown-unknown", + "max-atomic-width": 16, + "metadata": { + "description": null, + "host_tools": false, + "std": false, + "tier": 3 + }, + "pre-link-args": { + "gnu-cc": [], + "gnu-lld-cc": [] + }, + "relocation-model": "static", + "target-c-int-width": 16, + "target-pointer-width": 16 +} diff --git a/tests/run-make/avr-custom-target-missing-cpu/foo.rs b/tests/run-make/avr-custom-target-missing-cpu/foo.rs new file mode 100644 index 0000000000000..399af7798dccb --- /dev/null +++ b/tests/run-make/avr-custom-target-missing-cpu/foo.rs @@ -0,0 +1,13 @@ +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "pointee_sized"] +pub trait PointeeSized {} + +#[lang = "meta_sized"] +pub trait MetaSized: PointeeSized {} + +#[lang = "sized"] +trait Sized {} + +pub fn foo() {} diff --git a/tests/run-make/avr-custom-target-missing-cpu/rmake.rs b/tests/run-make/avr-custom-target-missing-cpu/rmake.rs new file mode 100644 index 0000000000000..d076eb3d378b2 --- /dev/null +++ b/tests/run-make/avr-custom-target-missing-cpu/rmake.rs @@ -0,0 +1,16 @@ +// Custom AVR targets can reach ELF e_flags emission without an explicit CPU +// Make sure that reports the normal missing-CPU diagnostic instead of ICEing +// +//@ needs-llvm-components: avr + +use run_make_support::rustc; + +fn main() { + rustc() + .arg("-Zunstable-options") + .input("foo.rs") + .target("avr-custom-missing-cpu.json") + .crate_type("lib") + .run_fail() + .assert_stderr_contains("target requires explicitly specifying a cpu with `-C target-cpu`"); +} From c2cf85ba50d688310d4b3abcdb38b2cdfd558cda Mon Sep 17 00:00:00 2001 From: Yilin Chen <1479826151@qq.com> Date: Sun, 5 Jul 2026 19:43:37 +0800 Subject: [PATCH 48/56] Add supplementary information for get_unchecked(mut) --- library/core/src/ptr/const_ptr.rs | 3 ++- library/core/src/ptr/non_null.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index db9e60d379f84..56f6a561f4bb9 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1497,9 +1497,10 @@ impl *const [T] { /// Returns a raw pointer to an element or subslice, without doing bounds /// checking. /// - /// Calling this method with an out-of-bounds index or when `self` is not dereferenceable + /// Calling this method with an [out-of-bounds index] or when `self` is not dereferenceable /// is *[undefined behavior]* even if the resulting pointer is not used. /// + /// [out-of-bounds index]: #method.add /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// /// # Examples diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index bafc37469b32f..6ec34206a4248 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1573,9 +1573,10 @@ impl NonNull<[T]> { /// Returns a raw pointer to an element or subslice, without doing bounds /// checking. /// - /// Calling this method with an out-of-bounds index or when `self` is not dereferenceable + /// Calling this method with an [out-of-bounds index] or when `self` is not dereferenceable /// is *[undefined behavior]* even if the resulting pointer is not used. /// + /// [out-of-bounds index]: #method.add /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// /// # Examples From 6810f13f1d5de7d00e380b74c303a72b5bec5dbe Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 24 Jun 2026 21:29:11 +0200 Subject: [PATCH 49/56] add `-Zforce-intrinsic-fallback` flag --- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 11 ++++++ compiler/rustc_monomorphize/src/collector.rs | 11 +++++- compiler/rustc_session/src/options.rs | 3 ++ .../force-intrinsic-fallback.md | 6 +++ .../codegen-llvm/force-intrinsic-fallback.rs | 38 +++++++++++++++++++ 5 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/force-intrinsic-fallback.md create mode 100644 tests/codegen-llvm/force-intrinsic-fallback.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 99546bea65959..413cb5f2c860a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -63,6 +63,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { result_place: Option>, source_info: SourceInfo, ) -> IntrinsicResult<'tcx, Bx::Value> { + // When `-Zforce-intrinsic-fallback` is enabled, always use the fallback body if it exists, + if bx.tcx().sess.opts.unstable_opts.force_intrinsic_fallback + && let Some(def) = bx.tcx().intrinsic(instance.def_id()) + && !def.must_be_overridden + { + return IntrinsicResult::Fallback(ty::Instance::new_raw( + instance.def_id(), + instance.args, + )); + } + let span = source_info.span; let name = bx.tcx().item_name(instance.def_id()); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index ceb044c102f69..bd608583d818c 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -995,11 +995,18 @@ fn visit_instance_use<'tcx>( output.push(create_fn_mono_item(tcx, panic_instance, source)); } } else if !intrinsic.must_be_overridden - && !tcx.sess.replaced_intrinsics.contains(&intrinsic.name) + && (tcx.sess.opts.unstable_opts.force_intrinsic_fallback + || !tcx.sess.replaced_intrinsics.contains(&intrinsic.name)) { // Codegen the fallback body of intrinsics with fallback bodies. // We have to skip this otherwise as there's no body to codegen. - // We also skip intrinsics the backend handles, to reduce monomorphizations. + // + // We also skip `replaced_intrinsics` which are always replaced by the backend and hence + // monomorphizing the fallback body would be pointless. + // + // However, when -Zforce-intrinsic-fallback is set (e.g. to test the fallback + // implementations) we ignore the optimization hint and do monomorphize + // the fallback body. let instance = ty::Instance::new_raw(instance.def_id(), instance.args); if tcx.should_codegen_locally(instance) { output.push(create_fn_mono_item(tcx, instance, source)); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 4e5b38d34b824..493cf801a2be1 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2417,6 +2417,9 @@ options! { fmt_debug: FmtDebug = (FmtDebug::Full, parse_fmt_debug, [TRACKED], "how detailed `#[derive(Debug)]` should be. `full` prints types recursively, \ `shallow` prints only type names, `none` prints nothing and disables `{:?}`. (default: `full`)"), + force_intrinsic_fallback: bool = (false, parse_bool, [TRACKED], + "always use the fallback body of an intrinsic, if it has one, instead of lowering \ + the intrinsic in the codegen backend (default: no)."), force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED], "force all crates to be `rustc_private` unstable (default: no)"), function_return: FunctionReturn = (FunctionReturn::default(), parse_function_return, [TRACKED], diff --git a/src/doc/unstable-book/src/compiler-flags/force-intrinsic-fallback.md b/src/doc/unstable-book/src/compiler-flags/force-intrinsic-fallback.md new file mode 100644 index 0000000000000..41f6ae3237908 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/force-intrinsic-fallback.md @@ -0,0 +1,6 @@ +## `force-intrinsic-fallback` + +Configures codegen to always use the fallback body of an intrinsic, if it has one, +instead of lowering the intrinsic in the codegen backend. + +This is useful for testing the fallback implementation. diff --git a/tests/codegen-llvm/force-intrinsic-fallback.rs b/tests/codegen-llvm/force-intrinsic-fallback.rs new file mode 100644 index 0000000000000..1fb80b4e83f12 --- /dev/null +++ b/tests/codegen-llvm/force-intrinsic-fallback.rs @@ -0,0 +1,38 @@ +//@ compile-flags: --crate-type=lib -C no-prepopulate-passes -Copt-level=3 +// +//@ revisions: NORMAL FALLBACK +//@ [FALLBACK] compile-flags: -Zforce-intrinsic-fallback +#![feature(core_intrinsics, funnel_shifts)] + +// Check the effect of `-Zforce-intrinsic-fallback`. +// +// Without the flag, the dedicated backend lowering of the intrinsic is used. +// With the flag, the fallback body is called instead. + +#[no_mangle] +pub fn call_minimumf32(x: f32, y: f32) -> f32 { + // CHECK-LABEL: @call_minimumf32 + + // NORMAL: call float @llvm.minimum.f32 + // NORMAL-NOT: minimumf32 + + // FALLBACK-NOT: @llvm.minimum + // FALLBACK: call {{.*}}minimumf32 + core::intrinsics::minimumf32(x, y) +} + +// Codegen backends can return a list of `replaced_intrinsics`, for which codegen of the fallback is +// normally skipped. `unchecked_funnel_shl` is in that list for the LLVM backend, so we test it here +// to ensure that with the flag enabled the fallback body is actually code generated and called. + +#[no_mangle] +pub fn call_funnel_shl(a: u32, b: u32, shift: u32) -> u32 { + // CHECK-LABEL: @call_funnel_shl + + // NORMAL: call i32 @llvm.fshl.i32 + // NORMAL-NOT: funnel_shl + + // FALLBACK-NOT: @llvm.fshl + // FALLBACK: call {{.*}}funnel_shl + unsafe { core::intrinsics::unchecked_funnel_shl(a, b, shift) } +} From 54cfcdf60aa1a18fcc042234104bf240c558ed8c Mon Sep 17 00:00:00 2001 From: Frank Steffahn Date: Sun, 5 Jul 2026 17:19:22 +0200 Subject: [PATCH 50/56] Check NotInModule early since it can be a lot faster --- compiler/rustc_middle/src/ty/inhabitedness/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 57e48d3993019..55b359866bb97 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -93,7 +93,7 @@ impl<'tcx> VariantDef { match field.vis { Visibility::Public => pred, Visibility::Restricted(from) => { - pred.or(tcx, InhabitedPredicate::NotInModule(from)) + InhabitedPredicate::NotInModule(from).or(tcx, pred) } } }), From ee05842b01af65dc333a073b093b24e69439e6df Mon Sep 17 00:00:00 2001 From: Samy Date: Sun, 5 Jul 2026 19:07:05 +0200 Subject: [PATCH 51/56] Add regression test for builtin attr macro values --- .../builtin-attr-macro-value-issue-145922.rs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/ui/attributes/builtin-attr-macro-value-issue-145922.rs diff --git a/tests/ui/attributes/builtin-attr-macro-value-issue-145922.rs b/tests/ui/attributes/builtin-attr-macro-value-issue-145922.rs new file mode 100644 index 0000000000000..a7314188cba3d --- /dev/null +++ b/tests/ui/attributes/builtin-attr-macro-value-issue-145922.rs @@ -0,0 +1,34 @@ +//@ check-pass +#![allow(unused_attributes, unused_macros)] + +// Regression test for #145922. +// This used to create a delayed ICE while parsing builtin attributes. +#[crate_type = concat!("my", "crate")] +macro_rules! foo { + () => { + 32 + }; +} + +#[recursion_limit = concat!("1", "2")] +macro_rules! baz { + () => { + 32 + }; +} + +#[type_length_limit = concat!("1", "2")] +macro_rules! qux { + () => { + 32 + }; +} + +#[windows_subsystem = concat!("cons", "ole")] +macro_rules! bar { + () => { + 32 + }; +} + +fn main() {} From 43b05c8d1769cd2ba09fefa66a18b16801193a7f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 8 May 2026 16:41:00 +0200 Subject: [PATCH 52/56] Fix typo --- src/bootstrap/src/core/build_steps/compile.rs | 2 +- src/bootstrap/src/core/build_steps/llvm.rs | 4 ++-- src/bootstrap/src/core/build_steps/test.rs | 4 ++-- src/bootstrap/src/lib.rs | 2 +- src/bootstrap/src/utils/cc_detect.rs | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index ffbe4f4e74dbd..3216fd671c3f8 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1917,7 +1917,7 @@ pub fn compiler_file( return PathBuf::new(); } let mut cmd = command(compiler); - cmd.args(builder.cc_handled_clags(target, c)); + cmd.args(builder.cc_handled_cflags(target, c)); cmd.args(builder.cc_unhandled_cflags(target, GitRepo::Rustc, c)); cmd.arg(format!("-print-file-name={file}")); let out = cmd.run_capture_stdout(builder).stdout(); diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 087a395a067f0..6f1b8532f031b 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -800,7 +800,7 @@ fn configure_cmake( // Needs `suppressed_compiler_flag_prefixes` to be gone, and hence // https://github.com/llvm/llvm-project/issues/88780 to be fixed. for flag in builder - .cc_handled_clags(target, CLang::C) + .cc_handled_cflags(target, CLang::C) .into_iter() .chain(builder.cc_unhandled_cflags(target, GitRepo::Llvm, CLang::C)) .filter(|flag| !suppressed_compiler_flag_prefixes.iter().any(|p| flag.starts_with(p))) @@ -821,7 +821,7 @@ fn configure_cmake( cfg.define("CMAKE_C_FLAGS", cflags); let mut cxxflags = ccflags.cxxflags.clone(); for flag in builder - .cc_handled_clags(target, CLang::Cxx) + .cc_handled_cflags(target, CLang::Cxx) .into_iter() .chain(builder.cc_unhandled_cflags(target, GitRepo::Llvm, CLang::Cxx)) .filter(|flag| { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index a2d05f8347cbe..697f659816120 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2682,9 +2682,9 @@ Please disable assertions with `rust.debug-assertions = false`. // Only pass correct values for these flags for the `run-make` suite as it // requires that a C++ compiler was configured which isn't always the case. if !builder.config.dry_run() && mode == CompiletestMode::RunMake { - let mut cflags = builder.cc_handled_clags(target, CLang::C); + let mut cflags = builder.cc_handled_cflags(target, CLang::C); cflags.extend(builder.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::C)); - let mut cxxflags = builder.cc_handled_clags(target, CLang::Cxx); + let mut cxxflags = builder.cc_handled_cflags(target, CLang::Cxx); cxxflags.extend(builder.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::Cxx)); cmd.arg("--cc") .arg(builder.cc(target)) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 2231e0886bbcd..2c8e002123abf 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1280,7 +1280,7 @@ impl Build { /// Returns C flags that `cc-rs` thinks should be enabled for the /// specified target by default. - fn cc_handled_clags(&self, target: TargetSelection, c: CLang) -> Vec { + fn cc_handled_cflags(&self, target: TargetSelection, c: CLang) -> Vec { if self.config.dry_run() { return Vec::new(); } diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 320dfcc4e69ed..1ab2b92070c93 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -119,7 +119,7 @@ pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) { .or_else(|| cfg.try_get_archiver().map(|c| PathBuf::from(c.get_program())).ok()); build.cc.insert(target, compiler.clone()); - let mut cflags = build.cc_handled_clags(target, CLang::C); + let mut cflags = build.cc_handled_cflags(target, CLang::C); cflags.extend(build.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::C)); // If we use llvm-libunwind, we will need a C++ compiler as well for all targets @@ -146,7 +146,7 @@ pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) { build.do_if_verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target))); build.do_if_verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple)); if let Ok(cxx) = build.cxx(target) { - let mut cxxflags = build.cc_handled_clags(target, CLang::Cxx); + let mut cxxflags = build.cc_handled_cflags(target, CLang::Cxx); cxxflags.extend(build.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::Cxx)); build.do_if_verbose(|| println!("CXX_{} = {cxx:?}", target.triple)); build.do_if_verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple)); From 26e35d93dcc8e7b3285c51ee316d6914f304be15 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 4 Jul 2026 11:18:38 -0400 Subject: [PATCH 53/56] Add and use cfg(target_has_threads) to enforce no_thread impl usage The standard library has fallback code for targets without threads (e.g., using a Cell-based Mutex and similar). Today there's no enforcement in std that those targets truly don't have threads which makes that code potentially unsound. This will let us add a static assertion that the target spec agrees that the target is non-threaded. --- compiler/rustc_codegen_llvm/src/back/write.rs | 12 +--- compiler/rustc_feature/src/builtin_attrs.rs | 1 + compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_session/src/config/cfg.rs | 6 ++ compiler/rustc_span/src/symbol.rs | 2 + compiler/rustc_target/src/spec/mod.rs | 23 +++++- library/std/src/lib.rs | 1 + .../std/src/sys/sync/condvar/no_threads.rs | 3 + library/std/src/sys/sync/mutex/no_threads.rs | 3 + library/std/src/sys/sync/once/no_threads.rs | 3 + library/std/src/sys/sync/rwlock/no_threads.rs | 3 + .../std/src/sys/thread_local/no_threads.rs | 3 + tests/rustdoc-ui/doc-cfg-2.stderr | 2 +- tests/ui/cfg/disallowed-cli-cfgs.rs | 2 + ...llowed-cli-cfgs.target_has_threads_.stderr | 8 +++ tests/ui/check-cfg/cargo-build-script.stderr | 2 +- tests/ui/check-cfg/cargo-feature.none.stderr | 2 +- tests/ui/check-cfg/cargo-feature.some.stderr | 2 +- tests/ui/check-cfg/cfg-select.stderr | 2 +- .../cfg-value-for-cfg-name-duplicate.stderr | 2 +- .../cfg-value-for-cfg-name-multiple.stderr | 2 +- .../exhaustive-names-values.feature.stderr | 2 +- .../exhaustive-names-values.full.stderr | 2 +- tests/ui/check-cfg/hrtb-crash.stderr | 2 +- tests/ui/check-cfg/mix.stderr | 2 +- tests/ui/check-cfg/nested-cfg.stderr | 2 +- .../check-cfg/raw-keywords.edition2015.stderr | 2 +- .../check-cfg/raw-keywords.edition2021.stderr | 2 +- .../report-in-external-macros.cargo.stderr | 2 +- .../report-in-external-macros.rustc.stderr | 2 +- tests/ui/check-cfg/well-known-names.stderr | 1 + tests/ui/check-cfg/well-known-values.rs | 3 + tests/ui/check-cfg/well-known-values.stderr | 71 +++++++++++-------- .../feature-gate-cfg-target-has-threads.rs | 5 ++ ...feature-gate-cfg-target-has-threads.stderr | 12 ++++ tests/ui/macros/cfg.stderr | 2 +- tests/ui/macros/cfg_select.stderr | 2 +- 37 files changed, 142 insertions(+), 58 deletions(-) create mode 100644 tests/ui/cfg/disallowed-cli-cfgs.target_has_threads_.stderr create mode 100644 tests/ui/feature-gates/feature-gate-cfg-target-has-threads.rs create mode 100644 tests/ui/feature-gates/feature-gate-cfg-target-has-threads.stderr diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 4426f6ebb3c17..2b0ea569b5a71 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -22,7 +22,7 @@ use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath}; -use rustc_span::{BytePos, InnerSpan, Pos, RemapPathScopeComponents, SpanData, SyntaxContext, sym}; +use rustc_span::{BytePos, InnerSpan, Pos, RemapPathScopeComponents, SpanData, SyntaxContext}; use rustc_target::spec::{CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel}; use tracing::{debug, trace}; @@ -209,14 +209,8 @@ pub(crate) fn target_machine_factory( let code_model = to_llvm_code_model(sess.code_model()); - let mut singlethread = sess.target.singlethread; - - // On the wasm target once the `atomics` feature is enabled that means that - // we're no longer single-threaded, or otherwise we don't want LLVM to - // lower atomic operations to single-threaded operations. - if singlethread && sess.target.is_like_wasm && sess.target_features.contains(&sym::atomics) { - singlethread = false; - } + // This is used to set cfg_has_threads, so all logic must be in this method. + let singlethread = sess.target.singlethread(&sess.target_features); let triple = SmallCStr::new(&versioned_llvm_target(sess)); let cpu = SmallCStr::new(llvm_util::target_cpu(sess)); diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e081c2989d3c6..6a9cfeff49339 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -50,6 +50,7 @@ const GATED_CFGS: &[GatedCfg] = &[ sym::cfg_target_has_reliable_f16_f128, Features::cfg_target_has_reliable_f16_f128, ), + (sym::target_has_threads, sym::cfg_target_has_threads, Features::cfg_target_has_threads), (sym::target_object_format, sym::cfg_target_object_format, Features::cfg_target_object_format), ]; diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index fc38d9de6e143..0edd6a720800a 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -254,6 +254,8 @@ declare_features! ( (unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None), /// Allows checking whether or not the backend correctly supports unstable float types. (internal, cfg_target_has_reliable_f16_f128, "1.88.0", None), + /// Allows checking whether or not the target might have thread support. + (internal, cfg_target_has_threads, "CURRENT_RUSTC_VERSION", None), /// Allows identifying the `compiler_builtins` crate. (internal, compiler_builtins, "1.13.0", None), /// Allows skipping `ConstParamTy_` trait implementation checks diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index cd301bea4eebf..955a77f808588 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -149,6 +149,7 @@ pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) { | (sym::target_pointer_width, Some(_)) | (sym::target_vendor, None | Some(_)) | (sym::target_has_atomic, Some(_)) + | (sym::target_has_threads, None | Some(_)) | (sym::target_has_atomic_primitive_alignment, Some(_)) | (sym::target_has_atomic_load_store, Some(_)) | (sym::target_has_reliable_f16, None | Some(_)) @@ -303,6 +304,10 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg { } } + if !sess.target.singlethread(&sess.target_features) { + ins_none!(sym::target_has_threads); + } + ins_sym!(sym::target_os, sess.target.os.desc_symbol()); ins_sym!(sym::target_pointer_width, sym::integer(sess.target.pointer_width)); @@ -485,6 +490,7 @@ impl CheckCfg { ins!(sym::target_has_atomic_primitive_alignment, empty_values).extend(atomic_values); ins!(sym::target_thread_local, no_values); + ins!(sym::target_has_threads, no_values); ins!(sym::ub_checks, no_values); ins!(sym::contract_checks, no_values); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 71eae246ebaff..b99198d9ee8c4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -598,6 +598,7 @@ symbols! { cfg_target_has_atomic, cfg_target_has_atomic_equal_alignment, cfg_target_has_reliable_f16_f128, + cfg_target_has_threads, cfg_target_object_format, cfg_target_thread_local, cfg_target_vendor, @@ -2084,6 +2085,7 @@ symbols! { target_has_reliable_f16_math, target_has_reliable_f128, target_has_reliable_f128_math, + target_has_threads, target_object_format, target_os, target_pointer_width, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 5c19b35e1605c..a02e08d27a8f1 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2256,6 +2256,26 @@ impl Target { } } } + + /// Is this target single-threaded? + /// + /// This affects both optimizations (e.g., atomics can be lowered to regular operations) and + /// is also exposed as cfg(target_has_threads). + pub fn singlethread(&self, target_features: &FxIndexSet) -> bool { + // On the wasm target once the `atomics` feature is enabled that means that + // we're no longer single-threaded, or otherwise we don't want LLVM to + // lower atomic operations to single-threaded operations. + // + // FIXME: This (probably?) implies that atomics should be a target modifier, at which point + // it probably makes sense to be a separate target to ship precompiled artifacts for it? + // + // cc #77839 (tracking issue for wasm atomics) + if self.singlethread && self.is_like_wasm && target_features.contains(&sym::atomics) { + return false; + } + + self.singlethread + } } pub trait HasTargetSpec { @@ -2571,7 +2591,8 @@ pub struct TargetOptions { pub requires_lto: bool, /// This target has no support for threads. - pub singlethread: bool, + // This is private because wasm changes this depending on target features. + singlethread: bool, /// Whether library functions call lowering/optimization is disabled in LLVM /// for this target unconditionally. diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index afa30c8c00f27..6dc276f5599c8 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -276,6 +276,7 @@ #![feature(asm_experimental_arch)] #![feature(autodiff)] #![feature(cfg_sanitizer_cfi)] +#![feature(cfg_target_has_threads)] #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] #![feature(const_trait_impl)] diff --git a/library/std/src/sys/sync/condvar/no_threads.rs b/library/std/src/sys/sync/condvar/no_threads.rs index 18d97d4b17ab0..9dbba490b2851 100644 --- a/library/std/src/sys/sync/condvar/no_threads.rs +++ b/library/std/src/sys/sync/condvar/no_threads.rs @@ -2,6 +2,9 @@ use crate::sys::sync::Mutex; use crate::thread::sleep; use crate::time::Duration; +#[cfg(target_has_threads)] +compile_error!("Using no_threads implementation on a target with threads"); + pub struct Condvar {} impl Condvar { diff --git a/library/std/src/sys/sync/mutex/no_threads.rs b/library/std/src/sys/sync/mutex/no_threads.rs index a1c2696079f86..a87c2747451c5 100644 --- a/library/std/src/sys/sync/mutex/no_threads.rs +++ b/library/std/src/sys/sync/mutex/no_threads.rs @@ -1,5 +1,8 @@ use crate::cell::Cell; +#[cfg(target_has_threads)] +compile_error!("Using no_threads implementation on a target with threads"); + pub struct Mutex { // This platform has no threads, so we can use a Cell here. locked: Cell, diff --git a/library/std/src/sys/sync/once/no_threads.rs b/library/std/src/sys/sync/once/no_threads.rs index 42fe2417307aa..31c9aedb98f96 100644 --- a/library/std/src/sys/sync/once/no_threads.rs +++ b/library/std/src/sys/sync/once/no_threads.rs @@ -2,6 +2,9 @@ use crate::cell::Cell; use crate::sync as public; use crate::sync::once::OnceExclusiveState; +#[cfg(target_has_threads)] +compile_error!("Using no_threads implementation on a target with threads"); + pub struct Once { state: Cell, } diff --git a/library/std/src/sys/sync/rwlock/no_threads.rs b/library/std/src/sys/sync/rwlock/no_threads.rs index 6de5577504c43..efa2629b3110d 100644 --- a/library/std/src/sys/sync/rwlock/no_threads.rs +++ b/library/std/src/sys/sync/rwlock/no_threads.rs @@ -1,5 +1,8 @@ use crate::cell::Cell; +#[cfg(target_has_threads)] +compile_error!("Using no_threads implementation on a target with threads"); + pub struct RwLock { // This platform has no threads, so we can use a Cell here. mode: Cell, diff --git a/library/std/src/sys/thread_local/no_threads.rs b/library/std/src/sys/thread_local/no_threads.rs index 27a589a4a76ac..f9d0ed384fe24 100644 --- a/library/std/src/sys/thread_local/no_threads.rs +++ b/library/std/src/sys/thread_local/no_threads.rs @@ -5,6 +5,9 @@ use crate::cell::{Cell, UnsafeCell}; use crate::mem::MaybeUninit; use crate::ptr; +#[cfg(target_has_threads)] +compile_error!("Using no_threads implementation on a target with threads"); + #[doc(hidden)] #[allow_internal_unstable(thread_local_internals)] #[allow_internal_unsafe] diff --git a/tests/rustdoc-ui/doc-cfg-2.stderr b/tests/rustdoc-ui/doc-cfg-2.stderr index aeb842c338c6b..da202ea4809f1 100644 --- a/tests/rustdoc-ui/doc-cfg-2.stderr +++ b/tests/rustdoc-ui/doc-cfg-2.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `foo` LL | #[doc(cfg(foo), cfg(bar))] | ^^^ | - = help: expected names are: `FALSE` and `test` and 32 more + = help: expected names are: `FALSE` and `test` and 33 more = help: to expect this configuration use `--check-cfg=cfg(foo)` = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/cfg/disallowed-cli-cfgs.rs b/tests/ui/cfg/disallowed-cli-cfgs.rs index 57aed0016e971..8697f5a747e18 100644 --- a/tests/ui/cfg/disallowed-cli-cfgs.rs +++ b/tests/ui/cfg/disallowed-cli-cfgs.rs @@ -8,6 +8,7 @@ //@ revisions: target_object_format_ target_pointer_width_ target_vendor_ //@ revisions: target_has_atomic_ target_has_atomic_primitive_alignment_ //@ revisions: target_has_atomic_load_store_ target_thread_local_ relocation_model_ +//@ revisions: target_has_threads_ //@ revisions: fmt_debug_ //@ revisions: reliable_f16_ reliable_f16_math_ reliable_f128_ reliable_f128_math_ @@ -34,6 +35,7 @@ //@ [target_has_atomic_]compile-flags: --cfg target_has_atomic="32" //@ [target_has_atomic_primitive_alignment_]compile-flags: --cfg target_has_atomic_primitive_alignment="32" //@ [target_has_atomic_load_store_]compile-flags: --cfg target_has_atomic_load_store="32" +//@ [target_has_threads_]compile-flags: --cfg target_has_threads //@ [target_thread_local_]compile-flags: --cfg target_thread_local //@ [relocation_model_]compile-flags: --cfg relocation_model="a" //@ [fmt_debug_]compile-flags: --cfg fmt_debug="shallow" diff --git a/tests/ui/cfg/disallowed-cli-cfgs.target_has_threads_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.target_has_threads_.stderr new file mode 100644 index 0000000000000..7fc01e2493883 --- /dev/null +++ b/tests/ui/cfg/disallowed-cli-cfgs.target_has_threads_.stderr @@ -0,0 +1,8 @@ +error: unexpected `--cfg target_has_threads` flag + | + = note: config `target_has_threads` is only supposed to be controlled by `--target` + = note: manually setting a built-in cfg can and does create incoherent behaviors + = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default + +error: aborting due to 1 previous error + diff --git a/tests/ui/check-cfg/cargo-build-script.stderr b/tests/ui/check-cfg/cargo-build-script.stderr index 6039af936a319..9694a762a06c4 100644 --- a/tests/ui/check-cfg/cargo-build-script.stderr +++ b/tests/ui/check-cfg/cargo-build-script.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `has_foo` LL | #[cfg(has_foo)] | ^^^^^^^ | - = help: expected names are: `has_bar` and 32 more + = help: expected names are: `has_bar` and 33 more = help: consider using a Cargo feature instead = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint: [lints.rust] diff --git a/tests/ui/check-cfg/cargo-feature.none.stderr b/tests/ui/check-cfg/cargo-feature.none.stderr index c710781b68ce9..05d2a41238258 100644 --- a/tests/ui/check-cfg/cargo-feature.none.stderr +++ b/tests/ui/check-cfg/cargo-feature.none.stderr @@ -25,7 +25,7 @@ warning: unexpected `cfg` condition name: `tokio_unstable` LL | #[cfg(tokio_unstable)] | ^^^^^^^^^^^^^^ | - = help: expected names are: `docsrs`, `feature`, and `test` and 32 more + = help: expected names are: `docsrs`, `feature`, and `test` and 33 more = help: consider using a Cargo feature instead = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint: [lints.rust] diff --git a/tests/ui/check-cfg/cargo-feature.some.stderr b/tests/ui/check-cfg/cargo-feature.some.stderr index 9e3726f6c6259..de84eb2932e7e 100644 --- a/tests/ui/check-cfg/cargo-feature.some.stderr +++ b/tests/ui/check-cfg/cargo-feature.some.stderr @@ -25,7 +25,7 @@ warning: unexpected `cfg` condition name: `tokio_unstable` LL | #[cfg(tokio_unstable)] | ^^^^^^^^^^^^^^ | - = help: expected names are: `CONFIG_NVME`, `docsrs`, `feature`, and `test` and 32 more + = help: expected names are: `CONFIG_NVME`, `docsrs`, `feature`, and `test` and 33 more = help: consider using a Cargo feature instead = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint: [lints.rust] diff --git a/tests/ui/check-cfg/cfg-select.stderr b/tests/ui/check-cfg/cfg-select.stderr index 8733f42b14710..e4bc800f7cc07 100644 --- a/tests/ui/check-cfg/cfg-select.stderr +++ b/tests/ui/check-cfg/cfg-select.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `invalid_cfg1` LL | invalid_cfg1 => {} | ^^^^^^^^^^^^ | - = help: expected names are: `FALSE` and `test` and 32 more + = help: expected names are: `FALSE` and `test` and 33 more = help: to expect this configuration use `--check-cfg=cfg(invalid_cfg1)` = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr index ed80d25ffccda..50ae3d88f61df 100644 --- a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `value` LL | #[cfg(value)] | ^^^^^ | - = help: expected names are: `bar`, `bee`, `cow`, and `foo` and 32 more + = help: expected names are: `bar`, `bee`, `cow`, and `foo` and 33 more = help: to expect this configuration use `--check-cfg=cfg(value)` = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr index 5e0f1b02dd459..b432d46920a22 100644 --- a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `my_value` LL | #[cfg(my_value)] | ^^^^^^^^ | - = help: expected names are: `bar` and `foo` and 32 more + = help: expected names are: `bar` and `foo` and 33 more = help: to expect this configuration use `--check-cfg=cfg(my_value)` = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr index 6e21c47c1d7d1..8c0b623d445ed 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key` LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `feature` and 32 more + = help: expected names are: `feature` and 33 more = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))` = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/exhaustive-names-values.full.stderr b/tests/ui/check-cfg/exhaustive-names-values.full.stderr index 6e21c47c1d7d1..8c0b623d445ed 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.full.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.full.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key` LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `feature` and 32 more + = help: expected names are: `feature` and 33 more = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))` = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/hrtb-crash.stderr b/tests/ui/check-cfg/hrtb-crash.stderr index f83bef31e3a18..d07dee86d680c 100644 --- a/tests/ui/check-cfg/hrtb-crash.stderr +++ b/tests/ui/check-cfg/hrtb-crash.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `b` LL | for<#[cfg(b)] c> u8:; | ^ help: found config with similar value: `target_feature = "b"` | - = help: expected names are: `FALSE`, `docsrs`, and `test` and 32 more + = help: expected names are: `FALSE`, `docsrs`, and `test` and 33 more = help: to expect this configuration use `--check-cfg=cfg(b)` = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index b42619b04e9bf..bd0ecc2d0ac6b 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -44,7 +44,7 @@ warning: unexpected `cfg` condition name: `uu` LL | #[cfg_attr(uu, unix)] | ^^ | - = help: expected names are: `feature` and 32 more + = help: expected names are: `feature` and 33 more = help: to expect this configuration use `--check-cfg=cfg(uu)` = note: see for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/nested-cfg.stderr b/tests/ui/check-cfg/nested-cfg.stderr index 73a1160a2d487..19dd68753b74e 100644 --- a/tests/ui/check-cfg/nested-cfg.stderr +++ b/tests/ui/check-cfg/nested-cfg.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown` LL | #[cfg(unknown)] | ^^^^^^^ | - = help: expected names are: `FALSE` and `test` and 32 more + = help: expected names are: `FALSE` and `test` and 33 more = help: to expect this configuration use `--check-cfg=cfg(unknown)` = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/raw-keywords.edition2015.stderr b/tests/ui/check-cfg/raw-keywords.edition2015.stderr index 1524c3558fc95..46e02bfbb3ecd 100644 --- a/tests/ui/check-cfg/raw-keywords.edition2015.stderr +++ b/tests/ui/check-cfg/raw-keywords.edition2015.stderr @@ -14,7 +14,7 @@ warning: unexpected `cfg` condition name: `r#false` LL | #[cfg(r#false)] | ^^^^^^^ | - = help: expected names are: `async`, `edition2015`, `edition2021`, and `r#true` and 32 more + = help: expected names are: `async`, `edition2015`, `edition2021`, and `r#true` and 33 more = help: to expect this configuration use `--check-cfg=cfg(r#false)` = note: see for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/raw-keywords.edition2021.stderr b/tests/ui/check-cfg/raw-keywords.edition2021.stderr index 5859b7592941a..3e108debfcf8b 100644 --- a/tests/ui/check-cfg/raw-keywords.edition2021.stderr +++ b/tests/ui/check-cfg/raw-keywords.edition2021.stderr @@ -14,7 +14,7 @@ warning: unexpected `cfg` condition name: `r#false` LL | #[cfg(r#false)] | ^^^^^^^ | - = help: expected names are: `r#async`, `edition2015`, `edition2021`, and `r#true` and 32 more + = help: expected names are: `r#async`, `edition2015`, `edition2021`, and `r#true` and 33 more = help: to expect this configuration use `--check-cfg=cfg(r#false)` = note: see for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/report-in-external-macros.cargo.stderr b/tests/ui/check-cfg/report-in-external-macros.cargo.stderr index 18d361ccdbd7f..646c814ef65f6 100644 --- a/tests/ui/check-cfg/report-in-external-macros.cargo.stderr +++ b/tests/ui/check-cfg/report-in-external-macros.cargo.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `my_lib_cfg` LL | cfg_macro::my_lib_macro!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `feature` and 32 more + = help: expected names are: `feature` and 33 more = note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate = help: try referring to `cfg_macro::my_lib_macro` crate for guidance on how handle this unexpected cfg = note: see for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/report-in-external-macros.rustc.stderr b/tests/ui/check-cfg/report-in-external-macros.rustc.stderr index 860610baa9719..d38f3560063ac 100644 --- a/tests/ui/check-cfg/report-in-external-macros.rustc.stderr +++ b/tests/ui/check-cfg/report-in-external-macros.rustc.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `my_lib_cfg` LL | cfg_macro::my_lib_macro!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `feature` and 32 more + = help: expected names are: `feature` and 33 more = note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate = help: try referring to `cfg_macro::my_lib_macro` crate for guidance on how handle this unexpected cfg = help: to expect this configuration use `--check-cfg=cfg(my_lib_cfg)` diff --git a/tests/ui/check-cfg/well-known-names.stderr b/tests/ui/check-cfg/well-known-names.stderr index ec1345fd6b3cd..3f68bca37dd5d 100644 --- a/tests/ui/check-cfg/well-known-names.stderr +++ b/tests/ui/check-cfg/well-known-names.stderr @@ -28,6 +28,7 @@ LL | #[cfg(list_all_well_known_cfgs)] `target_has_atomic` `target_has_atomic_load_store` `target_has_atomic_primitive_alignment` +`target_has_threads` `target_object_format` `target_os` `target_pointer_width` diff --git a/tests/ui/check-cfg/well-known-values.rs b/tests/ui/check-cfg/well-known-values.rs index 5f961989d720f..c10139570570b 100644 --- a/tests/ui/check-cfg/well-known-values.rs +++ b/tests/ui/check-cfg/well-known-values.rs @@ -15,6 +15,7 @@ #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] #![feature(cfg_target_object_format)] +#![feature(cfg_target_has_threads)] #![feature(cfg_ub_checks)] #![feature(fmt_debug)] @@ -68,6 +69,8 @@ //~^ WARN unexpected `cfg` condition value target_has_atomic_primitive_alignment = "_UNEXPECTED_VALUE", //~^ WARN unexpected `cfg` condition value + target_has_threads = "_UNEXPECTED_VALUE", + //~^ WARN unexpected `cfg` condition value target_object_format = "_UNEXPECTED_VALUE", //~^ WARN unexpected `cfg` condition value target_os = "_UNEXPECTED_VALUE", diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 5c797783e48b8..693833decc971 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:29:5 + --> $DIR/well-known-values.rs:30:5 | LL | clippy = "_UNEXPECTED_VALUE", | ^^^^^^---------------------- @@ -11,7 +11,7 @@ LL | clippy = "_UNEXPECTED_VALUE", = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:31:5 + --> $DIR/well-known-values.rs:32:5 | LL | debug_assertions = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^---------------------- @@ -22,7 +22,7 @@ LL | debug_assertions = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:33:5 + --> $DIR/well-known-values.rs:34:5 | LL | doc = "_UNEXPECTED_VALUE", | ^^^---------------------- @@ -33,7 +33,7 @@ LL | doc = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:35:5 + --> $DIR/well-known-values.rs:36:5 | LL | doctest = "_UNEXPECTED_VALUE", | ^^^^^^^---------------------- @@ -44,7 +44,7 @@ LL | doctest = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:37:5 + --> $DIR/well-known-values.rs:38:5 | LL | fmt_debug = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -53,7 +53,7 @@ LL | fmt_debug = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:39:5 + --> $DIR/well-known-values.rs:40:5 | LL | miri = "_UNEXPECTED_VALUE", | ^^^^---------------------- @@ -64,7 +64,7 @@ LL | miri = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:41:5 + --> $DIR/well-known-values.rs:42:5 | LL | overflow_checks = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^---------------------- @@ -75,7 +75,7 @@ LL | overflow_checks = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:43:5 + --> $DIR/well-known-values.rs:44:5 | LL | panic = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL | panic = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:45:5 + --> $DIR/well-known-values.rs:46:5 | LL | proc_macro = "_UNEXPECTED_VALUE", | ^^^^^^^^^^---------------------- @@ -95,7 +95,7 @@ LL | proc_macro = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:47:5 + --> $DIR/well-known-values.rs:48:5 | LL | relocation_model = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +104,7 @@ LL | relocation_model = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:49:5 + --> $DIR/well-known-values.rs:50:5 | LL | rustfmt = "_UNEXPECTED_VALUE", | ^^^^^^^---------------------- @@ -115,7 +115,7 @@ LL | rustfmt = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:51:5 + --> $DIR/well-known-values.rs:52:5 | LL | sanitize = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -124,7 +124,7 @@ LL | sanitize = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:53:5 + --> $DIR/well-known-values.rs:54:5 | LL | target_abi = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL | target_abi = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:55:5 + --> $DIR/well-known-values.rs:56:5 | LL | target_arch = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -142,7 +142,7 @@ LL | target_arch = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:57:5 + --> $DIR/well-known-values.rs:58:5 | LL | target_endian = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -151,7 +151,7 @@ LL | target_endian = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:59:5 + --> $DIR/well-known-values.rs:60:5 | LL | target_env = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,7 +160,7 @@ LL | target_env = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:61:5 + --> $DIR/well-known-values.rs:62:5 | LL | target_family = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL | target_family = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:65:5 + --> $DIR/well-known-values.rs:66:5 | LL | target_has_atomic = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -178,7 +178,7 @@ LL | target_has_atomic = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:67:5 + --> $DIR/well-known-values.rs:68:5 | LL | target_has_atomic_load_store = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -187,7 +187,7 @@ LL | target_has_atomic_load_store = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:69:5 + --> $DIR/well-known-values.rs:70:5 | LL | target_has_atomic_primitive_alignment = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -196,7 +196,18 @@ LL | target_has_atomic_primitive_alignment = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:71:5 + --> $DIR/well-known-values.rs:72:5 + | +LL | target_has_threads = "_UNEXPECTED_VALUE", + | ^^^^^^^^^^^^^^^^^^---------------------- + | | + | help: remove the value + | + = note: no expected value for `target_has_threads` + = note: see for more information about checking conditional configuration + +warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` + --> $DIR/well-known-values.rs:74:5 | LL | target_object_format = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -205,7 +216,7 @@ LL | target_object_format = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:73:5 + --> $DIR/well-known-values.rs:76:5 | LL | target_os = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -214,7 +225,7 @@ LL | target_os = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:75:5 + --> $DIR/well-known-values.rs:78:5 | LL | target_pointer_width = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -223,7 +234,7 @@ LL | target_pointer_width = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:77:5 + --> $DIR/well-known-values.rs:80:5 | LL | target_thread_local = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^---------------------- @@ -234,7 +245,7 @@ LL | target_thread_local = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:79:5 + --> $DIR/well-known-values.rs:82:5 | LL | target_vendor = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -243,7 +254,7 @@ LL | target_vendor = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:81:5 + --> $DIR/well-known-values.rs:84:5 | LL | ub_checks = "_UNEXPECTED_VALUE", | ^^^^^^^^^---------------------- @@ -254,7 +265,7 @@ LL | ub_checks = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:83:5 + --> $DIR/well-known-values.rs:86:5 | LL | unix = "_UNEXPECTED_VALUE", | ^^^^---------------------- @@ -265,7 +276,7 @@ LL | unix = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:85:5 + --> $DIR/well-known-values.rs:88:5 | LL | windows = "_UNEXPECTED_VALUE", | ^^^^^^^---------------------- @@ -276,7 +287,7 @@ LL | windows = "_UNEXPECTED_VALUE", = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `linuz` - --> $DIR/well-known-values.rs:91:7 + --> $DIR/well-known-values.rs:94:7 | LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` | ^^^^^^^^^^^^------- @@ -286,5 +297,5 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `qnx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration -warning: 29 warnings emitted +warning: 30 warnings emitted diff --git a/tests/ui/feature-gates/feature-gate-cfg-target-has-threads.rs b/tests/ui/feature-gates/feature-gate-cfg-target-has-threads.rs new file mode 100644 index 0000000000000..4acafa8e601d6 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg-target-has-threads.rs @@ -0,0 +1,5 @@ +#[cfg(target_has_threads)] +//~^ ERROR `cfg(target_has_threads)` is experimental and subject to change +fn bar() {} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-cfg-target-has-threads.stderr b/tests/ui/feature-gates/feature-gate-cfg-target-has-threads.stderr new file mode 100644 index 0000000000000..f84f739b11ef6 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg-target-has-threads.stderr @@ -0,0 +1,12 @@ +error[E0658]: `cfg(target_has_threads)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-threads.rs:1:7 + | +LL | #[cfg(target_has_threads)] + | ^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(cfg_target_has_threads)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/macros/cfg.stderr b/tests/ui/macros/cfg.stderr index a5ee463f2a346..b4c7cd3306d26 100644 --- a/tests/ui/macros/cfg.stderr +++ b/tests/ui/macros/cfg.stderr @@ -46,7 +46,7 @@ warning: unexpected `cfg` condition name: `foo` LL | cfg!(foo); | ^^^ | - = help: expected names are: `FALSE` and `test` and 32 more + = help: expected names are: `FALSE` and `test` and 33 more = help: to expect this configuration use `--check-cfg=cfg(foo)` = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/macros/cfg_select.stderr b/tests/ui/macros/cfg_select.stderr index 1199b1f4d026c..1a72e7a9c0ace 100644 --- a/tests/ui/macros/cfg_select.stderr +++ b/tests/ui/macros/cfg_select.stderr @@ -169,7 +169,7 @@ warning: unexpected `cfg` condition name: `a` LL | a + 1 => {} | ^ help: found config with similar value: `target_feature = "a"` | - = help: expected names are: `FALSE` and `test` and 32 more + = help: expected names are: `FALSE` and `test` and 33 more = help: to expect this configuration use `--check-cfg=cfg(a)` = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default From fe2db9c9f5b732d9d12ddb1a3c251ff6bb18596e Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 5 Jul 2026 15:43:22 -0400 Subject: [PATCH 54/56] Split TargetTuple definition to separate file This avoids compiler/rustc_target/src/spec/mod.rs hitting tidy's file length check by moving out a chunk of code into a separate file. It's probably not the last such move needed (this only offsets ~100 lines), but it's a reasonable chunk of code to separate. --- compiler/rustc_target/src/spec/mod.rs | 147 +----------------------- compiler/rustc_target/src/spec/tuple.rs | 146 +++++++++++++++++++++++ 2 files changed, 150 insertions(+), 143 deletions(-) create mode 100644 compiler/rustc_target/src/spec/tuple.rs diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index a02e08d27a8f1..c386e4f50bddb 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -40,11 +40,11 @@ use core::result::Result; use std::borrow::Cow; use std::collections::BTreeMap; -use std::hash::{Hash, Hasher}; +use std::fmt; +use std::hash::Hash; use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; use std::str::FromStr; -use std::{fmt, io}; use rustc_abi::{ Align, CVariadicStatus, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout, @@ -52,9 +52,7 @@ use rustc_abi::{ }; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_error_messages::{DiagArgValue, IntoDiagArg, into_diag_arg_using_display}; -use rustc_fs_util::try_canonicalize; use rustc_macros::{BlobDecodable, Decodable, Encodable, StableHash}; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::{Symbol, kw, sym}; use serde_json::Value; use tracing::debug; @@ -67,11 +65,13 @@ pub mod crt_objects; mod abi_map; mod base; mod json; +mod tuple; pub use abi_map::{AbiMap, AbiMapping}; pub use base::apple; pub use base::avr::ef_avr_arch; pub use json::json_schema; +pub use tuple::TargetTuple; /// Linker is called through a C/C++ compiler. #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] @@ -3914,142 +3914,3 @@ impl Target { Symbol::intern(&self.vendor) } } - -/// Either a target tuple string or a path to a JSON file. -#[derive(Clone, Debug)] -pub enum TargetTuple { - TargetTuple(String), - TargetJson { - /// Warning: This field may only be used by rustdoc. Using it anywhere else will lead to - /// inconsistencies as it is discarded during serialization. - path_for_rustdoc: PathBuf, - tuple: String, - contents: String, - }, -} - -// Use a manual implementation to ignore the path field -impl PartialEq for TargetTuple { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::TargetTuple(l0), Self::TargetTuple(r0)) => l0 == r0, - ( - Self::TargetJson { path_for_rustdoc: _, tuple: l_tuple, contents: l_contents }, - Self::TargetJson { path_for_rustdoc: _, tuple: r_tuple, contents: r_contents }, - ) => l_tuple == r_tuple && l_contents == r_contents, - _ => false, - } - } -} - -// Use a manual implementation to ignore the path field -impl Hash for TargetTuple { - fn hash(&self, state: &mut H) -> () { - match self { - TargetTuple::TargetTuple(tuple) => { - 0u8.hash(state); - tuple.hash(state) - } - TargetTuple::TargetJson { path_for_rustdoc: _, tuple, contents } => { - 1u8.hash(state); - tuple.hash(state); - contents.hash(state) - } - } - } -} - -// Use a manual implementation to prevent encoding the target json file path in the crate metadata -impl Encodable for TargetTuple { - fn encode(&self, s: &mut S) { - match self { - TargetTuple::TargetTuple(tuple) => { - s.emit_u8(0); - s.emit_str(tuple); - } - TargetTuple::TargetJson { path_for_rustdoc: _, tuple, contents } => { - s.emit_u8(1); - s.emit_str(tuple); - s.emit_str(contents); - } - } - } -} - -impl Decodable for TargetTuple { - fn decode(d: &mut D) -> Self { - match d.read_u8() { - 0 => TargetTuple::TargetTuple(d.read_str().to_owned()), - 1 => TargetTuple::TargetJson { - path_for_rustdoc: PathBuf::new(), - tuple: d.read_str().to_owned(), - contents: d.read_str().to_owned(), - }, - _ => { - panic!("invalid enum variant tag while decoding `TargetTuple`, expected 0..2"); - } - } - } -} - -impl TargetTuple { - /// Creates a target tuple from the passed target tuple string. - pub fn from_tuple(tuple: &str) -> Self { - TargetTuple::TargetTuple(tuple.into()) - } - - /// Creates a target tuple from the passed target path. - pub fn from_path(path: &Path) -> Result { - let canonicalized_path = try_canonicalize(path)?; - let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| { - io::Error::new( - io::ErrorKind::InvalidInput, - format!("target path {canonicalized_path:?} is not a valid file: {err}"), - ) - })?; - let tuple = canonicalized_path - .file_stem() - .expect("target path must not be empty") - .to_str() - .expect("target path must be valid unicode") - .to_owned(); - Ok(TargetTuple::TargetJson { path_for_rustdoc: canonicalized_path, tuple, contents }) - } - - /// Returns a string tuple for this target. - /// - /// If this target is a path, the file name (without extension) is returned. - pub fn tuple(&self) -> &str { - match *self { - TargetTuple::TargetTuple(ref tuple) | TargetTuple::TargetJson { ref tuple, .. } => { - tuple - } - } - } - - /// Returns an extended string tuple for this target. - /// - /// If this target is a path, a hash of the path is appended to the tuple returned - /// by `tuple()`. - pub fn debug_tuple(&self) -> String { - use std::hash::DefaultHasher; - - match self { - TargetTuple::TargetTuple(tuple) => tuple.to_owned(), - TargetTuple::TargetJson { path_for_rustdoc: _, tuple, contents: content } => { - let mut hasher = DefaultHasher::new(); - content.hash(&mut hasher); - let hash = hasher.finish(); - format!("{tuple}-{hash}") - } - } - } -} - -impl fmt::Display for TargetTuple { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.debug_tuple()) - } -} - -into_diag_arg_using_display!(&TargetTuple); diff --git a/compiler/rustc_target/src/spec/tuple.rs b/compiler/rustc_target/src/spec/tuple.rs new file mode 100644 index 0000000000000..2c4a879d79440 --- /dev/null +++ b/compiler/rustc_target/src/spec/tuple.rs @@ -0,0 +1,146 @@ +use std::hash::{Hash, Hasher}; +use std::path::{Path, PathBuf}; +use std::{fmt, io}; + +use rustc_error_messages::into_diag_arg_using_display; +use rustc_fs_util::try_canonicalize; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; + +/// Either a target tuple string or a path to a JSON file. +#[derive(Clone, Debug)] +pub enum TargetTuple { + TargetTuple(String), + TargetJson { + /// Warning: This field may only be used by rustdoc. Using it anywhere else will lead to + /// inconsistencies as it is discarded during serialization. + path_for_rustdoc: PathBuf, + tuple: String, + contents: String, + }, +} + +// Use a manual implementation to ignore the path field +impl PartialEq for TargetTuple { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::TargetTuple(l0), Self::TargetTuple(r0)) => l0 == r0, + ( + Self::TargetJson { path_for_rustdoc: _, tuple: l_tuple, contents: l_contents }, + Self::TargetJson { path_for_rustdoc: _, tuple: r_tuple, contents: r_contents }, + ) => l_tuple == r_tuple && l_contents == r_contents, + _ => false, + } + } +} + +// Use a manual implementation to ignore the path field +impl Hash for TargetTuple { + fn hash(&self, state: &mut H) -> () { + match self { + TargetTuple::TargetTuple(tuple) => { + 0u8.hash(state); + tuple.hash(state) + } + TargetTuple::TargetJson { path_for_rustdoc: _, tuple, contents } => { + 1u8.hash(state); + tuple.hash(state); + contents.hash(state) + } + } + } +} + +// Use a manual implementation to prevent encoding the target json file path in the crate metadata +impl Encodable for TargetTuple { + fn encode(&self, s: &mut S) { + match self { + TargetTuple::TargetTuple(tuple) => { + s.emit_u8(0); + s.emit_str(tuple); + } + TargetTuple::TargetJson { path_for_rustdoc: _, tuple, contents } => { + s.emit_u8(1); + s.emit_str(tuple); + s.emit_str(contents); + } + } + } +} + +impl Decodable for TargetTuple { + fn decode(d: &mut D) -> Self { + match d.read_u8() { + 0 => TargetTuple::TargetTuple(d.read_str().to_owned()), + 1 => TargetTuple::TargetJson { + path_for_rustdoc: PathBuf::new(), + tuple: d.read_str().to_owned(), + contents: d.read_str().to_owned(), + }, + _ => { + panic!("invalid enum variant tag while decoding `TargetTuple`, expected 0..2"); + } + } + } +} + +impl TargetTuple { + /// Creates a target tuple from the passed target tuple string. + pub fn from_tuple(tuple: &str) -> Self { + TargetTuple::TargetTuple(tuple.into()) + } + + /// Creates a target tuple from the passed target path. + pub fn from_path(path: &Path) -> Result { + let canonicalized_path = try_canonicalize(path)?; + let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| { + io::Error::new( + io::ErrorKind::InvalidInput, + format!("target path {canonicalized_path:?} is not a valid file: {err}"), + ) + })?; + let tuple = canonicalized_path + .file_stem() + .expect("target path must not be empty") + .to_str() + .expect("target path must be valid unicode") + .to_owned(); + Ok(TargetTuple::TargetJson { path_for_rustdoc: canonicalized_path, tuple, contents }) + } + + /// Returns a string tuple for this target. + /// + /// If this target is a path, the file name (without extension) is returned. + pub fn tuple(&self) -> &str { + match *self { + TargetTuple::TargetTuple(ref tuple) | TargetTuple::TargetJson { ref tuple, .. } => { + tuple + } + } + } + + /// Returns an extended string tuple for this target. + /// + /// If this target is a path, a hash of the path is appended to the tuple returned + /// by `tuple()`. + pub fn debug_tuple(&self) -> String { + use std::hash::DefaultHasher; + + match self { + TargetTuple::TargetTuple(tuple) => tuple.to_owned(), + TargetTuple::TargetJson { path_for_rustdoc: _, tuple, contents: content } => { + let mut hasher = DefaultHasher::new(); + content.hash(&mut hasher); + let hash = hasher.finish(); + format!("{tuple}-{hash}") + } + } + } +} + +impl fmt::Display for TargetTuple { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.debug_tuple()) + } +} + +into_diag_arg_using_display!(&TargetTuple); From 851d8f3632c067ae8dd9f7c11e59b5fb344ffc85 Mon Sep 17 00:00:00 2001 From: "Shoyu Vanilla (Flint)" Date: Mon, 6 Jul 2026 04:46:30 +0000 Subject: [PATCH 55/56] tidy: Use `empty_alternate = true` for triagebot mention glob check * tidy: Use `empty_alternate = true` for triagebot mention glob check * fmt --- src/tools/tidy/src/triagebot.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tools/tidy/src/triagebot.rs b/src/tools/tidy/src/triagebot.rs index a74d980cfcb7f..4eb3e9a82ab35 100644 --- a/src/tools/tidy/src/triagebot.rs +++ b/src/tools/tidy/src/triagebot.rs @@ -51,7 +51,12 @@ pub fn check(path: &Path, tidy_ctx: TidyCtx) { // The full-path doesn't exists, maybe it's a glob, let's add it to the glob set builder // to be checked against all the file and directories in the repository. let trimmed_path = clean_path.trim_end_matches('/'); - builder.add(globset::Glob::new(&format!("{trimmed_path}{{,/*}}")).unwrap()); + builder.add( + globset::GlobBuilder::new(&format!("{trimmed_path}{{,/*}}")) + .empty_alternates(true) + .build() + .unwrap(), + ); glob_entries.push(clean_path.to_string()); } else if is_in_submodule(Path::new(clean_path)) { check.error(format!( From 3f928456be2a87b8c9189712bf8313917d9c1f10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 1 Jul 2026 16:35:22 +0200 Subject: [PATCH 56/56] positive test for closures needing expectations --- .../closures/closure_requires_expectation.rs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/ui/closures/closure_requires_expectation.rs diff --git a/tests/ui/closures/closure_requires_expectation.rs b/tests/ui/closures/closure_requires_expectation.rs new file mode 100644 index 0000000000000..6e5c27886d01c --- /dev/null +++ b/tests/ui/closures/closure_requires_expectation.rs @@ -0,0 +1,41 @@ +//@ check-pass + +// `slot` is an out reference. +// We move `state` into a closure, i.e. the closure holds a &'long mut (). +// +// We move it out of the closure again though, in two steps. +// We first assign it to `temp`. +// `temp` has an expected type, so rust inserts a reborrow. +// +// We then move it again, into `slot`, moving it out of the closure. +// The reborrow could've resulted in `temp` having a shorter lifetime. +// Only in borrowck do we require the lifetime in `temp` to also be `'long`. +// +// However, when we analyze upvars, *we don't know that yet*. +// The reborrow gets treated as: a borrow. And the closure gets inferred to be an FnMut. +// This would make the assignment invalid, you cannot move out of an FnMut! +// +// The reason this compiles is that the closure is checked with an `FnOnce` expectation, +// which makes it so despite the upvars not indicating it should be, the closure becomes FnOnce +// and borrowck is happy that we're moving out of the closure. +// +// Note that the `move` keyword only influences how the upvars are moved into the closure. +// It doesn't change whether the closure can be called more than once. +// This example compiles without `move` keyword as long as `state` is moved into the closure in +// some way. This can alternatively be implemented with `let temp = temp` (without expectation), +// since that doesn't insert a reborrow. +fn wrap<'short, 'long>(slot: &'short mut &'long mut (), state: &'long mut ()) { + fnonce_requirement(move || { + let temp: &mut _ = /* rust inserts `&mut *` */ state; + *slot = temp; + }) +} + +fn fnonce_requirement(wrap: F) +where + F: FnOnce(), +{ + todo!() +} + +fn main() {}