Allow casting mut array ref to mut ptr
We now allow two new casts: - mut array reference to mut ptr. Example: let mut x: [usize; 2] = [0, 0]; let p = &mut x as *mut usize; We allow casting const array references to const pointers so not allowing mut references to mut pointers was inconsistent. - mut array reference to const ptr. Example: let mut x: [usize; 2] = [0, 0]; let p = &mut x as *const usize; This was similarly inconsistent as we allow casting mut references to const pointers. Existing test 'vector-cast-weirdness' updated to test both cases. Fixes #24151
This commit is contained in:
parent
6523b721c3
commit
d64b749f2c
4 changed files with 55 additions and 25 deletions
|
@ -2191,19 +2191,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
CastKind::Pointer(PointerCast::ArrayToPointer) => {
|
CastKind::Pointer(PointerCast::ArrayToPointer) => {
|
||||||
let ty_from = op.ty(body, tcx);
|
let ty_from = op.ty(body, tcx);
|
||||||
|
|
||||||
let opt_ty_elem = match ty_from.kind() {
|
let opt_ty_elem_mut = match ty_from.kind() {
|
||||||
ty::RawPtr(ty::TypeAndMut {
|
ty::RawPtr(ty::TypeAndMut { mutbl: array_mut, ty: array_ty }) => {
|
||||||
mutbl: hir::Mutability::Not,
|
match array_ty.kind() {
|
||||||
ty: array_ty,
|
ty::Array(ty_elem, _) => Some((ty_elem, *array_mut)),
|
||||||
}) => match array_ty.kind() {
|
_ => None,
|
||||||
ty::Array(ty_elem, _) => Some(ty_elem),
|
}
|
||||||
_ => None,
|
}
|
||||||
},
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let ty_elem = match opt_ty_elem {
|
let (ty_elem, ty_mut) = match opt_ty_elem_mut {
|
||||||
Some(ty_elem) => ty_elem,
|
Some(ty_elem_mut) => ty_elem_mut,
|
||||||
None => {
|
None => {
|
||||||
span_mirbug!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
|
@ -2215,11 +2214,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let ty_to = match ty.kind() {
|
let (ty_to, ty_to_mut) = match ty.kind() {
|
||||||
ty::RawPtr(ty::TypeAndMut {
|
ty::RawPtr(ty::TypeAndMut { mutbl: ty_to_mut, ty: ty_to }) => {
|
||||||
mutbl: hir::Mutability::Not,
|
(ty_to, *ty_to_mut)
|
||||||
ty: ty_to,
|
}
|
||||||
}) => ty_to,
|
|
||||||
_ => {
|
_ => {
|
||||||
span_mirbug!(
|
span_mirbug!(
|
||||||
self,
|
self,
|
||||||
|
@ -2231,6 +2229,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if ty_to_mut == Mutability::Mut && ty_mut == Mutability::Not {
|
||||||
|
span_mirbug!(
|
||||||
|
self,
|
||||||
|
rvalue,
|
||||||
|
"ArrayToPointer cast from const {:?} to mut {:?}",
|
||||||
|
ty,
|
||||||
|
ty_to
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if let Err(terr) = self.sub_types(
|
if let Err(terr) = self.sub_types(
|
||||||
ty_elem,
|
ty_elem,
|
||||||
ty_to,
|
ty_to,
|
||||||
|
|
|
@ -765,9 +765,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||||
m_expr: ty::TypeAndMut<'tcx>,
|
m_expr: ty::TypeAndMut<'tcx>,
|
||||||
m_cast: ty::TypeAndMut<'tcx>,
|
m_cast: ty::TypeAndMut<'tcx>,
|
||||||
) -> Result<CastKind, CastError> {
|
) -> Result<CastKind, CastError> {
|
||||||
// array-ptr-cast.
|
// array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
|
||||||
|
if m_expr.mutbl == hir::Mutability::Mut || m_cast.mutbl == hir::Mutability::Not {
|
||||||
if m_expr.mutbl == hir::Mutability::Not && m_cast.mutbl == hir::Mutability::Not {
|
|
||||||
if let ty::Array(ety, _) = m_expr.ty.kind() {
|
if let ty::Array(ety, _) = m_expr.ty.kind() {
|
||||||
// Due to the limitations of LLVM global constants,
|
// Due to the limitations of LLVM global constants,
|
||||||
// region pointers end up pointing at copies of
|
// region pointers end up pointing at copies of
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
// Issue #14893. Tests that casts from vectors don't behave strangely in the
|
// Issue #14893. Tests that casts from vectors don't behave strangely in the
|
||||||
// presence of the `_` type shorthand notation.
|
// presence of the `_` type shorthand notation.
|
||||||
|
//
|
||||||
// Update: after a change to the way casts are done, we have more type information
|
// Update: after a change to the way casts are done, we have more type information
|
||||||
// around and so the errors here are no longer exactly the same.
|
// around and so the errors here are no longer exactly the same.
|
||||||
|
//
|
||||||
|
// Update: With PR #81479 some of the previously rejected cases are now allowed.
|
||||||
|
// New test cases added.
|
||||||
|
|
||||||
struct X {
|
struct X {
|
||||||
y: [u8; 2],
|
y: [u8; 2],
|
||||||
|
@ -12,13 +16,19 @@ fn main() {
|
||||||
|
|
||||||
// No longer a type mismatch - the `_` can be fully resolved by type inference.
|
// No longer a type mismatch - the `_` can be fully resolved by type inference.
|
||||||
let p1: *const u8 = &x1.y as *const _;
|
let p1: *const u8 = &x1.y as *const _;
|
||||||
|
let p1: *mut u8 = &x1.y as *mut _;
|
||||||
|
//~^ ERROR: casting `&[u8; 2]` as `*mut u8` is invalid
|
||||||
let t1: *const [u8; 2] = &x1.y as *const _;
|
let t1: *const [u8; 2] = &x1.y as *const _;
|
||||||
|
let t1: *mut [u8; 2] = &x1.y as *mut _;
|
||||||
|
//~^ ERROR: casting `&[u8; 2]` as `*mut [u8; 2]` is invalid
|
||||||
let h1: *const [u8; 2] = &x1.y as *const [u8; 2];
|
let h1: *const [u8; 2] = &x1.y as *const [u8; 2];
|
||||||
|
let t1: *mut [u8; 2] = &x1.y as *mut [u8; 2];
|
||||||
|
//~^ ERROR: casting `&[u8; 2]` as `*mut [u8; 2]` is invalid
|
||||||
|
|
||||||
let mut x1 = X { y: [0, 0] };
|
let mut x1 = X { y: [0, 0] };
|
||||||
|
|
||||||
// This is still an error since we don't allow casts from &mut [T; n] to *mut T.
|
let p1: *mut u8 = &mut x1.y as *mut _;
|
||||||
let p1: *mut u8 = &mut x1.y as *mut _; //~ ERROR casting
|
let p2: *const u8 = &mut x1.y as *const _;
|
||||||
let t1: *mut [u8; 2] = &mut x1.y as *mut _;
|
let t1: *mut [u8; 2] = &mut x1.y as *mut _;
|
||||||
let h1: *mut [u8; 2] = &mut x1.y as *mut [u8; 2];
|
let h1: *mut [u8; 2] = &mut x1.y as *mut [u8; 2];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,21 @@
|
||||||
error[E0606]: casting `&mut [u8; 2]` as `*mut u8` is invalid
|
error[E0606]: casting `&[u8; 2]` as `*mut u8` is invalid
|
||||||
--> $DIR/vector-cast-weirdness.rs:21:23
|
--> $DIR/vector-cast-weirdness.rs:19:23
|
||||||
|
|
|
|
||||||
LL | let p1: *mut u8 = &mut x1.y as *mut _;
|
LL | let p1: *mut u8 = &x1.y as *mut _;
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error[E0606]: casting `&[u8; 2]` as `*mut [u8; 2]` is invalid
|
||||||
|
--> $DIR/vector-cast-weirdness.rs:22:28
|
||||||
|
|
|
||||||
|
LL | let t1: *mut [u8; 2] = &x1.y as *mut _;
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0606]: casting `&[u8; 2]` as `*mut [u8; 2]` is invalid
|
||||||
|
--> $DIR/vector-cast-weirdness.rs:25:28
|
||||||
|
|
|
||||||
|
LL | let t1: *mut [u8; 2] = &x1.y as *mut [u8; 2];
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0606`.
|
For more information about this error, try `rustc --explain E0606`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue