Skip to content

Commit

Permalink
Rollup merge of rust-lang#65831 - matthewjasper:array-ptr-cast, r=oli…
Browse files Browse the repository at this point in the history
…-obk

Don't cast directly from &[T; N] to *const T

Split out from rust-lang#64588

r? @oli-obk
  • Loading branch information
JohnTitor authored Nov 10, 2019
2 parents e88aa39 + 972c3be commit 401d9e1
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 56 deletions.
3 changes: 3 additions & 0 deletions src/librustc/ty/adjustment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ pub enum PointerCast {
/// Go from a mut raw pointer to a const raw pointer.
MutToConstPointer,

/// Go from `*const [T; N]` to `*const T`
ArrayToPointer,

/// Unsize a pointer/reference value, e.g., `&[T; n]` to
/// `&[T]`. Note that the source could be a thin or fat pointer.
/// This will do things like convert thin pointers to fat
Expand Down
1 change: 1 addition & 0 deletions src/librustc_codegen_ssa/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
mir::CastKind::Pointer(PointerCast::MutToConstPointer)
| mir::CastKind::Pointer(PointerCast::ArrayToPointer)
| mir::CastKind::Misc => {
assert!(bx.cx().is_backend_immediate(cast));
let ll_t_out = bx.cx().immediate_backend_type(cast);
Expand Down
162 changes: 108 additions & 54 deletions src/librustc_mir/borrow_check/nll/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ use rustc::traits::query::type_op::custom::CustomTypeOp;
use rustc::traits::query::{Fallible, NoSolution};
use rustc::traits::{self, ObligationCause, PredicateObligations};
use rustc::ty::adjustment::{PointerCast};
use rustc::ty::cast::CastTy;
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::{Subst, SubstsRef, GenericArgKind, UserSubsts};
use rustc::ty::{
Expand Down Expand Up @@ -2177,72 +2178,125 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
ty_from,
ty_to,
terr
)
);
}
}

CastKind::Misc => {
if let ty::Ref(_, mut ty_from, _) = op.ty(body, tcx).kind {
let (mut ty_to, mutability) = if let ty::RawPtr(ty::TypeAndMut {
ty: ty_to,
mutbl,
}) = ty.kind {
(ty_to, mutbl)
} else {
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::MutImmutable, ty: array_ty }
) => {
match array_ty.kind {
ty::Array(ty_elem, _) => Some(ty_elem),
_ => None,
}
}
_ => None,
};

let ty_elem = match opt_ty_elem {
Some(ty_elem) => ty_elem,
None => {
span_mirbug!(
self,
rvalue,
"invalid cast types {:?} -> {:?}",
op.ty(body, tcx),
"ArrayToPointer cast from unexpected type {:?}",
ty_from,
);
return;
}
};

let ty_to = match ty.kind {
ty::RawPtr(
ty::TypeAndMut { mutbl: hir::MutImmutable, ty: ty_to }
) => {
ty_to
}
_ => {
span_mirbug!(
self,
rvalue,
"ArrayToPointer cast to unexpected type {:?}",
ty,
);
return;
};

// Handle the direct cast from `&[T; N]` to `*const T` by unwrapping
// any array we find.
while let ty::Array(ty_elem_from, _) = ty_from.kind {
ty_from = ty_elem_from;
if let ty::Array(ty_elem_to, _) = ty_to.kind {
ty_to = ty_elem_to;
} else {
break;
}
}
};

