diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 3bef5cfcd780e..c1b4c23a3b9ae 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -512,22 +512,40 @@ fn method_autoderef_steps<'tcx>( .include_raw_pointers() .silence_errors(); let mut reached_raw_pointer = false; - let mut steps: Vec<_> = autoderef - .by_ref() - .map(|(ty, d)| { + let mut steps = Vec::new(); + for (ty, d) in &mut autoderef { + let step = CandidateStep { + self_ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, ty), + autoderefs: d, + from_unsafe_deref: reached_raw_pointer, + unsize: false, + }; + steps.push(step); + if let ty::RawPtr(_) = ty.kind() { + // all the subsequent steps will be from_unsafe_deref + reached_raw_pointer = true; + } else if let ty::Array(elem_ty, _) = ty.kind() { + // Array implements Deref/DerefMut so we would always deref instead of unsizing the + // array without this check. This is fine in theory, but it is currently not possible + // to deref in a const context on stable, while unsizing is so to keep that working + // we need to still special case the autoderef step handling here. let step = CandidateStep { - self_ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, ty), + self_ty: infcx.make_query_response_ignoring_pending_obligations( + inference_vars, + infcx.tcx.mk_slice(*elem_ty), + ), autoderefs: d, + // this could be from an unsafe deref if we had + // a *mut/const [T; N] from_unsafe_deref: reached_raw_pointer, - unsize: false, + unsize: true, }; - if let ty::RawPtr(_) = ty.kind() { - // all the subsequent steps will be from_unsafe_deref - reached_raw_pointer = true; - } - step - }) - .collect(); + steps.push(step); + // We just added the slice step manually, so break out early. Slices don't deref + // into anything so the final type of the autoderef is set up correctly. + break; + } + } let final_ty = autoderef.final_ty(true); let opt_bad_ty = match final_ty.kind() { @@ -535,23 +553,6 @@ fn method_autoderef_steps<'tcx>( reached_raw_pointer, ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty), }), - ty::Array(elem_ty, _) => { - let dereferences = steps.len() - 1; - - steps.push(CandidateStep { - self_ty: infcx.make_query_response_ignoring_pending_obligations( - inference_vars, - infcx.tcx.mk_slice(*elem_ty), - ), - autoderefs: dereferences, - // this could be from an unsafe deref if we had - // a *mut/const [T; N] - from_unsafe_deref: reached_raw_pointer, - unsize: true, - }); - - None - } _ => None, }; diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 1643842d60756..e36f09f102852 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -15,6 +15,8 @@ use crate::mem::{self, MaybeUninit}; use crate::ops::{ ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try, }; +#[cfg(not(bootstrap))] +use crate::ops::{Deref, DerefMut}; use crate::slice::{Iter, IterMut}; mod drain; @@ -187,6 +189,28 @@ impl const BorrowMut<[T]> for [T; N] { } } +#[cfg(not(bootstrap))] +#[stable(feature = "array_deref", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_unstable(feature = "const_array_deref", issue = "none")] +impl const Deref for [T; N] { + type Target = [T]; + + fn deref(&self) -> &Self::Target { + // SAFETY: self points to `N` consecutive properly initialized values of type `T`. + unsafe { core::slice::from_raw_parts(self as *const [T] as *const T, N) } + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "array_deref", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_unstable(feature = "const_array_deref", issue = "none")] +impl const DerefMut for [T; N] { + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: self points to `N` consecutive properly initialized values of type `T`. + unsafe { core::slice::from_raw_parts_mut(self as *mut [T] as *mut T, N) } + } +} + /// Tries to create an array `[T; N]` by copying from a slice `&[T]`. Succeeds if /// `slice.len() == N`. /// diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed index 345f6d604c4f0..da33ed7e38e74 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed @@ -74,8 +74,8 @@ fn main() { require_slice(slice); require_slice(&Cow::from(slice)); - require_slice(array.as_ref()); - require_slice(array_ref.as_ref()); + require_slice(&array); + require_slice(array_ref); require_slice(slice); require_slice(&x_ref.to_owned()); // No longer flagged because of #8759. diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr index 4918fe3559860..7c3486a4695ff 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr @@ -146,16 +146,16 @@ LL | require_slice(&Cow::from(slice).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> $DIR/unnecessary_to_owned.rs:77:19 + --> $DIR/unnecessary_to_owned.rs:77:25 | LL | require_slice(&array.to_owned()); - | ^^^^^^^^^^^^^^^^^ help: use: `array.as_ref()` + | ^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` --> $DIR/unnecessary_to_owned.rs:78:19 | LL | require_slice(&array_ref.to_owned()); - | ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref.as_ref()` + | ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` --> $DIR/unnecessary_to_owned.rs:79:19 diff --git a/tests/ui/coercion/coerce-block-tail-83850.rs b/tests/ui/coercion/coerce-block-tail-83850.rs index 77fdf99983332..377991a745190 100644 --- a/tests/ui/coercion/coerce-block-tail-83850.rs +++ b/tests/ui/coercion/coerce-block-tail-83850.rs @@ -1,7 +1,6 @@ -// check-fail +// run-pass fn f(_: &[i32]) {} fn main() { f(&Box::new([1, 2])); - //~^ ERROR mismatched types } diff --git a/tests/ui/coercion/coerce-block-tail-83850.stderr b/tests/ui/coercion/coerce-block-tail-83850.stderr deleted file mode 100644 index 3cfebb8a54372..0000000000000 --- a/tests/ui/coercion/coerce-block-tail-83850.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/coerce-block-tail-83850.rs:5:7 - | -LL | f(&Box::new([1, 2])); - | - ^^^^^^^^^^^^^^^^^ expected `&[i32]`, found `&Box<[{integer}; 2]>` - | | - | arguments to this function are incorrect - | - = note: expected reference `&[i32]` - found reference `&Box<[{integer}; 2]>` -note: function defined here - --> $DIR/coerce-block-tail-83850.rs:2:4 - | -LL | fn f(_: &[i32]) {} - | ^ --------- - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/coercion/issue-73886.stderr b/tests/ui/coercion/issue-73886.stderr index a6f8ba65ab51a..ed225c230356e 100644 --- a/tests/ui/coercion/issue-73886.stderr +++ b/tests/ui/coercion/issue-73886.stderr @@ -1,9 +1,3 @@ -error[E0605]: non-primitive cast: `&&[i32; 1]` as `&[_]` - --> $DIR/issue-73886.rs:2:13 - | -LL | let _ = &&[0] as &[_]; - | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object - error[E0605]: non-primitive cast: `u32` as `Option<_>` --> $DIR/issue-73886.rs:4:13 | @@ -12,6 +6,6 @@ LL | let _ = 7u32 as Option<_>; | = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0605`.