Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change equate for binders to not rely on subtyping #118247

Merged
merged 3 commits into from
Feb 29, 2024

Conversation

spastorino
Copy link
Member

@spastorino spastorino commented Nov 24, 2023

summary by @spastorino and @lcnr

Context

The following code:

type One = for<'a> fn(&'a (), &'a ());
type Two = for<'a, 'b> fn(&'a (), &'b ());

mod my_api {
    use std::any::Any;
    use std::marker::PhantomData;

    pub struct Foo<T: 'static> {
        a: &'static dyn Any,
        _p: PhantomData<*mut T>, // invariant, the type of the `dyn Any`
    }
    
    impl<T: 'static> Foo<T> {
        pub fn deref(&self) -> &'static T {
            match self.a.downcast_ref::<T>() {
                None => unsafe { std::hint::unreachable_unchecked() },
                Some(a) => a,
            }
        }
        
        pub fn new(a: T) -> Foo<T> {
           Foo::<T> {
                a: Box::leak(Box::new(a)),
                _p: PhantomData,
            } 
        }
    }
}

use my_api::*;

fn main() {
    let foo = Foo::<One>::new((|_, _| ()) as One);
    foo.deref();
    let foo: Foo<Two> = foo;
    foo.deref();
}

has UB from hitting the unreachable_unchecked. This happens because TypeId::of::<One>() is not the same as TypeId::of::<Two>() despite them being considered the same types by the type checker.

Currently the type checker considers binders to be equal if subtyping succeeds in both directions: for<'a> T<'a> eq for<'b> U<'b> holds if for<'a> exists<'b> T<'b> <: T'<a> AND for<'b> exists<'a> T<'a> <: T<'b> holds. This results in for<'a> fn(&'a (), &'a ()) and for<'a, 'b> fn(&'a (), &'b ()) being equal in the type system.

TypeId is computed by looking at the structure of a type. Even though these types are semantically equal, they have a different structure resulting in them having different TypeId. This can break invariants of unsafe code at runtime and is unsound when happening at compile time, e.g. when using const generics.

So as seen in main, we can assign a value of type Foo::<One> to a binding of type Foo<Two> given those are considered the same type but then when we call deref, it calls downcast_ref that relies on TypeId and we would hit the None arm as these have different TypeIds.

As stated in #97156 (comment), this causes the API of existing crates to be unsound.

What should we do about this

The same type resulting in different TypeIds is a significant footgun, breaking a very reasonable assumptions by authors of unsafe code. It will also be unsound by itself once they are usable in generic contexts with const generics.

There are two options going forward here:

  • change how the structure of a type is computed before relying on it. i.e. continue considering for<'a> fn(&'a (), &'a ()) and for<'a, 'b> fn(&'a (), &'b ()) to be equal, but normalize them to a common representation so that their TypeId are also the same.
  • change how the semantic equality of binders to match the way we compute the structure of types. i.e. for<'a> fn(&'a (), &'a ()) and for<'a, 'b> fn(&'a (), &'b ()) still have different TypeIds but are now also considered to not be semantically equal.

Advantages of the first approach:

  • with the second approach some higher ranked types stop being equal, even though they are subtypes of each other

General thoughts:

  • changing the approach in the future will be breaking
    • going from first to second may break ordinary type checking, as types which were previously equal are now distinct
    • going from second to first may break coherence, because previously disjoint impls overlap as the used types are now equal
    • both of these are quite unlikely. This PR did not result in any crater failures, so this should not matter too much

Advantages of the second approach:

  • the soundness of the first approach requires more non-local reasoning. We have to make sure that changes to subtyping do not cause the representative computation to diverge from semantic equality
  • computing a representative type is non-trivial and soundness critical, therefore adding complexity to the "core type system"

This PR goes with the second approach. A crater run did not result in any regressions. I am personally very hesitant about trying the first approach due to the above reasons. It feels like there are more unknowns when going that route.

Changing the way we equate binders

Relating bound variables from different depths already results in a universe error in equate. We therefore only need to make sure that there is 1-to-1 correspondence between bound variables when relating binders. This results in concrete types being structurally equal after anonymizing their bound variables.

