Skip to content

Commit 49bee9d

Browse files
committed
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`.
2 parents e177df3 + 99ada04 commit 49bee9d

File tree

4 files changed

+111
-23
lines changed

4 files changed

+111
-23
lines changed

src/librustc_typeck/check/cast.rs

+59-23
Original file line numberDiff line numberDiff line change
@@ -83,28 +83,30 @@ enum PointerKind<'tcx> {
8383

8484
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
8585
/// Returns the kind of unsize information of t, or None
86-
/// if t is sized or it is unknown.
87-
fn pointer_kind(&self, t: Ty<'tcx>, span: Span) -> PointerKind<'tcx> {
86+
/// if t is unknown.
87+
fn pointer_kind(&self, t: Ty<'tcx>, span: Span) -> Option<PointerKind<'tcx>> {
8888
if self.type_is_known_to_be_sized(t, span) {
89-
return PointerKind::Thin;
89+
return Some(PointerKind::Thin);
9090
}
9191

9292
match t.sty {
93-
ty::TySlice(_) | ty::TyStr => PointerKind::Length,
93+
ty::TySlice(_) | ty::TyStr => Some(PointerKind::Length),
9494
ty::TyDynamic(ref tty, ..) =>
95-
PointerKind::Vtable(tty.principal().map(|p| p.def_id())),
95+
Some(PointerKind::Vtable(tty.principal().map(|p| p.def_id()))),
9696
ty::TyAdt(def, substs) if def.is_struct() => {
9797
// FIXME(arielb1): do some kind of normalization
9898
match def.struct_variant().fields.last() {
99-
None => PointerKind::Thin,
99+
None => Some(PointerKind::Thin),
100100
Some(f) => self.pointer_kind(f.ty(self.tcx, substs), span),
101101
}
102102
}
103103
// Pointers to foreign types are thin, despite being unsized
104-
ty::TyForeign(..) => PointerKind::Thin,
104+
ty::TyForeign(..) => Some(PointerKind::Thin),
105105
// We should really try to normalize here.
106-
ty::TyProjection(ref pi) => PointerKind::OfProjection(pi),
107-
ty::TyParam(ref p) => PointerKind::OfParam(p),
106+
ty::TyProjection(ref pi) => Some(PointerKind::OfProjection(pi)),
107+
ty::TyParam(ref p) => Some(PointerKind::OfParam(p)),
108+
// Insufficient type information.
109+
ty::TyInfer(_) => None,
108110
_ => panic!(),
109111
}
110112
}
@@ -123,6 +125,8 @@ enum CastError {
123125
NeedViaThinPtr,
124126
NeedViaInt,
125127
NonScalar,
128+
UnknownExprPtrKind,
129+
UnknownCastPtrKind,
126130
}
127131

128132
fn make_invalid_casting_error<'a, 'gcx, 'tcx>(sess: &'a Session,
@@ -241,6 +245,25 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
241245
self.expr_ty,
242246
fcx.ty_to_string(self.cast_ty)).emit();
243247
}
248+
CastError::UnknownCastPtrKind |
249+
CastError::UnknownExprPtrKind => {
250+
let unknown_cast_to = match e {
251+
CastError::UnknownCastPtrKind => true,
252+
CastError::UnknownExprPtrKind => false,
253+
_ => bug!(),
254+
};
255+
let mut err = struct_span_err!(fcx.tcx.sess, self.span, E0641,
256+
"cannot cast {} a pointer of an unknown kind",
257+
if unknown_cast_to { "to" } else { "from" });
258+
err.note("The type information given here is insufficient to check whether \
259+
the pointer cast is valid");
260+
if unknown_cast_to {
261+
err.span_suggestion_short(self.cast_span,
262+
"consider giving more type information",
263+
String::new());
264+
}
265+
err.emit();
266+
}
244267
}
245268
}
246269

@@ -457,14 +480,27 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
457480
debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast);
458481
// ptr-ptr cast. vtables must match.
459482

460-
// Cast to thin pointer is OK
483+
let expr_kind = fcx.pointer_kind(m_expr.ty, self.span);
461484
let cast_kind = fcx.pointer_kind(m_cast.ty, self.span);
485+
486+
let cast_kind = match cast_kind {
487+
// We can't cast if target pointer kind is unknown
488+
None => return Err(CastError::UnknownCastPtrKind),
489+
Some(cast_kind) => cast_kind,
490+
};
491+
492+
// Cast to thin pointer is OK
462493
if cast_kind == PointerKind::Thin {
463494
return Ok(CastKind::PtrPtrCast);
464495
}
465496

497+
let expr_kind = match expr_kind {
498+
// We can't cast to fat pointer if source pointer kind is unknown
499+
None => return Err(CastError::UnknownExprPtrKind),
500+
Some(expr_kind) => expr_kind,
501+
};
502+
466503
// thin -> fat? report invalid cast (don't complain about vtable kinds)
467-
let expr_kind = fcx.pointer_kind(m_expr.ty, self.span);
468504
if expr_kind == PointerKind::Thin {
469505
return Err(CastError::SizedUnsizedCast);
470506
}
@@ -483,10 +519,10 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
483519
-> Result<CastKind, CastError> {
484520
// fptr-ptr cast. must be to thin ptr
485521

486-
if fcx.pointer_kind(m_cast.ty, self.span) == PointerKind::Thin {
487-
Ok(CastKind::FnPtrPtrCast)
488-
} else {
489-
Err(CastError::IllegalCast)
522+
match fcx.pointer_kind(m_cast.ty, self.span) {
523+
None => Err(CastError::UnknownCastPtrKind),
524+
Some(PointerKind::Thin) => Ok(CastKind::FnPtrPtrCast),
525+
_ => Err(CastError::IllegalCast),
490526
}
491527
}
492528

@@ -496,10 +532,10 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
496532
-> Result<CastKind, CastError> {
497533
// ptr-addr cast. must be from thin ptr
498534

499-
if fcx.pointer_kind(m_expr.ty, self.span) == PointerKind::Thin {
500-
Ok(CastKind::PtrAddrCast)
501-
} else {
502-
Err(CastError::NeedViaThinPtr)
535+
match fcx.pointer_kind(m_expr.ty, self.span) {
536+
None => Err(CastError::UnknownExprPtrKind),
537+
Some(PointerKind::Thin) => Ok(CastKind::PtrAddrCast),
538+
_ => Err(CastError::NeedViaThinPtr),
503539
}
504540
}
505541

@@ -533,10 +569,10 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
533569
m_cast: &'tcx ty::TypeAndMut<'tcx>)
534570
-> Result<CastKind, CastError> {
535571
// ptr-addr cast. pointer must be thin.
536-
if fcx.pointer_kind(m_cast.ty, self.span) == PointerKind::Thin {
537-
Ok(CastKind::AddrPtrCast)
538-
} else {
539-
Err(CastError::IllegalCast)
572+
match fcx.pointer_kind(m_cast.ty, self.span) {
573+
None => Err(CastError::UnknownCastPtrKind),
574+
Some(PointerKind::Thin) => Ok(CastKind::AddrPtrCast),
575+
_ => Err(CastError::IllegalCast),
540576
}
541577
}
542578

src/librustc_typeck/diagnostics.rs

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

src/test/ui/issue-45730.rs

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

src/test/ui/issue-45730.stderr

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
error[E0641]: cannot cast to a pointer of an unknown kind
2+
--> $DIR/issue-45730.rs:13:23
3+
|
4+
13 | let x: *const _ = 0 as _;
5+
| ^^^^^-
6+
| |
7+
| help: consider giving more type information
8+
|
9+
= note: The type information given here is insufficient to check whether the pointer cast is valid
10+
11+
error[E0641]: cannot cast to a pointer of an unknown kind
12+
--> $DIR/issue-45730.rs:15:23
13+
|
14+
15 | let x: *const _ = 0 as *const _;
15+
| ^^^^^--------
16+
| |
17+
| help: consider giving more type information
18+
|
19+
= note: The type information given here is insufficient to check whether the pointer cast is valid
20+
21+
error[E0641]: cannot cast to a pointer of an unknown kind
22+
--> $DIR/issue-45730.rs:18:13
23+
|
24+
18 | let x = 0 as *const i32 as *const _ as *mut _;
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------
26+
| |
27+
| help: consider giving more type information
28+
|
29+
= note: The type information given here is insufficient to check whether the pointer cast is valid
30+
31+
error: aborting due to 3 previous errors
32+

0 commit comments

Comments
 (0)