Skip to content

Commit 972c3be

Browse files
committed
Don't cast directly from &[T; N] to *const T
Instead coerce to `*const [T; N]` and then cast.
1 parent 23f890f commit 972c3be

File tree

7 files changed

+131
-56
lines changed

7 files changed

+131
-56
lines changed

src/librustc/ty/adjustment.rs

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ pub enum PointerCast {
2020
/// Go from a mut raw pointer to a const raw pointer.
2121
MutToConstPointer,
2222

23+
/// Go from `*const [T; N]` to `*const T`
24+
ArrayToPointer,
25+
2326
/// Unsize a pointer/reference value, e.g., `&[T; n]` to
2427
/// `&[T]`. Note that the source could be a thin or fat pointer.
2528
/// This will do things like convert thin pointers to fat

src/librustc_codegen_ssa/mir/rvalue.rs

+1
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
269269
}
270270
}
271271
mir::CastKind::Pointer(PointerCast::MutToConstPointer)
272+
| mir::CastKind::Pointer(PointerCast::ArrayToPointer)
272273
| mir::CastKind::Misc => {
273274
assert!(bx.cx().is_backend_immediate(cast));
274275
let ll_t_out = bx.cx().immediate_backend_type(cast);

src/librustc_mir/borrow_check/nll/type_check/mod.rs

+108-54
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use rustc::traits::query::type_op::custom::CustomTypeOp;
3535
use rustc::traits::query::{Fallible, NoSolution};
3636
use rustc::traits::{self, ObligationCause, PredicateObligations};
3737
use rustc::ty::adjustment::{PointerCast};
38+
use rustc::ty::cast::CastTy;
3839
use rustc::ty::fold::TypeFoldable;
3940
use rustc::ty::subst::{Subst, SubstsRef, GenericArgKind, UserSubsts};
4041
use rustc::ty::{
@@ -2169,72 +2170,125 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
21692170
ty_from,
21702171
ty_to,
21712172
terr
2172-
)
2173+
);
21732174
}
21742175
}
21752176

