diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 5d751a250805f..36b214b6ae734 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -9,6 +9,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_middle::bug; +use rustc_middle::ty::fast_reject::{TreatParams, simplify_type}; use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _}; use rustc_middle::ty::{ self, AdtDef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, @@ -998,12 +999,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { )), .. }) = node - && let Some(adt_def) = qself_ty.ty_adt_def() - && let [inherent_impl] = tcx.inherent_impls(adt_def.did()) - && let name = format!("{ident2}_{ident3}") - && let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = tcx - .associated_items(inherent_impl) - .filter_by_name_unhygienic(Symbol::intern(&name)) + && let Some(inherent_impls) = qself_ty + .ty_adt_def() + .map(|adt_def| tcx.inherent_impls(adt_def.did())) + .or_else(|| { + simplify_type(tcx, qself_ty, TreatParams::InstantiateWithInfer) + .map(|simple_ty| tcx.incoherent_impls(simple_ty)) + }) + && let name = Symbol::intern(&format!("{ident2}_{ident3}")) + && let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = inherent_impls + .iter() + .flat_map(|inherent_impl| { + tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name) + }) .next() { Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type") diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 1f2df7f0168cb..37564ab38fca4 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1853,6 +1853,8 @@ supported_targets! { ("armv7a-none-eabi", armv7a_none_eabi), ("armv7a-none-eabihf", armv7a_none_eabihf), + ("armv7a-nuttx-eabi", armv7a_nuttx_eabi), + ("armv7a-nuttx-eabihf", armv7a_nuttx_eabihf), ("msp430-none-elf", msp430_none_elf), @@ -1896,6 +1898,7 @@ supported_targets! { ("aarch64-unknown-none", aarch64_unknown_none), ("aarch64-unknown-none-softfloat", aarch64_unknown_none_softfloat), + ("aarch64-unknown-nuttx", aarch64_unknown_nuttx), ("x86_64-fortanix-unknown-sgx", x86_64_fortanix_unknown_sgx), @@ -1971,6 +1974,8 @@ supported_targets! { ("x86_64-unknown-linux-none", x86_64_unknown_linux_none), ("thumbv6m-nuttx-eabi", thumbv6m_nuttx_eabi), + ("thumbv7a-nuttx-eabi", thumbv7a_nuttx_eabi), + ("thumbv7a-nuttx-eabihf", thumbv7a_nuttx_eabihf), ("thumbv7m-nuttx-eabi", thumbv7m_nuttx_eabi), ("thumbv7em-nuttx-eabi", thumbv7em_nuttx_eabi), ("thumbv7em-nuttx-eabihf", thumbv7em_nuttx_eabihf), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs new file mode 100644 index 0000000000000..04fd3ec1c26de --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nuttx.rs @@ -0,0 +1,46 @@ +// Generic AArch64 target for NuttX OS +// +// Can be used in conjunction with the `target-feature` and +// `target-cpu` compiler flags to opt-in more hardware-specific +// features. +// +// For example, `-C target-cpu=cortex-a53`. + +use crate::spec::{ + Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, Target, + TargetOptions, cvs, +}; + +pub(crate) fn target() -> Target { + let opts = TargetOptions { + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + // Enable the Cortex-A53 errata 843419 mitigation by default + pre_link_args: TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), &[ + "--fix-cortex-a53-843419", + ]), + features: "+v8a,+strict-align,+neon,+fp-armv8".into(), + supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(128), + stack_probes: StackProbeType::Inline, + panic_strategy: PanicStrategy::Abort, + families: cvs!["unix"], + os: "nuttx".into(), + ..Default::default() + }; + Target { + llvm_target: "aarch64-unknown-none".into(), + metadata: crate::spec::TargetMetadata { + description: Some("AArch64 NuttX".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 64, + data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), + arch: "aarch64".into(), + options: opts, + } +} diff --git a/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs new file mode 100644 index 0000000000000..138716e8f1433 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs @@ -0,0 +1,41 @@ +// Targets Cortex-A7/A8/A9 processors (ARMv7-A) running NuttX +// +// This target assumes that the device does NOT have a FPU (Floating Point Unit) +// and will use software floating point operations. This matches the NuttX EABI +// configuration without hardware floating point support. + +use crate::spec::{ + Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs, +}; + +pub(crate) fn target() -> Target { + let opts = TargetOptions { + abi: "eabi".into(), + llvm_floatabi: Some(FloatAbi::Soft), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + features: "+v7,+thumb2,+soft-float,-neon,+strict-align".into(), + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(64), + panic_strategy: PanicStrategy::Abort, + emit_debug_gdb_scripts: false, + c_enum_min_bits: Some(8), + families: cvs!["unix"], + os: "nuttx".into(), + ..Default::default() + }; + Target { + llvm_target: "armv7a-none-eabi".into(), + metadata: crate::spec::TargetMetadata { + description: Some("ARMv7-A Cortex-A with NuttX".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + arch: "arm".into(), + options: opts, + } +} diff --git a/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs new file mode 100644 index 0000000000000..40391c9f48e40 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabihf.rs @@ -0,0 +1,41 @@ +// Targets Cortex-A7/A8/A9 processors (ARMv7-A) running NuttX with hardware floating point +// +// This target assumes that the device has a FPU (Floating Point Unit) +// and will use hardware floating point operations. This matches the NuttX EABI +// configuration with hardware floating point support. + +use crate::spec::{ + Cc, FloatAbi, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions, cvs, +}; + +pub(crate) fn target() -> Target { + let opts = TargetOptions { + abi: "eabihf".into(), + llvm_floatabi: Some(FloatAbi::Hard), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + features: "+v7,+thumb2,+vfp3,+neon,+strict-align".into(), + relocation_model: RelocModel::Static, + disable_redzone: true, + max_atomic_width: Some(64), + panic_strategy: PanicStrategy::Abort, + emit_debug_gdb_scripts: false, + c_enum_min_bits: Some(8), + families: cvs!["unix"], + os: "nuttx".into(), + ..Default::default() + }; + Target { + llvm_target: "armv7a-none-eabihf".into(), + metadata: crate::spec::TargetMetadata { + description: Some("ARMv7-A Cortex-A with NuttX (hard float)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + arch: "arm".into(), + options: opts, + } +} diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs new file mode 100644 index 0000000000000..7fd22602e5622 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabi.rs @@ -0,0 +1,33 @@ +// Targets Cortex-A7/A8/A9 processors (ARMv7-A) +// +// This target assumes that the device does NOT have a FPU (Floating Point Unit) +// and will use software floating point operations. This matches the NuttX EABI +// configuration without hardware floating point support. + +use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs}; + +pub(crate) fn target() -> Target { + Target { + llvm_target: "thumbv7a-none-eabi".into(), + metadata: crate::spec::TargetMetadata { + description: None, + tier: None, + host_tools: None, + std: None, + }, + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + arch: "arm".into(), + + options: TargetOptions { + families: cvs!["unix"], + os: "nuttx".into(), + abi: "eabi".into(), + llvm_floatabi: Some(FloatAbi::Soft), + // Cortex-A7/A8/A9 with software floating point + features: "+soft-float,-neon".into(), + max_atomic_width: Some(64), + ..base::thumb::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs new file mode 100644 index 0000000000000..d3148c53a829d --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/thumbv7a_nuttx_eabihf.rs @@ -0,0 +1,37 @@ +// Targets Cortex-A7/A8/A9 processors (ARMv7-A) +// +// This target assumes that the device has a FPU (Floating Point Unit) and lowers all (single +// precision) floating point operations to hardware instructions. Cortex-A7/A8/A9 processors +// support VFPv3-D32 or VFPv4-D32 floating point units with optional double-precision support. +// +// This target uses the "hard" floating convention (ABI) where floating point values +// are passed to/from subroutines via FPU registers (S0, S1, D0, D1, etc.). + +use crate::spec::{FloatAbi, Target, TargetOptions, base, cvs}; + +pub(crate) fn target() -> Target { + Target { + llvm_target: "thumbv7a-none-eabihf".into(), + metadata: crate::spec::TargetMetadata { + description: None, + tier: None, + host_tools: None, + std: None, + }, + pointer_width: 32, + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + arch: "arm".into(), + + options: TargetOptions { + families: cvs!["unix"], + os: "nuttx".into(), + abi: "eabihf".into(), + llvm_floatabi: Some(FloatAbi::Hard), + // Cortex-A7/A8/A9 support VFPv3-D32/VFPv4-D32 with optional double-precision + // and NEON SIMD instructions + features: "+vfp3,+neon".into(), + max_atomic_width: Some(64), + ..base::thumb::opts() + }, + } +} diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 4004e354dc189..26ba1511b540e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -6,8 +6,7 @@ use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument}; use crate::traits::query::NoSolution; -use crate::traits::query::normalize::QueryNormalizeExt; -use crate::traits::{Normalized, ObligationCause, ObligationCtxt}; +use crate::traits::{ObligationCause, ObligationCtxt}; /// This returns true if the type `ty` is "trivial" for /// dropck-outlives -- that is, if it doesn't require any types to @@ -172,13 +171,18 @@ pub fn compute_dropck_outlives_inner<'tcx>( // do not themselves define a destructor", more or less. We have // to push them onto the stack to be expanded. for ty in constraints.dtorck_types.drain(..) { - let Normalized { value: ty, obligations } = - ocx.infcx.at(&cause, param_env).query_normalize(ty)?; - ocx.register_obligations(obligations); + let normalized_ty = ocx.normalize(&cause, param_env, ty); - debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); + let errors = ocx.select_where_possible(); + if !errors.is_empty() { + debug!("failed to normalize dtorck type: {ty} ~> {errors:#?}"); + return Err(NoSolution); + } + + let normalized_ty = ocx.infcx.resolve_vars_if_possible(normalized_ty); + debug!("dropck_outlives: ty from dtorck_types = {:?}", normalized_ty); - match ty.kind() { + match normalized_ty.kind() { // All parameters live for the duration of the // function. ty::Param(..) => {} @@ -186,12 +190,12 @@ pub fn compute_dropck_outlives_inner<'tcx>( // A projection that we couldn't resolve - it // might have a destructor. ty::Alias(..) => { - result.kinds.push(ty.into()); + result.kinds.push(normalized_ty.into()); } _ => { - if ty_set.insert(ty) { - ty_stack.push((ty, depth + 1)); + if ty_set.insert(normalized_ty) { + ty_stack.push((normalized_ty, depth + 1)); } } } diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index 71088a598bb93..5d041c2623aa8 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -6,13 +6,12 @@ use rustc_middle::query::Providers; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{Clause, FnSig, ParamEnvAnd, PolyFnSig, Ty, TyCtxt, TypeFoldable}; use rustc_trait_selection::infer::InferCtxtBuilderExt; -use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{ AscribeUserType, type_op_ascribe_user_type_with_span, }; use rustc_trait_selection::traits::query::type_op::normalize::Normalize; use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate; -use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt}; +use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; pub(crate) fn provide(p: &mut Providers) { *p = Providers { @@ -43,10 +42,7 @@ where T: fmt::Debug + TypeFoldable>, { let (param_env, Normalize { value }) = key.into_parts(); - let Normalized { value, obligations } = - ocx.infcx.at(&ObligationCause::dummy(), param_env).query_normalize(value)?; - ocx.register_obligations(obligations); - Ok(value) + Ok(ocx.normalize(&ObligationCause::dummy(), param_env, value)) } fn type_op_normalize_ty<'tcx>( diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 0b6a55297e1ab..1c33f8f60d824 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1735,6 +1735,52 @@ impl VecDeque { } } + /// Removes and returns the first element from the deque if the predicate + /// returns `true`, or [`None`] if the predicate returns false or the deque + /// is empty (the predicate will not be called in that case). + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_pop_if)] + /// use std::collections::VecDeque; + /// + /// let mut deque: VecDeque = vec![0, 1, 2, 3, 4].into(); + /// let pred = |x: &mut i32| *x % 2 == 0; + /// + /// assert_eq!(deque.pop_front_if(pred), Some(0)); + /// assert_eq!(deque, [1, 2, 3, 4]); + /// assert_eq!(deque.pop_front_if(pred), None); + /// ``` + #[unstable(feature = "vec_deque_pop_if", issue = "135889")] + pub fn pop_front_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option { + let first = self.front_mut()?; + if predicate(first) { self.pop_front() } else { None } + } + + /// Removes and returns the last element from the deque if the predicate + /// returns `true`, or [`None`] if the predicate returns false or the deque + /// is empty (the predicate will not be called in that case). + /// + /// # Examples + /// + /// ``` + /// #![feature(vec_deque_pop_if)] + /// use std::collections::VecDeque; + /// + /// let mut deque: VecDeque = vec![0, 1, 2, 3, 4].into(); + /// let pred = |x: &mut i32| *x % 2 == 0; + /// + /// assert_eq!(deque.pop_back_if(pred), Some(4)); + /// assert_eq!(deque, [0, 1, 2, 3]); + /// assert_eq!(deque.pop_back_if(pred), None); + /// ``` + #[unstable(feature = "vec_deque_pop_if", issue = "135889")] + pub fn pop_back_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option { + let first = self.back_mut()?; + if predicate(first) { self.pop_back() } else { None } + } + /// Prepends an element to the deque. /// /// # Examples diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 393bdfe48b741..d8364d750fa8f 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -38,6 +38,7 @@ #![feature(str_as_str)] #![feature(strict_provenance_lints)] #![feature(vec_pop_if)] +#![feature(vec_deque_pop_if)] #![feature(unique_rc_arc)] #![feature(macro_metavar_expr_concat)] #![allow(internal_features)] diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index 4b8d3c735f72b..1b03c29e5bda1 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -80,6 +80,45 @@ fn test_parameterized(a: T, b: T, c: T, d: T) { assert_eq!(deq[3].clone(), d.clone()); } +#[test] +fn test_pop_if() { + let mut deq: VecDeque<_> = vec![0, 1, 2, 3, 4].into(); + let pred = |x: &mut i32| *x % 2 == 0; + + assert_eq!(deq.pop_front_if(pred), Some(0)); + assert_eq!(deq, [1, 2, 3, 4]); + + assert_eq!(deq.pop_front_if(pred), None); + assert_eq!(deq, [1, 2, 3, 4]); + + assert_eq!(deq.pop_back_if(pred), Some(4)); + assert_eq!(deq, [1, 2, 3]); + + assert_eq!(deq.pop_back_if(pred), None); + assert_eq!(deq, [1, 2, 3]); +} + +#[test] +fn test_pop_if_empty() { + let mut deq = VecDeque::::new(); + assert_eq!(deq.pop_front_if(|_| true), None); + assert_eq!(deq.pop_back_if(|_| true), None); + assert!(deq.is_empty()); +} + +#[test] +fn test_pop_if_mutates() { + let mut v: VecDeque<_> = vec![-1, 1].into(); + let pred = |x: &mut i32| { + *x *= 2; + false + }; + assert_eq!(v.pop_front_if(pred), None); + assert_eq!(v, [-2, 1]); + assert_eq!(v.pop_back_if(pred), None); + assert_eq!(v, [-2, 2]); +} + #[test] fn test_push_front_grow() { let mut deq = VecDeque::new(); diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index ba61679564a69..28329bb090845 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -156,7 +156,6 @@ pub const fn from_mut(s: &mut T) -> &mut [T; 1] { /// The error type returned when a conversion from a slice to an array fails. #[stable(feature = "try_from", since = "1.34.0")] -#[rustc_allowed_through_unstable_modules] #[derive(Debug, Copy, Clone)] pub struct TryFromSliceError(()); diff --git a/src/doc/rustc-dev-guide/src/stability.md b/src/doc/rustc-dev-guide/src/stability.md index 1bfe911c900c4..230925252bac3 100644 --- a/src/doc/rustc-dev-guide/src/stability.md +++ b/src/doc/rustc-dev-guide/src/stability.md @@ -34,7 +34,8 @@ Previously, due to a [rustc bug], stable items inside unstable modules were available to stable code in that location. As of September 2024, items with [accidentally stabilized paths] are marked with the `#[rustc_allowed_through_unstable_modules]` attribute -to prevent code dependent on those paths from breaking. +to prevent code dependent on those paths from breaking. Do *not* add this attribute +to any more items unless that is needed to avoid breaking changes. The `unstable` attribute may also have the `soft` value, which makes it a future-incompatible deny-by-default lint instead of a hard error. This is used diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index deeabd810d3da..a706926f7435c 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -260,6 +260,7 @@ target | std | host | notes [`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD [`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? | | ARM64 QNX Neutrino 7.0 RTOS | [`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS | +[`aarch64-unknown-nuttx`](platform-support/nuttx.md) | * | | ARM64 with NuttX [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD [`aarch64-unknown-redox`](platform-support/redox.md) | ✓ | | ARM64 Redox OS [`aarch64-unknown-teeos`](platform-support/aarch64-unknown-teeos.md) | ? | | ARM64 TEEOS | @@ -295,6 +296,8 @@ target | std | host | notes [`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | Armv7-A Apple WatchOS [`armv7s-apple-ios`](platform-support/apple-ios.md) | ✓ | | Armv7-A Apple-A6 Apple iOS [`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * | | Bare Armv8-R, hardfloat +[`armv7a-nuttx-eabi`](platform-support/nuttx.md) | * | | ARMv7-A with NuttX +[`armv7a-nuttx-eabihf`](platform-support/nuttx.md) | * | | ARMv7-A with NuttX, hardfloat `avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core` `bpfeb-unknown-none` | * | | BPF (big endian) `bpfel-unknown-none` | * | | BPF (little endian) @@ -389,6 +392,8 @@ target | std | host | notes [`thumbv6m-nuttx-eabi`](platform-support/nuttx.md) | * | | ARMv6M with NuttX `thumbv7a-pc-windows-msvc` | | | [`thumbv7a-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | | | +[`thumbv7a-nuttx-eabi`](platform-support/nuttx.md) | * | | ARMv7-A with NuttX +[`thumbv7a-nuttx-eabihf`](platform-support/nuttx.md) | * | | ARMv7-A with NuttX, hardfloat [`thumbv7em-nuttx-eabi`](platform-support/nuttx.md) | * | | ARMv7EM with NuttX [`thumbv7em-nuttx-eabihf`](platform-support/nuttx.md) | * | | ARMv7EM with NuttX, hardfloat [`thumbv7m-nuttx-eabi`](platform-support/nuttx.md) | * | | ARMv7M with NuttX diff --git a/src/doc/rustc/src/platform-support/nuttx.md b/src/doc/rustc/src/platform-support/nuttx.md index 433a092aab22a..f76fe0887b5dd 100644 --- a/src/doc/rustc/src/platform-support/nuttx.md +++ b/src/doc/rustc/src/platform-support/nuttx.md @@ -20,8 +20,13 @@ The target name follow this format: `ARCH[-VENDOR]-nuttx-ABI`, where `ARCH` is t The following target names are defined: -- `thumbv6m-nuttx-eal` -- `thumbv7m-nuttx-eal` +- `aarch64-unknown-nuttx` +- `armv7a-nuttx-eabi` +- `armv7a-nuttx-eabihf` +- `thumbv6m-nuttx-eabi` +- `thumbv7a-nuttx-eabi` +- `thumbv7a-nuttx-eabihf` +- `thumbv7m-nuttx-eabi` - `thumbv7em-nuttx-eabi` - `thumbv7em-nuttx-eabihf` - `thumbv8m.base-nuttx-eabi` diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 33166a395741c..afe81937495df 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -622,7 +622,7 @@ impl FromClean for Type { impl FromClean for Path { fn from_clean(path: clean::Path, renderer: &JsonRenderer<'_>) -> Path { Path { - name: path.last_opt().map_or(String::from(""), |s| String::from(s.as_str())), + path: path.whole_name(), id: renderer.id_from_item_default(path.def_id().into()), args: path.segments.last().map(|args| Box::new(args.clone().args.into_json(renderer))), } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 916f0ab3cc85b..e67e17a73cb73 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -30,7 +30,7 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc /// This integer is incremented with every breaking change to the API, /// and is returned along with the JSON blob as [`Crate::format_version`]. /// Consuming code should assert that this value matches the format version(s) that it supports. -pub const FORMAT_VERSION: u32 = 38; +pub const FORMAT_VERSION: u32 = 39; /// The root of the emitted JSON blob. /// @@ -1036,16 +1036,20 @@ pub enum Type { /// A type that has a simple path to it. This is the kind of type of structs, unions, enums, etc. #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Path { - /// The name of the type as declared, e.g. in + /// The path of the type. + /// + /// This will be the path that is *used* (not where it is defined), so + /// multiple `Path`s may have different values for this field even if + /// they all refer to the same item. e.g. /// /// ```rust - /// mod foo { - /// struct Bar; - /// } + /// pub type Vec1 = std::vec::Vec; // path: "std::vec::Vec" + /// pub type Vec2 = Vec; // path: "Vec" + /// pub type Vec3 = std::prelude::v1::Vec; // path: "std::prelude::v1::Vec" /// ``` - /// - /// for `foo::Bar`, this field will be `Bar`. - pub name: String, + // + // Example tested in ./tests/rustdoc-json/path_name.rs + pub path: String, /// The ID of the type. pub id: Id, /// Generic arguments to the type. diff --git a/src/tools/jsondoclint/src/validator/tests.rs b/src/tools/jsondoclint/src/validator/tests.rs index 7fcb8ffd1f991..a37e6c2eb5c92 100644 --- a/src/tools/jsondoclint/src/validator/tests.rs +++ b/src/tools/jsondoclint/src/validator/tests.rs @@ -163,7 +163,7 @@ fn errors_on_missing_path() { sig: FunctionSignature { inputs: vec![], output: Some(Type::ResolvedPath(Path { - name: "Bar".to_owned(), + path: "Bar".to_owned(), id: Id(1), args: None, })), @@ -191,7 +191,7 @@ fn errors_on_missing_path() { check(&krate, &[Error { kind: ErrorKind::Custom( - r#"No entry in '$.paths' for Path { name: "Bar", id: Id(1), args: None }"#.to_owned(), + r#"No entry in '$.paths' for Path { path: "Bar", id: Id(1), args: None }"#.to_owned(), ), id: Id(1), }]); diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index de3380502bfcd..5878cce5ffbdd 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -3857,7 +3857,6 @@ ui/suggestions/issue-106443-sugg-clone-for-arg.rs ui/suggestions/issue-106443-sugg-clone-for-bound.rs ui/suggestions/issue-107860.rs ui/suggestions/issue-108470.rs -ui/suggestions/issue-109195.rs ui/suggestions/issue-109291.rs ui/suggestions/issue-109396.rs ui/suggestions/issue-109436.rs diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs index acfa868c2df03..6bb3389c40959 100644 --- a/tests/assembly/targets/targets-elf.rs +++ b/tests/assembly/targets/targets-elf.rs @@ -66,6 +66,9 @@ //@ revisions: aarch64_unknown_teeos //@ [aarch64_unknown_teeos] compile-flags: --target aarch64-unknown-teeos //@ [aarch64_unknown_teeos] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_nuttx +//@ [aarch64_unknown_nuttx] compile-flags: --target aarch64-unknown-nuttx +//@ [aarch64_unknown_nuttx] needs-llvm-components: aarch64 //@ revisions: aarch64_unknown_trusty //@ [aarch64_unknown_trusty] compile-flags: --target aarch64-unknown-trusty //@ [aarch64_unknown_trusty] needs-llvm-components: aarch64 @@ -177,6 +180,12 @@ //@ revisions: armv7a_none_eabihf //@ [armv7a_none_eabihf] compile-flags: --target armv7a-none-eabihf //@ [armv7a_none_eabihf] needs-llvm-components: arm +//@ revisions: armv7a_nuttx_eabi +//@ [armv7a_nuttx_eabi] compile-flags: --target armv7a-nuttx-eabi +//@ [armv7a_nuttx_eabi] needs-llvm-components: arm +//@ revisions: armv7a_nuttx_eabihf +//@ [armv7a_nuttx_eabihf] compile-flags: --target armv7a-nuttx-eabihf +//@ [armv7a_nuttx_eabihf] needs-llvm-components: arm //@ revisions: armv7r_none_eabi //@ [armv7r_none_eabi] compile-flags: --target armv7r-none-eabi //@ [armv7r_none_eabi] needs-llvm-components: arm @@ -621,6 +630,12 @@ //@ revisions: thumbv6m_nuttx_eabi //@ [thumbv6m_nuttx_eabi] compile-flags: --target thumbv6m-nuttx-eabi //@ [thumbv6m_nuttx_eabi] needs-llvm-components: arm +//@ revisions: thumbv7a_nuttx_eabi +//@ [thumbv7a_nuttx_eabi] compile-flags: --target thumbv7a-nuttx-eabi +//@ [thumbv7a_nuttx_eabi] needs-llvm-components: arm +//@ revisions: thumbv7a_nuttx_eabihf +//@ [thumbv7a_nuttx_eabihf] compile-flags: --target thumbv7a-nuttx-eabihf +//@ [thumbv7a_nuttx_eabihf] needs-llvm-components: arm //@ revisions: thumbv7m_nuttx_eabi //@ [thumbv7m_nuttx_eabi] compile-flags: --target thumbv7m-nuttx-eabi //@ [thumbv7m_nuttx_eabi] needs-llvm-components: arm diff --git a/tests/rustdoc-json/auxiliary/defines_and_reexports.rs b/tests/rustdoc-json/auxiliary/defines_and_reexports.rs new file mode 100644 index 0000000000000..72434ef152f30 --- /dev/null +++ b/tests/rustdoc-json/auxiliary/defines_and_reexports.rs @@ -0,0 +1,10 @@ +pub mod m1 { + pub struct InPubMod; +} + +mod m2 { + pub struct InPrivMod; +} + +pub use m1::{InPubMod, InPubMod as InPubMod2}; +pub use m2::{InPrivMod, InPrivMod as InPrivMod2}; diff --git a/tests/rustdoc-json/blanket_impls.rs b/tests/rustdoc-json/blanket_impls.rs index f2acabbe37254..bf0983e66a17f 100644 --- a/tests/rustdoc-json/blanket_impls.rs +++ b/tests/rustdoc-json/blanket_impls.rs @@ -4,5 +4,5 @@ //@ has "$.index[*][?(@.name=='Error')].inner.assoc_type" //@ has "$.index[*][?(@.name=='Error')].inner.assoc_type.type.resolved_path" -//@ has "$.index[*][?(@.name=='Error')].inner.assoc_type.type.resolved_path.name" \"Infallible\" +//@ has "$.index[*][?(@.name=='Error')].inner.assoc_type.type.resolved_path.path" \"Infallible\" pub struct ForBlanketTryFromImpl; diff --git a/tests/rustdoc-json/fns/async_return.rs b/tests/rustdoc-json/fns/async_return.rs index 18a8a586e76d9..ff88fa99c61b5 100644 --- a/tests/rustdoc-json/fns/async_return.rs +++ b/tests/rustdoc-json/fns/async_return.rs @@ -17,7 +17,7 @@ pub async fn get_int_async() -> i32 { 42 } -//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.name" '"Future"' +//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.path" '"Future"' //@ is "$.index[*][?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].name" '"Output"' //@ is "$.index[*][?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].binding.equality.type.primitive" \"i32\" //@ is "$.index[*][?(@.name=='get_int_future')].inner.function.header.is_async" false @@ -25,7 +25,7 @@ pub fn get_int_future() -> impl Future { async { 42 } } -//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.name" '"Future"' +//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.path" '"Future"' //@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].name" '"Output"' //@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].binding.equality.type.primitive" \"i32\" //@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.header.is_async" true diff --git a/tests/rustdoc-json/impl-trait-in-assoc-type.rs b/tests/rustdoc-json/impl-trait-in-assoc-type.rs index 907a0f6c603e0..14ea29507692b 100644 --- a/tests/rustdoc-json/impl-trait-in-assoc-type.rs +++ b/tests/rustdoc-json/impl-trait-in-assoc-type.rs @@ -10,7 +10,7 @@ impl IntoIterator for AlwaysTrue { type Item = bool; //@ count '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[*]' 1 - //@ is '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.name' '"Iterator"' + //@ is '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.path' '"Iterator"' //@ count '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[*]' 1 //@ is '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].name' '"Item"' //@ is '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].binding.equality.type.primitive' '"bool"' diff --git a/tests/rustdoc-json/path_name.rs b/tests/rustdoc-json/path_name.rs new file mode 100644 index 0000000000000..67843dfc8ff39 --- /dev/null +++ b/tests/rustdoc-json/path_name.rs @@ -0,0 +1,83 @@ +// Test for the Path::name field within a single crate. +// +// See https://github.com/rust-lang/rust/issues/135600 +// and https://github.com/rust-lang/rust/pull/134880#issuecomment-2596386111 +// +// ignore-tidy-linelength +//@ aux-build: defines_and_reexports.rs +extern crate defines_and_reexports; + +mod priv_mod { + pub struct InPrivMod; +} + +pub mod pub_mod { + pub struct InPubMod; +} + +use priv_mod::InPrivMod as InPrivMod3; +pub use priv_mod::{InPrivMod, InPrivMod as InPrivMod2}; +use pub_mod::InPubMod as InPubMod3; +pub use pub_mod::{InPubMod, InPubMod as InPubMod2}; + +//@ is "$.index[*][?(@.name=='T0')].inner.type_alias.type.resolved_path.path" '"priv_mod::InPrivMod"' +pub type T0 = priv_mod::InPrivMod; +//@ is "$.index[*][?(@.name=='T1')].inner.type_alias.type.resolved_path.path" '"InPrivMod"' +pub type T1 = InPrivMod; +//@ is "$.index[*][?(@.name=='T2')].inner.type_alias.type.resolved_path.path" '"InPrivMod2"' +pub type T2 = InPrivMod2; +//@ is "$.index[*][?(@.name=='T3')].inner.type_alias.type.resolved_path.path" '"priv_mod::InPrivMod"' +pub type T3 = InPrivMod3; + +//@ is "$.index[*][?(@.name=='U0')].inner.type_alias.type.resolved_path.path" '"pub_mod::InPubMod"' +pub type U0 = pub_mod::InPubMod; +//@ is "$.index[*][?(@.name=='U1')].inner.type_alias.type.resolved_path.path" '"InPubMod"' +pub type U1 = InPubMod; +//@ is "$.index[*][?(@.name=='U2')].inner.type_alias.type.resolved_path.path" '"InPubMod2"' +pub type U2 = InPubMod2; +//@ is "$.index[*][?(@.name=='U3')].inner.type_alias.type.resolved_path.path" '"pub_mod::InPubMod"' +pub type U3 = InPubMod3; + +// Check we only have paths for structs at their original path +//@ ismany "$.paths[*][?(@.crate_id==0 && @.kind=='struct')].path" '["path_name", "priv_mod", "InPrivMod"]' '["path_name", "pub_mod", "InPubMod"]' + +pub use defines_and_reexports::{InPrivMod as XPrivMod, InPubMod as XPubMod}; +use defines_and_reexports::{InPrivMod as XPrivMod2, InPubMod as XPubMod2}; + +//@ is "$.index[*][?(@.name=='X0')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::m1::InPubMod"' +pub type X0 = defines_and_reexports::m1::InPubMod; +//@ is "$.index[*][?(@.name=='X1')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPubMod"' +pub type X1 = defines_and_reexports::InPubMod; +//@ is "$.index[*][?(@.name=='X2')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPubMod2"' +pub type X2 = defines_and_reexports::InPubMod2; +//@ is "$.index[*][?(@.name=='X3')].inner.type_alias.type.resolved_path.path" '"XPubMod"' +pub type X3 = XPubMod; +// N.B. This isn't the path as used *or* the original path! +//@ is "$.index[*][?(@.name=='X4')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPubMod"' +pub type X4 = XPubMod2; + +//@ is "$.index[*][?(@.name=='Y1')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPrivMod"' +pub type Y1 = defines_and_reexports::InPrivMod; +//@ is "$.index[*][?(@.name=='Y2')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPrivMod2"' +pub type Y2 = defines_and_reexports::InPrivMod2; +//@ is "$.index[*][?(@.name=='Y3')].inner.type_alias.type.resolved_path.path" '"XPrivMod"' +pub type Y3 = XPrivMod; +//@ is "$.index[*][?(@.name=='Y4')].inner.type_alias.type.resolved_path.path" '"defines_and_reexports::InPrivMod"' +pub type Y4 = XPrivMod2; + +// For foreign items, $.paths contains the *origional* path, even if it's not publicly +// assessable. This should probably be changed. + +//@ has "$.paths[*].path" '["defines_and_reexports", "m1", "InPubMod"]' +//@ has "$.paths[*].path" '["defines_and_reexports", "m2", "InPrivMod"]' +//@ !has "$.paths[*].path" '["defines_and_reexports", "InPubMod"]' +//@ !has "$.paths[*].path" '["defines_and_reexports", "InPrivMod"]' + +// Tests for the example in the docs of Path::name. +// If these change, chage the docs. +//@ is "$.index[*][?(@.name=='Vec1')].inner.type_alias.type.resolved_path.path" '"std::vec::Vec"' +pub type Vec1 = std::vec::Vec; +//@ is "$.index[*][?(@.name=='Vec2')].inner.type_alias.type.resolved_path.path" '"Vec"' +pub type Vec2 = Vec; +//@ is "$.index[*][?(@.name=='Vec3')].inner.type_alias.type.resolved_path.path" '"std::prelude::v1::Vec"' +pub type Vec3 = std::prelude::v1::Vec; diff --git a/tests/rustdoc-json/return_private.rs b/tests/rustdoc-json/return_private.rs index c238a536e0d8d..bfcbed8904009 100644 --- a/tests/rustdoc-json/return_private.rs +++ b/tests/rustdoc-json/return_private.rs @@ -2,11 +2,13 @@ // ignore-tidy-linelength mod secret { + //@ set struct_secret = "$.index[*][?(@.name == 'Secret' && @.inner.struct)].id" pub struct Secret; } //@ has "$.index[*][?(@.name=='get_secret')].inner.function" -//@ is "$.index[*][?(@.name=='get_secret')].inner.function.sig.output.resolved_path.name" \"Secret\" +//@ is "$.index[*][?(@.name=='get_secret')].inner.function.sig.output.resolved_path.path" '"secret::Secret"' +//@ is "$.index[*][?(@.name=='get_secret')].inner.function.sig.output.resolved_path.id" $struct_secret pub fn get_secret() -> secret::Secret { secret::Secret } diff --git a/tests/rustdoc-json/type/dyn.rs b/tests/rustdoc-json/type/dyn.rs index 97c8689a7c80a..f990a2cb53a7f 100644 --- a/tests/rustdoc-json/type/dyn.rs +++ b/tests/rustdoc-json/type/dyn.rs @@ -10,7 +10,7 @@ use std::fmt::Debug; //@ has "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias" //@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.generics" '{"params": [], "where_predicates": []}' //@ has "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path" -//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.name" \"Box\" +//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.path" \"Box\" //@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.constraints" [] //@ count "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args" 1 //@ has "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait" @@ -19,9 +19,9 @@ use std::fmt::Debug; //@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].generic_params" [] //@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].generic_params" [] //@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[2].generic_params" [] -//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.name" '"Fn"' -//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.name" '"Send"' -//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[2].trait.name" '"Sync"' +//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.path" '"Fn"' +//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.path" '"Send"' +//@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[2].trait.path" '"Sync"' //@ is "$.index[*][?(@.name=='SyncIntGen')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.args" '{"parenthesized": {"inputs": [],"output": {"primitive": "i32"}}}' pub type SyncIntGen = Box i32 + Send + Sync + 'static>; @@ -34,13 +34,13 @@ pub type SyncIntGen = Box i32 + Send + Sync + 'static>; //@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.lifetime" null //@ count "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[*]" 1 //@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' -//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.name" '"Fn"' +//@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.path" '"Fn"' //@ has "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.inputs[0].borrowed_ref" //@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.inputs[0].borrowed_ref.lifetime" "\"'b\"" //@ has "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.output.borrowed_ref" //@ is "$.index[*][?(@.name=='RefFn')].inner.type_alias.type.borrowed_ref.type.dyn_trait.traits[0].trait.args.parenthesized.output.borrowed_ref.lifetime" "\"'b\"" pub type RefFn<'a> = &'a dyn for<'b> Fn(&'b i32) -> &'b i32; -//@ is "$.index[*][?(@.name=='WeirdOrder')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.name" '"Send"' -//@ is "$.index[*][?(@.name=='WeirdOrder')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.name" '"Debug"' +//@ is "$.index[*][?(@.name=='WeirdOrder')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[0].trait.path" '"Send"' +//@ is "$.index[*][?(@.name=='WeirdOrder')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.dyn_trait.traits[1].trait.path" '"Debug"' pub type WeirdOrder = Box; diff --git a/tests/rustdoc-json/type/generic_default.rs b/tests/rustdoc-json/type/generic_default.rs index c1a05805014a9..7eaa299af5c7e 100644 --- a/tests/rustdoc-json/type/generic_default.rs +++ b/tests/rustdoc-json/type/generic_default.rs @@ -21,10 +21,10 @@ pub struct MyError {} //@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[0].kind.type.default" null //@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path" //@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path.id" $my_error -//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path.name" \"MyError\" +//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.generics.params[1].kind.type.default.resolved_path.path" \"MyError\" //@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path" //@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.id" $result -//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.name" \"Result\" +//@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.path" \"Result\" //@ is "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.constraints" [] //@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[0].type.generic" //@ has "$.index[*][?(@.name=='MyResult')].inner.type_alias.type.resolved_path.args.angle_bracketed.args[1].type.generic" diff --git a/tests/rustdoc-json/type/hrtb.rs b/tests/rustdoc-json/type/hrtb.rs index 825720e9198b6..e71d9fc1e1e93 100644 --- a/tests/rustdoc-json/type/hrtb.rs +++ b/tests/rustdoc-json/type/hrtb.rs @@ -15,7 +15,7 @@ where //@ is "$.index[*][?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.lifetime" null //@ count "$.index[*][?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.traits[*]" 1 //@ is "$.index[*][?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.traits[0].generic_params" '[{"kind": {"lifetime": {"outlives": []}},"name": "'\''a"},{"kind": {"lifetime": {"outlives": []}},"name": "'\''b"}]' -//@ is "$.index[*][?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.traits[0].trait.name" '"Fn"' +//@ is "$.index[*][?(@.name=='dynfn')].inner.function.sig.inputs[0][1].borrowed_ref.type.dyn_trait.traits[0].trait.path" '"Fn"' pub fn dynfn(f: &dyn for<'a, 'b> Fn(&'a i32, &'b i32)) { let zero = 0; f(&zero, &zero); diff --git a/tests/ui/drop/drop-order-comparisons.e2021.fixed b/tests/ui/drop/drop-order-comparisons.e2021.fixed new file mode 100644 index 0000000000000..78cf421cfbf34 --- /dev/null +++ b/tests/ui/drop/drop-order-comparisons.e2021.fixed @@ -0,0 +1,575 @@ +// This tests various aspects of the drop order with a focus on: +// +// - The lifetime of temporaries with the `if let` construct (and with +// various similar constructs) and how these lifetimes were shortened +// for `if let` in Rust 2024. +// +// - The shortening of the lifetimes of temporaries in tail +// expressions in Rust 2024. +// +// - The behavior of `let` chains and how this behavior compares to +// nested `if let` expressions and chained `let .. else` statements. +// +// In the tests below, `Events` tracks a sequence of numbered events. +// Calling `e.mark(..)` logs a numbered event immediately. Calling +// `e.ok(..)` or `e.err(..)` returns an `Ok(_)` or `Err(_)` value, +// respectively, and logs the numbered event when that value is +// dropped. Calling `e.assert()` verifies that the correct number of +// events were logged and that they were logged in the correct order. + +//@ revisions: e2021 e2024 +//@ [e2021] edition: 2021 +//@ [e2021] run-rustfix +//@ [e2021] rustfix-only-machine-applicable +//@ [e2024] edition: 2024 +//@ run-pass + +#![feature(let_chains)] +#![cfg_attr(e2021, warn(rust_2024_compatibility))] + +fn t_bindings() { + let e = Events::new(); + _ = { + e.mark(1); + let _v = e.ok(8); + let _v = e.ok(2).is_ok(); + let _ = e.ok(3); + let Ok(_) = e.ok(4) else { unreachable!() }; + let Ok(_) = e.ok(5).as_ref() else { unreachable!() }; + let _v = e.ok(7); + e.mark(6); + }; + e.assert(8); +} + +fn t_tuples() { + let e = Events::new(); + _ = (e.ok(1), e.ok(4).is_ok(), e.ok(2), e.ok(3).is_ok()); + e.assert(4); +} + +fn t_arrays() { + let e = Events::new(); + trait Tr {} + impl Tr for T {} + fn b<'a, T: 'a>(x: T) -> Box { + Box::new(x) + } + _ = [b(e.ok(1)), b(e.ok(4).is_ok()), b(e.ok(2)), b(e.ok(3).is_ok())]; + e.assert(4); +} + +fn t_fncalls() { + let e = Events::new(); + let f = |_, _, _, _| {}; + _ = f(e.ok(2), e.ok(4).is_ok(), e.ok(1), e.ok(3).is_ok()); + e.assert(4); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_tailexpr_bindings() { + let e = Events::new(); + _ = ({ + let _v = e.ok(2); + let _v = e.ok(1); + e.ok(5).is_ok() + //[e2021]~^ WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + }, e.mark(3), e.ok(4)); + e.assert(5); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_tailexpr_bindings() { + let e = Events::new(); + _ = ({ + let _v = e.ok(3); + let _v = e.ok(2); + e.ok(1).is_ok() + }, e.mark(4), e.ok(5)); + e.assert(5); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_tailexpr_tuples() { + let e = Events::new(); + _ = ({ + (e.ok(2), e.ok(6).is_ok(), e.ok(3), e.ok(5).is_ok()) + //[e2021]~^ WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + //[e2021]~| WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + }, e.mark(1), e.ok(4)); + e.assert(6); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_tailexpr_tuples() { + let e = Events::new(); + _ = ({ + (e.ok(4), e.ok(2).is_ok(), e.ok(5), e.ok(1).is_ok()) + }, e.mark(3), e.ok(6)); + e.assert(6); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_then() { + let e = Events::new(); + _ = (match e.ok(4).as_ref() { Ok(_) => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(1); + } _ => {}}, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_then() { + let e = Events::new(); + _ = (if let Ok(_) = e.ok(2).as_ref() { + e.mark(1); + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_else() { + let e = Events::new(); + _ = (match e.err(4).as_ref() { Ok(_) => {} _ => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(1); + }}, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_else() { + let e = Events::new(); + _ = (if let Ok(_) = e.err(1).as_ref() {} else { + e.mark(2); + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_match_then() { + let e = Events::new(); + _ = (match e.ok(4).as_ref() { + Ok(_) => e.mark(1), + _ => unreachable!(), + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_match_else() { + let e = Events::new(); + _ = (match e.err(4).as_ref() { + Ok(_) => unreachable!(), + _ => e.mark(1), + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_let_else_then() { + let e = Events::new(); + _ = ('top: { + 'chain: { + let Ok(_) = e.ok(1).as_ref() else { break 'chain }; + // The "then" branch: + e.mark(2); + break 'top; + } + // The "else" branch: + unreachable!() + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_let_else_else() { + let e = Events::new(); + _ = ('top: { + 'chain: { + let Ok(_) = e.err(1).as_ref() else { break 'chain }; + // The "then" branch: + unreachable!(); + #[allow(unreachable_code)] + break 'top; + } + // The "else" branch: + e.mark(2); + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_then_tailexpr() { + let e = Events::new(); + _ = ({ + if let Ok(_) = e.ok(4).as_ref() { + //[e2021]~^ WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(1); + } + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_then_tailexpr() { + let e = Events::new(); + _ = ({ + if let Ok(_) = e.ok(2).as_ref() { + e.mark(1); + } + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_else_tailexpr() { + let e = Events::new(); + _ = ({ + match e.err(4).as_ref() { Ok(_) => {} _ => { + //[e2021]~^ WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + //[e2021]~| WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(1); + }} + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_else_tailexpr() { + let e = Events::new(); + _ = ({ + if let Ok(_) = e.err(1).as_ref() {} else { + e.mark(2); + } + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_if_let_nested_then() { + let e = Events::new(); + _ = { + // The unusual formatting, here and below, is to make the + // comparison with `let` chains more direct. + if e.ok(1).is_ok() { + if let true = e.ok(9).is_ok() { + if let Ok(_v) = e.ok(8) { + if let Ok(_) = e.ok(7) { + if let Ok(_) = e.ok(6).as_ref() { + if e.ok(2).is_ok() { + if let Ok(_v) = e.ok(5) { + if let Ok(_) = e.ok(4).as_ref() { + e.mark(3); + }}}}}}}} + }; + e.assert(9); +} + +#[rustfmt::skip] +fn t_let_else_chained_then() { + let e = Events::new(); + _ = 'top: { + 'chain: { + if e.ok(1).is_ok() {} else { break 'chain }; + let true = e.ok(2).is_ok() else { break 'chain }; + let Ok(_v) = e.ok(9) else { break 'chain }; + let Ok(_) = e.ok(3) else { break 'chain }; + let Ok(_) = e.ok(4).as_ref() else { break 'chain }; + if e.ok(5).is_ok() {} else { break 'chain }; + let Ok(_v) = e.ok(8) else { break 'chain }; + let Ok(_) = e.ok(6).as_ref() else { break 'chain }; + // The "then" branch: + e.mark(7); + break 'top; + } + // The "else" branch: + unreachable!() + }; + e.assert(9); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_chains_then() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(9).is_ok() + && let Ok(_v) = e.ok(5) + && let Ok(_) = e.ok(8) + && let Ok(_) = e.ok(7).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(4) + && let Ok(_) = e.ok(6).as_ref() { + e.mark(3); + }; + e.assert(9); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_chains_then() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(9).is_ok() + && let Ok(_v) = e.ok(8) + && let Ok(_) = e.ok(7) + && let Ok(_) = e.ok(6).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(5) + && let Ok(_) = e.ok(4).as_ref() { + e.mark(3); + }; + e.assert(9); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_nested_else() { + let e = Events::new(); + _ = if e.err(1).is_ok() {} else { + match e.err(9).is_ok() { true => {} _ => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + match e.err(8) { Ok(_v) => {} _ => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + match e.err(7) { Ok(_) => {} _ => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + match e.err(6).as_ref() { Ok(_) => {} _ => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + if e.err(2).is_ok() {} else { + match e.err(5) { Ok(_v) => {} _ => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + match e.err(4) { Ok(_) => {} _ => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(3); + }}}}}}}}}}}}}}; + e.assert(9); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_nested_else() { + let e = Events::new(); + _ = if e.err(1).is_ok() {} else { + if let true = e.err(2).is_ok() {} else { + if let Ok(_v) = e.err(3) {} else { + if let Ok(_) = e.err(4) {} else { + if let Ok(_) = e.err(5).as_ref() {} else { + if e.err(6).is_ok() {} else { + if let Ok(_v) = e.err(7) {} else { + if let Ok(_) = e.err(8) {} else { + e.mark(9); + }}}}}}}}; + e.assert(9); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_nested_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() { + if let true = e.ok(9).is_ok() { + if let Ok(_v) = e.ok(8) { + if let Ok(_) = e.ok(7) { + if let Ok(_) = e.ok(6).as_ref() { + if e.ok(2).is_ok() { + if let Ok(_v) = e.ok(5) { + match e.err(4).as_ref() { Ok(_) => {} _ => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(3); + }}}}}}}}}; + e.assert(9); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_nested_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() { + if let true = e.ok(9).is_ok() { + if let Ok(_v) = e.ok(8) { + if let Ok(_) = e.ok(7) { + if let Ok(_) = e.ok(6).as_ref() { + if e.ok(2).is_ok() { + if let Ok(_v) = e.ok(5) { + if let Ok(_) = e.err(3).as_ref() {} else { + e.mark(4); + }}}}}}}}; + e.assert(9); +} + +#[rustfmt::skip] +fn t_let_else_chained_then_else() { + let e = Events::new(); + _ = 'top: { + 'chain: { + if e.ok(1).is_ok() {} else { break 'chain }; + let true = e.ok(2).is_ok() else { break 'chain }; + let Ok(_v) = e.ok(8) else { break 'chain }; + let Ok(_) = e.ok(3) else { break 'chain }; + let Ok(_) = e.ok(4).as_ref() else { break 'chain }; + if e.ok(5).is_ok() {} else { break 'chain }; + let Ok(_v) = e.ok(7) else { break 'chain }; + let Ok(_) = e.err(6).as_ref() else { break 'chain }; + // The "then" branch: + unreachable!(); + #[allow(unreachable_code)] + break 'top; + } + // The "else" branch: + e.mark(9); + }; + e.assert(9); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_chains_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(9).is_ok() + && let Ok(_v) = e.ok(4) + && let Ok(_) = e.ok(8) + && let Ok(_) = e.ok(7).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(3) + && let Ok(_) = e.err(6) {} else { + e.mark(5); + }; + e.assert(9); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_chains_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(8).is_ok() + && let Ok(_v) = e.ok(7) + && let Ok(_) = e.ok(6) + && let Ok(_) = e.ok(5).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(4) + && let Ok(_) = e.err(3) {} else { + e.mark(9); + }; + e.assert(9); +} + +fn main() { + t_bindings(); + t_tuples(); + t_arrays(); + t_fncalls(); + t_tailexpr_bindings(); + t_tailexpr_tuples(); + t_if_let_then(); + t_if_let_else(); + t_match_then(); + t_match_else(); + t_let_else_then(); + t_let_else_else(); + t_if_let_then_tailexpr(); + t_if_let_else_tailexpr(); + t_if_let_nested_then(); + t_let_else_chained_then(); + t_if_let_chains_then(); + t_if_let_nested_else(); + t_if_let_nested_then_else(); + t_let_else_chained_then_else(); + t_if_let_chains_then_else(); +} + +// # Test scaffolding + +use core::cell::RefCell; +use std::collections::HashSet; + +/// A buffer to track the order of events. +/// +/// First, numbered events are logged into this buffer. +/// +/// Then, `assert` is called to verify that the correct number of +/// events were logged, and that they were logged in the expected +/// order. +struct Events(RefCell>>); + +impl Events { + const fn new() -> Self { + Self(RefCell::new(Some(Vec::new()))) + } + #[track_caller] + fn assert(&self, max: u64) { + let buf = &self.0; + let v1 = buf.borrow().as_ref().unwrap().clone(); + let mut v2 = buf.borrow().as_ref().unwrap().clone(); + *buf.borrow_mut() = None; + v2.sort(); + let uniq_len = v2.iter().collect::>().len(); + // Check that the sequence is sorted. + assert_eq!(v1, v2); + // Check that there are no duplicates. + assert_eq!(v2.len(), uniq_len); + // Check that the length is the expected one. + assert_eq!(max, uniq_len as u64); + // Check that the last marker is the expected one. + assert_eq!(v2.last().unwrap(), &max); + } + /// Return an `Ok` value that logs its drop. + fn ok(&self, m: u64) -> Result, LogDrop<'_>> { + Ok(LogDrop(self, m)) + } + /// Return an `Err` value that logs its drop. + fn err(&self, m: u64) -> Result { + Err(LogDrop(self, m)) + } + /// Log an event. + fn mark(&self, m: u64) { + self.0.borrow_mut().as_mut().unwrap().push(m); + } +} + +impl Drop for Events { + fn drop(&mut self) { + if self.0.borrow().is_some() { + panic!("failed to call `Events::assert()`"); + } + } +} + +/// A type that logs its drop events. +struct LogDrop<'b>(&'b Events, u64); + +impl<'b> Drop for LogDrop<'b> { + fn drop(&mut self) { + self.0.mark(self.1); + } +} diff --git a/tests/ui/drop/drop-order-comparisons.e2021.stderr b/tests/ui/drop/drop-order-comparisons.e2021.stderr new file mode 100644 index 0000000000000..158d18f68826b --- /dev/null +++ b/tests/ui/drop/drop-order-comparisons.e2021.stderr @@ -0,0 +1,477 @@ +warning: relative drop order changing in Rust 2024 + --> $DIR/drop-order-comparisons.rs:76:9 + | +LL | _ = ({ + | _________- +LL | | let _v = e.ok(2); + | | -- + | | | + | | `_v` calls a custom destructor + | | `_v` will be dropped later as of Edition 2024 +LL | | let _v = e.ok(1); + | | -- + | | | + | | this value will be stored in a temporary; let us call it `#2` + | | `#2` will be dropped later as of Edition 2024 +LL | | e.ok(5).is_ok() + | | ^^^^^^^ + | | | + | | this value will be stored in a temporary; let us call it `#3` + | | up until Edition 2021 `#3` is dropped last but will be dropped earlier in Edition 2024 +... | +LL | | }, e.mark(3), e.ok(4)); + | | - + | | | + | | now the temporary value is dropped here, before the local variables in the block or statement + | |__________________________this value will be stored in a temporary; let us call it `#1` + | `#1` will be dropped later as of Edition 2024 + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +note: `#3` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ +note: `#1` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ +note: `_v` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ +note: `#2` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages +note: the lint level is defined here + --> $DIR/drop-order-comparisons.rs:28:25 + | +LL | #![cfg_attr(e2021, warn(rust_2024_compatibility))] + | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(tail_expr_drop_order)]` implied by `#[warn(rust_2024_compatibility)]` + +warning: relative drop order changing in Rust 2024 + --> $DIR/drop-order-comparisons.rs:100:45 + | +LL | _ = ({ + | _________- +LL | | (e.ok(2), e.ok(6).is_ok(), e.ok(3), e.ok(5).is_ok()) + | | ^^^^^^^ + | | | + | | this value will be stored in a temporary; let us call it `#2` + | | up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024 +... | +LL | | }, e.mark(1), e.ok(4)); + | | - + | | | + | | now the temporary value is dropped here, before the local variables in the block or statement + | |__________________________this value will be stored in a temporary; let us call it `#1` + | `#1` will be dropped later as of Edition 2024 + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +note: `#2` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ +note: `#1` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +warning: relative drop order changing in Rust 2024 + --> $DIR/drop-order-comparisons.rs:100:19 + | +LL | _ = ({ + | _________- +LL | | (e.ok(2), e.ok(6).is_ok(), e.ok(3), e.ok(5).is_ok()) + | | ^^^^^^^ + | | | + | | this value will be stored in a temporary; let us call it `#2` + | | up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024 +... | +LL | | }, e.mark(1), e.ok(4)); + | | - + | | | + | | now the temporary value is dropped here, before the local variables in the block or statement + | |__________________________this value will be stored in a temporary; let us call it `#1` + | `#1` will be dropped later as of Edition 2024 + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +note: `#2` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ +note: `#1` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +warning: relative drop order changing in Rust 2024 + --> $DIR/drop-order-comparisons.rs:221:24 + | +LL | _ = ({ + | _________- +LL | | if let Ok(_) = e.ok(4).as_ref() { + | | ^^^^^^^ + | | | + | | this value will be stored in a temporary; let us call it `#2` + | | up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024 +... | +LL | | }, e.mark(2), e.ok(3)); + | | - + | | | + | | now the temporary value is dropped here, before the local variables in the block or statement + | |__________________________this value will be stored in a temporary; let us call it `#1` + | `#1` will be dropped later as of Edition 2024 + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +note: `#2` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ +note: `#1` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +warning: relative drop order changing in Rust 2024 + --> $DIR/drop-order-comparisons.rs:247:24 + | +LL | _ = ({ + | _________- +LL | | if let Ok(_) = e.err(4).as_ref() {} else { + | | ^^^^^^^^ + | | | + | | this value will be stored in a temporary; let us call it `#2` + | | up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024 +... | +LL | | }, e.mark(2), e.ok(3)); + | | - + | | | + | | now the temporary value is dropped here, before the local variables in the block or statement + | |__________________________this value will be stored in a temporary; let us call it `#1` + | `#1` will be dropped later as of Edition 2024 + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +note: `#2` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ +note: `#1` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:123:13 + | +LL | _ = (if let Ok(_) = e.ok(4).as_ref() { + | ^^^^^^^^^^^^-------^^^^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:127:5 + | +LL | }, e.mark(2), e.ok(3)); + | ^ + = note: `#[warn(if_let_rescope)]` implied by `#[warn(rust_2024_compatibility)]` +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ _ = (match e.ok(4).as_ref() { Ok(_) => { +LL | +LL | +LL | e.mark(1); +LL ~ } _ => {}}, e.mark(2), e.ok(3)); + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:145:13 + | +LL | _ = (if let Ok(_) = e.err(4).as_ref() {} else { + | ^^^^^^^^^^^^--------^^^^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:145:44 + | +LL | _ = (if let Ok(_) = e.err(4).as_ref() {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ _ = (match e.err(4).as_ref() { Ok(_) => {} _ => { +LL | +LL | +LL | e.mark(1); +LL ~ }}, e.mark(2), e.ok(3)); + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:247:12 + | +LL | if let Ok(_) = e.err(4).as_ref() {} else { + | ^^^^^^^^^^^^--------^^^^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:247:43 + | +LL | if let Ok(_) = e.err(4).as_ref() {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match e.err(4).as_ref() { Ok(_) => {} _ => { +LL | +... +LL | e.mark(1); +LL ~ }} + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:352:12 + | +LL | if let true = e.err(9).is_ok() {} else { + | ^^^^^^^^^^^--------^^^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:352:41 + | +LL | if let true = e.err(9).is_ok() {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match e.err(9).is_ok() { true => {} _ => { +LL | +... +LL | e.mark(3); +LL ~ }}}}}}}}}; + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:355:12 + | +LL | if let Ok(_v) = e.err(8) {} else { + | ^^^^^^^^^^^^^-------- + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:355:35 + | +LL | if let Ok(_v) = e.err(8) {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match e.err(8) { Ok(_v) => {} _ => { +LL | +... +LL | e.mark(3); +LL ~ }}}}}}}}}; + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:358:12 + | +LL | if let Ok(_) = e.err(7) {} else { + | ^^^^^^^^^^^^-------- + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:358:34 + | +LL | if let Ok(_) = e.err(7) {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match e.err(7) { Ok(_) => {} _ => { +LL | +... +LL | e.mark(3); +LL ~ }}}}}}}}}; + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:361:12 + | +LL | if let Ok(_) = e.err(6).as_ref() {} else { + | ^^^^^^^^^^^^--------^^^^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:361:43 + | +LL | if let Ok(_) = e.err(6).as_ref() {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match e.err(6).as_ref() { Ok(_) => {} _ => { +LL | +... +LL | e.mark(3); +LL ~ }}}}}}}}}; + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:365:12 + | +LL | if let Ok(_v) = e.err(5) {} else { + | ^^^^^^^^^^^^^-------- + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:365:35 + | +LL | if let Ok(_v) = e.err(5) {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match e.err(5) { Ok(_v) => {} _ => { +LL | +... +LL | e.mark(3); +LL ~ }}}}}}}}}; + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:368:12 + | +LL | if let Ok(_) = e.err(4) {} else { + | ^^^^^^^^^^^^-------- + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:368:34 + | +LL | if let Ok(_) = e.err(4) {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match e.err(4) { Ok(_) => {} _ => { +LL | +LL | +LL | e.mark(3); +LL ~ }}}}}}}}}; + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:404:12 + | +LL | if let Ok(_) = e.err(4).as_ref() {} else { + | ^^^^^^^^^^^^--------^^^^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:404:43 + | +LL | if let Ok(_) = e.err(4).as_ref() {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match e.err(4).as_ref() { Ok(_) => {} _ => { +LL | +LL | +LL | e.mark(3); +LL ~ }}}}}}}}}; + | + +warning: 15 warnings emitted + diff --git a/tests/ui/drop/drop-order-comparisons.rs b/tests/ui/drop/drop-order-comparisons.rs new file mode 100644 index 0000000000000..78c75a9449f17 --- /dev/null +++ b/tests/ui/drop/drop-order-comparisons.rs @@ -0,0 +1,575 @@ +// This tests various aspects of the drop order with a focus on: +// +// - The lifetime of temporaries with the `if let` construct (and with +// various similar constructs) and how these lifetimes were shortened +// for `if let` in Rust 2024. +// +// - The shortening of the lifetimes of temporaries in tail +// expressions in Rust 2024. +// +// - The behavior of `let` chains and how this behavior compares to +// nested `if let` expressions and chained `let .. else` statements. +// +// In the tests below, `Events` tracks a sequence of numbered events. +// Calling `e.mark(..)` logs a numbered event immediately. Calling +// `e.ok(..)` or `e.err(..)` returns an `Ok(_)` or `Err(_)` value, +// respectively, and logs the numbered event when that value is +// dropped. Calling `e.assert()` verifies that the correct number of +// events were logged and that they were logged in the correct order. + +//@ revisions: e2021 e2024 +//@ [e2021] edition: 2021 +//@ [e2021] run-rustfix +//@ [e2021] rustfix-only-machine-applicable +//@ [e2024] edition: 2024 +//@ run-pass + +#![feature(let_chains)] +#![cfg_attr(e2021, warn(rust_2024_compatibility))] + +fn t_bindings() { + let e = Events::new(); + _ = { + e.mark(1); + let _v = e.ok(8); + let _v = e.ok(2).is_ok(); + let _ = e.ok(3); + let Ok(_) = e.ok(4) else { unreachable!() }; + let Ok(_) = e.ok(5).as_ref() else { unreachable!() }; + let _v = e.ok(7); + e.mark(6); + }; + e.assert(8); +} + +fn t_tuples() { + let e = Events::new(); + _ = (e.ok(1), e.ok(4).is_ok(), e.ok(2), e.ok(3).is_ok()); + e.assert(4); +} + +fn t_arrays() { + let e = Events::new(); + trait Tr {} + impl Tr for T {} + fn b<'a, T: 'a>(x: T) -> Box { + Box::new(x) + } + _ = [b(e.ok(1)), b(e.ok(4).is_ok()), b(e.ok(2)), b(e.ok(3).is_ok())]; + e.assert(4); +} + +fn t_fncalls() { + let e = Events::new(); + let f = |_, _, _, _| {}; + _ = f(e.ok(2), e.ok(4).is_ok(), e.ok(1), e.ok(3).is_ok()); + e.assert(4); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_tailexpr_bindings() { + let e = Events::new(); + _ = ({ + let _v = e.ok(2); + let _v = e.ok(1); + e.ok(5).is_ok() + //[e2021]~^ WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + }, e.mark(3), e.ok(4)); + e.assert(5); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_tailexpr_bindings() { + let e = Events::new(); + _ = ({ + let _v = e.ok(3); + let _v = e.ok(2); + e.ok(1).is_ok() + }, e.mark(4), e.ok(5)); + e.assert(5); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_tailexpr_tuples() { + let e = Events::new(); + _ = ({ + (e.ok(2), e.ok(6).is_ok(), e.ok(3), e.ok(5).is_ok()) + //[e2021]~^ WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + //[e2021]~| WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + }, e.mark(1), e.ok(4)); + e.assert(6); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_tailexpr_tuples() { + let e = Events::new(); + _ = ({ + (e.ok(4), e.ok(2).is_ok(), e.ok(5), e.ok(1).is_ok()) + }, e.mark(3), e.ok(6)); + e.assert(6); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_then() { + let e = Events::new(); + _ = (if let Ok(_) = e.ok(4).as_ref() { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(1); + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_then() { + let e = Events::new(); + _ = (if let Ok(_) = e.ok(2).as_ref() { + e.mark(1); + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_else() { + let e = Events::new(); + _ = (if let Ok(_) = e.err(4).as_ref() {} else { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(1); + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_else() { + let e = Events::new(); + _ = (if let Ok(_) = e.err(1).as_ref() {} else { + e.mark(2); + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_match_then() { + let e = Events::new(); + _ = (match e.ok(4).as_ref() { + Ok(_) => e.mark(1), + _ => unreachable!(), + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_match_else() { + let e = Events::new(); + _ = (match e.err(4).as_ref() { + Ok(_) => unreachable!(), + _ => e.mark(1), + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_let_else_then() { + let e = Events::new(); + _ = ('top: { + 'chain: { + let Ok(_) = e.ok(1).as_ref() else { break 'chain }; + // The "then" branch: + e.mark(2); + break 'top; + } + // The "else" branch: + unreachable!() + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_let_else_else() { + let e = Events::new(); + _ = ('top: { + 'chain: { + let Ok(_) = e.err(1).as_ref() else { break 'chain }; + // The "then" branch: + unreachable!(); + #[allow(unreachable_code)] + break 'top; + } + // The "else" branch: + e.mark(2); + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_then_tailexpr() { + let e = Events::new(); + _ = ({ + if let Ok(_) = e.ok(4).as_ref() { + //[e2021]~^ WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(1); + } + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_then_tailexpr() { + let e = Events::new(); + _ = ({ + if let Ok(_) = e.ok(2).as_ref() { + e.mark(1); + } + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_else_tailexpr() { + let e = Events::new(); + _ = ({ + if let Ok(_) = e.err(4).as_ref() {} else { + //[e2021]~^ WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + //[e2021]~| WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(1); + } + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_else_tailexpr() { + let e = Events::new(); + _ = ({ + if let Ok(_) = e.err(1).as_ref() {} else { + e.mark(2); + } + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_if_let_nested_then() { + let e = Events::new(); + _ = { + // The unusual formatting, here and below, is to make the + // comparison with `let` chains more direct. + if e.ok(1).is_ok() { + if let true = e.ok(9).is_ok() { + if let Ok(_v) = e.ok(8) { + if let Ok(_) = e.ok(7) { + if let Ok(_) = e.ok(6).as_ref() { + if e.ok(2).is_ok() { + if let Ok(_v) = e.ok(5) { + if let Ok(_) = e.ok(4).as_ref() { + e.mark(3); + }}}}}}}} + }; + e.assert(9); +} + +#[rustfmt::skip] +fn t_let_else_chained_then() { + let e = Events::new(); + _ = 'top: { + 'chain: { + if e.ok(1).is_ok() {} else { break 'chain }; + let true = e.ok(2).is_ok() else { break 'chain }; + let Ok(_v) = e.ok(9) else { break 'chain }; + let Ok(_) = e.ok(3) else { break 'chain }; + let Ok(_) = e.ok(4).as_ref() else { break 'chain }; + if e.ok(5).is_ok() {} else { break 'chain }; + let Ok(_v) = e.ok(8) else { break 'chain }; + let Ok(_) = e.ok(6).as_ref() else { break 'chain }; + // The "then" branch: + e.mark(7); + break 'top; + } + // The "else" branch: + unreachable!() + }; + e.assert(9); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_chains_then() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(9).is_ok() + && let Ok(_v) = e.ok(5) + && let Ok(_) = e.ok(8) + && let Ok(_) = e.ok(7).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(4) + && let Ok(_) = e.ok(6).as_ref() { + e.mark(3); + }; + e.assert(9); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_chains_then() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(9).is_ok() + && let Ok(_v) = e.ok(8) + && let Ok(_) = e.ok(7) + && let Ok(_) = e.ok(6).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(5) + && let Ok(_) = e.ok(4).as_ref() { + e.mark(3); + }; + e.assert(9); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_nested_else() { + let e = Events::new(); + _ = if e.err(1).is_ok() {} else { + if let true = e.err(9).is_ok() {} else { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + if let Ok(_v) = e.err(8) {} else { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + if let Ok(_) = e.err(7) {} else { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + if let Ok(_) = e.err(6).as_ref() {} else { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + if e.err(2).is_ok() {} else { + if let Ok(_v) = e.err(5) {} else { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + if let Ok(_) = e.err(4) {} else { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(3); + }}}}}}}}; + e.assert(9); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_nested_else() { + let e = Events::new(); + _ = if e.err(1).is_ok() {} else { + if let true = e.err(2).is_ok() {} else { + if let Ok(_v) = e.err(3) {} else { + if let Ok(_) = e.err(4) {} else { + if let Ok(_) = e.err(5).as_ref() {} else { + if e.err(6).is_ok() {} else { + if let Ok(_v) = e.err(7) {} else { + if let Ok(_) = e.err(8) {} else { + e.mark(9); + }}}}}}}}; + e.assert(9); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_nested_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() { + if let true = e.ok(9).is_ok() { + if let Ok(_v) = e.ok(8) { + if let Ok(_) = e.ok(7) { + if let Ok(_) = e.ok(6).as_ref() { + if e.ok(2).is_ok() { + if let Ok(_v) = e.ok(5) { + if let Ok(_) = e.err(4).as_ref() {} else { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(3); + }}}}}}}}; + e.assert(9); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_nested_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() { + if let true = e.ok(9).is_ok() { + if let Ok(_v) = e.ok(8) { + if let Ok(_) = e.ok(7) { + if let Ok(_) = e.ok(6).as_ref() { + if e.ok(2).is_ok() { + if let Ok(_v) = e.ok(5) { + if let Ok(_) = e.err(3).as_ref() {} else { + e.mark(4); + }}}}}}}}; + e.assert(9); +} + +#[rustfmt::skip] +fn t_let_else_chained_then_else() { + let e = Events::new(); + _ = 'top: { + 'chain: { + if e.ok(1).is_ok() {} else { break 'chain }; + let true = e.ok(2).is_ok() else { break 'chain }; + let Ok(_v) = e.ok(8) else { break 'chain }; + let Ok(_) = e.ok(3) else { break 'chain }; + let Ok(_) = e.ok(4).as_ref() else { break 'chain }; + if e.ok(5).is_ok() {} else { break 'chain }; + let Ok(_v) = e.ok(7) else { break 'chain }; + let Ok(_) = e.err(6).as_ref() else { break 'chain }; + // The "then" branch: + unreachable!(); + #[allow(unreachable_code)] + break 'top; + } + // The "else" branch: + e.mark(9); + }; + e.assert(9); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_chains_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(9).is_ok() + && let Ok(_v) = e.ok(4) + && let Ok(_) = e.ok(8) + && let Ok(_) = e.ok(7).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(3) + && let Ok(_) = e.err(6) {} else { + e.mark(5); + }; + e.assert(9); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_chains_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(8).is_ok() + && let Ok(_v) = e.ok(7) + && let Ok(_) = e.ok(6) + && let Ok(_) = e.ok(5).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(4) + && let Ok(_) = e.err(3) {} else { + e.mark(9); + }; + e.assert(9); +} + +fn main() { + t_bindings(); + t_tuples(); + t_arrays(); + t_fncalls(); + t_tailexpr_bindings(); + t_tailexpr_tuples(); + t_if_let_then(); + t_if_let_else(); + t_match_then(); + t_match_else(); + t_let_else_then(); + t_let_else_else(); + t_if_let_then_tailexpr(); + t_if_let_else_tailexpr(); + t_if_let_nested_then(); + t_let_else_chained_then(); + t_if_let_chains_then(); + t_if_let_nested_else(); + t_if_let_nested_then_else(); + t_let_else_chained_then_else(); + t_if_let_chains_then_else(); +} + +// # Test scaffolding + +use core::cell::RefCell; +use std::collections::HashSet; + +/// A buffer to track the order of events. +/// +/// First, numbered events are logged into this buffer. +/// +/// Then, `assert` is called to verify that the correct number of +/// events were logged, and that they were logged in the expected +/// order. +struct Events(RefCell>>); + +impl Events { + const fn new() -> Self { + Self(RefCell::new(Some(Vec::new()))) + } + #[track_caller] + fn assert(&self, max: u64) { + let buf = &self.0; + let v1 = buf.borrow().as_ref().unwrap().clone(); + let mut v2 = buf.borrow().as_ref().unwrap().clone(); + *buf.borrow_mut() = None; + v2.sort(); + let uniq_len = v2.iter().collect::>().len(); + // Check that the sequence is sorted. + assert_eq!(v1, v2); + // Check that there are no duplicates. + assert_eq!(v2.len(), uniq_len); + // Check that the length is the expected one. + assert_eq!(max, uniq_len as u64); + // Check that the last marker is the expected one. + assert_eq!(v2.last().unwrap(), &max); + } + /// Return an `Ok` value that logs its drop. + fn ok(&self, m: u64) -> Result, LogDrop<'_>> { + Ok(LogDrop(self, m)) + } + /// Return an `Err` value that logs its drop. + fn err(&self, m: u64) -> Result { + Err(LogDrop(self, m)) + } + /// Log an event. + fn mark(&self, m: u64) { + self.0.borrow_mut().as_mut().unwrap().push(m); + } +} + +impl Drop for Events { + fn drop(&mut self) { + if self.0.borrow().is_some() { + panic!("failed to call `Events::assert()`"); + } + } +} + +/// A type that logs its drop events. +struct LogDrop<'b>(&'b Events, u64); + +impl<'b> Drop for LogDrop<'b> { + fn drop(&mut self) { + self.0.mark(self.1); + } +} diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs index a44ed9e5ef59b..34548e2487e0a 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs @@ -43,9 +43,9 @@ fn main() { } foo(bar, "string", |s| s.len() == 5); - //~^ ERROR implementation of `FnOnce` is not general enough - //~| ERROR implementation of `FnOnce` is not general enough + //~^ ERROR implementation of `Parser` is not general enough + //~| ERROR implementation of `Parser` is not general enough foo(baz, "string", |s| s.0.len() == 5); - //~^ ERROR implementation of `FnOnce` is not general enough - //~| ERROR implementation of `FnOnce` is not general enough + //~^ ERROR implementation of `Parser` is not general enough + //~| ERROR implementation of `Parser` is not general enough } diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr index b2bb417a8f01b..23fc6e2f7f40a 100644 --- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr +++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.stderr @@ -1,39 +1,39 @@ -error: implementation of `FnOnce` is not general enough +error: implementation of `Parser` is not general enough --> $DIR/issue-71955.rs:45:5 | LL | foo(bar, "string", |s| s.len() == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Parser` is not general enough | - = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2` + = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` -error: implementation of `FnOnce` is not general enough +error: implementation of `Parser` is not general enough --> $DIR/issue-71955.rs:45:5 | LL | foo(bar, "string", |s| s.len() == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Parser` is not general enough | - = note: closure with signature `for<'a> fn(&'a &'2 str) -> bool` must implement `FnOnce<(&&'1 str,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&&'2 str,)>`, for some specific lifetime `'2` + = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: implementation of `FnOnce` is not general enough +error: implementation of `Parser` is not general enough --> $DIR/issue-71955.rs:48:5 | LL | foo(baz, "string", |s| s.0.len() == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Parser` is not general enough | - = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2` + = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` -error: implementation of `FnOnce` is not general enough +error: implementation of `Parser` is not general enough --> $DIR/issue-71955.rs:48:5 | LL | foo(baz, "string", |s| s.0.len() == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Parser` is not general enough | - = note: closure with signature `for<'a> fn(&'a Wrapper<'2>) -> bool` must implement `FnOnce<(&Wrapper<'1>,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&Wrapper<'2>,)>`, for some specific lifetime `'2` + = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`... + = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 4 previous errors diff --git a/tests/ui/intrinsics/reify-intrinsic.rs b/tests/ui/intrinsics/reify-intrinsic.rs index 0d047ccf4a324..5b2324235c1a9 100644 --- a/tests/ui/intrinsics/reify-intrinsic.rs +++ b/tests/ui/intrinsics/reify-intrinsic.rs @@ -3,17 +3,17 @@ #![feature(core_intrinsics, intrinsics)] fn a() { - let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute; + let _: unsafe fn(isize) -> usize = std::mem::transmute; //~^ ERROR cannot coerce } fn b() { - let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize; + let _ = std::mem::transmute as unsafe fn(isize) -> usize; //~^ ERROR casting } fn c() { - let _: [unsafe extern "rust-intrinsic" fn(f32) -> f32; 2] = [ + let _: [unsafe fn(f32) -> f32; 2] = [ std::intrinsics::floorf32, //~ ERROR cannot coerce std::intrinsics::log2f32, ]; diff --git a/tests/ui/intrinsics/reify-intrinsic.stderr b/tests/ui/intrinsics/reify-intrinsic.stderr index aea6d263a727d..aea6f838e0d44 100644 --- a/tests/ui/intrinsics/reify-intrinsic.stderr +++ b/tests/ui/intrinsics/reify-intrinsic.stderr @@ -1,19 +1,19 @@ error[E0308]: cannot coerce intrinsics to function pointers - --> $DIR/reify-intrinsic.rs:6:64 + --> $DIR/reify-intrinsic.rs:6:40 | -LL | let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute; - | ------------------------------------------------- ^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers +LL | let _: unsafe fn(isize) -> usize = std::mem::transmute; + | ------------------------- ^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers | | | expected due to this | - = note: expected fn pointer `unsafe extern "rust-intrinsic" fn(isize) -> usize` + = note: expected fn pointer `unsafe fn(isize) -> usize` found fn item `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` -error[E0606]: casting `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid +error[E0606]: casting `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` as `unsafe fn(isize) -> usize` is invalid --> $DIR/reify-intrinsic.rs:11:13 | -LL | let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _ = std::mem::transmute as unsafe fn(isize) -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: cannot coerce intrinsics to function pointers --> $DIR/reify-intrinsic.rs:17:9 @@ -21,7 +21,7 @@ error[E0308]: cannot coerce intrinsics to function pointers LL | std::intrinsics::floorf32, | ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers | - = note: expected fn pointer `unsafe extern "rust-intrinsic" fn(_) -> _` + = note: expected fn pointer `unsafe fn(_) -> _` found fn item `unsafe fn(_) -> _ {floorf32}` error: aborting due to 3 previous errors diff --git a/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.rs b/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.rs new file mode 100644 index 0000000000000..a9c2c20ef374a --- /dev/null +++ b/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.rs @@ -0,0 +1,51 @@ +// https://github.com/rust-lang/rust/issues/109195 +struct Foo; + +impl Foo { + fn bar_baz() {} +} + +impl Foo { + fn bar_quux() {} +} + +fn main() { + String::from::utf8; + //~^ ERROR ambiguous associated type [E0223] + //~| HELP there is an associated function with a similar name: `from_utf8` + String::from::utf8(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP there is an associated function with a similar name: `from_utf8` + String::from::utf16(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP there is an associated function with a similar name: `from_utf16` + String::from::method_that_doesnt_exist(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP if there were a trait named `Example` with associated type `from` + str::into::string(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP there is an associated function with a similar name: `into_string` + str::char::indices(); + //~^ ERROR ambiguous associated type [E0223] + //~| HELP there is an associated function with a similar name: `char_indices` + Foo::bar::baz; + //~^ ERROR ambiguous associated type [E0223] + //~| HELP there is an associated function with a similar name: `bar_baz` + Foo::bar::quux; + //~^ ERROR ambiguous associated type [E0223] + //~| HELP there is an associated function with a similar name: `bar_quux` + Foo::bar::fizz; + //~^ ERROR ambiguous associated type [E0223] + //~| HELP if there were a trait named `Example` with associated type `bar` + i32::wrapping::add; + //~^ ERROR ambiguous associated type [E0223] + //~| HELP there is an associated function with a similar name: `wrapping_add` + i32::wrapping::method_that_doesnt_exist; + //~^ ERROR ambiguous associated type [E0223] + //~| HELP if there were a trait named `Example` with associated type `wrapping` + + // this one ideally should suggest `downcast_mut_unchecked` + ::downcast::mut_unchecked; + //~^ ERROR ambiguous associated type [E0223] + //~| HELP if there were a trait named `Example` with associated type `downcast` +} diff --git a/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.stderr b/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.stderr new file mode 100644 index 0000000000000..5863aa28f41f3 --- /dev/null +++ b/tests/ui/suggestions/ambiguous-assoc-type-path-suggest-similar-item.stderr @@ -0,0 +1,135 @@ +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:13:5 + | +LL | String::from::utf8; + | ^^^^^^^^^^^^ + | +help: there is an associated function with a similar name: `from_utf8` + | +LL | String::from_utf8; + | ~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:16:5 + | +LL | String::from::utf8(); + | ^^^^^^^^^^^^ + | +help: there is an associated function with a similar name: `from_utf8` + | +LL | String::from_utf8(); + | ~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:19:5 + | +LL | String::from::utf16(); + | ^^^^^^^^^^^^ + | +help: there is an associated function with a similar name: `from_utf16` + | +LL | String::from_utf16(); + | ~~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:22:5 + | +LL | String::from::method_that_doesnt_exist(); + | ^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `from` implemented for `String`, you could use the fully-qualified path + | +LL | ::from::method_that_doesnt_exist(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:25:5 + | +LL | str::into::string(); + | ^^^^^^^^^ + | +help: there is an associated function with a similar name: `into_string` + | +LL | str::into_string(); + | ~~~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:28:5 + | +LL | str::char::indices(); + | ^^^^^^^^^ + | +help: there is an associated function with a similar name: `char_indices` + | +LL | str::char_indices(); + | ~~~~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:31:5 + | +LL | Foo::bar::baz; + | ^^^^^^^^ + | +help: there is an associated function with a similar name: `bar_baz` + | +LL | Foo::bar_baz; + | ~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:34:5 + | +LL | Foo::bar::quux; + | ^^^^^^^^ + | +help: there is an associated function with a similar name: `bar_quux` + | +LL | Foo::bar_quux; + | ~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:37:5 + | +LL | Foo::bar::fizz; + | ^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `bar` implemented for `Foo`, you could use the fully-qualified path + | +LL | ::bar::fizz; + | ~~~~~~~~~~~~~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:40:5 + | +LL | i32::wrapping::add; + | ^^^^^^^^^^^^^ + | +help: there is an associated function with a similar name: `wrapping_add` + | +LL | i32::wrapping_add; + | ~~~~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:43:5 + | +LL | i32::wrapping::method_that_doesnt_exist; + | ^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `wrapping` implemented for `i32`, you could use the fully-qualified path + | +LL | ::wrapping::method_that_doesnt_exist; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0223]: ambiguous associated type + --> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:48:5 + | +LL | ::downcast::mut_unchecked; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `downcast` implemented for `(dyn Any + 'static)`, you could use the fully-qualified path + | +LL | <(dyn Any + 'static) as Example>::downcast::mut_unchecked; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/suggestions/issue-109195.rs b/tests/ui/suggestions/issue-109195.rs deleted file mode 100644 index cc499b0d77618..0000000000000 --- a/tests/ui/suggestions/issue-109195.rs +++ /dev/null @@ -1,20 +0,0 @@ -fn main() { - String::from::utf8; - //~^ ERROR ambiguous associated type [E0223] - //~| HELP there is an associated function with a similar name: `from_utf8` - String::from::utf8(); - //~^ ERROR ambiguous associated type [E0223] - //~| HELP there is an associated function with a similar name: `from_utf8` - String::from::utf16(); - //~^ ERROR ambiguous associated type [E0223] - //~| HELP there is an associated function with a similar name: `from_utf16` - String::from::method_that_doesnt_exist(); - //~^ ERROR ambiguous associated type [E0223] - //~| HELP if there were a trait named `Example` with associated type `from` - str::from::utf8(); - //~^ ERROR ambiguous associated type [E0223] - //~| HELP if there were a trait named `Example` with associated type `from` - str::from::utf8_mut(); - //~^ ERROR ambiguous associated type [E0223] - //~| HELP if there were a trait named `Example` with associated type `from` -} diff --git a/tests/ui/suggestions/issue-109195.stderr b/tests/ui/suggestions/issue-109195.stderr deleted file mode 100644 index 10cf9cfd28ca7..0000000000000 --- a/tests/ui/suggestions/issue-109195.stderr +++ /dev/null @@ -1,69 +0,0 @@ -error[E0223]: ambiguous associated type - --> $DIR/issue-109195.rs:2:5 - | -LL | String::from::utf8; - | ^^^^^^^^^^^^ - | -help: there is an associated function with a similar name: `from_utf8` - | -LL | String::from_utf8; - | ~~~~~~~~~ - -error[E0223]: ambiguous associated type - --> $DIR/issue-109195.rs:5:5 - | -LL | String::from::utf8(); - | ^^^^^^^^^^^^ - | -help: there is an associated function with a similar name: `from_utf8` - | -LL | String::from_utf8(); - | ~~~~~~~~~ - -error[E0223]: ambiguous associated type - --> $DIR/issue-109195.rs:8:5 - | -LL | String::from::utf16(); - | ^^^^^^^^^^^^ - | -help: there is an associated function with a similar name: `from_utf16` - | -LL | String::from_utf16(); - | ~~~~~~~~~~ - -error[E0223]: ambiguous associated type - --> $DIR/issue-109195.rs:11:5 - | -LL | String::from::method_that_doesnt_exist(); - | ^^^^^^^^^^^^ - | -help: if there were a trait named `Example` with associated type `from` implemented for `String`, you could use the fully-qualified path - | -LL | ::from::method_that_doesnt_exist(); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ - -error[E0223]: ambiguous associated type - --> $DIR/issue-109195.rs:14:5 - | -LL | str::from::utf8(); - | ^^^^^^^^^ - | -help: if there were a trait named `Example` with associated type `from` implemented for `str`, you could use the fully-qualified path - | -LL | ::from::utf8(); - | ~~~~~~~~~~~~~~~~~~~~~~ - -error[E0223]: ambiguous associated type - --> $DIR/issue-109195.rs:17:5 - | -LL | str::from::utf8_mut(); - | ^^^^^^^^^ - | -help: if there were a trait named `Example` with associated type `from` implemented for `str`, you could use the fully-qualified path - | -LL | ::from::utf8_mut(); - | ~~~~~~~~~~~~~~~~~~~~~~ - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0223`.