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:
bors 2025-01-24 08:28:35 +00:00
commit 061ee95ce1
41 changed files with 2317 additions and 173 deletions

View file

@ -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")

View file

@ -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),

View file

@ -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,
}
}

View 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,
}
}

View file

@ -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,
}
}

View file

@ -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()
},
}
}

View file

@ -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()
},
}
}

View file

@ -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));
}
}
}

View file

@ -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>(

View file

@ -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

View file

@ -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)]

View file

@ -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();

View file

@ -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(());

View file

@ -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

View file

@ -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

View file

@ -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`

View file

@ -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))),
}

View file

@ -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.

View file

@ -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),
}]);

View file

@ -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

View file

@ -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

View 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};

View file

@ -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;

View file

@ -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

View file

@ -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"'

View 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>;

View file

@ -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
}

View file

@ -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>;

View file

@ -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"

View file

@ -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);

View 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);
}
}

View 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

View 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);
}
}

View file

@ -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
}

View file

@ -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

View file

@ -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,
];

View file

@ -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

View file

@ -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`
}

View file

@ -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`.

View file

@ -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`
}

View file

@ -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`.