2176-
CastKind::Misc => {
2177-
if let ty::Ref(_, mut ty_from, _) = op.ty(body, tcx).kind {
2178-
let (mut ty_to, mutability) = if let ty::RawPtr(ty::TypeAndMut {
2179-
ty: ty_to,
2180-
mutbl,
2181-
}) = ty.kind {
2182-
(ty_to, mutbl)
2183-
} else {
2177+
CastKind::Pointer(PointerCast::ArrayToPointer) => {
2178+
let ty_from = op.ty(body, tcx);
2179+
2180+
let opt_ty_elem = match ty_from.kind {
2181+
ty::RawPtr(
2182+
ty::TypeAndMut { mutbl: hir::MutImmutable, ty: array_ty }
2183+
) => {
2184+
match array_ty.kind {
2185+
ty::Array(ty_elem, _) => Some(ty_elem),
2186+
_ => None,
2187+
}
2188+
}
2189+
_ => None,
2190+
};
2191+
2192+
let ty_elem = match opt_ty_elem {
2193+
Some(ty_elem) => ty_elem,
2194+
None => {
21842195
span_mirbug!(
21852196
self,
21862197
rvalue,
2187-
"invalid cast types {:?} -> {:?}",
2188-
op.ty(body, tcx),
2198+
"ArrayToPointer cast from unexpected type {:?}",
2199+
ty_from,
2200+
);
2201+
return;
2202+
}
2203+
};
2204+
2205+
let ty_to = match ty.kind {
2206+
ty::RawPtr(
2207+
ty::TypeAndMut { mutbl: hir::MutImmutable, ty: ty_to }
2208+
) => {
2209+
ty_to
2210+
}
2211+
_ => {
2212+
span_mirbug!(
2213+
self,
2214+
rvalue,
2215+
"ArrayToPointer cast to unexpected type {:?}",
21892216
ty,
21902217
);
21912218
return;
2192-
};
2193-
2194-
// Handle the direct cast from `&[T; N]` to `*const T` by unwrapping
2195-
// any array we find.
2196-
while let ty::Array(ty_elem_from, _) = ty_from.kind {
2197-
ty_from = ty_elem_from;
2198-
if let ty::Array(ty_elem_to, _) = ty_to.kind {
2199-
ty_to = ty_elem_to;
2200-
} else {
2201-
break;
2202-
}
22032219
}
2220+
};
22042221

2205-
if let hir::MutMutable = mutability {
2206-
if let Err(terr) = self.eq_types(
2207-
ty_from,
2208-
ty_to,
2209-
location.to_locations(),
2210-
ConstraintCategory::Cast,
2211-
) {
2212-
span_mirbug!(
2213-
self,
2214-
rvalue,
2215-
"equating {:?} with {:?} yields {:?}",
2216-
ty_from,
2217-
ty_to,
2218-
terr
2219-
)
2220-
}
2221-
} else {
2222-
if let Err(terr) = self.sub_types(
2223-
ty_from,
2224-
ty_to,
2225-
location.to_locations(),
2226-
ConstraintCategory::Cast,
2227-
) {
2228-
span_mirbug!(
2229-
self,
2230-
rvalue,
2231-
"relating {:?} with {:?} yields {:?}",
2232-
ty_from,
2233-
ty_to,
2234-
terr
2235-
)
2222+
if let Err(terr) = self.sub_types(
2223+
ty_elem,
2224+
ty_to,
2225+
location.to_locations(),
2226+
ConstraintCategory::Cast,
2227+
) {
2228+
span_mirbug!(
2229+
self,
2230+
rvalue,
2231+
"relating {:?} with {:?} yields {:?}",
2232+
ty_elem,
2233+
ty_to,
2234+
terr
2235+
)
2236+
}
2237+
}
2238+
2239+
CastKind::Misc => {
2240+
let ty_from = op.ty(body, tcx);
2241+
let cast_ty_from = CastTy::from_ty(ty_from);
2242+
let cast_ty_to = CastTy::from_ty(ty);
2243+
match (cast_ty_from, cast_ty_to) {
2244+
(Some(CastTy::RPtr(ref_tm)), Some(CastTy::Ptr(ptr_tm))) => {
2245+
if let hir::MutMutable = ptr_tm.mutbl {
2246+
if let Err(terr) = self.eq_types(
2247+
ref_tm.ty,
2248+
ptr_tm.ty,
2249+
location.to_locations(),
2250+
ConstraintCategory::Cast,
2251+
) {
2252+
span_mirbug!(
2253+
self,
2254+
rvalue,
2255+
"equating {:?} with {:?} yields {:?}",
2256+
ref_tm.ty,
2257+
ptr_tm.ty,
2258+
terr
2259+
)
2260+
}
2261+
} else {
2262+
if let Err(terr) = self.sub_types(
2263+
ref_tm.ty,
2264+
ptr_tm.ty,
2265+
location.to_locations(),
2266+
ConstraintCategory::Cast,
2267+
) {
2268+
span_mirbug!(
2269+
self,
2270+
rvalue,
2271+
"relating {:?} with {:?} yields {:?}",
2272+
ref_tm.ty,
2273+
ptr_tm.ty,
2274+
terr
2275+
)
2276+
}
22362277
}
2237-
}
2278+
},
2279+
(None, _)
2280+
| (_, None)
2281+
| (_, Some(CastTy::FnPtr))
2282+
| (Some(CastTy::Float), Some(CastTy::Ptr(_)))
2283+
| (Some(CastTy::Ptr(_)), Some(CastTy::Float))
2284+
| (Some(CastTy::FnPtr), Some(CastTy::Float)) => span_mirbug!(
2285+
self,
2286+
rvalue,
2287+
"Invalid cast {:?} -> {:?}",
2288+
ty_from,
2289+
ty,
2290+
),
2291+
_ => (),
22382292
}
22392293
}
22402294
}

src/librustc_mir/hair/cx/expr.rs

+5
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,11 @@ fn make_mirror_unadjusted<'a, 'tcx>(
628628
let cast = if cx.tables().is_coercion_cast(source.hir_id) {
629629
// Convert the lexpr to a vexpr.
630630
ExprKind::Use { source: source.to_ref() }
631+
} else if cx.tables().expr_ty(source).is_region_ptr() {
632+
// Special cased so that we can type check that the element
633+
// type of the source matches the pointed to type of the
634+
// destination.
635+
ExprKind::Pointer { source: source.to_ref(), cast: PointerCast::ArrayToPointer }
631636
} else {
632637
// check whether this is casting an enum variant discriminant
633638
// to prevent cycles, we refer to the discriminant initializer

src/librustc_mir/interpret/cast.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
2626
self.unsize_into(src, dest)?;
2727
}
2828

29-
Misc | Pointer(PointerCast::MutToConstPointer) => {
29+
Misc
30+
| Pointer(PointerCast::MutToConstPointer)
31+
| Pointer(PointerCast::ArrayToPointer) => {
3032
let src = self.read_immediate(src)?;
3133
let res = self.cast_immediate(src, dest.layout)?;
3234
self.write_immediate(res, dest)?;

src/librustc_mir/transform/qualify_min_const_fn.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@ fn check_rvalue(
150150
_ => check_operand(tcx, operand, span, def_id, body),
151151
}
152152
}
153-
Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, _) => {
153+
Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, _)
154+
| Rvalue::Cast(CastKind::Pointer(PointerCast::ArrayToPointer), operand, _) => {
154155
check_operand(tcx, operand, span, def_id, body)
155156
}
156157
Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), _, _) |

src/librustc_typeck/check/cast.rs

+9
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,15 @@ impl<'a, 'tcx> CastCheck<'tcx> {
639639
// need to special-case obtaining a raw pointer
640640
// from a region pointer to a vector.
641641

642+
// Coerce to a raw pointer so that we generate AddressOf in MIR.
643+
let array_ptr_type = fcx.tcx.mk_ptr(m_expr);
644+
fcx.try_coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No)
645+
.unwrap_or_else(|_| bug!(
646+
"could not cast from reference to array to pointer to array ({:?} to {:?})",
647+
self.expr_ty,
648+
array_ptr_type,
649+
));
650+
642651
// this will report a type mismatch if needed
643652
fcx.demand_eqtype(self.span, ety, m_cast.ty);
644653
return Ok(CastKind::ArrayPtrCast);

0 commit comments

Comments
 (0)