1
Fork 0

Auto merge of #45735 - tirr-c:issue-45730, r=arielb1

Forbid casting to/from a pointer of unknown kind

Fixes #45730.

Before, it ICE'd when `pointer_kind` encountered `TyInfer`.
This commit is contained in:
bors 2017-11-08 07:12:15 +00:00
commit 49bee9d09a
4 changed files with 111 additions and 23 deletions

View file

@ -83,28 +83,30 @@ enum PointerKind<'tcx> {
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
/// Returns the kind of unsize information of t, or None /// Returns the kind of unsize information of t, or None
/// if t is sized or it is unknown. /// if t is unknown.
fn pointer_kind(&self, t: Ty<'tcx>, span: Span) -> PointerKind<'tcx> { fn pointer_kind(&self, t: Ty<'tcx>, span: Span) -> Option<PointerKind<'tcx>> {
if self.type_is_known_to_be_sized(t, span) { if self.type_is_known_to_be_sized(t, span) {
return PointerKind::Thin; return Some(PointerKind::Thin);
} }
match t.sty { match t.sty {
ty::TySlice(_) | ty::TyStr => PointerKind::Length, ty::TySlice(_) | ty::TyStr => Some(PointerKind::Length),
ty::TyDynamic(ref tty, ..) => ty::TyDynamic(ref tty, ..) =>
PointerKind::Vtable(tty.principal().map(|p| p.def_id())), Some(PointerKind::Vtable(tty.principal().map(|p| p.def_id()))),
ty::TyAdt(def, substs) if def.is_struct() => { ty::TyAdt(def, substs) if def.is_struct() => {
// FIXME(arielb1): do some kind of normalization // FIXME(arielb1): do some kind of normalization
match def.struct_variant().fields.last() { match def.struct_variant().fields.last() {
None => PointerKind::Thin, None => Some(PointerKind::Thin),
Some(f) => self.pointer_kind(f.ty(self.tcx, substs), span), Some(f) => self.pointer_kind(f.ty(self.tcx, substs), span),
} }
} }
// Pointers to foreign types are thin, despite being unsized // Pointers to foreign types are thin, despite being unsized
ty::TyForeign(..) => PointerKind::Thin, ty::TyForeign(..) => Some(PointerKind::Thin),
// We should really try to normalize here. // We should really try to normalize here.
ty::TyProjection(ref pi) => PointerKind::OfProjection(pi), ty::TyProjection(ref pi) => Some(PointerKind::OfProjection(pi)),
ty::TyParam(ref p) => PointerKind::OfParam(p), ty::TyParam(ref p) => Some(PointerKind::OfParam(p)),
// Insufficient type information.
ty::TyInfer(_) => None,
_ => panic!(), _ => panic!(),
} }
} }
@ -123,6 +125,8 @@ enum CastError {
NeedViaThinPtr, NeedViaThinPtr,
NeedViaInt, NeedViaInt,
NonScalar, NonScalar,
UnknownExprPtrKind,
UnknownCastPtrKind,
} }
fn make_invalid_casting_error<'a, 'gcx, 'tcx>(sess: &'a Session, fn make_invalid_casting_error<'a, 'gcx, 'tcx>(sess: &'a Session,
@ -241,6 +245,25 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
self.expr_ty, self.expr_ty,
fcx.ty_to_string(self.cast_ty)).emit(); fcx.ty_to_string(self.cast_ty)).emit();
} }
CastError::UnknownCastPtrKind |
CastError::UnknownExprPtrKind => {
let unknown_cast_to = match e {
CastError::UnknownCastPtrKind => true,
CastError::UnknownExprPtrKind => false,
_ => bug!(),
};
let mut err = struct_span_err!(fcx.tcx.sess, self.span, E0641,
"cannot cast {} a pointer of an unknown kind",
if unknown_cast_to { "to" } else { "from" });
err.note("The type information given here is insufficient to check whether \
the pointer cast is valid");
if unknown_cast_to {
err.span_suggestion_short(self.cast_span,
"consider giving more type information",
String::new());
}
err.emit();
}
} }
} }
@ -457,14 +480,27 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast); debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast);
// ptr-ptr cast. vtables must match. // ptr-ptr cast. vtables must match.
// Cast to thin pointer is OK let expr_kind = fcx.pointer_kind(m_expr.ty, self.span);
let cast_kind = fcx.pointer_kind(m_cast.ty, self.span); let cast_kind = fcx.pointer_kind(m_cast.ty, self.span);
let cast_kind = match cast_kind {
// We can't cast if target pointer kind is unknown
None => return Err(CastError::UnknownCastPtrKind),
Some(cast_kind) => cast_kind,
};
// Cast to thin pointer is OK
if cast_kind == PointerKind::Thin { if cast_kind == PointerKind::Thin {
return Ok(CastKind::PtrPtrCast); return Ok(CastKind::PtrPtrCast);
} }
let expr_kind = match expr_kind {
// We can't cast to fat pointer if source pointer kind is unknown
None => return Err(CastError::UnknownExprPtrKind),
Some(expr_kind) => expr_kind,
};
// thin -> fat? report invalid cast (don't complain about vtable kinds) // thin -> fat? report invalid cast (don't complain about vtable kinds)
let expr_kind = fcx.pointer_kind(m_expr.ty, self.span);
if expr_kind == PointerKind::Thin { if expr_kind == PointerKind::Thin {
return Err(CastError::SizedUnsizedCast); return Err(CastError::SizedUnsizedCast);
} }
@ -483,10 +519,10 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
-> Result<CastKind, CastError> { -> Result<CastKind, CastError> {
// fptr-ptr cast. must be to thin ptr // fptr-ptr cast. must be to thin ptr
if fcx.pointer_kind(m_cast.ty, self.span) == PointerKind::Thin { match fcx.pointer_kind(m_cast.ty, self.span) {
Ok(CastKind::FnPtrPtrCast) None => Err(CastError::UnknownCastPtrKind),
} else { Some(PointerKind::Thin) => Ok(CastKind::FnPtrPtrCast),
Err(CastError::IllegalCast) _ => Err(CastError::IllegalCast),
} }
} }
@ -496,10 +532,10 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
-> Result<CastKind, CastError> { -> Result<CastKind, CastError> {
// ptr-addr cast. must be from thin ptr // ptr-addr cast. must be from thin ptr
if fcx.pointer_kind(m_expr.ty, self.span) == PointerKind::Thin { match fcx.pointer_kind(m_expr.ty, self.span) {
Ok(CastKind::PtrAddrCast) None => Err(CastError::UnknownExprPtrKind),
} else { Some(PointerKind::Thin) => Ok(CastKind::PtrAddrCast),
Err(CastError::NeedViaThinPtr) _ => Err(CastError::NeedViaThinPtr),
} }
} }
@ -533,10 +569,10 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
m_cast: &'tcx ty::TypeAndMut<'tcx>) m_cast: &'tcx ty::TypeAndMut<'tcx>)
-> Result<CastKind, CastError> { -> Result<CastKind, CastError> {
// ptr-addr cast. pointer must be thin. // ptr-addr cast. pointer must be thin.
if fcx.pointer_kind(m_cast.ty, self.span) == PointerKind::Thin { match fcx.pointer_kind(m_cast.ty, self.span) {
Ok(CastKind::AddrPtrCast) None => Err(CastError::UnknownCastPtrKind),
} else { Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast),
Err(CastError::IllegalCast) _ => Err(CastError::IllegalCast),
} }
} }