if let hir::MutMutable = mutability {
if let Err(terr) = self.eq_types(
ty_from,
ty_to,
location.to_locations(),
ConstraintCategory::Cast,
) {
span_mirbug!(
self,
rvalue,
"equating {:?} with {:?} yields {:?}",
ty_from,
ty_to,
terr
)
}
} else {
if let Err(terr) = self.sub_types(
ty_from,
ty_to,
location.to_locations(),
ConstraintCategory::Cast,
) {
span_mirbug!(
self,
rvalue,
"relating {:?} with {:?} yields {:?}",
ty_from,
ty_to,
terr
)
if let Err(terr) = self.sub_types(
ty_elem,
ty_to,
location.to_locations(),
ConstraintCategory::Cast,
) {
span_mirbug!(
self,
rvalue,
"relating {:?} with {:?} yields {:?}",
ty_elem,
ty_to,
terr
)
}
}

CastKind::Misc => {
let ty_from = op.ty(body, tcx);
let cast_ty_from = CastTy::from_ty(ty_from);
let cast_ty_to = CastTy::from_ty(ty);
match (cast_ty_from, cast_ty_to) {
(Some(CastTy::RPtr(ref_tm)), Some(CastTy::Ptr(ptr_tm))) => {
if let hir::MutMutable = ptr_tm.mutbl {
if let Err(terr) = self.eq_types(
ref_tm.ty,
ptr_tm.ty,
location.to_locations(),
ConstraintCategory::Cast,
) {
span_mirbug!(
self,
rvalue,
"equating {:?} with {:?} yields {:?}",
ref_tm.ty,
ptr_tm.ty,
terr
)
}
} else {
if let Err(terr) = self.sub_types(
ref_tm.ty,
ptr_tm.ty,
location.to_locations(),
ConstraintCategory::Cast,
) {
span_mirbug!(
self,
rvalue,
"relating {:?} with {:?} yields {:?}",
ref_tm.ty,
ptr_tm.ty,
terr
)
}
}
}
},
(None, _)
| (_, None)
| (_, Some(CastTy::FnPtr))
| (Some(CastTy::Float), Some(CastTy::Ptr(_)))
| (Some(CastTy::Ptr(_)), Some(CastTy::Float))
| (Some(CastTy::FnPtr), Some(CastTy::Float)) => span_mirbug!(
self,
rvalue,
"Invalid cast {:?} -> {:?}",
ty_from,
ty,
),
_ => (),
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/librustc_mir/hair/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,11 @@ fn make_mirror_unadjusted<'a, 'tcx>(
let cast = if cx.tables().is_coercion_cast(source.hir_id) {
// Convert the lexpr to a vexpr.
ExprKind::Use { source: source.to_ref() }
} else if cx.tables().expr_ty(source).is_region_ptr() {
// Special cased so that we can type check that the element
// type of the source matches the pointed to type of the
// destination.
ExprKind::Pointer { source: source.to_ref(), cast: PointerCast::ArrayToPointer }
} else {
// check whether this is casting an enum variant discriminant
// to prevent cycles, we refer to the discriminant initializer
Expand Down
4 changes: 3 additions & 1 deletion src/librustc_mir/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.unsize_into(src, dest)?;
}

Misc | Pointer(PointerCast::MutToConstPointer) => {
Misc
| Pointer(PointerCast::MutToConstPointer)
| Pointer(PointerCast::ArrayToPointer) => {
let src = self.read_immediate(src)?;
let res = self.cast_immediate(src, dest.layout)?;
self.write_immediate(res, dest)?;
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_mir/transform/qualify_min_const_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ fn check_rvalue(
_ => check_operand(tcx, operand, span, def_id, body),
}
}
Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, _) => {
Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, _)
| Rvalue::Cast(CastKind::Pointer(PointerCast::ArrayToPointer), operand, _) => {
check_operand(tcx, operand, span, def_id, body)
}
Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), _, _) |
Expand Down
9 changes: 9 additions & 0 deletions src/librustc_typeck/check/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,15 @@ impl<'a, 'tcx> CastCheck<'tcx> {
// need to special-case obtaining a raw pointer
// from a region pointer to a vector.

// Coerce to a raw pointer so that we generate AddressOf in MIR.
let array_ptr_type = fcx.tcx.mk_ptr(m_expr);
fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No)
.unwrap_or_else(|_| bug!(
"could not cast from reference to array to pointer to array ({:?} to {:?})",
self.expr_ty,
array_ptr_type,
));

// this will report a type mismatch if needed
fcx.demand_eqtype(self.span, ety, m_cast.ty);
return Ok(CastKind::ArrayPtrCast);
Expand Down

0 comments on commit 401d9e1

Please sign in to comment.