Skip to content

Commit 1a8ef28

Browse files
authored
Unrolled build for rust-lang#122835
Rollup merge of rust-lang#122835 - compiler-errors:deref-pure, r=Nadrieril Require `DerefMut` and `DerefPure` on `deref!()` patterns when appropriate Waiting on the deref pattern syntax pr to merge r? nadrieril
2 parents 47ecded + fc1d7d2 commit 1a8ef28

File tree

14 files changed

+124
-5
lines changed

14 files changed

+124
-5
lines changed

compiler/rustc_hir/src/lang_items.rs

+1
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ language_item_table! {
199199

200200
Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);
201201
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0);
202+
DerefPure, sym::deref_pure, deref_pure_trait, Target::Trait, GenericRequirement::Exact(0);
202203
DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None;
203204
Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None;
204205

compiler/rustc_hir_typeck/src/pat.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -2002,8 +2002,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20022002
pat_info: PatInfo<'tcx, '_>,
20032003
) -> Ty<'tcx> {
20042004
let tcx = self.tcx;
2005-
// FIXME(deref_patterns): use `DerefPure` for soundness
2006-
// FIXME(deref_patterns): use `DerefMut` when required
2005+
// Register a `DerefPure` bound, which is required by all `deref!()` pats.
2006+
self.register_bound(
2007+
expected,
2008+
tcx.require_lang_item(hir::LangItem::DerefPure, Some(span)),
2009+
self.misc(span),
2010+
);
20072011
// <expected as Deref>::Target
20082012
let ty = Ty::new_projection(
20092013
tcx,
@@ -2013,6 +2017,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
20132017
let ty = self.normalize(span, ty);
20142018
let ty = self.try_structurally_resolve_type(span, ty);
20152019
self.check_pat(inner, ty, pat_info);
2020+
2021+
// Check if the pattern has any `ref mut` bindings, which would require
2022+
// `DerefMut` to be emitted in MIR building instead of just `Deref`.
2023+
// We do this *after* checking the inner pattern, since we want to make
2024+
// sure to apply any match-ergonomics adjustments.
2025+
if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) {
2026+
self.register_bound(
2027+
expected,
2028+
tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)),
2029+
self.misc(span),
2030+
);
2031+
}
2032+
20162033
expected
20172034
}
20182035

compiler/rustc_middle/src/ty/typeck_results.rs

+25
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,31 @@ impl<'tcx> TypeckResults<'tcx> {
430430
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
431431
}
432432

433+
/// Does the pattern recursively contain a `ref mut` binding in it?
434+
///
435+
/// This is used to determined whether a `deref` pattern should emit a `Deref`
436+
/// or `DerefMut` call for its pattern scrutinee.
437+
///
438+
/// This is computed from the typeck results since we want to make
439+
/// sure to apply any match-ergonomics adjustments, which we cannot
440+
/// determine from the HIR alone.
441+
pub fn pat_has_ref_mut_binding(&self, pat: &'tcx hir::Pat<'tcx>) -> bool {
442+
let mut has_ref_mut = false;
443+
pat.walk(|pat| {
444+
if let hir::PatKind::Binding(_, id, _, _) = pat.kind
445+
&& let Some(ty::BindByReference(ty::Mutability::Mut)) =
446+
self.pat_binding_modes().get(id)
447+
{
448+
has_ref_mut = true;
449+
// No need to continue recursing
450+
false
451+
} else {
452+
true
453+
}
454+
});
455+
has_ref_mut
456+
}
457+
433458
/// For a given closure, returns the iterator of `ty::CapturedPlace`s that are captured
434459
/// by the closure.
435460
pub fn closure_min_captures_flattened(

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,7 @@ symbols! {
674674
deref_mut,
675675
deref_mut_method,
676676
deref_patterns,
677+
deref_pure,
677678
deref_target,
678679
derive,
679680
derive_const,

library/alloc/src/boxed.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ use core::marker::Unsize;
161161
use core::mem::{self, SizedTypeProperties};
162162
use core::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce};
163163
use core::ops::{
164-
CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut, DispatchFromDyn, Receiver,
164+
CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver,
165165
};
166166
use core::pin::Pin;
167167
use core::ptr::{self, addr_of_mut, NonNull, Unique};
@@ -1939,6 +1939,9 @@ impl<T: ?Sized, A: Allocator> DerefMut for Box<T, A> {
19391939
}
19401940
}
19411941

1942+
#[unstable(feature = "deref_pure_trait", issue = "87121")]
1943+
unsafe impl<T: ?Sized, A: Allocator> DerefPure for Box<T, A> {}
1944+
19421945
#[unstable(feature = "receiver_trait", issue = "none")]
19431946
impl<T: ?Sized, A: Allocator> Receiver for Box<T, A> {}
19441947

library/alloc/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
#![feature(const_waker)]
123123
#![feature(core_intrinsics)]
124124
#![feature(deprecated_suggestion)]
125+
#![feature(deref_pure_trait)]
125126
#![feature(dispatch_from_dyn)]
126127
#![feature(error_generic_member_access)]
127128
#![feature(error_in_core)]

library/alloc/src/rc.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ use core::marker::{PhantomData, Unsize};
260260
#[cfg(not(no_global_oom_handling))]
261261
use core::mem::size_of_val;
262262
use core::mem::{self, align_of_val_raw, forget, ManuallyDrop};
263-
use core::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver};
263+
use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver};
264264
use core::panic::{RefUnwindSafe, UnwindSafe};
265265
#[cfg(not(no_global_oom_handling))]
266266
use core::pin::Pin;
@@ -2126,6 +2126,9 @@ impl<T: ?Sized, A: Allocator> Deref for Rc<T, A> {
21262126
}
21272127
}
21282128

2129+
#[unstable(feature = "deref_pure_trait", issue = "87121")]
2130+
unsafe impl<T: ?Sized, A: Allocator> DerefPure for Rc<T, A> {}
2131+
21292132
#[unstable(feature = "receiver_trait", issue = "none")]
21302133
impl<T: ?Sized> Receiver for Rc<T> {}
21312134

library/alloc/src/string.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2479,6 +2479,9 @@ impl ops::Deref for String {
24792479
}
24802480
}
24812481

2482+
#[unstable(feature = "deref_pure_trait", issue = "87121")]
2483+
unsafe impl ops::DerefPure for String {}
2484+
24822485
#[stable(feature = "derefmut_for_string", since = "1.3.0")]
24832486
impl ops::DerefMut for String {
24842487
#[inline]

library/alloc/src/sync.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use core::marker::{PhantomData, Unsize};
2121
#[cfg(not(no_global_oom_handling))]
2222
use core::mem::size_of_val;
2323
use core::mem::{self, align_of_val_raw};
24-
use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
24+
use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver};
2525
use core::panic::{RefUnwindSafe, UnwindSafe};
2626
use core::pin::Pin;
2727
use core::ptr::{self, NonNull};
@@ -2107,6 +2107,9 @@ impl<T: ?Sized, A: Allocator> Deref for Arc<T, A> {
21072107
}
21082108
}
21092109

2110+
#[unstable(feature = "deref_pure_trait", issue = "87121")]
2111+
unsafe impl<T: ?Sized, A: Allocator> DerefPure for Arc<T, A> {}
2112+
21102113
#[unstable(feature = "receiver_trait", issue = "none")]
21112114
impl<T: ?Sized> Receiver for Arc<T> {}
21122115

library/alloc/src/vec/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2772,6 +2772,9 @@ impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
27722772
}
27732773
}
27742774

2775+
#[unstable(feature = "deref_pure_trait", issue = "87121")]
2776+
unsafe impl<T, A: Allocator> ops::DerefPure for Vec<T, A> {}
2777+
27752778
#[cfg(not(no_global_oom_handling))]
27762779
#[stable(feature = "rust1", since = "1.0.0")]
27772780
impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {

library/core/src/ops/deref.rs

+19
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,25 @@ impl<T: ?Sized> DerefMut for &mut T {
275275
}
276276
}
277277

278+
/// Perma-unstable marker trait. Indicates that the type has a well-behaved [`Deref`]
279+
/// (and, if applicable, [`DerefMut`]) implementation. This is relied on for soundness
280+
/// of deref patterns.
281+
///
282+
/// FIXME(deref_patterns): The precise semantics are undecided; the rough idea is that
283+
/// successive calls to `deref`/`deref_mut` without intermediate mutation should be
284+
/// idempotent, in the sense that they return the same value as far as pattern-matching
285+
/// is concerned. Calls to `deref`/`deref_mut`` must leave the pointer itself likewise
286+
/// unchanged.
287+
#[unstable(feature = "deref_pure_trait", issue = "87121")]
288+
#[cfg_attr(not(bootstrap), lang = "deref_pure")]
289+
pub unsafe trait DerefPure {}
290+
291+
#[unstable(feature = "deref_pure_trait", issue = "87121")]
292+
unsafe impl<T: ?Sized> DerefPure for &T {}
293+
294+
#[unstable(feature = "deref_pure_trait", issue = "87121")]
295+
unsafe impl<T: ?Sized> DerefPure for &mut T {}
296+
278297
/// Indicates that a struct can be used as a method receiver, without the
279298
/// `arbitrary_self_types` feature. This is implemented by stdlib pointer types like `Box<T>`,
280299
/// `Rc<T>`, `&T`, and `Pin<P>`.

library/core/src/ops/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ pub use self::bit::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssig
165165
#[stable(feature = "rust1", since = "1.0.0")]
166166
pub use self::deref::{Deref, DerefMut};
167167

168+
#[unstable(feature = "deref_pure_trait", issue = "87121")]
169+
pub use self::deref::DerefPure;
170+
168171
#[unstable(feature = "receiver_trait", issue = "none")]
169172
pub use self::deref::Receiver;
170173

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![feature(deref_patterns)]
2+
//~^ WARN the feature `deref_patterns` is incomplete
3+
4+
use std::rc::Rc;
5+
6+
fn main() {
7+
match &mut vec![1] {
8+
deref!(x) => {}
9+
_ => {}
10+
}
11+
12+
match &mut Rc::new(1) {
13+
deref!(x) => {}
14+
//~^ ERROR the trait bound `Rc<{integer}>: DerefMut` is not satisfied
15+
_ => {}
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
warning: the feature `deref_patterns` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/ref-mut.rs:1:12
3+
|
4+
LL | #![feature(deref_patterns)]
5+
| ^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #87121 <https://github.com/rust-lang/rust/issues/87121> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
error[E0277]: the trait bound `Rc<{integer}>: DerefMut` is not satisfied
11+
--> $DIR/ref-mut.rs:13:9
12+
|
13+
LL | deref!(x) => {}
14+
| ^^^^^^^^^ the trait `DerefMut` is not implemented for `Rc<{integer}>`
15+
|
16+
= note: this error originates in the macro `deref` (in Nightly builds, run with -Z macro-backtrace for more info)
17+
18+
error: aborting due to 1 previous error; 1 warning emitted
19+
20+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)