Auto merge of #153617 - JonathanBrouwer:rollup-udG4Tzr, r=JonathanBrouwer

Rollup of 4 pull requests

Successful merges:

 - rust-lang/rust#147834 (Always make tuple elements a coercion site)
 - rust-lang/rust#150446 (miri/const eval: support `MaybeDangling`)
 - rust-lang/rust#153053 (stop marking `deref_patterns` as an incomplete feature)
 - rust-lang/rust#153398 (fix ICE in `const_c_variadic` when passing ZSTs)
This commit is contained in:
bors
2026-03-09 17:03:26 +00:00
64 changed files with 344 additions and 149 deletions
@@ -12,7 +12,7 @@
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef};
use rustc_middle::{bug, mir, span_bug};
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
use rustc_target::callconv::{ArgAbi, FnAbi};
use tracing::field::Empty;
use tracing::{info, instrument, trace};
@@ -284,7 +284,7 @@ fn pass_argument<'x, 'y>(
'tcx: 'y,
{
assert_eq!(callee_ty, callee_abi.layout.ty);
if callee_abi.mode == PassMode::Ignore {
if callee_abi.is_ignore() {
// This one is skipped. Still must be made live though!
if !already_live {
self.storage_live(callee_arg.as_local().unwrap())?;
@@ -450,7 +450,7 @@ pub fn init_stack_frame(
let mut caller_args = args
.iter()
.zip(caller_fn_abi.args.iter())
.filter(|arg_and_abi| !matches!(arg_and_abi.1.mode, PassMode::Ignore));
.filter(|arg_and_abi| !arg_and_abi.1.is_ignore());
// Now we have to spread them out across the callee's locals,
// taking into account the `spread_arg`. If we could write
@@ -480,7 +480,12 @@ pub fn init_stack_frame(
// Consume the remaining arguments by putting them into the variable argument
// list.
let varargs = self.allocate_varargs(&mut caller_args, &mut callee_args_abis)?;
let varargs = self.allocate_varargs(
&mut caller_args,
// "Ignored" arguments aren't actually passed, so the callee should also
// ignore them. (`pass_argument` does this for regular arguments.)
(&mut callee_args_abis).filter(|(_, abi)| !abi.is_ignore()),
)?;
// When the frame is dropped, these variable arguments are deallocated.
self.frame_mut().va_list = varargs.clone();
let key = self.va_list_ptr(varargs.into());
@@ -631,8 +631,8 @@ impl<'a, 'tcx: 'a, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// of variadic arguments. Return a list of the places that hold those arguments.
pub(crate) fn allocate_varargs<I, J>(
&mut self,
caller_args: &mut I,
callee_abis: &mut J,
caller_args: I,
mut callee_abis: J,
) -> InterpResult<'tcx, Vec<MPlaceTy<'tcx, M::Provenance>>>
where
I: Iterator<Item = (&'a FnArg<'tcx, M::Provenance>, &'a ArgAbi<'tcx, Ty<'tcx>>)>,
@@ -7,6 +7,7 @@
use std::borrow::Cow;
use std::fmt::Write;
use std::hash::Hash;
use std::mem;
use std::num::NonZero;
use either::{Left, Right};
@@ -288,6 +289,8 @@ struct ValidityVisitor<'rt, 'tcx, M: Machine<'tcx>> {
/// If this is `Some`, then `reset_provenance_and_padding` must be true (but not vice versa:
/// we might not track data vs padding bytes if the operand isn't stored in memory anyway).
data_bytes: Option<RangeSet>,
/// True if we are inside of `MaybeDangling`. This disables pointer access checks.
may_dangle: bool,
}
impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
@@ -489,7 +492,8 @@ fn check_safe_pointer(
if place.layout.is_unsized() {
self.check_wide_ptr_meta(place.meta(), place.layout)?;
}
// Make sure this is dereferenceable and all.
// Determine size and alignment of pointee.
let size_and_align = try_validation!(
self.ecx.size_and_align_of_val(&place),
self.path,
@@ -503,27 +507,33 @@ fn check_safe_pointer(
// alignment and size determined by the layout (size will be 0,
// alignment should take attributes into account).
.unwrap_or_else(|| (place.layout.size, place.layout.align.abi));
// Direct call to `check_ptr_access_align` checks alignment even on CTFE machines.
try_validation!(
self.ecx.check_ptr_access(
place.ptr(),
size,
CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message
),
self.path,
Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind, maybe: false },
Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance {
ptr_kind,
// FIXME this says "null pointer" when null but we need translate
pointer: format!("{}", Pointer::<Option<AllocId>>::without_provenance(i))
},
Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds {
ptr_kind
},
Ub(PointerUseAfterFree(..)) => DanglingPtrUseAfterFree {
ptr_kind,
},
);
if !self.may_dangle {
// Make sure this is dereferenceable and all.
// Direct call to `check_ptr_access_align` checks alignment even on CTFE machines.
// Call `check_ptr_access` to avoid checking alignment here.
try_validation!(
self.ecx.check_ptr_access(
place.ptr(),
size,
CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message
),
self.path,
Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind, maybe: false },
Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance {
ptr_kind,
pointer: format!("{}", Pointer::<Option<AllocId>>::without_provenance(i))
},
Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds {
ptr_kind
},
Ub(PointerUseAfterFree(..)) => DanglingPtrUseAfterFree {
ptr_kind,
},
);
}
try_validation!(
self.ecx.check_ptr_align(
place.ptr(),
@@ -536,8 +546,10 @@ fn check_safe_pointer(
found_bytes: has.bytes()
},
);
// Make sure this is non-null. We checked dereferenceability above, but if `size` is zero
// that does not imply non-null.
// Make sure this is non-null. This is obviously needed when `may_dangle` is set,
// but even if we did check dereferenceability above that would still allow null
// pointers if `size` is zero.
let scalar = Scalar::from_maybe_pointer(place.ptr(), self.ecx);
if self.ecx.scalar_may_be_null(scalar)? {
let maybe = !M::Provenance::OFFSET_IS_ADDR && matches!(scalar, Scalar::Ptr(..));
@@ -1265,6 +1277,14 @@ fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'t
ty::PatternKind::Or(_patterns) => {}
}
}
ty::Adt(adt, _) if adt.is_maybe_dangling() => {
let old_may_dangle = mem::replace(&mut self.may_dangle, true);
let inner = self.ecx.project_field(val, FieldIdx::ZERO)?;
self.visit_value(&inner)?;
self.may_dangle = old_may_dangle;
}
_ => {
// default handler
try_validation!(
@@ -1350,6 +1370,7 @@ fn validate_operand_internal(
ecx,
reset_provenance_and_padding,
data_bytes: reset_padding.then_some(RangeSet(Vec::new())),
may_dangle: false,
};
v.visit_value(val)?;
v.reset_padding(val)?;
+1 -1
View File
@@ -465,7 +465,7 @@ pub fn internal(&self, feature: Symbol) -> bool {
/// Allows having using `suggestion` in the `#[deprecated]` attribute.
(unstable, deprecated_suggestion, "1.61.0", Some(94785)),
/// Allows deref patterns.
(incomplete, deref_patterns, "1.79.0", Some(87121)),
(unstable, deref_patterns, "1.79.0", Some(87121)),
/// Allows deriving the From trait on single-field structs.
(unstable, derive_from, "1.91.0", Some(144889)),
/// Allows giving non-const impls custom diagnostic messages if attempted to be used as const
+13 -16
View File
@@ -1792,27 +1792,24 @@ fn check_expr_repeat(
fn check_expr_tuple(
&self,
elts: &'tcx [hir::Expr<'tcx>],
elements: &'tcx [hir::Expr<'tcx>],
expected: Expectation<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
let flds = expected.only_has_type(self).and_then(|ty| {
let ty = self.try_structurally_resolve_type(expr.span, ty);
match ty.kind() {
ty::Tuple(flds) => Some(&flds[..]),
_ => None,
}
let mut expectations = expected
.only_has_type(self)
.and_then(|ty| self.try_structurally_resolve_type(expr.span, ty).opt_tuple_fields())
.unwrap_or_default()
.iter();
let elements = elements.iter().map(|e| {
let ty = expectations.next().unwrap_or_else(|| self.next_ty_var(e.span));
self.check_expr_coercible_to_type(e, ty, None);
ty
});
let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| match flds {
Some(fs) if i < fs.len() => {
let ety = fs[i];
self.check_expr_coercible_to_type(e, ety, None);
ety
}
_ => self.check_expr_with_expectation(e, NoExpectation),
});
let tuple = Ty::new_tup_from_iter(self.tcx, elt_ts_iter);
let tuple = Ty::new_tup_from_iter(self.tcx, elements);
if let Err(guar) = tuple.error_reported() {
Ty::new_error(self.tcx, guar)
} else {
+11 -1
View File
@@ -1592,7 +1592,8 @@ pub fn ty_adt_def(self) -> Option<AdtDef<'tcx>> {
}
}
/// Iterates over tuple fields.
/// Returns a list of tuple type arguments.
///
/// Panics when called on anything but a tuple.
#[inline]
pub fn tuple_fields(self) -> &'tcx List<Ty<'tcx>> {
@@ -1602,6 +1603,15 @@ pub fn tuple_fields(self) -> &'tcx List<Ty<'tcx>> {
}
}
/// Returns a list of tuple type arguments, or `None` if `self` isn't a tuple.
#[inline]
pub fn opt_tuple_fields(self) -> Option<&'tcx List<Ty<'tcx>>> {
match self.kind() {
Tuple(args) => Some(args),
_ => None,
}
}
/// If the type contains variants, returns the valid range of variant indices.
//
// FIXME: This requires the optimized MIR in the case of coroutines.
@@ -6,8 +6,7 @@ The tracking issue for this feature is: [#87121]
------------------------
> **Note**: This feature is incomplete. In the future, it is meant to supersede
> [`box_patterns`].
> **Note**: This feature supersedes [`box_patterns`].
This feature permits pattern matching on [smart pointers in the standard library] through their
`Deref` target types, either implicitly or with explicit `deref!(_)` patterns (the syntax of which
@@ -15,7 +14,6 @@ is currently a placeholder).
```rust
#![feature(deref_patterns)]
#![allow(incomplete_features)]
let mut v = vec![Box::new(Some(0))];
@@ -58,7 +56,6 @@ Like [`box_patterns`], deref patterns may move out of boxes:
```rust
# #![feature(deref_patterns)]
# #![allow(incomplete_features)]
struct NoCopy;
let deref!(x) = Box::new(NoCopy);
drop::<NoCopy>(x);
@@ -69,7 +66,6 @@ allowing then to be used in deref patterns:
```rust
# #![feature(deref_patterns)]
# #![allow(incomplete_features)]
match ("test".to_string(), Box::from("test"), b"test".to_vec()) {
("test", "test", b"test") => {}
_ => panic!(),
@@ -917,6 +917,7 @@ fn retag_ptr_inplace(
RetagInfo { cause: self.retag_cause, in_field: self.in_field },
)?;
self.ecx.write_immediate(*val, place)?;
interp_ok(())
}
}
@@ -964,6 +965,9 @@ fn visit_value(&mut self, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> {
// even if field retagging is not enabled. *shrug*)
self.walk_value(place)?;
}
ty::Adt(adt, _) if adt.is_maybe_dangling() => {
// Skip traversing for everything inside of `MaybeDangling`
}
_ => {
// Not a reference/pointer/box. Recurse.
let in_field = mem::replace(&mut self.in_field, true); // remember and restore old value
@@ -523,6 +523,9 @@ fn visit_value(&mut self, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> {
// even if field retagging is not enabled. *shrug*)
self.walk_value(place)?;
}
ty::Adt(adt, _) if adt.is_maybe_dangling() => {
// Skip traversing for everything inside of `MaybeDangling`
}
_ => {
// Not a reference/pointer/box. Recurse.
self.walk_value(place)?;
@@ -0,0 +1,15 @@
// Test that an unaligned `MaybeDangling<&u8>` is still detected as UB.
//
//@compile-flags: -Zmiri-disable-stacked-borrows
#![feature(maybe_dangling)]
use std::mem::{MaybeDangling, transmute};
fn main() {
let a = [1u16, 0u16];
unsafe {
let unaligned = MaybeDangling::new(a.as_ptr().byte_add(1));
transmute::<MaybeDangling<*const u16>, MaybeDangling<&u16>>(unaligned)
//~^ ERROR: Undefined Behavior: constructing invalid value: encountered an unaligned reference
};
}
@@ -0,0 +1,13 @@
error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN)
--> tests/fail/unaligned_pointers/maybe_dangling_unalighed.rs:LL:CC
|
LL | transmute::<MaybeDangling<*const u16>, MaybeDangling<&u16>>(unaligned)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error
@@ -0,0 +1,13 @@
// Test that a null `MaybeDangling<&u8>` is still detected as UB.
//
//@compile-flags: -Zmiri-disable-stacked-borrows
#![feature(maybe_dangling)]
use std::mem::{MaybeDangling, transmute};
use std::ptr::null;
fn main() {
let null = MaybeDangling::new(null());
unsafe { transmute::<MaybeDangling<*const u8>, MaybeDangling<&u8>>(null) };
//~^ ERROR: Undefined Behavior: constructing invalid value: encountered a null reference
}
@@ -0,0 +1,13 @@
error: Undefined Behavior: constructing invalid value: encountered a null reference
--> tests/fail/validity/maybe_dangling_null.rs:LL:CC
|
LL | unsafe { transmute::<MaybeDangling<*const u8>, MaybeDangling<&u8>>(null) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to 1 previous error
@@ -0,0 +1,59 @@
// Check that `MaybeDangling` actually prevents UB when it wraps dangling
// boxes and references
//
//@revisions: stack tree
//@[tree]compile-flags: -Zmiri-tree-borrows
#![feature(maybe_dangling)]
use std::mem::{self, MaybeDangling};
use std::ptr::drop_in_place;
fn main() {
boxy();
reference();
write_through_shared_ref();
}
fn boxy() {
let mut x = MaybeDangling::new(Box::new(1));
// make the box dangle
unsafe { drop_in_place(x.as_mut()) };
// move the dangling box (without `MaybeDangling` this causes UB)
let x: MaybeDangling<Box<u32>> = x;
mem::forget(x);
}
fn reference() {
let x = {
let local = 0;
// erase the lifetime to make a dangling reference
unsafe {
mem::transmute::<MaybeDangling<&u32>, MaybeDangling<&u32>>(MaybeDangling::new(&local))
}
};
// move the dangling reference (without `MaybeDangling` this causes UB)
let _x: MaybeDangling<&u32> = x;
}
fn write_through_shared_ref() {
// Under the current models, we do not forbid writing through
// `MaybeDangling<&i32>`. That's not yet finally decided, but meanwhile
// ensure we document this and notice when it changes.
unsafe {
let mutref = &mut 0;
write_through_shr(mem::transmute(mutref));
}
fn write_through_shr(x: MaybeDangling<&i32>) {
unsafe {
let y: *mut i32 = mem::transmute(x);
y.write(1);
}
}
}
@@ -0,0 +1,21 @@
//@ ignore-target: windows # does not ignore ZST arguments
//@ ignore-target: powerpc # does not ignore ZST arguments
//@ ignore-target: s390x # does not ignore ZST arguments
//@ ignore-target: sparc # does not ignore ZST arguments
#![feature(c_variadic)]
// Some platforms ignore ZSTs, meaning that the argument is not passed, even though it is part
// of the callee's ABI. Test that this doesn't trip any asserts.
//
// NOTE: this test only succeeds when the `()` argument uses `Passmode::Ignore`. For some targets,
// notably msvc, such arguments are not ignored, which would cause UB when attempting to read the
// second `i32` argument while the next item in the variable argument list is `()`.
fn main() {
unsafe extern "C" fn variadic(mut ap: ...) {
ap.arg::<i32>();
ap.arg::<i32>();
}
unsafe { variadic(0i32, (), 1i32) }
}
@@ -1,6 +1,6 @@
0..1: [ SharedReadWrite<TAG> ]
0..1: [ SharedReadWrite<TAG> ]
0..1: [ SharedReadWrite<TAG> ]
0..1: [ SharedReadWrite<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> ]
0..1: [ SharedReadWrite<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> SharedReadOnly<TAG> ]
0..1: [ SharedReadWrite<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> Unique<TAG> ]
0..1: [ SharedReadWrite<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> Disabled<TAG> SharedReadOnly<TAG> ]
0..1: [ unknown-bottom(..<TAG>) ]
@@ -2,7 +2,6 @@
//@ compile-flags: -Z mir-opt-level=0 -C panic=abort
#![feature(deref_patterns)]
#![expect(incomplete_features)]
#![crate_type = "lib"]
// EMIT_MIR string.foo.PreCodegen.after.mir
@@ -0,0 +1,18 @@
//@ build-pass
//@ compile-flags: --emit=obj
#![feature(c_variadic)]
#![feature(const_c_variadic)]
#![feature(const_destruct)]
#![crate_type = "lib"]
// Regression test for when a c-variadic argument is `PassMode::Ignore`. The caller won't pass the
// argument, but the callee ABI does have the argument. Ensure that const-eval is able to handle
// this case without tripping any asserts.
const unsafe extern "C" fn read_n<const N: usize>(_: ...) {}
unsafe fn read_too_many() {
const { read_n::<0>((), 1i32) }
}
fn read_as<T>() -> () {}
+2 -2
View File
@@ -232,10 +232,10 @@ LL | break (break, break);
| || |
| || expected because of this `break`
| |expected because of this `break`
| expected `()`, found `(!, !)`
| expected `()`, found `(_, _)`
|
= note: expected unit type `()`
found tuple `(!, !)`
found tuple `(_, _)`
error[E0308]: mismatched types
--> $DIR/loop-break-value.rs:89:15
@@ -22,10 +22,10 @@ error[E0308]: mismatched types
LL | fn f() -> isize {
| ----- expected `isize` because of return type
LL | (return 1, return 2)
| ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `(!, !)`
| ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `(_, _)`
|
= note: expected type `isize`
found tuple `(!, !)`
found tuple `(_, _)`
error: aborting due to 2 previous errors
-1
View File
@@ -1,7 +1,6 @@
//@ run-pass
//@ check-run-results
#![feature(deref_patterns)]
#![expect(incomplete_features)]
fn main() {
test(Some(String::from("42")));
@@ -1,7 +1,6 @@
//@ revisions: explicit implicit
//@ run-pass
#![feature(deref_patterns)]
#![allow(incomplete_features)]
use std::rc::Rc;
@@ -2,7 +2,6 @@
//@ run-pass
// Test the execution of deref patterns.
#![feature(deref_patterns)]
#![allow(incomplete_features)]
#[cfg(explicit)]
fn branch(vec: Vec<u32>) -> u32 {
@@ -5,7 +5,6 @@
//@ dont-require-annotations: NOTE
#![feature(deref_patterns)]
#![expect(incomplete_features)]
fn main() {
// Baseline 1: under normal circumstances, byte string literal patterns have type `&[u8; N]`,
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
--> $DIR/byte-string-type-errors.rs:13:12
--> $DIR/byte-string-type-errors.rs:12:12
|
LL | if let b"test" = () {}
| ^^^^^^^ -- this expression has type `()`
@@ -7,7 +7,7 @@ LL | if let b"test" = () {}
| expected `()`, found `&[u8; 4]`
error[E0308]: mismatched types
--> $DIR/byte-string-type-errors.rs:20:12
--> $DIR/byte-string-type-errors.rs:19:12
|
LL | if let b"test" = &[] as &[i8] {}
| ^^^^^^^ ------------ this expression has type `&[i8]`
@@ -18,7 +18,7 @@ LL | if let b"test" = &[] as &[i8] {}
found reference `&'static [u8]`
error[E0308]: mismatched types
--> $DIR/byte-string-type-errors.rs:25:12
--> $DIR/byte-string-type-errors.rs:24:12
|
LL | if let b"test" = *(&[] as &[i8]) {}
| ^^^^^^^ --------------- this expression has type `[i8]`
@@ -29,7 +29,7 @@ LL | if let b"test" = *(&[] as &[i8]) {}
found slice `[u8]`
error[E0308]: mismatched types
--> $DIR/byte-string-type-errors.rs:30:12
--> $DIR/byte-string-type-errors.rs:29:12
|
LL | if let b"test" = [()] {}
| ^^^^^^^ ---- this expression has type `[(); 1]`
@@ -40,7 +40,7 @@ LL | if let b"test" = [()] {}
found array `[u8; 4]`
error[E0308]: mismatched types
--> $DIR/byte-string-type-errors.rs:33:12
--> $DIR/byte-string-type-errors.rs:32:12
|
LL | if let b"test" = *b"this array is too long" {}
| ^^^^^^^ -------------------------- this expression has type `[u8; 22]`
@@ -48,7 +48,7 @@ LL | if let b"test" = *b"this array is too long" {}
| expected an array with a size of 22, found one with a size of 4
error[E0308]: mismatched types
--> $DIR/byte-string-type-errors.rs:39:12
--> $DIR/byte-string-type-errors.rs:38:12
|
LL | if let b"test" = &mut () {}
| ^^^^^^^ ------- this expression has type `&mut ()`
@@ -56,7 +56,7 @@ LL | if let b"test" = &mut () {}
| expected `()`, found `&[u8; 4]`
error[E0308]: mismatched types
--> $DIR/byte-string-type-errors.rs:44:12
--> $DIR/byte-string-type-errors.rs:43:12
|
LL | if let b"test" = &mut [] as &mut [i8] {}
| ^^^^^^^ -------------------- this expression has type `&mut [i8]`
@@ -67,7 +67,7 @@ LL | if let b"test" = &mut [] as &mut [i8] {}
found slice `[u8]`
error[E0308]: mismatched types
--> $DIR/byte-string-type-errors.rs:48:12
--> $DIR/byte-string-type-errors.rs:47:12
|
LL | if let b"test" = &mut [()] {}
| ^^^^^^^ --------- this expression has type `&mut [(); 1]`
@@ -78,7 +78,7 @@ LL | if let b"test" = &mut [()] {}
found array `[u8; 4]`
error[E0308]: mismatched types
--> $DIR/byte-string-type-errors.rs:52:12
--> $DIR/byte-string-type-errors.rs:51:12
|
LL | if let b"test" = &mut *b"this array is too long" {}
| ^^^^^^^ ------------------------------- this expression has type `&mut [u8; 22]`
@@ -1,5 +1,4 @@
#![feature(deref_patterns)]
#![allow(incomplete_features)]
use std::rc::Rc;
@@ -1,5 +1,5 @@
error[E0508]: cannot move out of type `[Struct]`, a non-copy slice
--> $DIR/cant_move_out_of_pattern.rs:9:11
--> $DIR/cant_move_out_of_pattern.rs:8:11
|
LL | match b {
| ^ cannot move out of here
@@ -16,7 +16,7 @@ LL | deref!([ref x]) => x,
| +++
error[E0507]: cannot move out of a shared reference
--> $DIR/cant_move_out_of_pattern.rs:17:11
--> $DIR/cant_move_out_of_pattern.rs:16:11
|
LL | match rc {
| ^^
@@ -33,7 +33,7 @@ LL | deref!(ref x) => x,
| +++
error[E0508]: cannot move out of type `[Struct]`, a non-copy slice
--> $DIR/cant_move_out_of_pattern.rs:25:11
--> $DIR/cant_move_out_of_pattern.rs:24:11
|
LL | match b {
| ^ cannot move out of here
@@ -50,7 +50,7 @@ LL | [ref x] => x,
| +++
error[E0507]: cannot move out of a shared reference
--> $DIR/cant_move_out_of_pattern.rs:35:11
--> $DIR/cant_move_out_of_pattern.rs:34:11
|
LL | match rc {
| ^^
@@ -1,6 +1,5 @@
//@ run-pass
#![feature(deref_patterns)]
#![allow(incomplete_features)]
use std::rc::Rc;
@@ -8,7 +8,6 @@
//! we'd get without `deref_patterns` enabled.
#![cfg_attr(deref_patterns, feature(deref_patterns))]
#![cfg_attr(deref_patterns, expect(incomplete_features))]
fn uninferred<T>() -> T { unimplemented!() }
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
--> $DIR/const-pats-do-not-mislead-inference.rs:33:12
--> $DIR/const-pats-do-not-mislead-inference.rs:32:12
|
LL | if let b"..." = &&x {}
| ^^^^^^ --- this expression has type `&&_`
@@ -10,7 +10,7 @@ LL | if let b"..." = &&x {}
found reference `&'static [u8; 3]`
error[E0308]: mismatched types
--> $DIR/const-pats-do-not-mislead-inference.rs:39:12
--> $DIR/const-pats-do-not-mislead-inference.rs:38:12
|
LL | if let "..." = &Box::new(x) {}
| ^^^^^ ------------ this expression has type `&Box<_>`
@@ -25,7 +25,7 @@ LL | if let "..." = &*Box::new(x) {}
| +
error[E0308]: mismatched types
--> $DIR/const-pats-do-not-mislead-inference.rs:45:12
--> $DIR/const-pats-do-not-mislead-inference.rs:44:12
|
LL | if let b"..." = Box::new(&x) {}
| ^^^^^^ ------------ this expression has type `Box<&_>`
@@ -40,7 +40,7 @@ LL | if let b"..." = *Box::new(&x) {}
| +
error[E0308]: mismatched types
--> $DIR/const-pats-do-not-mislead-inference.rs:51:12
--> $DIR/const-pats-do-not-mislead-inference.rs:50:12
|
LL | if let "..." = &mut x {}
| ^^^^^ ------ this expression has type `&mut _`
@@ -1,6 +1,5 @@
//@ check-pass
#![feature(deref_patterns)]
#![expect(incomplete_features)]
fn main() {
match <_ as Default>::default() {
@@ -3,7 +3,6 @@
//! and `DerefMut::deref_mut`. Test that they work as expected.
#![feature(deref_patterns)]
#![expect(incomplete_features)]
fn unbox_1<T>(b: Box<T>) -> T {
let deref!(x) = b;
@@ -3,7 +3,6 @@
//! inside a deref pattern inside a closure: rust-lang/rust#125059
#![feature(deref_patterns)]
#![allow(incomplete_features, unused)]
fn simple_vec(vec: Vec<u32>) -> u32 {
(|| match Vec::<u32>::new() {
@@ -1,5 +1,4 @@
#![feature(deref_patterns)]
#![allow(incomplete_features)]
#[rustfmt::skip]
fn main() {
@@ -1,5 +1,5 @@
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> $DIR/fake_borrows.rs:9:16
--> $DIR/fake_borrows.rs:8:16
|
LL | match v {
| - immutable borrow occurs here
@@ -10,7 +10,7 @@ LL | _ if { v[0] = true; false } => {}
| mutable borrow occurs here
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> $DIR/fake_borrows.rs:16:16
--> $DIR/fake_borrows.rs:15:16
|
LL | match v {
| - immutable borrow occurs here
@@ -21,7 +21,7 @@ LL | _ if { v[0] = true; false } => {}
| mutable borrow occurs here
error[E0510]: cannot assign `*b` in match guard
--> $DIR/fake_borrows.rs:26:16
--> $DIR/fake_borrows.rs:25:16
|
LL | match b {
| - value is immutable in match guard
@@ -30,7 +30,7 @@ LL | _ if { *b = true; false } => {}
| ^^^^^^^^^ cannot assign
error[E0510]: cannot assign `*b` in match guard
--> $DIR/fake_borrows.rs:33:16
--> $DIR/fake_borrows.rs:32:16
|
LL | match b {
| - value is immutable in match guard
@@ -1,5 +1,4 @@
#![feature(deref_patterns)]
#![expect(incomplete_features)]
fn main() {
let vec![const { vec![] }]: Vec<usize> = vec![];
@@ -1,5 +1,5 @@
error[E0532]: expected a pattern, found a function call
--> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:9
--> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:4:9
|
LL | let vec![const { vec![] }]: Vec<usize> = vec![];
| ^^^^^^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
@@ -7,7 +7,7 @@ LL | let vec![const { vec![] }]: Vec<usize> = vec![];
= note: function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>
error[E0532]: expected a pattern, found a function call
--> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:9
--> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:4:9
|
LL | let vec![const { vec![] }]: Vec<usize> = vec![];
| ^^^^^^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
@@ -15,7 +15,7 @@ LL | let vec![const { vec![] }]: Vec<usize> = vec![];
= note: function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>
error: arbitrary expressions aren't allowed in patterns
--> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:14
--> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:4:14
|
LL | let vec![const { vec![] }]: Vec<usize> = vec![];
| ^^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@ LL | let vec![const { vec![] }]: Vec<usize> = vec![];
= help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead
error[E0164]: expected tuple struct or tuple variant, found associated function `::alloc::boxed::Box::new_uninit`
--> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:9
--> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:4:9
|
LL | let vec![const { vec![] }]: Vec<usize> = vec![];
| ^^^^^^^^^^^^^^^^^^^^^^ `fn` calls are not allowed in patterns
@@ -4,7 +4,6 @@
//! scrutinee and end up with a type error; this would prevent us from reporting that only constants
//! supporting structural equality can be used as patterns.
#![feature(deref_patterns)]
#![allow(incomplete_features)]
const EMPTY: Vec<()> = Vec::new();
@@ -1,5 +1,5 @@
error: constant of non-structural type `Vec<()>` in a pattern
--> $DIR/implicit-const-deref.rs:15:9
--> $DIR/implicit-const-deref.rs:14:9
|
LL | const EMPTY: Vec<()> = Vec::new();
| -------------------- constant defined here
@@ -1,7 +1,6 @@
//@ run-pass
//! Test that implicit deref patterns interact as expected with `Cow` constructor patterns.
#![feature(deref_patterns)]
#![allow(incomplete_features)]
use std::borrow::Cow;
use std::rc::Rc;
@@ -1,6 +1,5 @@
//! Test that implicit deref patterns respect the recursion limit
#![feature(deref_patterns)]
#![allow(incomplete_features)]
#![recursion_limit = "8"]
use std::ops::Deref;
@@ -1,5 +1,5 @@
error[E0055]: reached the recursion limit while auto-dereferencing `Cyclic`
--> $DIR/recursion-limit.rs:18:9
--> $DIR/recursion-limit.rs:17:9
|
LL | () => {}
| ^^ deref recursion limit reached
@@ -7,13 +7,13 @@ LL | () => {}
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`recursion_limit`)
error[E0277]: the trait bound `Cyclic: DerefPure` is not satisfied
--> $DIR/recursion-limit.rs:18:9
--> $DIR/recursion-limit.rs:17:9
|
LL | () => {}
| ^^ unsatisfied trait bound
|
help: the nightly-only, unstable trait `DerefPure` is not implemented for `Cyclic`
--> $DIR/recursion-limit.rs:8:1
--> $DIR/recursion-limit.rs:7:1
|
LL | struct Cyclic;
| ^^^^^^^^^^^^^
@@ -1,5 +1,4 @@
#![feature(deref_patterns)]
//~^ WARN the feature `deref_patterns` is incomplete
use std::rc::Rc;
+3 -12
View File
@@ -1,14 +1,5 @@
warning: the feature `deref_patterns` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/ref-mut.rs:1:12
|
LL | #![feature(deref_patterns)]
| ^^^^^^^^^^^^^^
|
= note: see issue #87121 <https://github.com/rust-lang/rust/issues/87121> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0277]: the trait bound `Rc<{integer}>: DerefMut` is not satisfied
--> $DIR/ref-mut.rs:17:9
--> $DIR/ref-mut.rs:16:9
|
LL | deref!(x) => {}
| ^^^^^^^^^ the trait `DerefMut` is not implemented for `Rc<{integer}>`
@@ -16,11 +7,11 @@ LL | deref!(x) => {}
= note: this error originates in the macro `deref` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `Rc<({integer},)>: DerefMut` is not satisfied
--> $DIR/ref-mut.rs:22:9
--> $DIR/ref-mut.rs:21:9
|
LL | (x,) => {}
| ^^^^ the trait `DerefMut` is not implemented for `Rc<({integer},)>`
error: aborting due to 2 previous errors; 1 warning emitted
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
-1
View File
@@ -1,6 +1,5 @@
//@ check-pass
#![feature(deref_patterns)]
#![expect(incomplete_features)]
fn foo(s: &String) -> i32 {
match *s {
@@ -2,7 +2,6 @@
//! Test deref patterns using string and bytestring literals.
#![feature(deref_patterns)]
#![allow(incomplete_features)]
fn main() {
for (test_in, test_expect) in [("zero", 0), ("one", 1), ("two", 2)] {
@@ -1,6 +1,5 @@
//@ check-pass
#![feature(deref_patterns)]
#![allow(incomplete_features)]
use std::rc::Rc;
@@ -1,5 +1,4 @@
#![feature(deref_patterns)]
#![allow(incomplete_features)]
fn main() {
// Make sure we don't try implicitly dereferncing any ADT.
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
--> $DIR/typeck_fail.rs:7:9
--> $DIR/typeck_fail.rs:6:9
|
LL | match Some(0) {
| ------- this expression has type `Option<{integer}>`
@@ -1,5 +1,4 @@
#![feature(deref_patterns)]
#![allow(incomplete_features)]
struct MyPointer;
@@ -1,11 +1,11 @@
error[E0277]: the trait bound `MyPointer: DerefPure` is not satisfied
--> $DIR/unsatisfied-bounds.rs:17:9
--> $DIR/unsatisfied-bounds.rs:16:9
|
LL | () => {}
| ^^ unsatisfied trait bound
|
help: the nightly-only, unstable trait `DerefPure` is not implemented for `MyPointer`
--> $DIR/unsatisfied-bounds.rs:4:1
--> $DIR/unsatisfied-bounds.rs:3:1
|
LL | struct MyPointer;
| ^^^^^^^^^^^^^^^^
@@ -4,7 +4,6 @@
// FIXME(deref_patterns): On stabilization, cases for deref patterns could be worked into that file
// to keep the tests for empty types in one place and test more thoroughly.
#![feature(deref_patterns)]
#![expect(incomplete_features)]
#![deny(unreachable_patterns)]
enum Void {}
@@ -1,5 +1,5 @@
error[E0004]: non-exhaustive patterns: `deref!(Some(_))` not covered
--> $DIR/empty-types.rs:21:11
--> $DIR/empty-types.rs:20:11
|
LL | match box_opt_void {
| ^^^^^^^^^^^^ pattern `deref!(Some(_))` not covered
@@ -15,7 +15,7 @@ LL + deref!(Some(_)) => todo!()
|
error[E0004]: non-exhaustive patterns: `Some(_)` not covered
--> $DIR/empty-types.rs:35:11
--> $DIR/empty-types.rs:34:11
|
LL | match *box_opt_void {
| ^^^^^^^^^^^^^ pattern `Some(_)` not covered
@@ -2,7 +2,6 @@
//! doesn't support this, so make sure we catch it beforehand. As a consequence, it takes priority
//! over non-exhaustive match and unreachable pattern errors.
#![feature(deref_patterns)]
#![expect(incomplete_features)]
#![deny(unreachable_patterns)]
use std::borrow::Cow;
@@ -1,5 +1,5 @@
error: mix of deref patterns and normal constructors
--> $DIR/mixed-constructors.rs:16:9
--> $DIR/mixed-constructors.rs:15:9
|
LL | false => {}
| ^^^^^ matches on the result of dereferencing `Cow<'_, bool>`
@@ -7,7 +7,7 @@ LL | Cow::Borrowed(_) => {}
| ^^^^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>`
error: mix of deref patterns and normal constructors
--> $DIR/mixed-constructors.rs:22:9
--> $DIR/mixed-constructors.rs:21:9
|
LL | Cow::Borrowed(_) => {}
| ^^^^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>`
@@ -15,7 +15,7 @@ LL | true => {}
| ^^^^ matches on the result of dereferencing `Cow<'_, bool>`
error: mix of deref patterns and normal constructors
--> $DIR/mixed-constructors.rs:29:9
--> $DIR/mixed-constructors.rs:28:9
|
LL | Cow::Owned(_) => {}
| ^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>`
@@ -23,7 +23,7 @@ LL | false => {}
| ^^^^^ matches on the result of dereferencing `Cow<'_, bool>`
error: mix of deref patterns and normal constructors
--> $DIR/mixed-constructors.rs:36:10
--> $DIR/mixed-constructors.rs:35:10
|
LL | (Cow::Borrowed(_), 0) => {}
| ^^^^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>`
@@ -31,7 +31,7 @@ LL | (true, 0) => {}
| ^^^^ matches on the result of dereferencing `Cow<'_, bool>`
error: mix of deref patterns and normal constructors
--> $DIR/mixed-constructors.rs:43:13
--> $DIR/mixed-constructors.rs:42:13
|
LL | (0, Cow::Borrowed(_)) => {}
| ^^^^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>`
@@ -1,6 +1,5 @@
//! Test non-exhaustive matches involving deref patterns.
#![feature(deref_patterns)]
#![expect(incomplete_features)]
#![deny(unreachable_patterns)]
fn main() {
@@ -1,5 +1,5 @@
error[E0004]: non-exhaustive patterns: `deref!(true)` not covered
--> $DIR/non-exhaustive.rs:7:11
--> $DIR/non-exhaustive.rs:6:11
|
LL | match Box::new(false) {
| ^^^^^^^^^^^^^^^ pattern `deref!(true)` not covered
@@ -14,7 +14,7 @@ LL + deref!(true) => todo!()
|
error[E0004]: non-exhaustive patterns: `deref!(deref!(false))` not covered
--> $DIR/non-exhaustive.rs:12:11
--> $DIR/non-exhaustive.rs:11:11
|
LL | match Box::new(Box::new(false)) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `deref!(deref!(false))` not covered
@@ -29,7 +29,7 @@ LL + deref!(deref!(false)) => todo!()
|
error[E0004]: non-exhaustive patterns: `deref!((true, deref!(true)))` and `deref!((false, deref!(false)))` not covered
--> $DIR/non-exhaustive.rs:17:11
--> $DIR/non-exhaustive.rs:16:11
|
LL | match Box::new((true, Box::new(false))) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ patterns `deref!((true, deref!(true)))` and `deref!((false, deref!(false)))` not covered
@@ -44,7 +44,7 @@ LL + deref!((true, deref!(true))) | deref!((false, deref!(false))) => to
|
error[E0004]: non-exhaustive patterns: `deref!((deref!(T::C), _))` not covered
--> $DIR/non-exhaustive.rs:24:11
--> $DIR/non-exhaustive.rs:23:11
|
LL | match Box::new((Box::new(T::A), Box::new(T::A))) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `deref!((deref!(T::C), _))` not covered
@@ -1,6 +1,5 @@
//! Test unreachable patterns involving deref patterns.
#![feature(deref_patterns)]
#![expect(incomplete_features)]
#![deny(unreachable_patterns)]
fn main() {
@@ -1,5 +1,5 @@
error: unreachable pattern
--> $DIR/unreachable-patterns.rs:10:9
--> $DIR/unreachable-patterns.rs:9:9
|
LL | false => {}
| ----- matches all the relevant values
@@ -7,13 +7,13 @@ LL | false => {}
| ^^^^^ no value can reach this
|
note: the lint level is defined here
--> $DIR/unreachable-patterns.rs:4:9
--> $DIR/unreachable-patterns.rs:3:9
|
LL | #![deny(unreachable_patterns)]
| ^^^^^^^^^^^^^^^^^^^^
error: unreachable pattern
--> $DIR/unreachable-patterns.rs:16:9
--> $DIR/unreachable-patterns.rs:15:9
|
LL | true => {}
| ---- matches all the relevant values
@@ -22,13 +22,13 @@ LL | true => {}
| ^^^^ no value can reach this
error: unreachable pattern
--> $DIR/unreachable-patterns.rs:23:9
--> $DIR/unreachable-patterns.rs:22:9
|
LL | _ => {}
| ^ no value can reach this
|
note: multiple earlier patterns match some of the same values
--> $DIR/unreachable-patterns.rs:23:9
--> $DIR/unreachable-patterns.rs:22:9
|
LL | (true, _) => {}
| --------- matches some of the same values
@@ -40,7 +40,7 @@ LL | _ => {}
| ^ collectively making this unreachable
error: unreachable pattern
--> $DIR/unreachable-patterns.rs:29:9
--> $DIR/unreachable-patterns.rs:28:9
|
LL | (T::A | T::B, T::A | T::C) => {}
| -------------------------- matches all the relevant values
@@ -48,7 +48,7 @@ LL | (T::A, T::C) => {}
| ^^^^^^^^^^^^ no value can reach this
error: unreachable pattern
--> $DIR/unreachable-patterns.rs:30:9
--> $DIR/unreachable-patterns.rs:29:9
|
LL | (T::A | T::B, T::A | T::C) => {}
| -------------------------- matches all the relevant values
+1 -1
View File
@@ -1,7 +1,7 @@
fn main() {
let _tmp = [
("C200B40A82", 3),
("C200B40A83", 4) //~ ERROR: expected function, found `(&'static str, {integer})` [E0618]
("C200B40A83", 4) //~ ERROR: expected function, found `(&str, {integer})` [E0618]
("C200B40A8537", 5),
];
}
+1 -1
View File
@@ -1,4 +1,4 @@
error[E0618]: expected function, found `(&'static str, {integer})`
error[E0618]: expected function, found `(&str, {integer})`
--> $DIR/array-diagnostics.rs:4:9
|
LL | ("C200B40A83", 4)
+16
View File
@@ -0,0 +1,16 @@
// This test checks if tuple elements are a coercion site or not.
// Note that the code here is a degenerate case, but you can get similar effects in real code, when
// unifying match arms, for example.
//
// See also coercion-slice.rs
//
//@ check-pass
fn main() {
let _: ((),) = (loop {},);
((),) = (loop {},);
let x = (loop {},);
let _: ((),) = x;
}
+12
View File
@@ -0,0 +1,12 @@
// This test checks if tuple elements are a coercion site or not.
// Note that the code here is a degenerate case, but you can get similar effects in real code, when
// unifying match arms, for example.
//
// See also: coercion-never.rs
fn main() {
let _: (&[u8],) = (&[],);
let y = (&[],);
let _: (&[u8],) = y; //~ error: mismatched types
}
+14
View File
@@ -0,0 +1,14 @@
error[E0308]: mismatched types
--> $DIR/coercion-slice.rs:11:23
|
LL | let _: (&[u8],) = y;
| -------- ^ expected `(&[u8],)`, found `(&[_; 0],)`
| |
| expected due to this
|
= note: expected tuple `(&[u8],)`
found tuple `(&[_; 0],)`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.