Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from
Nov 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -35,6 +35,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 @@ -2169,72 +2170,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 @@ -639,6 +639,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