Commit Graph

526 Commits

Author SHA1 Message Date
bors f8463896a9 Auto merge of #150681 - meithecatte:always-discriminate, r=JonathanBrouwer,Nadrieril
Make operational semantics of pattern matching independent of crate and module

The question of "when does matching an enum against a pattern of one of its variants read its discriminant" is currently an underspecified part of the language, causing weird behavior around borrowck, drop order, and UB.

Of course, in the common cases, the discriminant must be read to distinguish the variant of the enum, but currently the following exceptions are implemented:

1. If the enum has only one variant, we currently skip the discriminant read.
     - This has the advantage that single-variant enums behave the same way as structs in this regard.
     - However, it means that if the discriminant exists in the layout, we can't say that this discriminant being invalid is UB. This makes me particularly uneasy in its interactions with niches – consider the following example ([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=5904a6155cbdd39af4a2e7b1d32a9b1a)), where miri currently doesn't detect any UB (because the semantics don't specify any):

        <details><summary>Example 1</summary>

        ```rust
        #![allow(dead_code)]
        use core::mem::{size_of, transmute};
        
        #[repr(u8)]
        enum Inner {
            X(u8),
        }
        
        enum Outer {
            A(Inner),
            B(u8),
        }
        
        fn f(x: &Inner) {
            match x {
                Inner::X(v) => {
                    println!("{v}");
                }
            }
        }
        
        fn main() {
            assert_eq!(size_of::<Inner>(), 2);
            assert_eq!(size_of::<Outer>(), 2);
            let x = Outer::B(42);
            let y = &x;
            f(unsafe { transmute(y) });
        }
        ```

      </details>

2. For the purpose of the above, enums with marked with `#[non_exhaustive]` are always considered to have multiple variants when observed from foreign crates, but the actual number of variants is considered in the current crate.
    - This means that whether code has UB can depend on which crate it is in: https://github.com/rust-lang/rust/issues/147722
    - In another case of `#[non_exhaustive]` affecting the runtime semantics, its presence or absence can change what gets captured by a closure, and by extension, the drop order: https://github.com/rust-lang/rust/issues/147722#issuecomment-3674554872
    - Also at the above link, there is an example where removing `#[non_exhaustive]` can cause borrowck to suddenly start failing in another crate.
3. Moreover, we currently make a more specific check: we only read the discriminant if there is more than one *inhabited* variant in the enum.
    - This means that the semantics can differ between `foo<!>`, and a copy of `foo` where `T` was manually replaced with `!`: rust-lang/rust#146803
    - Moreover, due to the privacy rules for inhabitedness, it means that the semantics of code can depend on the *module* in which it is located.
    - Additionally, this inhabitedness rule is even uglier due to the fact that closure capture analysis needs to happen before we can determine whether types are uninhabited, which means that whether the discriminant read happens has a different answer specifically for capture analysis.
    - For the two above points, see the following example ([playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=a07d8a3ec0b31953942e96e2130476d9)):

        <details><summary>Example 2</summary>

        ```rust
        #![allow(unused)]
        
        mod foo {
            enum Never {}
            struct PrivatelyUninhabited(Never);
            pub enum A {
                V(String, String),
                Y(PrivatelyUninhabited),
            }
            
            fn works(mut x: A) {
                let a = match x {
                    A::V(ref mut a, _) => a,
                    _ => unreachable!(),
                };
                
                let b = match x {
                    A::V(_, ref mut b) => b,
                    _ => unreachable!(),
                };
            
                a.len(); b.len();
            }
            
            fn fails(mut x: A) {
                let mut f = || match x {
                    A::V(ref mut a, _) => (),
                    _ => unreachable!(),
                };
                
                let mut g = || match x {
                    A::V(_, ref mut b) => (),
                    _ => unreachable!(),
                };
            
                f(); g();
            }
        }
        
        use foo::A;
        
        fn fails(mut x: A) {
            let a = match x {
                A::V(ref mut a, _) => a,
                _ => unreachable!(),
            };
            
            let b = match x {
                A::V(_, ref mut b) => b,
                _ => unreachable!(),
            };
        
            a.len(); b.len();
        }
        
        
        fn fails2(mut x: A) {
            let mut f = || match x {
                A::V(ref mut a, _) => (),
                _ => unreachable!(),
            };
            
            let mut g = || match x {
                A::V(_, ref mut b) => (),
                _ => unreachable!(),
            };
        
            f(); g();
        }
        ```

        </details>

In light of the above, and following the discussion at rust-lang/rust#138961 and rust-lang/rust#147722, this PR ~~makes it so that, operationally, matching on an enum *always* reads its discriminant.~~ introduces the following changes to this behavior:

 - matching on a `#[non_exhaustive]` enum will always introduce a discriminant read, regardless of whether the enum is from an external crate
 - uninhabited variants now count just like normal ones, and don't get skipped in the checks

As per the discussion below, the resolution for point (1) above is that it should land as part of a separate PR, so that the subtler decision can be more carefully considered.

Note that this is a breaking change, due to the aforementioned changes in borrow checking behavior, new UB (or at least UB newly detected by miri), as well as drop order around closure captures. However, it seems to me that the combination of this PR with rust-lang/rust#138961 should have smaller real-world impact than rust-lang/rust#138961 by itself.

Fixes rust-lang/rust#142394 
Fixes rust-lang/rust#146590
Fixes rust-lang/rust#146803 (though already marked as duplicate)
Fixes parts of rust-lang/rust#147722
Fixes rust-lang/miri#4778

r? @Nadrieril @RalfJung 

@rustbot label +A-closures +A-patterns +T-opsem +T-lang
2026-02-14 12:53:09 +00:00
Alan Egerton c43a33eec7 Feed ErrorGuaranteed from late lifetime resolution to RBV
If late lifetime resolution fails for whatever reason, forward to RBV
the guarantee that an error was emitted - thereby eliminating the need
for a "hack" to suppress subsequent/superfluous error diagnostics.
2026-02-13 16:24:39 +00:00
Jonathan Brouwer eeb3a24813 Rollup merge of #151833 - clubby789:union-adt, r=JonathanBrouwer
Treat unions as 'data types' in attr parsing diagnostics

I found 'data types _and_ unions' to be a little surprising
2026-01-29 17:47:32 +01:00
Jamie Hill-Daniel b226583d94 Treat unions as 'data types' in attr parsing diagnostics 2026-01-29 15:51:43 +00:00
Stuart Cook 36a2726bb4 Rollup merge of #151475 - KaiTomotake:add-foreign-type-tests, r=Kivooeo
add foregin type tests for issue 64458

add tests/ui/rfcs/rfc-1861-extern-types/comparison.rs

close rust-lang/rust#64458
2026-01-29 22:34:09 +11:00
Esteban Küber 4a27be6972 Do not mention -Zmacro-backtrace for std macros that are a wrapper around a compiler intrinsic 2026-01-26 17:34:31 +00:00
KaiTomotake e86cfa0577 add foregin type tests
add tests/ui/rfcs/rfc-1861-extern-types/comparison.rs
2026-01-23 08:56:44 +09:00
joboet ee24f22b7c update UI tests 2026-01-21 19:20:04 +01:00
Maja Kądziołka af302a67fd discriminant reads: make semantics independent of module/crate 2026-01-15 19:12:13 +01:00
Jonathan Brouwer cbcd1c3eef Rollup merge of #151036 - issue-151026, r=mati865
Better handle when trying to iterate on a `Range` of a type that isn't `Step`

Mention when a trait bound corresponds to an unstable trait.

Mention `Range` when `Step` bound is unment, and explain that only some std types impl `Iterator` for `Range`.

CC rust-lang/rust#151026
2026-01-14 11:05:40 +01:00
Lukas Bergdoll 506762f3ff Explicitly export core and std macros
Currently all core and std macros are automatically added to the prelude
via #[macro_use]. However a situation arose where we want to add a new macro
`assert_matches` but don't want to pull it into the standard prelude for
compatibility reasons. By explicitly exporting the macros found in the core and
std crates we get to decide on a per macro basis and can later add them via
the rust_20xx preludes.
2026-01-13 08:47:48 +01:00
Esteban Küber cafe91749f On unmet trait bound, mention if trait is unstable 2026-01-13 01:16:58 +00:00
Rémy Rakic fa77598824 update tests and bless expectations
just to show the diagnostics impact
2025-12-10 14:47:49 +00:00
Christian Poveda b2ab7cf980 Gate 2015 UI tests 2025-11-27 11:19:00 -05:00
reddevilmidzy d3e4dd29a8 Use let...else consistently in user-facing diagnostics 2025-11-24 11:41:52 +09:00
Esteban Küber 71b0755a98 Provide more context when mutably borrowing an imutable borrow
Point at statics and consts being mutable borrowed or written to:

```
error[E0594]: cannot assign to immutable static item `NUM`
  --> $DIR/E0594.rs:4:5
   |
LL | static NUM: i32 = 18;
   | --------------- this `static` cannot be written to
...
LL |     NUM = 20;
   |     ^^^^^^^^ cannot assign
```

Point at the expression that couldn't be mutably borrowed from a pattern:

```
error[E0596]: cannot borrow data in a `&` reference as mutable
  --> $DIR/mut-pattern-of-immutable-borrow.rs:19:14
   |
LL |     match &arg.field {
   |           ---------- this cannot be borrowed as mutable
LL |         Some(ref mut s) => s.push('a'),
   |              ^^^^^^^^^ cannot borrow as mutable
```
2025-11-09 22:14:48 +00:00
Jonathan Brouwer 66b8a9db1f Update uitests with new unused_attributes warnings
Signed-off-by: Jonathan Brouwer <jonathantbrouwer@gmail.com>
2025-10-18 21:17:48 +02:00
Matthias Krüger a5d38ede1d Rollup merge of #145724 - folkertdev:track-caller-drop-no-mangle, r=fee1-dead
the `#[track_caller]` shim should not inherit `#[no_mangle]`

fixes https://github.com/rust-lang/rust/issues/143162

builds on https://github.com/rust-lang/rust/pull/143293 which introduced a mechanism to strip attributes from shims.

cc `@Jules-Bertholet` `@workingjubilee` `@bjorn3`

---

Summary:

This PR fixes an interaction between `#[track_caller]`, `#[no_mangle]`, and casting to a function pointer.

A function annotated with `#[track_caller]` internally has a hidden extra argument for the panic location. The `#[track_caller]` attribute is only allowed on `extern "Rust"` functions. When a function is annotated with both `#[no_mangle]` and `#[track_caller]`, the exported symbol has the signature that includes the extra panic location argument. This works on stable rust today:

```rust
extern "Rust" {
    #[track_caller]
    fn rust_track_caller_ffi_test_tracked() -> &'static Location<'static>;
}

mod provides {
    use std::panic::Location;
    #[track_caller] // UB if we did not have this!
    #[no_mangle]
    fn rust_track_caller_ffi_test_tracked() -> &'static Location<'static> {
        Location::caller()
    }
}
```

When a `#[track_caller]` function is converted to a function pointer, a shim is added to drop the additional argument. So this is a valid program:

```rust
#[track_caller]
fn foo() {}

fn main() {
    let f = foo as fn();
    f();
}
```

The issue arises when `foo` is additionally annotated with `#[no_mangle]`, the generated shim currently inherits this attribute, also exporting a symbol named `foo`, but one without the hidden panic location argument. The linker rightfully complains about a duplicate symbol.

The solution of this PR is to have the generated shim drop the `#[no_mangle]` attribute.
2025-10-18 08:08:36 +02:00
Camille GILLOT ca0379d6cd Diagnose liveness on MIR. 2025-10-11 20:50:21 +00:00
Folkert de Vries 9db778155e add indirect call example to track-caller-ffi.rs 2025-10-02 20:53:13 +02:00
Folkert de Vries 20d62469ba the #[track_caller] shim should not inherit #[no_mangle] 2025-10-02 20:53:12 +02:00
Guillaume Gomez a535c7be54 Ignore more failing ui tests for GCC backend 2025-09-26 15:33:48 +02:00
Alice Ryhl 46727f4cb0 Stabilize file_as_c_str 2025-08-29 08:33:54 +00:00
Alice Ryhl dacae07b6d Rename Location::file_with_nul to file_as_c_str 2025-08-27 12:42:49 +00:00
Esteban Küber 049c32797b On E0277, point at type that doesn't implement bound
When encountering an unmet trait bound, point at local type that doesn't implement the trait:

```
error[E0277]: the trait bound `Bar<T>: Foo` is not satisfied
  --> $DIR/issue-64855.rs:9:19
   |
LL | pub struct Bar<T>(<Self as Foo>::Type) where Self: ;
   |                   ^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
   |
help: the trait `Foo` is not implemented for `Bar<T>`
  --> $DIR/issue-64855.rs:9:1
   |
LL | pub struct Bar<T>(<Self as Foo>::Type) where Self: ;
   | ^^^^^^^^^^^^^^^^^
```
2025-08-22 17:55:15 +00:00
Jana Dönszelmann 2158e2d4d7 refactor target checking, move out of context.rs and rename MaybeWarn to Policy 2025-08-21 13:15:30 +02:00
lcnr 8365ad17da handle opaque types before region inference 2025-08-20 11:04:38 +02:00
Karol Zwolak d14b83e378 bless tests with new lint messages 2025-08-19 21:27:10 +02:00
Jacob Pratt 7a05f26a3b Rollup merge of #144054 - jsimmons:stabilize-as-array-of-cells, r=tgross35
Stabilize as_array_of_cells

This PR stabilizes

```rust
impl<T, const N: usize> Cell<[T; N]> {
    pub const fn as_array_of_cells(&self) -> &[Cell<T>; N];
}
```

Stabilization report: https://github.com/rust-lang/rust/issues/88248#issuecomment-3082986863
Closes: https://github.com/rust-lang/rust/issues/88248
2025-08-15 18:13:27 -04:00
bors 3507a749b3 Auto merge of #145407 - Kobzol:rollup-g6yhx82, r=Kobzol
Rollup of 11 pull requests

Successful merges:

 - rust-lang/rust#137872 (Include whitespace in "remove |" suggestion and make it hidden)
 - rust-lang/rust#144631 (Fix test intrinsic-raw_eq-const-bad for big-endian)
 - rust-lang/rust#145233 (cfg_select: Support unbraced expressions)
 - rust-lang/rust#145261 (Improve tracing in bootstrap)
 - rust-lang/rust#145324 (Rename and document `ONLY_HOSTS` in bootstrap)
 - rust-lang/rust#145353 (bootstrap: Fix jemalloc 64K page support for aarch64 tools)
 - rust-lang/rust#145379 (bootstrap: Support passing `--timings` to cargo)
 - rust-lang/rust#145397 (Rust documentation, use `rustc-dev-guide` :3)
 - rust-lang/rust#145398 (Use `default_field_values` in `Resolver`)
 - rust-lang/rust#145401 (cleanup: Remove useless `[T].iter().last()`)
 - rust-lang/rust#145403 (Adjust error message grammar to be less awkward)

r? `@ghost`
`@rustbot` modify labels: rollup
2025-08-14 23:30:10 +00:00
Jakub Beránek 18afb69767 Rollup merge of #137872 - estebank:extra-vert, r=compiler-errors
Include whitespace in "remove |" suggestion and make it hidden

Tweak error rendering of patterns with an extra `|` on either end.

Built on #137409. Only last commit is relevant.

? ``@compiler-errors``
2025-08-14 21:48:41 +02:00
Jonathan Brouwer 4bb7bf64e0 Update uitests
Signed-off-by: Jonathan Brouwer <jonathantbrouwer@gmail.com>
2025-08-14 18:18:42 +02:00
Stuart Cook 9d989bf1cf Rollup merge of #145115 - lcnr:less-borrowck-tainting, r=compiler-errors
defer opaque type errors, generally greatly reduce tainting

fixes the test for rust-lang/rust#135528, does not actually fix that issue properly.

This is useful as it causes the migration to rust-lang/rust#139587 to be a lot easier.
2025-08-09 13:58:53 +10:00
Josh Triplett 2054a0c56b mbe: In error messages, don't assume attributes are always proc macros
Now that `macro_rules` macros can define attribute rules, make sure
error messages account for that.
2025-08-08 10:35:47 -07:00
lcnr 4eee55691a borrowck: defer opaque type errors 2025-08-08 19:24:53 +02:00
Esteban Küber 2db126d651 Include whitespace in "remove |" suggestion and make it hidden 2025-08-04 18:06:18 +00:00
Vadim Petrochenkov c56f49dc34 expand: Micro-optimize prelude injection
Use `splice` to avoid shifting the other items twice.
Put `extern crate std;` first so it's already resolved when we resolve `::std::prelude::rust_20XX`.
2025-07-28 17:35:09 +03:00
Jacob Pratt c92d61d121 Rollup merge of #144409 - GuillaumeGomez:macro-expansion-early-abort, r=oli-obk
Stop compilation early if macro expansion failed

Fixes rust-lang/rust#116180.

So there isn't really a type that is central for macro expansion and some errors are actually emitted (because the resolution happens after the expansion I suppose) after the expansion pass (like "not found macro"). Sometimes, errors are only emitted on the second "try" (to improve error output). So I couldn't reach a similar solution than what was done in https://github.com/rust-lang/rust/pull/133937 and suggested by ````@estebank```` in https://github.com/rust-lang/rust/issues/116180#issuecomment-3109468922. But maybe I missed something?

So in the end, I realized that there is method called every time (except one, described below) a macro error is actually emitted: `ExtCtxt::trace_macros_diag`. Considering I updated what it did, I renamed it into `macro_error_and_trace_macros_diag` to better reflect it.

There is only one call of `trace_macros_diag` which isn't reporting an error but just used for `macro_trace` feature, so I kept it as is.

r? ````@oli-obk````
2025-07-26 22:42:35 -04:00
Trevor Gross 6b1b68f4ee Rollup merge of #144356 - GuillaumeGomez:gcc-ignore-tests, r=jieyouxu
Add `ignore-backends` annotations in failing GCC backend ui tests

Follow-up of https://github.com/rust-lang/rust/pull/144125.

In the GCC backend, we don't support all ui tests yet and we have a list of tests we currently ignore available [here](https://github.com/rust-lang/rustc_codegen_gcc/blob/master/tests/failing-ui-tests.txt).

This PR adds the `ignore-backends` annotations to the corresponding ui tests.

The second commit is a fix to compiletest, complaining about `ignore-backends`.

r? ```@jieyouxu```
2025-07-26 01:15:08 -05:00
Guillaume Gomez 272513868f Update ui tests with new macro early erroring 2025-07-25 23:46:28 +02:00
Guillaume Gomez de93fb13fe Add ignore-backends annotations in failing GCC backend ui tests 2025-07-23 13:48:04 +02:00
Josh Simmons 14c6e50d47 Stabilize as_array_of_cells 2025-07-17 09:11:44 +02:00
dianne 41e6f767b6 future-incompat lints: don't link to the nightly edition-guide version 2025-07-16 01:44:02 -07:00
Jonathan Brouwer 027126ce0b Port #[non_exhaustive] to the new attribute parsing infrastructure 2025-07-04 20:30:42 +02:00
bors 1ce9c977ff Auto merge of #143214 - camsteffen:remove-let-chains-feature, r=est31
Remove let_chains unstable feature

Per https://github.com/rust-lang/rust/issues/53667#issuecomment-3016742982 (but then I also noticed rust-lang/rust#140722)

This replaces the feature gate with a parser error that says let chains require 2024.

A lot of tests were using the unstable feature. I either added edition:2024 to the test or split out the parts that require 2024.
2025-07-02 17:18:47 +00:00
Cameron Steffen dc9879cb3d Remove let_chains feature 2025-06-30 07:49:20 -05:00
Oli Scherer 6166cd6b50 Avoid looking at HIR for trait and impl items 2025-06-30 08:45:43 +00:00
Jana Dönszelmann f9cdf3fd74 fix 142783 2025-06-24 23:00:31 +02:00
Jana Dönszelmann 5c0a625205 move naked checks out of check_attr.rs 2025-06-23 12:22:57 +02:00
mejrs 29ce695cd4 Stop dbg! macro yapping about format modifiers 2025-06-22 10:58:27 +02:00