View file

@ -4743,4 +4743,5 @@ register_diagnostics! {
E0627, // yield statement outside of generator literal E0627, // yield statement outside of generator literal
E0632, // cannot provide explicit type parameters when `impl Trait` is used in E0632, // cannot provide explicit type parameters when `impl Trait` is used in
// argument position. // argument position.
E0641, // cannot cast to/from a pointer with an unknown kind
} }

View file

@ -0,0 +1,19 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::fmt;
fn main() {
let x: *const _ = 0 as _;
let x: *const _ = 0 as *const _;
let y: Option<*const fmt::Debug> = Some(x) as _;
let x = 0 as *const i32 as *const _ as *mut _;
}

View file

@ -0,0 +1,32 @@
error[E0641]: cannot cast to a pointer of an unknown kind
--> $DIR/issue-45730.rs:13:23
|
13 | let x: *const _ = 0 as _;
| ^^^^^-
| |
| help: consider giving more type information
|
= note: The type information given here is insufficient to check whether the pointer cast is valid
error[E0641]: cannot cast to a pointer of an unknown kind
--> $DIR/issue-45730.rs:15:23
|
15 | let x: *const _ = 0 as *const _;
| ^^^^^--------
| |
| help: consider giving more type information
|
= note: The type information given here is insufficient to check whether the pointer cast is valid
error[E0641]: cannot cast to a pointer of an unknown kind
--> $DIR/issue-45730.rs:18:13
|
18 | let x = 0 as *const i32 as *const _ as *mut _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------
| |
| help: consider giving more type information
|
= note: The type information given here is insufficient to check whether the pointer cast is valid
error: aborting due to 3 previous errors