We implement this by instantiating one of the binder with placeholders and the other with inference variables and then equating the instantiated types. We do so in both directions.

More formally, we change the typing rules as follows:

for<'r0, .., 'rn> exists<'l0, .., 'ln> LHS<'l0, .., 'ln> <: RHS<'r0, .., 'rn>
for<'l0, .., 'ln> exists<'r0, .., 'rn> RHS<'r0, .., 'rn> <: LHS<'l0, .., 'ln>
--------------------------------------------------------------------------
for<'l0, .., 'ln> LHS<'l0, .., 'ln> eq for<'r0, .., 'rn> RHS<'r0, .., 'rn>

to

for<'r0, .., 'rn> exists<'l0, .., 'ln> LHS<'l0, .., 'ln> eq RHS<'r0, .., 'rn>
for<'l0, .., 'ln> exists<'r0, .., 'rn> RHS<'r0, .., 'rn> eq LHS<'l0, .., 'ln>
--------------------------------------------------------------------------
for<'l0, .., 'ln> LHS<'l0, .., 'ln> eq for<'r0, .., 'rn> RHS<'r0, .., 'rn>

Fixes #97156

r? @lcnr

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative labels Nov 24, 2023
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@spastorino
Copy link
Member Author

Firing a crater run as failing tests are related to nightly features and are going to be fixed as soon as PRs like #118118 land.

@bors try

@bors
Copy link
Contributor

bors commented Nov 24, 2023

⌛ Trying commit 3679fde with merge 5698a58...

bors added a commit to rust-lang-ci/rust that referenced this pull request Nov 24, 2023
…r=<try>

Fix for TypeId exposes equality-by-subtyping vs normal-form-syntactic-equality unsoundness

Fixes rust-lang#97156

This PR revives rust-lang#97427 idea, it sits on top of rust-lang#118118 because the idea uncovered some problems with IATs.

r? `@lcnr`

This is ICEing yet for `tests/ui/traits/new-solver/escaping-bound-vars-in-writeback-normalization.rs` using the new trait solver.
After rust-lang#118118 and this ICE is fixed, we would need a rebase and a crater run.

Opening as a WIP for now.
@rust-log-analyzer

This comment has been minimized.

@bors
Copy link
Contributor

bors commented Nov 24, 2023

☀️ Try build successful - checks-actions
Build commit: 5698a58 (5698a58b0ad644406b5e61434ba7c63af6e05169)

@spastorino
Copy link
Member Author

@craterbot check

@craterbot
Copy link
Collaborator

👌 Experiment pr-118247 created and queued.
🤖 Automatically detected try build 5698a58
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 25, 2023
@spastorino
Copy link
Member Author

@bors try

@bors
Copy link
Contributor

bors commented Nov 28, 2023

⌛ Trying commit d3841fb with merge ab2dc84...

bors added a commit to rust-lang-ci/rust that referenced this pull request Nov 28, 2023
…r=<try>

Fix for TypeId exposes equality-by-subtyping vs normal-form-syntactic-equality unsoundness

Fixes rust-lang#97156

This PR revives rust-lang#97427 idea, it sits on top of rust-lang#118118 because the idea uncovered some problems with IATs.

r? `@lcnr`

This is ICEing yet for `tests/ui/traits/new-solver/escaping-bound-vars-in-writeback-normalization.rs` using the new trait solver.
After rust-lang#118118 and this ICE is fixed, we would need a rebase and a crater run.

Opening as a WIP for now.
@craterbot
Copy link
Collaborator

🚧 Experiment pr-118247 is now running

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@bors
Copy link
Contributor

bors commented Nov 28, 2023

☀️ Try build successful - checks-actions
Build commit: ab2dc84 (ab2dc84cfc2c30bb279a7cd2bfef172c30260142)

@spastorino
Copy link
Member Author

@craterbot cancel

@craterbot
Copy link
Collaborator

🗑️ Experiment pr-118247 deleted!

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-crater Status: Waiting on a crater run to be completed. labels Nov 28, 2023
@spastorino
Copy link
Member Author

