Auto merge of #135978 - matthiaskrgr:rollup-ni16gqr, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #133605 (Add extensive set of drop order tests) - #135489 (remove pointless allowed_through_unstable_modules on TryFromSliceError) - #135757 (Add NuttX support for AArch64 and ARMv7-A targets) - #135799 (rustdoc-json: Rename `Path::name` to `path`, and give it the path again.) - #135865 (For E0223, suggest associated functions that are similar to the path, even if the base type has multiple inherent impl blocks.) - #135890 (Implement `VecDeque::pop_front_if` & `VecDeque::pop_back_if`) - #135914 (Remove usages of `QueryNormalizer` in the compiler) - #135936 (fix reify-intrinsic test) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
061ee95ce1
41 changed files with 2317 additions and 173 deletions
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
41
compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs
Normal file
41
compiler/rustc_target/src/spec/targets/armv7a_nuttx_eabi.rs
Normal file
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
match ty.kind() {
|
||||
let normalized_ty = ocx.infcx.resolve_vars_if_possible(normalized_ty);
|
||||
debug!("dropck_outlives: ty from dtorck_types = {:?}", normalized_ty);
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<TyCtxt<'tcx>>,
|
||||
{
|
||||
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>(
|
||||
|
|
|
|||
|
|
@ -1735,6 +1735,52 @@ impl<T, A: Allocator> VecDeque<T, A> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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<i32> = 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<T> {
|
||||
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<i32> = 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<T> {
|
||||
let first = self.back_mut()?;
|
||||
if predicate(first) { self.pop_back() } else { None }
|
||||
}
|
||||
|
||||
/// Prepends an element to the deque.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -80,6 +80,45 @@ fn test_parameterized<T: Clone + PartialEq + Debug>(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::<i32>::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();
|
||||
|
|
|
|||
|
|
@ -156,7 +156,6 @@ pub const fn from_mut<T>(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(());
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <!-- date-check --> 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -622,7 +622,7 @@ impl FromClean<clean::Type> for Type {
|
|||
impl FromClean<clean::Path> 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))),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // 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<i32>; // path: "std::vec::Vec"
|
||||
/// pub type Vec2 = Vec<i32>; // path: "Vec"
|
||||
/// pub type Vec3 = std::prelude::v1::Vec<i32>; // 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.
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}]);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
10
tests/rustdoc-json/auxiliary/defines_and_reexports.rs
Normal file
10
tests/rustdoc-json/auxiliary/defines_and_reexports.rs
Normal file
|
|
@ -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};
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<Output = i32> {
|
|||
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
|
||||
|
|
|
|||
|
|
@ -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"'
|
||||
|
|
|
|||
83
tests/rustdoc-json/path_name.rs
Normal file
83
tests/rustdoc-json/path_name.rs
Normal file
|
|
@ -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<i32>;
|
||||
//@ is "$.index[*][?(@.name=='Vec2')].inner.type_alias.type.resolved_path.path" '"Vec"'
|
||||
pub type Vec2 = Vec<i32>;
|
||||
//@ is "$.index[*][?(@.name=='Vec3')].inner.type_alias.type.resolved_path.path" '"std::prelude::v1::Vec"'
|
||||
pub type Vec3 = std::prelude::v1::Vec<i32>;
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<dyn Fn() -> i32 + Send + Sync + 'static>;
|
||||
|
||||
|
|
@ -34,13 +34,13 @@ pub type SyncIntGen = Box<dyn Fn() -> 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<dyn Send + Debug>;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
575
tests/ui/drop/drop-order-comparisons.e2021.fixed
Normal file
575
tests/ui/drop/drop-order-comparisons.e2021.fixed
Normal file
|
|
@ -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<T> Tr for T {}
|
||||
fn b<'a, T: 'a>(x: T) -> Box<dyn Tr + 'a> {
|
||||
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<Option<Vec<u64>>>);
|
||||
|
||||
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::<HashSet<_>>().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<'_>, LogDrop<'_>> {
|
||||
Ok(LogDrop(self, m))
|
||||
}
|
||||
/// Return an `Err` value that logs its drop.
|
||||
fn err(&self, m: u64) -> Result<LogDrop, LogDrop> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
477
tests/ui/drop/drop-order-comparisons.e2021.stderr
Normal file
477
tests/ui/drop/drop-order-comparisons.e2021.stderr
Normal file
|
|
@ -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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
|
||||
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
|
||||
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
|
||||
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
|
||||
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html>
|
||||
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
|
||||
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
|
||||
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
|
||||
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
|
||||
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
|
||||
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
|
||||
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
|
||||
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
|
||||
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
|
||||
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 <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
|
||||
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
|
||||
|
||||
575
tests/ui/drop/drop-order-comparisons.rs
Normal file
575
tests/ui/drop/drop-order-comparisons.rs
Normal file
|
|
@ -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<T> Tr for T {}
|
||||
fn b<'a, T: 'a>(x: T) -> Box<dyn Tr + 'a> {
|
||||
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<Option<Vec<u64>>>);
|
||||
|
||||
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::<HashSet<_>>().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<'_>, LogDrop<'_>> {
|
||||
Ok(LogDrop(self, m))
|
||||
}
|
||||
/// Return an `Err` value that logs its drop.
|
||||
fn err(&self, m: u64) -> Result<LogDrop, LogDrop> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
<dyn std::any::Any>::downcast::mut_unchecked;
|
||||
//~^ ERROR ambiguous associated type [E0223]
|
||||
//~| HELP if there were a trait named `Example` with associated type `downcast`
|
||||
}
|
||||
|
|
@ -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 | <String as Example>::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 | <Foo as Example>::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 | <i32 as Example>::wrapping::method_that_doesnt_exist;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error[E0223]: ambiguous associated type
|
||||
--> $DIR/ambiguous-assoc-type-path-suggest-similar-item.rs:48:5
|
||||
|
|
||||
LL | <dyn std::any::Any>::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`.
|
||||
|
|
@ -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`
|
||||
}
|
||||
|
|
@ -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 | <String as Example>::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 | <str as Example>::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 | <str as Example>::from::utf8_mut();
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0223`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue