Skip to content

Commit aa0f494

Browse files
committed
Implement Deref{Mut} for arrays
1 parent 18caf88 commit aa0f494

File tree

2 files changed

+54
-29
lines changed
  • compiler/rustc_hir_typeck/src/method
  • library/core/src/array

2 files changed

+54
-29
lines changed

compiler/rustc_hir_typeck/src/method/probe.rs

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -512,46 +512,47 @@ fn method_autoderef_steps<'tcx>(
512512
.include_raw_pointers()
513513
.silence_errors();
514514
let mut reached_raw_pointer = false;
515-
let mut steps: Vec<_> = autoderef
516-
.by_ref()
517-
.map(|(ty, d)| {
515+
let mut steps = Vec::new();
516+
for (ty, d) in &mut autoderef {
517+
let step = CandidateStep {
518+
self_ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, ty),
519+
autoderefs: d,
520+
from_unsafe_deref: reached_raw_pointer,
521+
unsize: false,
522+
};
523+
steps.push(step);
524+
if let ty::RawPtr(_) = ty.kind() {
525+
// all the subsequent steps will be from_unsafe_deref
526+
reached_raw_pointer = true;
527+
} else if let ty::Array(elem_ty, _) = ty.kind() {
528+
// Array implements Deref/DerefMut so we would always deref instead of unsizing the
529+
// array without this check. This is fine in theory, but it is currently not possible
530+
// to deref in a const context on stable, while unsizing is so to keep that working
531+
// we need to still special case the autoderef step handling here.
518532
let step = CandidateStep {
519-
self_ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, ty),
533+
self_ty: infcx.make_query_response_ignoring_pending_obligations(
534+
inference_vars,
535+
infcx.tcx.mk_slice(*elem_ty),
536+
),
520537
autoderefs: d,
538+
// this could be from an unsafe deref if we had
539+
// a *mut/const [T; N]
521540
from_unsafe_deref: reached_raw_pointer,
522-
unsize: false,
541+
unsize: true,
523542
};
524-
if let ty::RawPtr(_) = ty.kind() {
525-
// all the subsequent steps will be from_unsafe_deref
526-
reached_raw_pointer = true;
527-
}
528-
step
529-
})
530-
.collect();
543+
steps.push(step);
544+
// We just added the slice step manually, so break out early. Slices don't deref
545+
// into anything so the final type of the autoderef is set up correctly.
546+
break;
547+
}
548+
}
531549

532550
let final_ty = autoderef.final_ty(true);
533551
let opt_bad_ty = match final_ty.kind() {
534552
ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy {
535553
reached_raw_pointer,
536554
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
537555
}),
538-
ty::Array(elem_ty, _) => {
539-
let dereferences = steps.len() - 1;
540-
541-
steps.push(CandidateStep {
542-
self_ty: infcx.make_query_response_ignoring_pending_obligations(
543-
inference_vars,
544-
infcx.tcx.mk_slice(*elem_ty),
545-
),
546-
autoderefs: dereferences,
547-
// this could be from an unsafe deref if we had
548-
// a *mut/const [T; N]
549-
from_unsafe_deref: reached_raw_pointer,
550-
unsize: true,
551-
});
552-
553-
None
554-
}
555556
_ => None,
556557
};
557558

library/core/src/array/mod.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use crate::mem::{self, MaybeUninit};
1515
use crate::ops::{
1616
ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try,
1717
};
18+
#[cfg(not(bootstrap))]
19+
use crate::ops::{Deref, DerefMut};
1820
use crate::slice::{Iter, IterMut};
1921

2022
mod drain;
@@ -187,6 +189,28 @@ impl<T, const N: usize> const BorrowMut<[T]> for [T; N] {
187189
}
188190
}
189191

192+
#[cfg(not(bootstrap))]
193+
#[stable(feature = "array_deref", since = "CURRENT_RUSTC_VERSION")]
194+
#[rustc_const_unstable(feature = "const_array_deref", issue = "none")]
195+
impl<T, const N: usize> const Deref for [T; N] {
196+
type Target = [T];
197+
198+
fn deref(&self) -> &Self::Target {
199+
// SAFETY: self points to `N` consecutive properly initialized values of type `T`.
200+
unsafe { core::slice::from_raw_parts(self as *const [T] as *const T, N) }
201+
}
202+
}
203+
204+
#[cfg(not(bootstrap))]
205+
#[stable(feature = "array_deref", since = "CURRENT_RUSTC_VERSION")]
206+
#[rustc_const_unstable(feature = "const_array_deref", issue = "none")]
207+
impl<T, const N: usize> const DerefMut for [T; N] {
208+
fn deref_mut(&mut self) -> &mut Self::Target {
209+
// SAFETY: self points to `N` consecutive properly initialized values of type `T`.
210+
unsafe { core::slice::from_raw_parts_mut(self as *mut [T] as *mut T, N) }
211+
}
212+
}
213+
190214
/// Tries to create an array `[T; N]` by copying from a slice `&[T]`. Succeeds if
191215
/// `slice.len() == N`.
192216
///

0 commit comments

Comments
 (0)