Skip to content

Commit

Permalink
Rollup merge of rust-lang#81479 - osa1:issue24151, r=lcnr
Browse files Browse the repository at this point in the history
Allow casting mut array ref to mut ptr

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 rust-lang#24151
  • Loading branch information
JohnTitor authored Feb 11, 2021
2 parents b16c54c + d64b749 commit e1f0108
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 25 deletions.
39 changes: 24 additions & 15 deletions compiler/rustc_mir/src/borrow_check/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2191,19 +2191,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
CastKind::Pointer(PointerCast::ArrayToPointer) => {
let ty_from = op.ty(body, tcx);

let opt_ty_elem = match ty_from.kind() {
ty::RawPtr(ty::TypeAndMut {
mutbl: hir::Mutability::Not,
ty: array_ty,
}) => match array_ty.kind() {
ty::Array(ty_elem, _) => Some(ty_elem),
_ => None,
},
let opt_ty_elem_mut = match ty_from.kind() {
ty::RawPtr(ty::TypeAndMut { mutbl: array_mut, ty: array_ty }) => {
match array_ty.kind() {
ty::Array(ty_elem, _) => Some((ty_elem, *array_mut)),
_ => None,
}
}
_ => None,
};

let ty_elem = match opt_ty_elem {
Some(ty_elem) => ty_elem,
let (ty_elem, ty_mut) = match opt_ty_elem_mut {
Some(ty_elem_mut) => ty_elem_mut,
None => {
span_mirbug!(
self,
Expand All @@ -2215,11 +2214,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
};

let ty_to = match ty.kind() {
ty::RawPtr(ty::TypeAndMut {
mutbl: hir::Mutability::Not,
ty: ty_to,
}) => ty_to,
let (ty_to, ty_to_mut) = match ty.kind() {
ty::RawPtr(ty::TypeAndMut { mutbl: ty_to_mut, ty: ty_to }) => {
(ty_to, *ty_to_mut)
}
_ => {
span_mirbug!(
self,
Expand All @@ -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(
ty_elem,
ty_to,
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_typeck/src/check/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -765,9 +765,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
m_expr: ty::TypeAndMut<'tcx>,
m_cast: ty::TypeAndMut<'tcx>,
) -> Result<CastKind, CastError> {
// array-ptr-cast.

if m_expr.mutbl == hir::Mutability::Not && m_cast.mutbl == hir::Mutability::Not {
// 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 let ty::Array(ety, _) = m_expr.ty.kind() {
// Due to the limitations of LLVM global constants,
// region pointers end up pointing at copies of
Expand Down
14 changes: 12 additions & 2 deletions src/test/ui/array-slice-vec/vector-cast-weirdness.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
// Issue #14893. Tests that casts from vectors don't behave strangely in the
// presence of the `_` type shorthand notation.
//
// 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.
//
// Update: With PR #81479 some of the previously rejected cases are now allowed.
// New test cases added.

struct X {
y: [u8; 2],
Expand All @@ -12,13 +16,19 @@ fn main() {

// No longer a type mismatch - the `_` can be fully resolved by type inference.
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: *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 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] };

// 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 _; //~ ERROR casting
let p1: *mut u8 = &mut x1.y as *mut _;
let p2: *const u8 = &mut x1.y as *const _;
let t1: *mut [u8; 2] = &mut x1.y as *mut _;
let h1: *mut [u8; 2] = &mut x1.y as *mut [u8; 2];
}
22 changes: 17 additions & 5 deletions src/test/ui/array-slice-vec/vector-cast-weirdness.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
error[E0606]: casting `&mut [u8; 2]` as `*mut u8` is invalid
--> $DIR/vector-cast-weirdness.rs:21:23
error[E0606]: casting `&[u8; 2]` as `*mut u8` is invalid
--> $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`.

0 comments on commit e1f0108

Please sign in to comment.