From 5a2e2a954bb4b74de5d99f6ddbc9ab41b141d0e7 Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 20 Dec 2024 15:22:36 +0000 Subject: [PATCH 01/12] add relnotes --- RELEASES.md | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 99733bade32c4..18ddb54f919c7 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,117 @@ +Version 1.84.0 (2025-01-09) +========================== + + + +Language +-------- +- [Allow `#[deny]` inside `#[forbid]` as a no-op](https://github.com/rust-lang/rust/pull/121560/) +- [Show a warning when `-Ctarget-feature` is used to toggle features that can lead to unsoundness due to ABI mismatches](https://github.com/rust-lang/rust/pull/129884) +- [Use the next-generation trait solver in coherence](https://github.com/rust-lang/rust/pull/130654) +- [Allow coercions to drop the principal of trait objects](https://github.com/rust-lang/rust/pull/131857) +- [Support `/` as the path separator for `include!()` in all cases on Windows](https://github.com/rust-lang/rust/pull/125205) +- [Taking a raw ref (`raw (const|mut)`) of a deref of a pointer (`*ptr`) is now safe](https://github.com/rust-lang/rust/pull/129248) +- [Stabilize s390x inline assembly](https://github.com/rust-lang/rust/pull/131258) +- [Stabilize Arm64EC inline assembly](https://github.com/rust-lang/rust/pull/131781) +- [Lint against creating pointers to immediately dropped temporaries](https://github.com/rust-lang/rust/pull/128985) +- [Execute drop glue when unwinding in an `extern "C"` function](https://github.com/rust-lang/rust/pull/129582) + + + +Compiler +-------- +- [Add `--print host-tuple` flag to print the host target tuple and affirm the "target tuple" terminology over "target triple"](https://github.com/rust-lang/rust/pull/125579) +- [Declaring functions with a calling convention not supported on the current target now triggers a hard error](https://github.com/rust-lang/rust/pull/129935) +- [Set up indirect access to external data for `loongarch64-unknown-linux-{musl,ohos}`](https://github.com/rust-lang/rust/pull/131583) +- [Enable XRay instrumentation for LoongArch Linux targets](https://github.com/rust-lang/rust/pull/131818) +- [Extend the `unexpected_cfgs` lint to also warn in external macros](https://github.com/rust-lang/rust/pull/132577) +- [Stabilize WebAssembly `multivalue`, `reference-types`, and `tail-call` target features](https://github.com/rust-lang/rust/pull/131080) +- [Added Tier 2 support for the `wasm32v1-none` target](https://github.com/rust-lang/rust/pull/131487) + + + +Libraries +--------- +- [Implement `From<&mut {slice}>` for `Box/Rc/Arc<{slice}>`](https://github.com/rust-lang/rust/pull/129329) +- [Move `::copysign`, `::abs`, `::signum` to `core`](https://github.com/rust-lang/rust/pull/131304) +- [Add `LowerExp` and `UpperExp` implementations to `NonZero`](https://github.com/rust-lang/rust/pull/131377) +- [Implement `FromStr` for `CString` and `TryFrom` for `String`](https://github.com/rust-lang/rust/pull/130608) +- [`std::os::darwin` has been made public](https://github.com/rust-lang/rust/pull/130635) + + + +Stabilized APIs +--------------- + +- [`Ipv6Addr::is_unique_local`] +- [`Ipv6Addr::is_unicast_link_local`] +- [`core::ptr::with_exposed_provenance`] +- [`core::ptr::with_exposed_provenance::mut`] +- [`::addr`] +- [`::expose_provenance`] +- [`::with_addr`] +- [`::map_addr`] + +These APIs are now stable in const contexts + +- [`AtomicBool::from_ptr`] +- [`AtomicPtr::from_ptr`] +- [`AtomicU8::from_ptr`] +- [`AtomicU16::from_ptr`] +- [`AtomicU32::from_ptr`] +- [`AtomicU64::from_ptr`] +- [`AtomicUsize::from_ptr`] +- [`AtomicI8::from_ptr`] +- [`AtomicI16::from_ptr`] +- [`AtomicI32::from_ptr`] +- [`AtomicI64::from_ptr`] +- [`AtomicIsize::from_ptr`] +- [`::is_null`] +- [`::as_ref`] +- [`::as_mut`] +- [`core::ptr::without_provenance`] +- [`core::ptr::without_provenance_mut`] +- [`core::ptr::dangling`] +- [`core::ptr::dangling_mut`] +- [`Pin::new`] +- [`Pin::new_unchecked`] +- [`Pin::get_ref`] +- [`Pin::into_ref`] +- [`Pin::get_mut`] +- [`Pin::get_unchecked_mut`] +- [`Pin::static_ref`] +- [`Pin::static_mut`] +- [`::isqrt`] +- [`::checked_isqrt`] +- [`::isqrt`] +- [`NonZero::isqrt`] + + + +Cargo +----- +- [Stabilize MSRV-aware resolver config](https://github.com/rust-lang/cargo/pull/14639/) +- [Stabilize resolver v3](https://github.com/rust-lang/cargo/pull/14754/) + + + +Rustdoc +------- + +- [rustdoc-search: improve type-driven search](https://github.com/rust-lang/rust/pull/127589) + + + +Compatibility Notes +------------------- +- [Enable by default the `LSX` target feature for LoongArch Linux targets](https://github.com/rust-lang/rust/pull/132140) +- [The unstable `-Zprofile` flag (“gcov-style” coverage instrumentation) has been removed.](https://github.com/rust-lang/rust/pull/131829) This does not affect the stable flags for coverage instrumentation (`-Cinstrument-coverage`) and profile-guided optimization (`-Cprofile-generate`, `-Cprofile-use`), which are unrelated and remain available. +- Support for the target named `wasm32-wasi` has been removed as the target is now named `wasm32-wasip1`. This completes the [transition](https://github.com/rust-lang/compiler-team/issues/607) [plan](https://github.com/rust-lang/compiler-team/issues/695) for this target following [the introduction of `wasm32-wasip1`](https://github.com/rust-lang/rust/pull/120468) in Rust 1.78. Compiler warnings on [use of `wasm32-wasi`](https://github.com/rust-lang/rust/pull/126662) introduced in Rust 1.81 are now gone as well as the target is removed. +- [The syntax `&pin (mut|const) T` is now parsed as a type which in theory could affect macro expansion results in some edge cases](https://github.com/rust-lang/rust/pull/130635#issuecomment-2375462821) +- [Legacy syntax for calling `std::arch` functions is no longer permitted to declare items or bodies (such as closures, inline consts, or async blocks).](https://github.com/rust-lang/rust/pull/130443#issuecomment-2445678945) +- The `wasm32-unknown-emscripten` target's binary release of the standard library is now [built with the latest emsdk 3.1.68](https://github.com/rust-lang/rust/pull/131533), which fixes an ABI-incompatibility with Emscripten >= 3.1.42. If you are locally using a version of emsdk with an incompatible ABI (e.g. before 3.1.42 or a future one), you should build your code with `-Zbuild-std` to ensure that `std` uses the correct ABI. + Version 1.83.0 (2024-11-28) ========================== From 575cdf7492f0390d355113a823897a7c7d02357b Mon Sep 17 00:00:00 2001 From: Boxy Date: Fri, 3 Jan 2025 14:08:47 +0000 Subject: [PATCH 02/12] Stabilized APIs --- RELEASES.md | 78 ++++++++++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 18ddb54f919c7..c95ded3b7509b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -44,48 +44,48 @@ Libraries Stabilized APIs --------------- -- [`Ipv6Addr::is_unique_local`] -- [`Ipv6Addr::is_unicast_link_local`] -- [`core::ptr::with_exposed_provenance`] -- [`core::ptr::with_exposed_provenance::mut`] -- [`::addr`] -- [`::expose_provenance`] -- [`::with_addr`] -- [`::map_addr`] +- [`Ipv6Addr::is_unique_local`](https://doc.rust-lang.org/stable/core/net/struct.Ipv6Addr.html#method.is_unique_local) +- [`Ipv6Addr::is_unicast_link_local`](https://doc.rust-lang.org/stable/core/net/struct.Ipv6Addr.html#method.is_unicast_link_local) +- [`core::ptr::with_exposed_provenance`](https://doc.rust-lang.org/stable/core/ptr/fn.with_exposed_provenance.html) +- [`core::ptr::with_exposed_provenance_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.with_exposed_provenance_mut.html) +- [`::addr`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.addr) +- [`::expose_provenance`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.expose_provenance) +- [`::with_addr`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.with_addr) +- [`::map_addr`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.map_addr) +- [`::isqrt`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.isqrt) +- [`::checked_isqrt`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.checked_isqrt) +- [`::isqrt`](https://doc.rust-lang.org/stable/core/primitive.u32.html#method.isqrt) +- [`NonZero::isqrt`](https://doc.rust-lang.org/stable/core/num/struct.NonZero.html#impl-NonZero%3Cu128%3E/method.isqrt) +- [`core::ptr::without_provenance`](https://doc.rust-lang.org/stable/core/ptr/fn.without_provenance.html) +- [`core::ptr::without_provenance_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.without_provenance_mut.html) +- [`core::ptr::dangling`](https://doc.rust-lang.org/stable/core/ptr/fn.dangling.html) +- [`core::ptr::dangling_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.dangling_mut.html) These APIs are now stable in const contexts -- [`AtomicBool::from_ptr`] -- [`AtomicPtr::from_ptr`] -- [`AtomicU8::from_ptr`] -- [`AtomicU16::from_ptr`] -- [`AtomicU32::from_ptr`] -- [`AtomicU64::from_ptr`] -- [`AtomicUsize::from_ptr`] -- [`AtomicI8::from_ptr`] -- [`AtomicI16::from_ptr`] -- [`AtomicI32::from_ptr`] -- [`AtomicI64::from_ptr`] -- [`AtomicIsize::from_ptr`] -- [`::is_null`] -- [`::as_ref`] -- [`::as_mut`] -- [`core::ptr::without_provenance`] -- [`core::ptr::without_provenance_mut`] -- [`core::ptr::dangling`] -- [`core::ptr::dangling_mut`] -- [`Pin::new`] -- [`Pin::new_unchecked`] -- [`Pin::get_ref`] -- [`Pin::into_ref`] -- [`Pin::get_mut`] -- [`Pin::get_unchecked_mut`] -- [`Pin::static_ref`] -- [`Pin::static_mut`] -- [`::isqrt`] -- [`::checked_isqrt`] -- [`::isqrt`] -- [`NonZero::isqrt`] +- [`AtomicBool::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicBool.html#method.from_ptr) +- [`AtomicPtr::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicPtr.html#method.from_ptr) +- [`AtomicU8::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU8.html#method.from_ptr) +- [`AtomicU16::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU16.html#method.from_ptr) +- [`AtomicU32::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU32.html#method.from_ptr) +- [`AtomicU64::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU64.html#method.from_ptr) +- [`AtomicUsize::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicUsize.html#method.from_ptr) +- [`AtomicI8::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicI8.html#method.from_ptr) +- [`AtomicI16::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicI16.html#method.from_ptr) +- [`AtomicI32::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicI32.html#method.from_ptr) +- [`AtomicI64::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicI64.html#method.from_ptr) +- [`AtomicIsize::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicIsize.html#method.from_ptr) +- [`::is_null`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.is_null-1) +- [`::as_ref`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.as_ref-1) +- [`::as_mut`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.as_mut) +- [`Pin::new`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.new) +- [`Pin::new_unchecked`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.new_unchecked) +- [`Pin::get_ref`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.get_ref) +- [`Pin::into_ref`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.into_ref) +- [`Pin::get_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.get_mut) +- [`Pin::get_unchecked_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.get_unchecked_mut) +- [`Pin::static_ref`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.static_ref) +- [`Pin::static_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.static_mut) From db17be84fe7902e663ad78d3bc419b3f32717c52 Mon Sep 17 00:00:00 2001 From: Caio Date: Sun, 5 Jan 2025 20:49:04 -0300 Subject: [PATCH 03/12] [generic_assert] Constify methods used by the formatting system --- library/core/src/fmt/mod.rs | 4 ++-- library/core/src/fmt/rt.rs | 12 ++++++------ tests/ui/consts/const-eval/format.rs | 2 -- tests/ui/consts/const-eval/format.stderr | 24 +++--------------------- 4 files changed, 11 insertions(+), 31 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index c2c78dd9c67eb..a033b8bd30514 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -596,7 +596,7 @@ impl<'a> Arguments<'a> { /// When using the format_args!() macro, this function is used to generate the /// Arguments structure. #[inline] - pub fn new_v1( + pub const fn new_v1( pieces: &'a [&'static str; P], args: &'a [rt::Argument<'a>; A], ) -> Arguments<'a> { @@ -612,7 +612,7 @@ impl<'a> Arguments<'a> { /// 2. Every `rt::Placeholder::position` value within `fmt` must be a valid index of `args`. /// 3. Every `rt::Count::Param` within `fmt` must contain a valid index of `args`. #[inline] - pub fn new_v1_formatted( + pub const fn new_v1_formatted( pieces: &'a [&'static str], args: &'a [rt::Argument<'a>], fmt: &'a [rt::Placeholder], diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 94341a4da66cd..85d089a079082 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -96,12 +96,12 @@ pub struct Argument<'a> { #[rustc_diagnostic_item = "ArgumentMethods"] impl Argument<'_> { #[inline] - fn new<'a, T>(x: &'a T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'a> { + const fn new<'a, T>(x: &'a T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'a> { Argument { // INVARIANT: this creates an `ArgumentType<'a>` from a `&'a T` and // a `fn(&T, ...)`, so the invariant is maintained. ty: ArgumentType::Placeholder { - value: NonNull::from(x).cast(), + value: NonNull::from_ref(x).cast(), // SAFETY: function pointers always have the same layout. formatter: unsafe { mem::transmute(f) }, _lifetime: PhantomData, @@ -150,7 +150,7 @@ impl Argument<'_> { Self::new(x, UpperExp::fmt) } #[inline] - pub fn from_usize(x: &usize) -> Argument<'_> { + pub const fn from_usize(x: &usize) -> Argument<'_> { Argument { ty: ArgumentType::Count(*x) } } @@ -181,7 +181,7 @@ impl Argument<'_> { } #[inline] - pub(super) fn as_usize(&self) -> Option { + pub(super) const fn as_usize(&self) -> Option { match self.ty { ArgumentType::Count(count) => Some(count), ArgumentType::Placeholder { .. } => None, @@ -199,7 +199,7 @@ impl Argument<'_> { /// println!("{f}"); /// ``` #[inline] - pub fn none() -> [Self; 0] { + pub const fn none() -> [Self; 0] { [] } } @@ -216,7 +216,7 @@ impl UnsafeArg { /// See documentation where `UnsafeArg` is required to know when it is safe to /// create and use `UnsafeArg`. #[inline] - pub unsafe fn new() -> Self { + pub const unsafe fn new() -> Self { Self { _private: () } } } diff --git a/tests/ui/consts/const-eval/format.rs b/tests/ui/consts/const-eval/format.rs index e56d15e935bc5..1878fc0382767 100644 --- a/tests/ui/consts/const-eval/format.rs +++ b/tests/ui/consts/const-eval/format.rs @@ -1,13 +1,11 @@ const fn failure() { panic!("{:?}", 0); //~^ ERROR cannot call non-const formatting macro in constant functions - //~| ERROR cannot call non-const associated function `Arguments::<'_>::new_v1::<1, 1>` in constant functions } const fn print() { println!("{:?}", 0); //~^ ERROR cannot call non-const formatting macro in constant functions - //~| ERROR cannot call non-const associated function `Arguments::<'_>::new_v1::<2, 1>` in constant functions //~| ERROR cannot call non-const function `_print` in constant functions } diff --git a/tests/ui/consts/const-eval/format.stderr b/tests/ui/consts/const-eval/format.stderr index 25ed44e0f3382..af90acc2a2605 100644 --- a/tests/ui/consts/const-eval/format.stderr +++ b/tests/ui/consts/const-eval/format.stderr @@ -7,17 +7,8 @@ LL | panic!("{:?}", 0); = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0015]: cannot call non-const associated function `Arguments::<'_>::new_v1::<1, 1>` in constant functions - --> $DIR/format.rs:2:5 - | -LL | panic!("{:?}", 0); - | ^^^^^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = note: this error originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0015]: cannot call non-const formatting macro in constant functions - --> $DIR/format.rs:8:15 + --> $DIR/format.rs:7:15 | LL | println!("{:?}", 0); | ^^^^ @@ -25,17 +16,8 @@ LL | println!("{:?}", 0); = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0015]: cannot call non-const associated function `Arguments::<'_>::new_v1::<2, 1>` in constant functions - --> $DIR/format.rs:8:5 - | -LL | println!("{:?}", 0); - | ^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0015]: cannot call non-const function `_print` in constant functions - --> $DIR/format.rs:8:5 + --> $DIR/format.rs:7:5 | LL | println!("{:?}", 0); | ^^^^^^^^^^^^^^^^^^^ @@ -43,6 +25,6 @@ LL | println!("{:?}", 0); = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0015`. From 49c74234a79107afa7f86ca947708c3abef07674 Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Thu, 17 Oct 2024 13:00:35 +0200 Subject: [PATCH 04/12] Add support for wasm exception handling to Emscripten target Gated behind an unstable `-Z emscripten-wasm-eh` flag --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 5 +- compiler/rustc_codegen_ssa/src/back/link.rs | 8 ++- compiler/rustc_codegen_ssa/src/base.rs | 3 +- compiler/rustc_feature/src/builtin_attrs.rs | 1 + compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_passes/src/weak_lang_items.rs | 5 +- compiler/rustc_session/src/config/cfg.rs | 5 ++ compiler/rustc_session/src/options.rs | 2 + compiler/rustc_span/src/symbol.rs | 2 + library/panic_unwind/Cargo.toml | 2 +- library/panic_unwind/src/lib.rs | 3 +- library/unwind/Cargo.toml | 2 +- library/unwind/src/lib.rs | 3 +- .../src/compiler-flags/emscripten-wasm-eh.md | 6 ++ ...nd.rs => emscripten-catch-unwind-js-eh.rs} | 0 .../emscripten-catch-unwind-wasm-eh.rs | 65 +++++++++++++++++++ ...llowed-cli-cfgs.emscripten_wasm_eh_.stderr | 8 +++ tests/ui/cfg/disallowed-cli-cfgs.rs | 2 + .../feature-gate-cfg-emscripten-wasm-eh.rs | 4 ++ ...feature-gate-cfg-emscripten-wasm-eh.stderr | 12 ++++ 21 files changed, 131 insertions(+), 10 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/emscripten-wasm-eh.md rename tests/codegen/{emcripten-catch-unwind.rs => emscripten-catch-unwind-js-eh.rs} (100%) create mode 100644 tests/codegen/emscripten-catch-unwind-wasm-eh.rs create mode 100644 tests/ui/cfg/disallowed-cli-cfgs.emscripten_wasm_eh_.stderr create mode 100644 tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs create mode 100644 tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 628c0b1c29c44..b3e1210632fe2 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -109,7 +109,10 @@ unsafe fn configure_llvm(sess: &Session) { add("-wasm-enable-eh", false); } - if sess.target.os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind { + if sess.target.os == "emscripten" + && !sess.opts.unstable_opts.emscripten_wasm_eh + && sess.panic_strategy() == PanicStrategy::Unwind + { add("-enable-emscripten-cxx-exceptions", false); } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 4bc064528f3f0..0a941a8960946 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2466,10 +2466,12 @@ fn add_order_independent_options( } if sess.target.os == "emscripten" { - cmd.cc_arg("-s").cc_arg(if sess.panic_strategy() == PanicStrategy::Abort { - "DISABLE_EXCEPTION_CATCHING=1" + cmd.cc_arg(if sess.panic_strategy() == PanicStrategy::Abort { + "-sDISABLE_EXCEPTION_CATCHING=1" + } else if sess.opts.unstable_opts.emscripten_wasm_eh { + "-fwasm-exceptions" } else { - "DISABLE_EXCEPTION_CATCHING=0" + "-sDISABLE_EXCEPTION_CATCHING=0" }); } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 77e1fed720dfb..544578b29f107 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -388,7 +388,8 @@ pub(crate) fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // exceptions. This means that the VM does the unwinding for // us pub fn wants_wasm_eh(sess: &Session) -> bool { - sess.target.is_like_wasm && sess.target.os != "emscripten" + sess.target.is_like_wasm + && (sess.target.os != "emscripten" || sess.opts.unstable_opts.emscripten_wasm_eh) } /// Returns `true` if this session's target will use SEH-based unwinding. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 4112ae8098075..09c8a8a06ec76 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -37,6 +37,7 @@ const GATED_CFGS: &[GatedCfg] = &[ (sym::sanitizer_cfi_normalize_integers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi), // this is consistent with naming of the compiler flag it's for (sym::fmt_debug, sym::fmt_debug, Features::fmt_debug), + (sym::emscripten_wasm_eh, sym::cfg_emscripten_wasm_eh, Features::cfg_emscripten_wasm_eh), ]; /// Find a gated cfg determined by the `pred`icate which is given the cfg's name. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index d40823d2ed627..8cc4c18c02abf 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -202,6 +202,8 @@ declare_features! ( (internal, allow_internal_unstable, "1.0.0", None), /// Allows using anonymous lifetimes in argument-position impl-trait. (unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None), + /// Allows access to the emscripten_wasm_eh config, used by panic_unwind and unwind + (internal, cfg_emscripten_wasm_eh, "CURRENT_RUSTC_VERSION", None), /// Allows identifying the `compiler_builtins` crate. (internal, compiler_builtins, "1.13.0", None), /// Allows writing custom MIR diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 9ad690399140e..b50f3b38f2e18 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -782,6 +782,7 @@ fn test_unstable_options_tracking_hash() { tracked!(dwarf_version, Some(5)); tracked!(embed_source, true); tracked!(emit_thin_lto, false); + tracked!(emscripten_wasm_eh, true); tracked!(export_executable_symbols, true); tracked!(fewer_names, Some(true)); tracked!(fixed_x18, true); diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 020128f29c59b..701f500e4f60b 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -26,7 +26,10 @@ pub(crate) fn check_crate( if items.eh_personality().is_none() { items.missing.push(LangItem::EhPersonality); } - if tcx.sess.target.os == "emscripten" && items.eh_catch_typeinfo().is_none() { + if tcx.sess.target.os == "emscripten" + && items.eh_catch_typeinfo().is_none() + && !tcx.sess.opts.unstable_opts.emscripten_wasm_eh + { items.missing.push(LangItem::EhCatchTypeinfo); } diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index 3426858495b71..40016cb76d6d4 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -143,6 +143,7 @@ pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) { | (sym::target_has_atomic_load_store, Some(_)) | (sym::target_thread_local, None) => disallow(cfg, "--target"), (sym::fmt_debug, None | Some(_)) => disallow(cfg, "-Z fmt-debug"), + (sym::emscripten_wasm_eh, None | Some(_)) => disallow(cfg, "-Z emscripten_wasm_eh"), _ => {} } } @@ -295,6 +296,10 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg { ins_none!(sym::ub_checks); } + // Nightly-only implementation detail for the `panic_unwind` and `unwind` crates. + if sess.is_nightly_build() && sess.opts.unstable_opts.emscripten_wasm_eh { + ins_none!(sym::emscripten_wasm_eh); + } ret } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 3772a4a08af01..a344ec94a263b 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1771,6 +1771,8 @@ options! { "emit a section containing stack size metadata (default: no)"), emit_thin_lto: bool = (true, parse_bool, [TRACKED], "emit the bc module with thin LTO info (default: yes)"), + emscripten_wasm_eh: bool = (false, parse_bool, [TRACKED], + "Use WebAssembly error handling for wasm32-unknown-emscripten"), enforce_type_length_limit: bool = (false, parse_bool, [TRACKED], "enforce the type length limit when monomorphizing instances in codegen"), export_executable_symbols: bool = (false, parse_bool, [TRACKED], diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4ecc4201f89d5..e62107c450ef3 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -570,6 +570,7 @@ symbols! { cfg_autodiff_fallback, cfg_boolean_literals, cfg_doctest, + cfg_emscripten_wasm_eh, cfg_eval, cfg_fmt_debug, cfg_hide, @@ -823,6 +824,7 @@ symbols! { emit_enum_variant_arg, emit_struct, emit_struct_field, + emscripten_wasm_eh, enable, encode, end, diff --git a/library/panic_unwind/Cargo.toml b/library/panic_unwind/Cargo.toml index 252f118fecfbb..c2abb79192e9f 100644 --- a/library/panic_unwind/Cargo.toml +++ b/library/panic_unwind/Cargo.toml @@ -23,4 +23,4 @@ libc = { version = "0.2", default-features = false } [lints.rust.unexpected_cfgs] level = "warn" -check-cfg = [] +check-cfg = ['cfg(emscripten_wasm_eh)'] diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 1981675f40922..085c07591d2aa 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -25,13 +25,14 @@ // `real_imp` is unused with Miri, so silence warnings. #![cfg_attr(miri, allow(dead_code))] #![allow(internal_features)] +#![cfg_attr(not(bootstrap), feature(cfg_emscripten_wasm_eh))] use alloc::boxed::Box; use core::any::Any; use core::panic::PanicPayload; cfg_if::cfg_if! { - if #[cfg(target_os = "emscripten")] { + if #[cfg(all(target_os = "emscripten", not(emscripten_wasm_eh)))] { #[path = "emcc.rs"] mod imp; } else if #[cfg(target_os = "hermit")] { diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml index e13c9a06c05d1..66e8d1a3ffe5f 100644 --- a/library/unwind/Cargo.toml +++ b/library/unwind/Cargo.toml @@ -37,4 +37,4 @@ system-llvm-libunwind = [] [lints.rust.unexpected_cfgs] level = "warn" -check-cfg = [] +check-cfg = ['cfg(emscripten_wasm_eh)'] diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 40d409310ffab..9b93f0b3da0a5 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -4,10 +4,11 @@ #![feature(staged_api)] #![cfg_attr(not(target_env = "msvc"), feature(libc))] #![cfg_attr( - all(target_family = "wasm", not(target_os = "emscripten")), + all(target_family = "wasm", any(not(target_os = "emscripten"), emscripten_wasm_eh)), feature(simd_wasm64, wasm_exception_handling_intrinsics) )] #![allow(internal_features)] +#![cfg_attr(not(bootstrap), feature(cfg_emscripten_wasm_eh))] // Force libc to be included even if unused. This is required by many platforms. #[cfg(not(all(windows, target_env = "msvc")))] diff --git a/src/doc/unstable-book/src/compiler-flags/emscripten-wasm-eh.md b/src/doc/unstable-book/src/compiler-flags/emscripten-wasm-eh.md new file mode 100644 index 0000000000000..eab29a1744b67 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/emscripten-wasm-eh.md @@ -0,0 +1,6 @@ +# `emscripten-wasm-eh` + +Use the WebAssembly exception handling ABI to unwind for the +`wasm32-unknown-emscripten`. If compiling with this setting, the `emcc` linker +should be invoked with `-fwasm-exceptions`. If linking with C/C++ files, the +C/C++ files should also be compiled with `-fwasm-exceptions`. diff --git a/tests/codegen/emcripten-catch-unwind.rs b/tests/codegen/emscripten-catch-unwind-js-eh.rs similarity index 100% rename from tests/codegen/emcripten-catch-unwind.rs rename to tests/codegen/emscripten-catch-unwind-js-eh.rs diff --git a/tests/codegen/emscripten-catch-unwind-wasm-eh.rs b/tests/codegen/emscripten-catch-unwind-wasm-eh.rs new file mode 100644 index 0000000000000..72395f432d5f8 --- /dev/null +++ b/tests/codegen/emscripten-catch-unwind-wasm-eh.rs @@ -0,0 +1,65 @@ +//@ compile-flags: -O --target wasm32-unknown-emscripten -Z emscripten-wasm-eh +//@ needs-llvm-components: webassembly + +// Emscripten catch_unwind using wasm exceptions + +#![feature(no_core, lang_items, intrinsics, rustc_attrs)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "freeze"] +trait Freeze {} +#[lang = "copy"] +trait Copy {} + +impl Copy for *mut T {} + +#[rustc_intrinsic] +fn size_of() -> usize { + loop {} +} + +extern "rust-intrinsic" { + fn catch_unwind( + try_fn: fn(_: *mut u8), + data: *mut u8, + catch_fn: fn(_: *mut u8, _: *mut u8), + ) -> i32; +} + +// CHECK-LABEL: @ptr_size +#[no_mangle] +pub fn ptr_size() -> usize { + // CHECK: ret [[PTR_SIZE:.*]] + size_of::<*mut u8>() +} + +// CHECK-LABEL: @test_catch_unwind +#[no_mangle] +pub unsafe fn test_catch_unwind( + try_fn: fn(_: *mut u8), + data: *mut u8, + catch_fn: fn(_: *mut u8, _: *mut u8), +) -> i32 { + // CHECK: start: + // CHECK: invoke void %try_fn(ptr %data) + // CHECK: to label %__rust_try.exit unwind label %catchswitch.i + // CHECK: catchswitch.i: ; preds = %start + // CHECK: %catchswitch1.i = catchswitch within none [label %catchpad.i] unwind to caller + + // CHECK: catchpad.i: ; preds = %catchswitch.i + // CHECK: %catchpad2.i = catchpad within %catchswitch1.i [ptr null] + // CHECK: %0 = tail call ptr @llvm.wasm.get.exception(token %catchpad2.i) + // CHECK: %1 = tail call i32 @llvm.wasm.get.ehselector(token %catchpad2.i) + // CHECK: call void %catch_fn(ptr %data, ptr %0) [ "funclet"(token %catchpad2.i) ] + // CHECK: catchret from %catchpad2.i to label %__rust_try.exit + + // CHECK: __rust_try.exit: ; preds = %start, %catchpad.i + // CHECK: %common.ret.op.i = phi i32 [ 0, %start ], [ 1, %catchpad.i ] + // CHECK: ret i32 %common.ret.op.i + + catch_unwind(try_fn, data, catch_fn) +} diff --git a/tests/ui/cfg/disallowed-cli-cfgs.emscripten_wasm_eh_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.emscripten_wasm_eh_.stderr new file mode 100644 index 0000000000000..8b2ee0e5c0c3d --- /dev/null +++ b/tests/ui/cfg/disallowed-cli-cfgs.emscripten_wasm_eh_.stderr @@ -0,0 +1,8 @@ +error: unexpected `--cfg emscripten_wasm_eh` flag + | + = note: config `emscripten_wasm_eh` is only supposed to be controlled by `-Z emscripten_wasm_eh` + = 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/cfg/disallowed-cli-cfgs.rs b/tests/ui/cfg/disallowed-cli-cfgs.rs index 3c9ee87f28ab8..cae9c65cb45ac 100644 --- a/tests/ui/cfg/disallowed-cli-cfgs.rs +++ b/tests/ui/cfg/disallowed-cli-cfgs.rs @@ -7,6 +7,7 @@ //@ revisions: target_has_atomic_equal_alignment_ target_has_atomic_load_store_ //@ revisions: target_thread_local_ relocation_model_ //@ revisions: fmt_debug_ +//@ revisions: emscripten_wasm_eh_ //@ [overflow_checks_]compile-flags: --cfg overflow_checks //@ [debug_assertions_]compile-flags: --cfg debug_assertions @@ -33,5 +34,6 @@ //@ [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" +//@ [emscripten_wasm_eh_]compile-flags: --cfg emscripten_wasm_eh fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs new file mode 100644 index 0000000000000..cff98b43fe745 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs @@ -0,0 +1,4 @@ +//@ compile-flags: --check-cfg=cfg(emscripten_wasm_eh) +#[cfg(not(emscripten_wasm_eh))] +//~^ `cfg(emscripten_wasm_eh)` is experimental +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr new file mode 100644 index 0000000000000..67769e3c7586b --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr @@ -0,0 +1,12 @@ +error[E0658]: `cfg(emscripten_wasm_eh)` is experimental and subject to change + --> $DIR/feature-gate-cfg-emscripten-wasm-eh.rs:2:11 + | +LL | #[cfg(not(emscripten_wasm_eh))] + | ^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(cfg_emscripten_wasm_eh)]` 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`. From 37f26311ebd2895e8052a4caa4c89dedf6fbef9d Mon Sep 17 00:00:00 2001 From: klensy Date: Sun, 5 Jan 2025 15:32:20 +0300 Subject: [PATCH 05/12] add deprecated and do nothing flag to options table inline_threshold mark deprecated no-stack-check print deprecation message for -Car too inline_threshold deprecated and do nothing: make in untracked make OptionDesc struct from tuple --- compiler/rustc_driver_impl/src/lib.rs | 30 ++++-------- compiler/rustc_interface/src/tests.rs | 2 +- compiler/rustc_session/src/options.rs | 48 +++++++++++++++---- tests/ui/deprecation/deprecated_ar.rs | 4 ++ tests/ui/deprecation/deprecated_ar.stderr | 2 + ...deprecated_inline_threshold.bad_val.stderr | 4 ++ ...eprecated_inline_threshold.good_val.stderr | 2 + .../deprecated_inline_threshold.no_val.stderr | 4 ++ .../deprecated_inline_threshold.rs | 8 +++- .../deprecated_inline_threshold.stderr | 2 - .../deprecated_no_stack_check_opt.rs | 4 ++ .../deprecated_no_stack_check_opt.stderr | 2 + 12 files changed, 78 insertions(+), 34 deletions(-) create mode 100644 tests/ui/deprecation/deprecated_ar.rs create mode 100644 tests/ui/deprecation/deprecated_ar.stderr create mode 100644 tests/ui/deprecation/deprecated_inline_threshold.bad_val.stderr create mode 100644 tests/ui/deprecation/deprecated_inline_threshold.good_val.stderr create mode 100644 tests/ui/deprecation/deprecated_inline_threshold.no_val.stderr delete mode 100644 tests/ui/deprecation/deprecated_inline_threshold.stderr create mode 100644 tests/ui/deprecation/deprecated_no_stack_check_opt.rs create mode 100644 tests/ui/deprecation/deprecated_no_stack_check_opt.stderr diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 90f382e72268b..0413e5e86348b 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -52,8 +52,8 @@ use rustc_metadata::locator; use rustc_middle::ty::TyCtxt; use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::config::{ - CG_OPTIONS, ErrorOutputType, Input, OutFileName, OutputType, UnstableOptions, Z_OPTIONS, - nightly_options, + CG_OPTIONS, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, UnstableOptions, + Z_OPTIONS, nightly_options, }; use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; @@ -1124,14 +1124,6 @@ pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, matches: &Matches) -> return true; } - if cg_flags.iter().any(|x| *x == "no-stack-check") { - early_dcx.early_warn("the `-Cno-stack-check` flag is deprecated and does nothing"); - } - - if cg_flags.iter().any(|x| x.starts_with("inline-threshold")) { - early_dcx.early_warn("the `-Cinline-threshold` flag is deprecated and does nothing (consider using `-Cllvm-args=--inline-threshold=...`)"); - } - if cg_flags.iter().any(|x| *x == "passes=list") { let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); @@ -1156,18 +1148,16 @@ fn describe_codegen_flags() { print_flag_list("-C", config::CG_OPTIONS); } -fn print_flag_list( - cmdline_opt: &str, - flag_list: &[(&'static str, T, &'static str, &'static str)], -) { - let max_len = flag_list.iter().map(|&(name, _, _, _)| name.chars().count()).max().unwrap_or(0); +fn print_flag_list(cmdline_opt: &str, flag_list: &[OptionDesc]) { + let max_len = + flag_list.iter().map(|opt_desc| opt_desc.name().chars().count()).max().unwrap_or(0); - for &(name, _, _, desc) in flag_list { + for opt_desc in flag_list { safe_println!( " {} {:>width$}=val -- {}", cmdline_opt, - name.replace('_', "-"), - desc, + opt_desc.name().replace('_', "-"), + opt_desc.desc(), width = max_len ); } @@ -1221,8 +1211,8 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option = match e { getopts::Fail::UnrecognizedOption(ref opt) => CG_OPTIONS .iter() - .map(|&(name, ..)| ('C', name)) - .chain(Z_OPTIONS.iter().map(|&(name, ..)| ('Z', name))) + .map(|opt_desc| ('C', opt_desc.name())) + .chain(Z_OPTIONS.iter().map(|opt_desc| ('Z', opt_desc.name()))) .find(|&(_, name)| *opt == name.replace('_', "-")) .map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")), getopts::Fail::ArgumentMissing(ref opt) => { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 9ad690399140e..bb5f1c295c712 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -582,6 +582,7 @@ fn test_codegen_options_tracking_hash() { untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe"))); untracked!(extra_filename, String::from("extra-filename")); untracked!(incremental, Some(String::from("abc"))); + untracked!(inline_threshold, Some(0xf007ba11)); // `link_arg` is omitted because it just forwards to `link_args`. untracked!(link_args, vec![String::from("abc"), String::from("def")]); untracked!(link_self_contained, LinkSelfContained::on()); @@ -613,7 +614,6 @@ fn test_codegen_options_tracking_hash() { tracked!(embed_bitcode, false); tracked!(force_frame_pointers, FramePointer::Always); tracked!(force_unwind_tables, Some(true)); - tracked!(inline_threshold, Some(0xf007ba11)); tracked!(instrument_coverage, InstrumentCoverage::Yes); tracked!(link_dead_code, Some(true)); tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 3772a4a08af01..30047339810e3 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -239,7 +239,8 @@ macro_rules! options { $init:expr, $parse:ident, [$dep_tracking_marker:ident], - $desc:expr) + $desc:expr + $(, deprecated_do_nothing: $dnn:literal )?) ),* ,) => ( #[derive(Clone)] @@ -280,7 +281,8 @@ macro_rules! options { } pub const $stat: OptionDescrs<$struct_name> = - &[ $( (stringify!($opt), $optmod::$opt, desc::$parse, $desc) ),* ]; + &[ $( OptionDesc{ name: stringify!($opt), setter: $optmod::$opt, + type_desc: desc::$parse, desc: $desc, is_deprecated_and_do_nothing: false $( || $dnn )? } ),* ]; mod $optmod { $( @@ -315,7 +317,27 @@ macro_rules! redirect_field { } type OptionSetter = fn(&mut O, v: Option<&str>) -> bool; -type OptionDescrs = &'static [(&'static str, OptionSetter, &'static str, &'static str)]; +type OptionDescrs = &'static [OptionDesc]; + +pub struct OptionDesc { + name: &'static str, + setter: OptionSetter, + // description for return value/type from mod desc + type_desc: &'static str, + // description for option from options table + desc: &'static str, + is_deprecated_and_do_nothing: bool, +} + +impl OptionDesc { + pub fn name(&self) -> &'static str { + self.name + } + + pub fn desc(&self) -> &'static str { + self.desc + } +} #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable fn build_options( @@ -333,8 +355,13 @@ fn build_options( }; let option_to_lookup = key.replace('-', "_"); - match descrs.iter().find(|(name, ..)| *name == option_to_lookup) { - Some((_, setter, type_desc, _)) => { + match descrs.iter().find(|opt_desc| opt_desc.name == option_to_lookup) { + Some(OptionDesc { name: _, setter, type_desc, desc, is_deprecated_and_do_nothing }) => { + if *is_deprecated_and_do_nothing { + // deprecation works for prefixed options only + assert!(!prefix.is_empty()); + early_dcx.early_warn(format!("`-{prefix} {key}`: {desc}")); + } if !setter(&mut op, value) { match value { None => early_dcx.early_fatal( @@ -1546,7 +1573,8 @@ options! { // tidy-alphabetical-start #[rustc_lint_opt_deny_field_access("documented to do nothing")] ar: String = (String::new(), parse_string, [UNTRACKED], - "this option is deprecated and does nothing"), + "this option is deprecated and does nothing", + deprecated_do_nothing: true), #[rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field")] code_model: Option = (None, parse_code_model, [TRACKED], "choose the code model to use (`rustc --print code-models` for details)"), @@ -1578,9 +1606,10 @@ options! { incremental: Option = (None, parse_opt_string, [UNTRACKED], "enable incremental compilation"), #[rustc_lint_opt_deny_field_access("documented to do nothing")] - inline_threshold: Option = (None, parse_opt_number, [TRACKED], + inline_threshold: Option = (None, parse_opt_number, [UNTRACKED], "this option is deprecated and does nothing \ - (consider using `-Cllvm-args=--inline-threshold=...`)"), + (consider using `-Cllvm-args=--inline-threshold=...`)", + deprecated_do_nothing: true), #[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")] instrument_coverage: InstrumentCoverage = (InstrumentCoverage::No, parse_instrument_coverage, [TRACKED], "instrument the generated code to support LLVM source-based code coverage reports \ @@ -1616,7 +1645,8 @@ options! { "disable the use of the redzone"), #[rustc_lint_opt_deny_field_access("documented to do nothing")] no_stack_check: bool = (false, parse_no_value, [UNTRACKED], - "this option is deprecated and does nothing"), + "this option is deprecated and does nothing", + deprecated_do_nothing: true), no_vectorize_loops: bool = (false, parse_no_value, [TRACKED], "disable loop vectorization optimization passes"), no_vectorize_slp: bool = (false, parse_no_value, [TRACKED], diff --git a/tests/ui/deprecation/deprecated_ar.rs b/tests/ui/deprecation/deprecated_ar.rs new file mode 100644 index 0000000000000..404d062e6a449 --- /dev/null +++ b/tests/ui/deprecation/deprecated_ar.rs @@ -0,0 +1,4 @@ +//@ check-pass +//@ compile-flags: -Car=foo + +fn main() {} diff --git a/tests/ui/deprecation/deprecated_ar.stderr b/tests/ui/deprecation/deprecated_ar.stderr new file mode 100644 index 0000000000000..de776c674996a --- /dev/null +++ b/tests/ui/deprecation/deprecated_ar.stderr @@ -0,0 +1,2 @@ +warning: `-C ar`: this option is deprecated and does nothing + diff --git a/tests/ui/deprecation/deprecated_inline_threshold.bad_val.stderr b/tests/ui/deprecation/deprecated_inline_threshold.bad_val.stderr new file mode 100644 index 0000000000000..2e7a99010ae9b --- /dev/null +++ b/tests/ui/deprecation/deprecated_inline_threshold.bad_val.stderr @@ -0,0 +1,4 @@ +warning: `-C inline-threshold`: this option is deprecated and does nothing (consider using `-Cllvm-args=--inline-threshold=...`) + +error: incorrect value `asd` for codegen option `inline-threshold` - a number was expected + diff --git a/tests/ui/deprecation/deprecated_inline_threshold.good_val.stderr b/tests/ui/deprecation/deprecated_inline_threshold.good_val.stderr new file mode 100644 index 0000000000000..2d6f3652d252e --- /dev/null +++ b/tests/ui/deprecation/deprecated_inline_threshold.good_val.stderr @@ -0,0 +1,2 @@ +warning: `-C inline-threshold`: this option is deprecated and does nothing (consider using `-Cllvm-args=--inline-threshold=...`) + diff --git a/tests/ui/deprecation/deprecated_inline_threshold.no_val.stderr b/tests/ui/deprecation/deprecated_inline_threshold.no_val.stderr new file mode 100644 index 0000000000000..25104e637e001 --- /dev/null +++ b/tests/ui/deprecation/deprecated_inline_threshold.no_val.stderr @@ -0,0 +1,4 @@ +warning: `-C inline-threshold`: this option is deprecated and does nothing (consider using `-Cllvm-args=--inline-threshold=...`) + +error: codegen option `inline-threshold` requires a number (C inline-threshold=) + diff --git a/tests/ui/deprecation/deprecated_inline_threshold.rs b/tests/ui/deprecation/deprecated_inline_threshold.rs index 56e033b8cf547..b54fa36397af0 100644 --- a/tests/ui/deprecation/deprecated_inline_threshold.rs +++ b/tests/ui/deprecation/deprecated_inline_threshold.rs @@ -1,4 +1,8 @@ -//@ check-pass -//@ compile-flags: -Cinline-threshold=666 +//@ revisions: good_val bad_val no_val +// +//@[good_val] compile-flags: -Cinline-threshold=666 +//@[good_val] check-pass +//@[bad_val] compile-flags: -Cinline-threshold=asd +//@[no_val] compile-flags: -Cinline-threshold fn main() {} diff --git a/tests/ui/deprecation/deprecated_inline_threshold.stderr b/tests/ui/deprecation/deprecated_inline_threshold.stderr deleted file mode 100644 index c4f8ff092b29a..0000000000000 --- a/tests/ui/deprecation/deprecated_inline_threshold.stderr +++ /dev/null @@ -1,2 +0,0 @@ -warning: the `-Cinline-threshold` flag is deprecated and does nothing (consider using `-Cllvm-args=--inline-threshold=...`) - diff --git a/tests/ui/deprecation/deprecated_no_stack_check_opt.rs b/tests/ui/deprecation/deprecated_no_stack_check_opt.rs new file mode 100644 index 0000000000000..62584ec23e336 --- /dev/null +++ b/tests/ui/deprecation/deprecated_no_stack_check_opt.rs @@ -0,0 +1,4 @@ +//@ check-pass +//@ compile-flags: -Cno-stack-check + +fn main() {} diff --git a/tests/ui/deprecation/deprecated_no_stack_check_opt.stderr b/tests/ui/deprecation/deprecated_no_stack_check_opt.stderr new file mode 100644 index 0000000000000..17efba787f070 --- /dev/null +++ b/tests/ui/deprecation/deprecated_no_stack_check_opt.stderr @@ -0,0 +1,2 @@ +warning: `-C no-stack-check`: this option is deprecated and does nothing + From 87ce94d56fba068dc1f1acea5fceb58d32efe697 Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Mon, 6 Jan 2025 17:14:16 +0100 Subject: [PATCH 06/12] last feedback items --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index c95ded3b7509b..fe557a08a9dc0 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -111,6 +111,8 @@ Compatibility Notes - [The syntax `&pin (mut|const) T` is now parsed as a type which in theory could affect macro expansion results in some edge cases](https://github.com/rust-lang/rust/pull/130635#issuecomment-2375462821) - [Legacy syntax for calling `std::arch` functions is no longer permitted to declare items or bodies (such as closures, inline consts, or async blocks).](https://github.com/rust-lang/rust/pull/130443#issuecomment-2445678945) - The `wasm32-unknown-emscripten` target's binary release of the standard library is now [built with the latest emsdk 3.1.68](https://github.com/rust-lang/rust/pull/131533), which fixes an ABI-incompatibility with Emscripten >= 3.1.42. If you are locally using a version of emsdk with an incompatible ABI (e.g. before 3.1.42 or a future one), you should build your code with `-Zbuild-std` to ensure that `std` uses the correct ABI. +- [Declaring functions with a calling convention not supported on the current target now triggers a hard error](https://github.com/rust-lang/rust/pull/129935) +- [The next-generation trait solver is now enabled for coherence, fixing multiple soundness issues](https://github.com/rust-lang/rust/pull/130654) Version 1.83.0 (2024-11-28) ========================== From 2be9ffc1afd0623ab0697cbaca5693b80c6d362c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 10 Dec 2024 22:08:44 +0000 Subject: [PATCH 07/12] Add derived causes for host effect predicates --- compiler/rustc_middle/src/traits/mod.rs | 89 +++++++++++++++---- compiler/rustc_middle/src/ty/predicate.rs | 22 +++++ .../src/solve/effect_goals.rs | 2 +- .../traits/fulfillment_errors.rs | 11 +-- .../src/error_reporting/traits/suggestions.rs | 57 +++++++++++- .../src/solve/fulfill.rs | 73 ++++++++++++++- .../src/traits/effects.rs | 21 ++++- compiler/rustc_type_ir/src/binder.rs | 1 + .../const-generics/issues/issue-88119.stderr | 18 ++++ ...type-const-bound-usage-fail.current.stderr | 2 +- ...oc-type-const-bound-usage-fail.next.stderr | 6 +- .../assoc-type-const-bound-usage-fail.rs | 6 +- .../const-traits/const-opaque.no.stderr | 2 +- tests/ui/traits/const-traits/const-opaque.rs | 2 +- .../item-bound-entailment-fails.stderr | 5 ++ 15 files changed, 278 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 99211c1f92440..db2bb8a7248a6 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -125,6 +125,15 @@ impl<'tcx> ObligationCause<'tcx> { self } + pub fn derived_host_cause( + mut self, + parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>, + variant: impl FnOnce(DerivedHostCause<'tcx>) -> ObligationCauseCode<'tcx>, + ) -> ObligationCause<'tcx> { + self.code = variant(DerivedHostCause { parent_host_pred, parent_code: self.code }).into(); + self + } + pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> { match self.code() { ObligationCauseCode::MatchImpl(cause, _) => cause.to_constraint_category(), @@ -278,6 +287,14 @@ pub enum ObligationCauseCode<'tcx> { /// Derived obligation for WF goals. WellFormedDerived(DerivedCause<'tcx>), + /// Derived obligation (i.e. `where` clause) on an user-provided impl + /// or a trait alias. + ImplDerivedHost(Box>), + + /// Derived obligation (i.e. `where` clause) on an user-provided impl + /// or a trait alias. + BuiltinDerivedHost(DerivedHostCause<'tcx>), + /// Derived obligation refined to point at a specific argument in /// a call or method expression. FunctionArg { @@ -437,36 +454,38 @@ pub enum WellFormedLoc { }, } -#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] -#[derive(TypeVisitable, TypeFoldable)] -pub struct ImplDerivedCause<'tcx> { - pub derived: DerivedCause<'tcx>, - /// The `DefId` of the `impl` that gave rise to the `derived` obligation. - /// If the `derived` obligation arose from a trait alias, which conceptually has a synthetic impl, - /// then this will be the `DefId` of that trait alias. Care should therefore be taken to handle - /// that exceptional case where appropriate. - pub impl_or_alias_def_id: DefId, - /// The index of the derived predicate in the parent impl's predicates. - pub impl_def_predicate_index: Option, - pub span: Span, -} - impl<'tcx> ObligationCauseCode<'tcx> { /// Returns the base obligation, ignoring derived obligations. pub fn peel_derives(&self) -> &Self { let mut base_cause = self; - while let Some((parent_code, _)) = base_cause.parent() { + while let Some(parent_code) = base_cause.parent() { base_cause = parent_code; } base_cause } + pub fn parent(&self) -> Option<&Self> { + match self { + ObligationCauseCode::FunctionArg { parent_code, .. } => Some(parent_code), + ObligationCauseCode::BuiltinDerived(derived) + | ObligationCauseCode::WellFormedDerived(derived) + | ObligationCauseCode::ImplDerived(box ImplDerivedCause { derived, .. }) => { + Some(&derived.parent_code) + } + ObligationCauseCode::BuiltinDerivedHost(derived) + | ObligationCauseCode::ImplDerivedHost(box ImplDerivedHostCause { derived, .. }) => { + Some(&derived.parent_code) + } + _ => None, + } + } + /// Returns the base obligation and the base trait predicate, if any, ignoring /// derived obligations. pub fn peel_derives_with_predicate(&self) -> (&Self, Option>) { let mut base_cause = self; let mut base_trait_pred = None; - while let Some((parent_code, parent_pred)) = base_cause.parent() { + while let Some((parent_code, parent_pred)) = base_cause.parent_with_predicate() { base_cause = parent_code; if let Some(parent_pred) = parent_pred { base_trait_pred = Some(parent_pred); @@ -476,7 +495,7 @@ impl<'tcx> ObligationCauseCode<'tcx> { (base_cause, base_trait_pred) } - pub fn parent(&self) -> Option<(&Self, Option>)> { + pub fn parent_with_predicate(&self) -> Option<(&Self, Option>)> { match self { ObligationCauseCode::FunctionArg { parent_code, .. } => Some((parent_code, None)), ObligationCauseCode::BuiltinDerived(derived) @@ -573,6 +592,42 @@ pub struct DerivedCause<'tcx> { pub parent_code: InternedObligationCauseCode<'tcx>, } +#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeVisitable, TypeFoldable)] +pub struct ImplDerivedCause<'tcx> { + pub derived: DerivedCause<'tcx>, + /// The `DefId` of the `impl` that gave rise to the `derived` obligation. + /// If the `derived` obligation arose from a trait alias, which conceptually has a synthetic impl, + /// then this will be the `DefId` of that trait alias. Care should therefore be taken to handle + /// that exceptional case where appropriate. + pub impl_or_alias_def_id: DefId, + /// The index of the derived predicate in the parent impl's predicates. + pub impl_def_predicate_index: Option, + pub span: Span, +} + +#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeVisitable, TypeFoldable)] +pub struct DerivedHostCause<'tcx> { + /// The trait predicate of the parent obligation that led to the + /// current obligation. Note that only trait obligations lead to + /// derived obligations, so we just store the trait predicate here + /// directly. + pub parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>, + + /// The parent trait had this cause. + pub parent_code: InternedObligationCauseCode<'tcx>, +} + +#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +#[derive(TypeVisitable, TypeFoldable)] +pub struct ImplDerivedHostCause<'tcx> { + pub derived: DerivedHostCause<'tcx>, + /// The `DefId` of the `impl` that gave rise to the `derived` obligation. + pub impl_def_id: DefId, + pub span: Span, +} + #[derive(Clone, Debug, PartialEq, Eq, TypeVisitable)] pub enum SelectionError<'tcx> { /// The trait is not implemented. diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 3ecaa3e22d39c..32d6455e82557 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -634,6 +634,28 @@ impl<'tcx> UpcastFrom, PolyProjectionPredicate<'tcx>> for Clause<'t } } +impl<'tcx> UpcastFrom, ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>> + for Predicate<'tcx> +{ + fn upcast_from( + from: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>, + tcx: TyCtxt<'tcx>, + ) -> Self { + from.map_bound(ty::ClauseKind::HostEffect).upcast(tcx) + } +} + +impl<'tcx> UpcastFrom, ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>> + for Clause<'tcx> +{ + fn upcast_from( + from: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>, + tcx: TyCtxt<'tcx>, + ) -> Self { + from.map_bound(ty::ClauseKind::HostEffect).upcast(tcx) + } +} + impl<'tcx> UpcastFrom, NormalizesTo<'tcx>> for Predicate<'tcx> { fn upcast_from(from: NormalizesTo<'tcx>, tcx: TyCtxt<'tcx>) -> Self { PredicateKind::NormalizesTo(from).upcast(tcx) diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index ce7552e30f0fe..281796e84b169 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -353,7 +353,7 @@ where ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { ecx.add_goals( - GoalSource::Misc, + GoalSource::ImplWhereBound, const_conditions.into_iter().map(|trait_ref| { goal.with( cx, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index f9a3040832601..1678aa8c657b4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -753,7 +753,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { applied_do_not_recommend = true; } } - if let Some((parent_cause, _parent_pred)) = base_cause.parent() { + if let Some(parent_cause) = base_cause.parent() { base_cause = parent_cause.clone(); } else { break; @@ -778,7 +778,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind() && !found_kind.extends(expected_kind) { - if let Some((_, Some(parent))) = obligation.cause.code().parent() { + if let Some((_, Some(parent))) = obligation.cause.code().parent_with_predicate() { // If we have a derived obligation, then the parent will be a `AsyncFn*` goal. trait_ref = parent.to_poly_trait_ref(); } else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } = @@ -926,7 +926,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let Some(typeck) = &self.typeck_results else { return false; }; - let Some((ObligationCauseCode::QuestionMark, Some(y))) = obligation.cause.code().parent() + let Some((ObligationCauseCode::QuestionMark, Some(y))) = + obligation.cause.code().parent_with_predicate() else { return false; }; @@ -1179,7 +1180,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut code = obligation.cause.code(); let mut pred = obligation.predicate.as_trait_clause(); - while let Some((next_code, next_pred)) = code.parent() { + while let Some((next_code, next_pred)) = code.parent_with_predicate() { if let Some(pred) = pred { self.enter_forall(pred, |pred| { diag.note(format!( @@ -2095,7 +2096,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut code = obligation.cause.code(); let mut trait_pred = trait_predicate; let mut peeled = false; - while let Some((parent_code, parent_trait_pred)) = code.parent() { + while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() { code = parent_code; if let Some(parent_trait_pred) = parent_trait_pred { trait_pred = parent_trait_pred; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 007a220ae697f..9d85ca1dd4dd7 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -464,7 +464,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Get the root obligation, since the leaf obligation we have may be unhelpful (#87437) let mut real_trait_pred = trait_pred; - while let Some((parent_code, parent_trait_pred)) = code.parent() { + while let Some((parent_code, parent_trait_pred)) = code.parent_with_predicate() { code = parent_code; if let Some(parent_trait_pred) = parent_trait_pred { real_trait_pred = parent_trait_pred; @@ -1447,7 +1447,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut span = obligation.cause.span; let mut trait_pred = trait_pred; let mut code = obligation.cause.code(); - while let Some((c, Some(parent_trait_pred))) = code.parent() { + while let Some((c, Some(parent_trait_pred))) = code.parent_with_predicate() { // We want the root obligation, in order to detect properly handle // `for _ in &mut &mut vec![] {}`. code = c; @@ -3470,6 +3470,59 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) }); } + ObligationCauseCode::ImplDerivedHost(ref data) => { + let self_ty = + self.resolve_vars_if_possible(data.derived.parent_host_pred.self_ty()); + let msg = format!( + "required for `{self_ty}` to implement `{} {}`", + data.derived.parent_host_pred.skip_binder().constness, + data.derived + .parent_host_pred + .map_bound(|pred| pred.trait_ref) + .print_only_trait_path(), + ); + match tcx.hir().get_if_local(data.impl_def_id) { + Some(Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }), + .. + })) => { + let mut spans = vec![self_ty.span]; + spans.extend(of_trait.as_ref().map(|t| t.path.span)); + let mut spans: MultiSpan = spans.into(); + spans.push_span_label(data.span, "unsatisfied trait bound introduced here"); + err.span_note(spans, msg); + } + _ => { + err.note(msg); + } + } + ensure_sufficient_stack(|| { + self.note_obligation_cause_code( + body_id, + err, + data.derived.parent_host_pred, + param_env, + &data.derived.parent_code, + obligated_types, + seen_requirements, + long_ty_file, + ) + }); + } + ObligationCauseCode::BuiltinDerivedHost(ref data) => { + ensure_sufficient_stack(|| { + self.note_obligation_cause_code( + body_id, + err, + data.parent_host_pred, + param_env, + &data.parent_code, + obligated_types, + seen_requirements, + long_ty_file, + ) + }); + } ObligationCauseCode::WellFormedDerived(ref data) => { let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); let parent_predicate = parent_trait_ref; diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 2b2623a050ec9..7aa82c52c9f26 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -474,8 +474,11 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { // for normalizes-to. let pred_kind = goal.goal().predicate.kind(); let child_mode = match pred_kind.skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(parent_trait_pred)) => { - ChildMode::Trait(pred_kind.rebind(parent_trait_pred)) + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { + ChildMode::Trait(pred_kind.rebind(pred)) + } + ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(pred)) => { + ChildMode::Host(pred_kind.rebind(pred)) } ty::PredicateKind::NormalizesTo(normalizes_to) if matches!( @@ -492,6 +495,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { }; let mut impl_where_bound_count = 0; + let mut impl_const_condition_bound_count = 0; for nested_goal in candidate.instantiate_nested_goals(self.span()) { trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result())); @@ -504,7 +508,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { let obligation; match (child_mode, nested_goal.source()) { - (ChildMode::Trait(_), GoalSource::Misc) => { + (ChildMode::Trait(_) | ChildMode::Host(_), GoalSource::Misc) => { continue; } (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => { @@ -517,6 +521,16 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { )); impl_where_bound_count += 1; } + (ChildMode::Host(parent_host_pred), GoalSource::ImplWhereBound) => { + obligation = make_obligation(derive_host_cause( + tcx, + candidate.kind(), + self.obligation.cause.clone(), + impl_const_condition_bound_count, + parent_host_pred, + )); + impl_const_condition_bound_count += 1; + } // Skip over a higher-ranked predicate. (_, GoalSource::InstantiateHigherRanked) => { obligation = self.obligation.clone(); @@ -575,6 +589,10 @@ enum ChildMode<'tcx> { // and skip all `GoalSource::Misc`, which represent useless obligations // such as alias-eq which may not hold. Trait(ty::PolyTraitPredicate<'tcx>), + // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`, + // and skip all `GoalSource::Misc`, which represent useless obligations + // such as alias-eq which may not hold. + Host(ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>), // Skip trying to derive an `ObligationCause` from this obligation, and // report *all* sub-obligations as if they came directly from the parent // obligation. @@ -616,3 +634,52 @@ fn derive_cause<'tcx>( }; cause } + +fn derive_host_cause<'tcx>( + tcx: TyCtxt<'tcx>, + candidate_kind: inspect::ProbeKind>, + mut cause: ObligationCause<'tcx>, + idx: usize, + parent_host_pred: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>, +) -> ObligationCause<'tcx> { + match candidate_kind { + inspect::ProbeKind::TraitCandidate { + source: CandidateSource::Impl(impl_def_id), + result: _, + } => { + if let Some((_, span)) = tcx + .predicates_of(impl_def_id) + .instantiate_identity(tcx) + .into_iter() + .chain(tcx.const_conditions(impl_def_id).instantiate_identity(tcx).into_iter().map( + |(trait_ref, span)| { + ( + trait_ref.to_host_effect_clause( + tcx, + parent_host_pred.skip_binder().constness, + ), + span, + ) + }, + )) + .nth(idx) + { + cause = + cause.derived_host_cause(parent_host_pred, |derived| { + ObligationCauseCode::ImplDerivedHost(Box::new( + traits::ImplDerivedHostCause { derived, impl_def_id, span }, + )) + }) + } + } + inspect::ProbeKind::TraitCandidate { + source: CandidateSource::BuiltinImpl(..), + result: _, + } => { + cause = + cause.derived_host_cause(parent_host_pred, ObligationCauseCode::BuiltinDerivedHost); + } + _ => {} + }; + cause +} diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 91484ef99dbb8..0ac24eb54e748 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -1,6 +1,8 @@ use rustc_hir as hir; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes}; -use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation}; +use rustc_infer::traits::{ + ImplDerivedHostCause, ImplSource, Obligation, ObligationCauseCode, PredicateObligation, +}; use rustc_middle::span_bug; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::{self, TypingMode}; @@ -248,9 +250,22 @@ fn evaluate_host_effect_from_selection_candiate<'tcx>( tcx.const_conditions(impl_.impl_def_id) .instantiate(tcx, impl_.args) .into_iter() - .map(|(trait_ref, _)| { - obligation.with( + .map(|(trait_ref, span)| { + Obligation::new( tcx, + obligation.cause.clone().derived_host_cause( + ty::Binder::dummy(obligation.predicate), + |derived| { + ObligationCauseCode::ImplDerivedHost(Box::new( + ImplDerivedHostCause { + derived, + impl_def_id: impl_.impl_def_id, + span, + }, + )) + }, + ), + obligation.param_env, trait_ref .to_host_effect_clause(tcx, obligation.predicate.constness), ) diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 47447af22158d..cb59bc608c203 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -89,6 +89,7 @@ impl_binder_encode_decode! { ty::ExistentialPredicate, ty::TraitRef, ty::ExistentialTraitRef, + ty::HostEffectPredicate, } impl Binder diff --git a/tests/ui/const-generics/issues/issue-88119.stderr b/tests/ui/const-generics/issues/issue-88119.stderr index 370244fe8c984..f219c90849a26 100644 --- a/tests/ui/const-generics/issues/issue-88119.stderr +++ b/tests/ui/const-generics/issues/issue-88119.stderr @@ -11,12 +11,30 @@ error[E0284]: type annotations needed: cannot normalize `<&T as ConstName>::{con | LL | impl const ConstName for &T | ^^ cannot normalize `<&T as ConstName>::{constant#0}` + | +note: required for `&T` to implement `~const ConstName` + --> $DIR/issue-88119.rs:19:35 + | +LL | impl const ConstName for &T + | ^^^^^^^^^ ^^ +LL | where +LL | [(); name_len::()]:, + | --------------------- unsatisfied trait bound introduced here error[E0284]: type annotations needed: cannot normalize `<&mut T as ConstName>::{constant#0}` --> $DIR/issue-88119.rs:26:49 | LL | impl const ConstName for &mut T | ^^^^^^ cannot normalize `<&mut T as ConstName>::{constant#0}` + | +note: required for `&mut T` to implement `~const ConstName` + --> $DIR/issue-88119.rs:26:35 + | +LL | impl const ConstName for &mut T + | ^^^^^^^^^ ^^^^^^ +LL | where +LL | [(); name_len::()]:, + | --------------------- unsatisfied trait bound introduced here error: aborting due to 3 previous errors diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.current.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.current.stderr index 9c29a894749e9..ccd4af99cf41b 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.current.stderr +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.current.stderr @@ -5,7 +5,7 @@ LL | T::Assoc::func(); | ^^^^^^^^ error[E0277]: the trait bound `T: ~const Trait` is not satisfied - --> $DIR/assoc-type-const-bound-usage-fail.rs:19:5 + --> $DIR/assoc-type-const-bound-usage-fail.rs:20:5 | LL | ::Assoc::func(); | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.next.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.next.stderr index 9c29a894749e9..ee1b663b99981 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.next.stderr +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.next.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `T: ~const Trait` is not satisfied +error[E0277]: the trait bound `::Assoc: ~const Trait` is not satisfied --> $DIR/assoc-type-const-bound-usage-fail.rs:17:5 | LL | T::Assoc::func(); | ^^^^^^^^ -error[E0277]: the trait bound `T: ~const Trait` is not satisfied - --> $DIR/assoc-type-const-bound-usage-fail.rs:19:5 +error[E0277]: the trait bound `::Assoc: ~const Trait` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail.rs:20:5 | LL | ::Assoc::func(); | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs index 3761fea19684d..224ebb2daf16e 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs @@ -15,9 +15,11 @@ trait Trait { const fn unqualified() { T::Assoc::func(); - //~^ ERROR the trait bound `T: ~const Trait` is not satisfied + //[current]~^ ERROR the trait bound `T: ~const Trait` is not satisfied + //[next]~^^ ERROR the trait bound `::Assoc: ~const Trait` is not satisfied ::Assoc::func(); - //~^ ERROR the trait bound `T: ~const Trait` is not satisfied + //[current]~^ ERROR the trait bound `T: ~const Trait` is not satisfied + //[next]~^^ ERROR the trait bound `::Assoc: ~const Trait` is not satisfied } const fn works() { diff --git a/tests/ui/traits/const-traits/const-opaque.no.stderr b/tests/ui/traits/const-traits/const-opaque.no.stderr index 1278e1257467b..33aa1065df356 100644 --- a/tests/ui/traits/const-traits/const-opaque.no.stderr +++ b/tests/ui/traits/const-traits/const-opaque.no.stderr @@ -12,7 +12,7 @@ note: required by a bound in `bar` LL | const fn bar(t: T) -> impl ~const Foo { | ^^^^^^ required by this bound in `bar` -error[E0277]: the trait bound `(): const Foo` is not satisfied +error[E0277]: the trait bound `impl Foo: const Foo` is not satisfied --> $DIR/const-opaque.rs:33:12 | LL | opaque.method(); diff --git a/tests/ui/traits/const-traits/const-opaque.rs b/tests/ui/traits/const-traits/const-opaque.rs index 96cdd7d9f2619..bfcadd521a54e 100644 --- a/tests/ui/traits/const-traits/const-opaque.rs +++ b/tests/ui/traits/const-traits/const-opaque.rs @@ -31,7 +31,7 @@ const _: () = { let opaque = bar(()); //[no]~^ ERROR the trait bound `(): const Foo` is not satisfied opaque.method(); - //[no]~^ ERROR the trait bound `(): const Foo` is not satisfied + //[no]~^ ERROR the trait bound `impl Foo: const Foo` is not satisfied std::mem::forget(opaque); }; diff --git a/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr index 3fc6f58470947..0d53bc5897ef3 100644 --- a/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr +++ b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr @@ -16,6 +16,11 @@ error[E0277]: the trait bound `T: ~const Bar` is not satisfied LL | type Assoc = C | ^^^^ | +note: required for `C` to implement `~const Bar` + --> $DIR/item-bound-entailment-fails.rs:14:15 + | +LL | impl const Bar for C where T: ~const Bar {} + | ^^^ ^^^^ ------ unsatisfied trait bound introduced here note: required by a bound in `Foo::Assoc` --> $DIR/item-bound-entailment-fails.rs:5:20 | From 96285bde3858b608258bdc48bb933c626bfd6a21 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 25 Dec 2024 02:22:08 +0000 Subject: [PATCH 08/12] Don't ice on bad transmute in typeck in new solver --- compiler/rustc_hir_typeck/src/intrinsicck.rs | 14 +++- .../dont-ice-on-bad-transmute-in-typeck.rs | 17 +++++ ...dont-ice-on-bad-transmute-in-typeck.stderr | 75 +++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 tests/ui/traits/next-solver/dont-ice-on-bad-transmute-in-typeck.rs create mode 100644 tests/ui/traits/next-solver/dont-ice-on-bad-transmute-in-typeck.stderr diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 789530d35dd81..f4929aae59901 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -40,13 +40,25 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + /// FIXME: Move this check out of typeck, since it'll easily cycle when revealing opaques, + /// and we shouldn't need to check anything here if the typeck results are tainted. pub(crate) fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) { let tcx = self.tcx; let dl = &tcx.data_layout; let span = tcx.hir().span(hir_id); let normalize = |ty| { let ty = self.resolve_vars_if_possible(ty); - self.tcx.normalize_erasing_regions(self.typing_env(self.param_env), ty) + if let Ok(ty) = + self.tcx.try_normalize_erasing_regions(self.typing_env(self.param_env), ty) + { + ty + } else { + Ty::new_error_with_message( + tcx, + span, + "tried to normalize non-wf type in check_transmute", + ) + } }; let from = normalize(from); let to = normalize(to); diff --git a/tests/ui/traits/next-solver/dont-ice-on-bad-transmute-in-typeck.rs b/tests/ui/traits/next-solver/dont-ice-on-bad-transmute-in-typeck.rs new file mode 100644 index 0000000000000..129e90a07f43a --- /dev/null +++ b/tests/ui/traits/next-solver/dont-ice-on-bad-transmute-in-typeck.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Znext-solver + +trait Trait<'a> { + type Assoc; +} + +fn foo(x: for<'a> fn(<() as Trait<'a>>::Assoc)) { + //~^ ERROR the trait bound `for<'a> (): Trait<'a>` is not satisfied + //~| ERROR the trait bound `for<'a> (): Trait<'a>` is not satisfied + //~| ERROR the trait bound `for<'a> (): Trait<'a>` is not satisfied + unsafe { std::mem::transmute::<_, ()>(x); } + //~^ ERROR the trait bound `for<'a> (): Trait<'a>` is not satisfied + //~| ERROR the trait bound `for<'a> (): Trait<'a>` is not satisfied + //~| ERROR the trait bound `for<'a> (): Trait<'a>` is not satisfied +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/dont-ice-on-bad-transmute-in-typeck.stderr b/tests/ui/traits/next-solver/dont-ice-on-bad-transmute-in-typeck.stderr new file mode 100644 index 0000000000000..2d42fedae4381 --- /dev/null +++ b/tests/ui/traits/next-solver/dont-ice-on-bad-transmute-in-typeck.stderr @@ -0,0 +1,75 @@ +error[E0277]: the trait bound `for<'a> (): Trait<'a>` is not satisfied + --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:7:11 + | +LL | fn foo(x: for<'a> fn(<() as Trait<'a>>::Assoc)) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a>` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:3:1 + | +LL | trait Trait<'a> { + | ^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `for<'a> (): Trait<'a>` is not satisfied + --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:7:8 + | +LL | fn foo(x: for<'a> fn(<() as Trait<'a>>::Assoc)) { + | ^ the trait `for<'a> Trait<'a>` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:3:1 + | +LL | trait Trait<'a> { + | ^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `for<'a> (): Trait<'a>` is not satisfied + --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:11:14 + | +LL | unsafe { std::mem::transmute::<_, ()>(x); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a>` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:3:1 + | +LL | trait Trait<'a> { + | ^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `for<'a> (): Trait<'a>` is not satisfied + --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:11:36 + | +LL | unsafe { std::mem::transmute::<_, ()>(x); } + | ^ the trait `for<'a> Trait<'a>` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:3:1 + | +LL | trait Trait<'a> { + | ^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `for<'a> (): Trait<'a>` is not satisfied + --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:11:43 + | +LL | unsafe { std::mem::transmute::<_, ()>(x); } + | ^ the trait `for<'a> Trait<'a>` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:3:1 + | +LL | trait Trait<'a> { + | ^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `for<'a> (): Trait<'a>` is not satisfied + --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:7:1 + | +LL | fn foo(x: for<'a> fn(<() as Trait<'a>>::Assoc)) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a>` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:3:1 + | +LL | trait Trait<'a> { + | ^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. From ebdf19a8bbd1efb533bab35b0a2b327e4a33282f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 23 Dec 2024 20:17:53 +0000 Subject: [PATCH 09/12] Recurse on GAT where clauses in fulfillment error proof tree visitor --- .../src/solve/effect_goals.rs | 4 ++-- .../rustc_trait_selection/src/solve/fulfill.rs | 14 +++++++++----- compiler/rustc_type_ir/src/solve/mod.rs | 4 ++++ ...oc-type-const-bound-usage-fail-2.current.stderr | 2 +- ...assoc-type-const-bound-usage-fail-2.next.stderr | 6 +++--- .../assoc-type-const-bound-usage-fail-2.rs | 6 ++---- ...ssoc-type-const-bound-usage-fail.current.stderr | 2 +- .../assoc-type-const-bound-usage-fail.next.stderr | 6 +++--- .../assoc-type-const-bound-usage-fail.rs | 6 ++---- .../ui/traits/const-traits/const-opaque.no.stderr | 2 +- tests/ui/traits/const-traits/const-opaque.rs | 2 +- 11 files changed, 29 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 281796e84b169..7669a305d58d1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -103,7 +103,7 @@ where |ecx| { // Const conditions must hold for the implied const bound to hold. ecx.add_goals( - GoalSource::Misc, + GoalSource::AliasBoundConstCondition, cx.const_conditions(alias_ty.def_id) .iter_instantiated(cx, alias_ty.args) .map(|trait_ref| { @@ -353,7 +353,7 @@ where ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { ecx.add_goals( - GoalSource::ImplWhereBound, + GoalSource::AliasBoundConstCondition, const_conditions.into_iter().map(|trait_ref| { goal.with( cx, diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 7aa82c52c9f26..986176aca770e 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -413,6 +413,7 @@ impl<'tcx> BestObligation<'tcx> { matches!( nested_goal.source(), GoalSource::ImplWhereBound + | GoalSource::AliasBoundConstCondition | GoalSource::InstantiateHigherRanked | GoalSource::AliasWellFormed ) && match self.consider_ambiguities { @@ -495,7 +496,6 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { }; let mut impl_where_bound_count = 0; - let mut impl_const_condition_bound_count = 0; for nested_goal in candidate.instantiate_nested_goals(self.span()) { trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result())); @@ -521,21 +521,25 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { )); impl_where_bound_count += 1; } - (ChildMode::Host(parent_host_pred), GoalSource::ImplWhereBound) => { + ( + ChildMode::Host(parent_host_pred), + GoalSource::ImplWhereBound | GoalSource::AliasBoundConstCondition, + ) => { obligation = make_obligation(derive_host_cause( tcx, candidate.kind(), self.obligation.cause.clone(), - impl_const_condition_bound_count, + impl_where_bound_count, parent_host_pred, )); - impl_const_condition_bound_count += 1; + impl_where_bound_count += 1; } // Skip over a higher-ranked predicate. (_, GoalSource::InstantiateHigherRanked) => { obligation = self.obligation.clone(); } - (ChildMode::PassThrough, _) | (_, GoalSource::AliasWellFormed) => { + (ChildMode::PassThrough, _) + | (_, GoalSource::AliasWellFormed | GoalSource::AliasBoundConstCondition) => { obligation = make_obligation(self.obligation.cause.clone()); } } diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 8fe512026e5d9..1ae904d50e066 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -68,6 +68,10 @@ pub enum GoalSource { /// FIXME(-Znext-solver=coinductive): Explain how and why this /// changes whether cycles are coinductive. ImplWhereBound, + /// Const conditions that need to hold for `~const` alias bounds to hold. + /// + /// FIXME(-Znext-solver=coinductive): Are these even coinductive? + AliasBoundConstCondition, /// Instantiating a higher-ranked goal and re-proving it. InstantiateHigherRanked, /// Predicate required for an alias projection to be well-formed. diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.current.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.current.stderr index 03da9159bea0b..4cd87002e4910 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.current.stderr +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.current.stderr @@ -5,7 +5,7 @@ LL | T::Assoc::::func(); | ^^^^^^^^^^^^^ error[E0277]: the trait bound `U: ~const Other` is not satisfied - --> $DIR/assoc-type-const-bound-usage-fail-2.rs:27:5 + --> $DIR/assoc-type-const-bound-usage-fail-2.rs:26:5 | LL | ::Assoc::::func(); | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.next.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.next.stderr index ce58b486a16ef..4cd87002e4910 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.next.stderr +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.next.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `::Assoc: ~const Trait` is not satisfied +error[E0277]: the trait bound `U: ~const Other` is not satisfied --> $DIR/assoc-type-const-bound-usage-fail-2.rs:24:5 | LL | T::Assoc::::func(); | ^^^^^^^^^^^^^ -error[E0277]: the trait bound `::Assoc: ~const Trait` is not satisfied - --> $DIR/assoc-type-const-bound-usage-fail-2.rs:27:5 +error[E0277]: the trait bound `U: ~const Other` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail-2.rs:26:5 | LL | ::Assoc::::func(); | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs index bdd98eaf541f8..e1c30b5361124 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail-2.rs @@ -22,11 +22,9 @@ trait Other {} const fn fails() { T::Assoc::::func(); - //[current]~^ ERROR the trait bound `U: ~const Other` is not satisfied - //[next]~^^ ERROR the trait bound `::Assoc: ~const Trait` is not satisfied + //~^ ERROR the trait bound `U: ~const Other` is not satisfied ::Assoc::::func(); - //[current]~^ ERROR the trait bound `U: ~const Other` is not satisfied - //[next]~^^ ERROR the trait bound `::Assoc: ~const Trait` is not satisfied + //~^ ERROR the trait bound `U: ~const Other` is not satisfied } const fn works() { diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.current.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.current.stderr index ccd4af99cf41b..9c29a894749e9 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.current.stderr +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.current.stderr @@ -5,7 +5,7 @@ LL | T::Assoc::func(); | ^^^^^^^^ error[E0277]: the trait bound `T: ~const Trait` is not satisfied - --> $DIR/assoc-type-const-bound-usage-fail.rs:20:5 + --> $DIR/assoc-type-const-bound-usage-fail.rs:19:5 | LL | ::Assoc::func(); | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.next.stderr b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.next.stderr index ee1b663b99981..9c29a894749e9 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.next.stderr +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.next.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `::Assoc: ~const Trait` is not satisfied +error[E0277]: the trait bound `T: ~const Trait` is not satisfied --> $DIR/assoc-type-const-bound-usage-fail.rs:17:5 | LL | T::Assoc::func(); | ^^^^^^^^ -error[E0277]: the trait bound `::Assoc: ~const Trait` is not satisfied - --> $DIR/assoc-type-const-bound-usage-fail.rs:20:5 +error[E0277]: the trait bound `T: ~const Trait` is not satisfied + --> $DIR/assoc-type-const-bound-usage-fail.rs:19:5 | LL | ::Assoc::func(); | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs index 224ebb2daf16e..3761fea19684d 100644 --- a/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs +++ b/tests/ui/traits/const-traits/assoc-type-const-bound-usage-fail.rs @@ -15,11 +15,9 @@ trait Trait { const fn unqualified() { T::Assoc::func(); - //[current]~^ ERROR the trait bound `T: ~const Trait` is not satisfied - //[next]~^^ ERROR the trait bound `::Assoc: ~const Trait` is not satisfied + //~^ ERROR the trait bound `T: ~const Trait` is not satisfied ::Assoc::func(); - //[current]~^ ERROR the trait bound `T: ~const Trait` is not satisfied - //[next]~^^ ERROR the trait bound `::Assoc: ~const Trait` is not satisfied + //~^ ERROR the trait bound `T: ~const Trait` is not satisfied } const fn works() { diff --git a/tests/ui/traits/const-traits/const-opaque.no.stderr b/tests/ui/traits/const-traits/const-opaque.no.stderr index 33aa1065df356..1278e1257467b 100644 --- a/tests/ui/traits/const-traits/const-opaque.no.stderr +++ b/tests/ui/traits/const-traits/const-opaque.no.stderr @@ -12,7 +12,7 @@ note: required by a bound in `bar` LL | const fn bar(t: T) -> impl ~const Foo { | ^^^^^^ required by this bound in `bar` -error[E0277]: the trait bound `impl Foo: const Foo` is not satisfied +error[E0277]: the trait bound `(): const Foo` is not satisfied --> $DIR/const-opaque.rs:33:12 | LL | opaque.method(); diff --git a/tests/ui/traits/const-traits/const-opaque.rs b/tests/ui/traits/const-traits/const-opaque.rs index bfcadd521a54e..96cdd7d9f2619 100644 --- a/tests/ui/traits/const-traits/const-opaque.rs +++ b/tests/ui/traits/const-traits/const-opaque.rs @@ -31,7 +31,7 @@ const _: () = { let opaque = bar(()); //[no]~^ ERROR the trait bound `(): const Foo` is not satisfied opaque.method(); - //[no]~^ ERROR the trait bound `impl Foo: const Foo` is not satisfied + //[no]~^ ERROR the trait bound `(): const Foo` is not satisfied std::mem::forget(opaque); }; From 304ccf45d15153b29c413a84334a9b4aaee23d53 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 4 Jan 2025 00:13:49 +0000 Subject: [PATCH 10/12] Suggest to replace tuple constructor through projection --- .../rustc_hir_typeck/src/method/suggest.rs | 26 ++++++++++++++++++- tests/ui/associated-types/invalid-ctor.fixed | 22 ++++++++++++++++ tests/ui/associated-types/invalid-ctor.rs | 22 ++++++++++++++++ tests/ui/associated-types/invalid-ctor.stderr | 14 ++++++++++ 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 tests/ui/associated-types/invalid-ctor.fixed create mode 100644 tests/ui/associated-types/invalid-ctor.rs create mode 100644 tests/ui/associated-types/invalid-ctor.stderr diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 0b008fd10b507..b4f1dcfb9cc8a 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -14,7 +14,7 @@ use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, MultiSpan, StashKey, pluralize, struct_span_code_err}; -use rustc_hir::def::DefKind; +use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::lang_items::LangItem; @@ -690,6 +690,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } + // Check if we wrote `Self::Assoc(1)` as if it were a tuple ctor. + if let SelfSource::QPath(ty) = source + && let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind + && let Res::SelfTyAlias { alias_to: impl_def_id, .. } = path.res + && let DefKind::Impl { .. } = self.tcx.def_kind(impl_def_id) + && let Some(candidate) = tcx.associated_items(impl_def_id).find_by_name_and_kind( + self.tcx, + item_name, + ty::AssocKind::Type, + impl_def_id, + ) + && let Some(adt_def) = tcx.type_of(candidate.def_id).skip_binder().ty_adt_def() + && adt_def.is_struct() + && adt_def.non_enum_variant().ctor_kind() == Some(CtorKind::Fn) + { + let def_path = tcx.def_path_str(adt_def.did()); + err.span_suggestion( + ty.span.to(item_name.span), + format!("to construct a value of type `{}`, use the explicit path", def_path), + def_path, + Applicability::MachineApplicable, + ); + } + err }; if tcx.sess.source_map().is_multiline(sugg_span) { diff --git a/tests/ui/associated-types/invalid-ctor.fixed b/tests/ui/associated-types/invalid-ctor.fixed new file mode 100644 index 0000000000000..eba3820de0c1c --- /dev/null +++ b/tests/ui/associated-types/invalid-ctor.fixed @@ -0,0 +1,22 @@ +//@ run-rustfix + +#![allow(unused)] + +struct Constructor(i32); + +trait Trait { + type Out; + + fn mk() -> Self::Out; +} + +impl Trait for () { + type Out = Constructor; + + fn mk() -> Self::Out { + Constructor(1) + //~^ ERROR no associated item named `Out` found for unit type `()` + } +} + +fn main() {} diff --git a/tests/ui/associated-types/invalid-ctor.rs b/tests/ui/associated-types/invalid-ctor.rs new file mode 100644 index 0000000000000..73335c065c2ae --- /dev/null +++ b/tests/ui/associated-types/invalid-ctor.rs @@ -0,0 +1,22 @@ +//@ run-rustfix + +#![allow(unused)] + +struct Constructor(i32); + +trait Trait { + type Out; + + fn mk() -> Self::Out; +} + +impl Trait for () { + type Out = Constructor; + + fn mk() -> Self::Out { + Self::Out(1) + //~^ ERROR no associated item named `Out` found for unit type `()` + } +} + +fn main() {} diff --git a/tests/ui/associated-types/invalid-ctor.stderr b/tests/ui/associated-types/invalid-ctor.stderr new file mode 100644 index 0000000000000..b545c95a76814 --- /dev/null +++ b/tests/ui/associated-types/invalid-ctor.stderr @@ -0,0 +1,14 @@ +error[E0599]: no associated item named `Out` found for unit type `()` in the current scope + --> $DIR/invalid-ctor.rs:17:15 + | +LL | Self::Out(1) + | ^^^ associated item not found in `()` + | +help: to construct a value of type `Constructor`, use the explicit path + | +LL | Constructor(1) + | ~~~~~~~~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. From 5172364b6752ee3d9c7e3607b4acb293a0e5ec34 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Mon, 6 Jan 2025 10:50:58 -0800 Subject: [PATCH 11/12] Update triagebot.toml: celinval vacation is over I'm also removing myself from the MIR syntax changes notifications. --- triagebot.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 7efa63c2642fd..2a0ad610c1a00 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -824,7 +824,7 @@ cc = ["@rust-lang/rustfmt"] [mentions."compiler/rustc_middle/src/mir/syntax.rs"] message = "This PR changes MIR" -cc = ["@oli-obk", "@RalfJung", "@JakobDegen", "@davidtwco", "@celinval", "@vakaras"] +cc = ["@oli-obk", "@RalfJung", "@JakobDegen", "@davidtwco", "@vakaras"] [mentions."compiler/rustc_error_messages"] message = "`rustc_error_messages` was changed" @@ -1004,7 +1004,6 @@ warn_non_default_branch.enable = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ "jyn514", - "celinval", "nnethercote", "spastorino", "workingjubilee", From b0aaa386d8f0af9dd4d08f3009498addbe0157fa Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sat, 4 Jan 2025 19:51:56 -0800 Subject: [PATCH 12/12] rustdoc: Fix mismatched capitalization in sidebar Previously, the main content used "Aliased Type", while the sidebar said "Aliased type". Now, they both say "Aliased Type", which is the more common capitalization in Rustdoc. See the following link for an example. https://doc.rust-lang.org/1.83.0/std/io/type.Result.html --- src/librustdoc/html/render/sidebar.rs | 2 +- tests/rustdoc/type-alias/deref-32077.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index af39d15f67175..881df8b005017 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -357,7 +357,7 @@ fn sidebar_type_alias<'a>( deref_id_map: &'a DefIdMap, ) { if let Some(inner_type) = &t.inner_type { - items.push(LinkBlock::forced(Link::new("aliased-type", "Aliased type"), "type")); + items.push(LinkBlock::forced(Link::new("aliased-type", "Aliased Type"), "type")); match inner_type { clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive: _ } => { let mut variants = variants diff --git a/tests/rustdoc/type-alias/deref-32077.rs b/tests/rustdoc/type-alias/deref-32077.rs index 79a833813406e..faab4b6f522ba 100644 --- a/tests/rustdoc/type-alias/deref-32077.rs +++ b/tests/rustdoc/type-alias/deref-32077.rs @@ -19,8 +19,8 @@ impl Foo for GenericStruct {} impl Bar for GenericStruct {} //@ has 'foo/type.TypedefStruct.html' -// We check that "Aliased type" is also present as a title in the sidebar. -//@ has - '//*[@class="sidebar-elems"]//h3/a[@href="#aliased-type"]' 'Aliased type' +// We check that "Aliased Type" is also present as a title in the sidebar. +//@ has - '//*[@class="sidebar-elems"]//h3/a[@href="#aliased-type"]' 'Aliased Type' // We check that we have the implementation of the type alias itself. //@ has - '//*[@id="impl-GenericStruct%3Cu8%3E"]/h3' 'impl TypedefStruct' //@ has - '//*[@id="method.on_alias"]/h4' 'pub fn on_alias()'