@craterbot check

@craterbot
Copy link
Collaborator

👌 Experiment pr-118247 created and queued.
🤖 Automatically detected try build ab2dc84
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

Copy link
Contributor

@lcnr lcnr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r=me after final nits

tests/ui/coherence/coherence-fn-inputs.rs Outdated Show resolved Hide resolved
tests/ui/coherence/coherence-free-regions.rs Outdated Show resolved Hide resolved
@apiraino apiraino removed the to-announce Announce this issue on triage meeting label Feb 29, 2024
@spastorino
Copy link
Member Author

@bors r=lcnr rollup=never

@bors
Copy link
Contributor

bors commented Feb 29, 2024

📌 Commit 4a2e3bc has been approved by lcnr

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-blocked Status: Marked as blocked ❌ on something else such as an RFC or other implementation work. labels Feb 29, 2024
@bors
Copy link
Contributor

bors commented Feb 29, 2024

⌛ Testing commit 4a2e3bc with merge 878c8a2...

@bors
Copy link
Contributor

bors commented Feb 29, 2024

☀️ Test successful - checks-actions
Approved by: lcnr
Pushing 878c8a2 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Feb 29, 2024
@bors bors merged commit 878c8a2 into rust-lang:master Feb 29, 2024
12 checks passed
@rustbot rustbot added this to the 1.78.0 milestone Feb 29, 2024
@bors bors mentioned this pull request Feb 29, 2024
@rust-timer
Copy link
Collaborator

Finished benchmarking commit (878c8a2): comparison URL.

Overall result: ❌ regressions - no action needed

@rustbot label: -perf-regression

Instruction count

This is a highly reliable metric that was used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
0.5% [0.4%, 1.0%] 7
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Max RSS (memory usage)

This benchmark run did not return any relevant results for this metric.

Cycles

This benchmark run did not return any relevant results for this metric.

Binary size

This benchmark run did not return any relevant results for this metric.

Bootstrap: 650.957s -> 651.156s (0.03%)
Artifact size: 311.09 MiB -> 311.50 MiB (0.13%)

wip-sync pushed a commit to NetBSD/pkgsrc-wip that referenced this pull request May 4, 2024
Pkgsrc changes:
 * Adapt checksums and patches, some have beene intregrated upstream.

Upstream chnages:

Version 1.78.0 (2024-05-02)
===========================

