-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Conversation
This comment has been minimized.
This comment has been minimized.
90695a5
to
b882e13
Compare
This comment has been minimized.
This comment has been minimized.
b882e13
to
3679fde
Compare
…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.
This comment has been minimized.
This comment has been minimized.
☀️ Try build successful - checks-actions |
@craterbot check |
👌 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
3679fde
to
d3841fb
Compare
@bors try |
…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.
🚧 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
☀️ Try build successful - checks-actions |
@craterbot cancel |
🗑️ Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
@craterbot check |
👌 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
dc3b1ae
to
4a2e3bc
Compare
@bors r=lcnr rollup=never |
☀️ Test successful - checks-actions |
Finished benchmarking commit (878c8a2): comparison URL. Overall result: ❌ regressions - no action needed@rustbot label: -perf-regression Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)This benchmark run did not return any relevant results for this metric. CyclesThis benchmark run did not return any relevant results for this metric. Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 650.957s -> 651.156s (0.03%) |
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)
…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
…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
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
…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).
…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).
…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).
@@ -7,5 +7,21 @@ LL | WHAT_A_TYPE => 0, | |||
= note: the traits must be derived, manual `impl`s are not sufficient | |||
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details | |||
|
|||
error: aborting due to 1 previous error | |||
error[E0277]: the trait bound `for<'a, 'b> fn(&'a (), &'b ()): WithAssoc<T>` is not satisfied |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@spastorino sorry to necro this PR, but this test is (even still on master today) labeled as known-bug and those should have been removed.(at least for 97156, not sure what's going on with the other)...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
… r=jackh726 Remove redundant test typeid equality by subtyping This known-bug label was a left over on rust-lang#118247 r? `@jackh726` This doesn't address rust-lang#110395, I didn't investigate about it yet.
Rollup merge of rust-lang#130482 - spastorino:remove-known-bug-97156, r=jackh726 Remove redundant test typeid equality by subtyping This known-bug label was a left over on rust-lang#118247 r? `@jackh726` This doesn't address rust-lang#110395, I didn't investigate about it yet.
summary by @spastorino and @lcnr
Context
The following code:
has UB from hitting the
unreachable_unchecked
. This happens becauseTypeId::of::<One>()
is not the same asTypeId::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 iffor<'a> exists<'b> T<'b> <: T'<a> AND for<'b> exists<'a> T<'a> <: T<'b>
holds. This results infor<'a> fn(&'a (), &'a ())
andfor<'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 differentTypeId
. 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 typeFoo::<One>
to a binding of typeFoo<Two>
given those are considered the same type but then when we callderef
, it callsdowncast_ref
that relies onTypeId
and we would hit theNone
arm as these have differentTypeId
s.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
TypeId
s 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:
for<'a> fn(&'a (), &'a ())
andfor<'a, 'b> fn(&'a (), &'b ())
to be equal, but normalize them to a common representation so that theirTypeId
are also the same.for<'a> fn(&'a (), &'a ())
andfor<'a, 'b> fn(&'a (), &'b ())
still have differentTypeId
s but are now also considered to not be semantically equal.Advantages of the first approach:
General thoughts:
Advantages of the second approach:
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:
to
Fixes #97156
r? @lcnr