Language
--------
- [Stabilize `#[cfg(target_abi = ...)]`]
  (rust-lang/rust#119590)
- [Stabilize the `#[diagnostic]` namespace and
  `#[diagnostic::on_unimplemented]` attribute]
  (rust-lang/rust#119888)
- [Make async-fn-in-trait implementable with concrete signatures]
  (rust-lang/rust#120103)
- [Make matching on NaN a hard error, and remove the rest of
  `illegal_floating_point_literal_pattern`]
  (rust-lang/rust#116284)
- [static mut: allow mutable reference to arbitrary types, not just
  slices and arrays]
  (rust-lang/rust#117614)
- [Extend `invalid_reference_casting` to include references casting
  to bigger memory layout]
  (rust-lang/rust#118983)
- [Add `non_contiguous_range_endpoints` lint for singleton gaps
  after exclusive ranges]
  (rust-lang/rust#118879)
- [Add `wasm_c_abi` lint for use of older wasm-bindgen versions]
  (rust-lang/rust#117918)
  This lint currently only works when using Cargo.
- [Update `indirect_structural_match` and `pointer_structural_match`
  lints to match RFC]
  (rust-lang/rust#120423)
- [Make non-`PartialEq`-typed consts as patterns a hard error]
  (rust-lang/rust#120805)
- [Split `refining_impl_trait` lint into `_reachable`, `_internal` variants]
  (rust-lang/rust#121720)
- [Remove unnecessary type inference when using associated types
  inside of higher ranked `where`-bounds]
  (rust-lang/rust#119849)
- [Weaken eager detection of cyclic types during type inference]
  (rust-lang/rust#119989)
- [`trait Trait: Auto {}`: allow upcasting from `dyn Trait` to `dyn Auto`]
  (rust-lang/rust#119338)

Compiler
--------

- [Made `INVALID_DOC_ATTRIBUTES` lint deny by default]
  (rust-lang/rust#111505)
- [Increase accuracy of redundant `use` checking]
  (rust-lang/rust#117772)
- [Suggest moving definition if non-found macro_rules! is defined later]
  (rust-lang/rust#121130)
- [Lower transmutes from int to pointer type as gep on null]
  (rust-lang/rust#121282)

Target changes:

- [Windows tier 1 targets now require at least Windows 10]
  (rust-lang/rust#115141)
 - [Enable CMPXCHG16B, SSE3, SAHF/LAHF and 128-bit Atomics in tier 1 Windows]
  (rust-lang/rust#120820)
- [Add `wasm32-wasip1` tier 2 (without host tools) target]
  (rust-lang/rust#120468)
- [Add `wasm32-wasip2` tier 3 target]
  (rust-lang/rust#119616)
- [Rename `wasm32-wasi-preview1-threads` to `wasm32-wasip1-threads`]
  (rust-lang/rust#122170)
- [Add `arm64ec-pc-windows-msvc` tier 3 target]
  (rust-lang/rust#119199)
- [Add `armv8r-none-eabihf` tier 3 target for the Cortex-R52]
  (rust-lang/rust#110482)
- [Add `loongarch64-unknown-linux-musl` tier 3 target]
  (rust-lang/rust#121832)

Refer to Rust's [platform support page][platform-support-doc]
for more information on Rust's tiered platform support.

Libraries
---------

- [Bump Unicode to version 15.1.0, regenerate tables]
  (rust-lang/rust#120777)
- [Make align_offset, align_to well-behaved in all cases]
  (rust-lang/rust#121201)
- [PartialEq, PartialOrd: document expectations for transitive chains]
  (rust-lang/rust#115386)
- [Optimize away poison guards when std is built with panic=abort]
  (rust-lang/rust#100603)
- [Replace pthread `RwLock` with custom implementation]
  (rust-lang/rust#110211)
- [Implement unwind safety for Condvar on all platforms]
  (rust-lang/rust#121768)
- [Add ASCII fast-path for `char::is_grapheme_extended`]
  (rust-lang/rust#121138)

Stabilized APIs
---------------

- [`impl Read for &Stdin`]
  (https://doc.rust-lang.org/stable/std/io/struct.Stdin.html#impl-Read-for-%26Stdin)
- [Accept non `'static` lifetimes for several `std::error::Error`
  related implementations] (rust-lang/rust#113833)
- [Make `impl<Fd: AsFd>` impl take `?Sized`]
  (rust-lang/rust#114655)
- [`impl From<TryReserveError> for io::Error`]
  (https://doc.rust-lang.org/stable/std/io/struct.Error.html#impl-From%3CTryReserveError%3E-for-Error)

These APIs are now stable in const contexts:

- [`Barrier::new()`]
  (https://doc.rust-lang.org/stable/std/sync/struct.Barrier.html#method.new)

Cargo
-----

- [Stabilize lockfile v4](rust-lang/cargo#12852)
- [Respect `rust-version` when generating lockfile]
  (rust-lang/cargo#12861)
- [Control `--charset` via auto-detecting config value]
  (rust-lang/cargo#13337)
- [Support `target.<triple>.rustdocflags` officially]
  (rust-lang/cargo#13197)
- [Stabilize global cache data tracking]
  (rust-lang/cargo#13492)

Misc
----

- [rustdoc: add `--test-builder-wrapper` arg to support wrappers
  such as RUSTC_WRAPPER when building doctests]
  (rust-lang/rust#114651)

Compatibility Notes
-------------------

- [Many unsafe precondition checks now run for user code with debug
  assertions enabled] (rust-lang/rust#120594)
  This change helps users catch undefined behavior in their code,
  though the details of how much is checked are generally not
  stable.
- [riscv only supports split_debuginfo=off for now]
  (rust-lang/rust#120518)
- [Consistently check bounds on hidden types of `impl Trait`]
  (rust-lang/rust#121679)
- [Change equality of higher ranked types to not rely on subtyping]
  (rust-lang/rust#118247)
- [When called, additionally check bounds on normalized function return type]
  (rust-lang/rust#118882)
- [Expand coverage for `arithmetic_overflow` lint]
  (rust-lang/rust#119432)

Internal Changes
----------------

These changes do not affect any public interfaces of Rust, but they represent
significant improvements to the performance or internals of rustc and related
tools.

- [Update to LLVM 18](rust-lang/rust#120055)
- [Build `rustc` with 1CGU on `x86_64-pc-windows-msvc`]
  (rust-lang/rust#112267)
- [Build `rustc` with 1CGU on `x86_64-apple-darwin`]
  (rust-lang/rust#112268)
- [Introduce `run-make` V2 infrastructure, a `run_make_support`
  library and port over 2 tests as example]
  (rust-lang/rust#113026)
- [Windows: Implement condvar, mutex and rwlock using futex]
  (rust-lang/rust#121956)
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Aug 14, 2024
…type, r=lcnr

Record the correct target type when coercing fn items/closures to pointers

Self-explanatory. We were previously not recording the *target* type of a coercion as the output of an adjustment. This should remedy that.

We must also modify the function pointer casts in MIR typeck to use subtyping, since those broke since rust-lang#118247.

r? lcnr
jieyouxu added a commit to jieyouxu/rust that referenced this pull request Aug 14, 2024
…type, r=lcnr

Record the correct target type when coercing fn items/closures to pointers

Self-explanatory. We were previously not recording the *target* type of a coercion as the output of an adjustment. This should remedy that.

We must also modify the function pointer casts in MIR typeck to use subtyping, since those broke since rust-lang#118247.

r? lcnr
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Aug 14, 2024
Rollup merge of rust-lang#129059 - compiler-errors:subtyping-correct-type, r=lcnr

Record the correct target type when coercing fn items/closures to pointers

Self-explanatory. We were previously not recording the *target* type of a coercion as the output of an adjustment. This should remedy that.

We must also modify the function pointer casts in MIR typeck to use subtyping, since those broke since rust-lang#118247.

r? lcnr
bors added a commit to rust-lang-ci/rust that referenced this pull request Sep 6, 2024
…verge-but-more, r=<try>

Do not consider match/let/ref of place that evaluates to `!` to diverge, disallow coercions from them too

Fixes rust-lang#117288.

This PR does two things:

### Don't consider `match`/`let`/`ref`/assignment-LHS of a place expression that evaluates to `!` to diverge.

Which fixes this unsoundness:

```
fn make_up_a_value<T>() -> T {
    unsafe {
        let x: *const ! = &0 as *const u8 as *const !;
        let _ = *x;
    }
}
```

Before this PR, it was UB since we consider the `unsafe` block to diverge which means the outer block evalutes to `!`, even though we've never actually *read* a value of type `!`.

### Do not perform coercions of those same place expressions.

Which fixes this inadvertent, sneaky unsoundness:

```
unsafe {
    let x: *const ! = &0 as *const u8 as *const !;
    let _: () = *x;
}
```

which is UB because currently rust emits an *implicit* NeverToAny coercion even though we really shouldn't be, since there's no read of the value pointed by `x`.

---

Detecting both of these situations is implemented in a heuristic function called `expr_consitutes_read`. It is tasked with detecting the situations where we have a place expression being passed to some parent expression that would not constitute a read necessarily, like a `let _ = *never_ptr` where `never_ptr: *const !`.

---

Specifically, for `let` and `match`, we don't consider it to be a read unless any of the subpatterns (i.e. the LHS of the `let` or the arms of the match) constitute a read. Almost all patterns constitute a read except for `_`, an `|` pattern, or the currently experimental `!` pattern.

---

I'm not totally certain that this deserves an FCP, since it's really a bugfix for UB. If it does, I'd be comfortable with it being a T-types FCP since we should be responsible with determining which coercions in the type system are sound (similar to how we adjusted subtyping behavior in rust-lang#118247 to be more sound).
bors added a commit to rust-lang-ci/rust that referenced this pull request Sep 6, 2024
…verge-but-more, r=<try>

Do not consider match/let/ref of place that evaluates to `!` to diverge, disallow coercions from them too

Fixes rust-lang#117288.

This PR does two things:

### Don't consider `match`/`let`/`ref`/assignment-LHS of a place expression that evaluates to `!` to diverge.

Which fixes this unsoundness:

```
fn make_up_a_value<T>() -> T {
    unsafe {
        let x: *const ! = &0 as *const u8 as *const !;
        let _ = *x;
    }
}
```

Before this PR, it was UB since we consider the `unsafe` block to diverge which means the outer block evalutes to `!`, even though we've never actually *read* a value of type `!`.

### Do not perform coercions of those same place expressions.

Which fixes this inadvertent, sneaky unsoundness:

```
unsafe {
    let x: *const ! = &0 as *const u8 as *const !;
    let _: () = *x;
}
```

which is UB because currently rust emits an *implicit* NeverToAny coercion even though we really shouldn't be, since there's no read of the value pointed by `x`.

---

Detecting both of these situations is implemented in a heuristic function called `expr_consitutes_read`. It is tasked with detecting the situations where we have a place expression being passed to some parent expression that would not constitute a read necessarily, like a `let _ = *never_ptr` where `never_ptr: *const !`.

---

Specifically, for `let` and `match`, we don't consider it to be a read unless any of the subpatterns (i.e. the LHS of the `let` or the arms of the match) constitute a read. Almost all patterns constitute a read except for `_`, an `|` pattern, or the currently experimental `!` pattern.

---

I'm not totally certain that this deserves an FCP, since it's really a bugfix for UB. If it does, I'd be comfortable with it being a T-types FCP since we should be responsible with determining which coercions in the type system are sound (similar to how we adjusted subtyping behavior in rust-lang#118247 to be more sound).
bors added a commit to rust-lang-ci/rust that referenced this pull request Sep 6, 2024
…verge-but-more, r=<try>

Do not consider match/let/ref of place that evaluates to `!` to diverge, disallow coercions from them too

Fixes rust-lang#117288.

This PR does two things:

### Don't consider `match`/`let`/`ref`/assignment-LHS of a place expression that evaluates to `!` to diverge.

Which fixes this unsoundness:

```
fn make_up_a_value<T>() -> T {
    unsafe {
        let x: *const ! = &0 as *const u8 as *const !;
        let _ = *x;
    }
}
```

Before this PR, it was UB since we consider the `unsafe` block to diverge which means the outer block evalutes to `!`, even though we've never actually *read* a value of type `!`.

### Do not perform coercions of those same place expressions.

Which fixes this inadvertent, sneaky unsoundness:

```
unsafe {
    let x: *const ! = &0 as *const u8 as *const !;
    let _: () = *x;
}
```

which is UB because currently rust emits an *implicit* NeverToAny coercion even though we really shouldn't be, since there's no read of the value pointed by `x`.

---

Detecting both of these situations is implemented in a heuristic function called `expr_consitutes_read`. It is tasked with detecting the situations where we have a place expression being passed to some parent expression that would not constitute a read necessarily, like a `let _ = *never_ptr` where `never_ptr: *const !`.

---

Specifically, for `let` and `match`, we don't consider it to be a read unless any of the subpatterns (i.e. the LHS of the `let` or the arms of the match) constitute a read. Almost all patterns constitute a read except for `_`, an `|` pattern, or the currently experimental `!` pattern.

---

I'm not totally certain that this deserves an FCP, since it's really a bugfix for UB. If it does, I'd be comfortable with it being a T-types FCP since we should be responsible with determining which coercions in the type system are sound (similar to how we adjusted subtyping behavior in rust-lang#118247 to be more sound).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. merged-by-bors This PR was explicitly merged by bors. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-types Relevant to the types team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative
Projects
None yet
Development

Successfully merging this pull request may close these issues.

TypeId exposes equality-by-subtyping vs normal-form-syntactic-equality unsoundness.