Skip to content

Commit 7d01aa8

Browse files
committed
Type check coercions to pointer types
1 parent 082c861 commit 7d01aa8

File tree

16 files changed

+274
-15
lines changed

16 files changed

+274
-15
lines changed

src/librustc/ich/impls_mir.rs

+1
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ impl_stable_hash_for!(enum mir::CastKind {
373373
ReifyFnPointer,
374374
ClosureFnPointer,
375375
UnsafeFnPointer,
376+
MutToConstPointer,
376377
Unsize
377378
});
378379

src/librustc/mir/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2220,6 +2220,9 @@ pub enum CastKind {
22202220
/// Converts safe fn() to unsafe fn()
22212221
UnsafeFnPointer,
22222222

2223+
/// Coerces *mut T to *const T, preserving T.
2224+
MutToConstPointer,
2225+
22232226
/// "Unsize" -- convert a thin-or-fat pointer to a fat pointer.
22242227
/// codegen must figure out the details once full monomorphization
22252228
/// is known. For example, this could be used to cast from a

src/librustc/ty/context.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ use std::hash::{Hash, Hasher};
5959
use std::fmt;
6060
use std::mem;
6161
use std::ops::{Deref, Bound};
62-
use std::ptr;
6362
use std::iter;
6463
use std::sync::mpsc;
6564
use std::sync::Arc;
@@ -171,7 +170,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
171170

172171
// Make sure we don't end up with inference
173172
// types/regions in the global interner
174-
if ptr::eq(local, global) {
173+
if ptr_eq(local, global) {
175174
bug!("Attempted to intern `{:?}` which contains \
176175
inference types/regions in the global type context",
177176
&ty_struct);
@@ -1163,7 +1162,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
11631162

11641163
/// Returns `true` if self is the same as self.global_tcx().
11651164
fn is_global(self) -> bool {
1166-
ptr::eq(self.interners, &self.global_interners)
1165+
ptr_eq(self.interners, &self.global_interners)
11671166
}
11681167

11691168
/// Creates a type context and call the closure with a `TyCtxt` reference
@@ -1819,12 +1818,11 @@ impl<'a, 'tcx> Lift<'tcx> for &'a mir::interpret::Allocation {
18191818
}
18201819

18211820
pub mod tls {
1822-
use super::{GlobalCtxt, TyCtxt};
1821+
use super::{GlobalCtxt, TyCtxt, ptr_eq};
18231822

18241823
use std::fmt;
18251824
use std::mem;
18261825
use std::marker::PhantomData;
1827-
use std::ptr;
18281826
use syntax_pos;
18291827
use crate::ty::query;
18301828
use errors::{Diagnostic, TRACK_DIAGNOSTICS};
@@ -2067,7 +2065,7 @@ pub mod tls {
20672065
{
20682066
with_context(|context| {
20692067
unsafe {
2070-
assert!(ptr::eq(context.tcx.gcx, tcx.gcx));
2068+
assert!(ptr_eq(context.tcx.gcx, tcx.gcx));
20712069
let context: &ImplicitCtxt<'_, '_, '_> = mem::transmute(context);
20722070
f(context)
20732071
}
@@ -2085,8 +2083,8 @@ pub mod tls {
20852083
{
20862084
with_context(|context| {
20872085
unsafe {
2088-
assert!(ptr::eq(context.tcx.gcx, tcx.gcx));
2089-
assert!(ptr::eq(context.tcx.interners, tcx.interners));
2086+
assert!(ptr_eq(context.tcx.gcx, tcx.gcx));
2087+
assert!(ptr_eq(context.tcx.interners, tcx.interners));
20902088
let context: &ImplicitCtxt<'_, '_, '_> = mem::transmute(context);
20912089
f(context)
20922090
}
@@ -2993,6 +2991,12 @@ impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> {
29932991
}
29942992
}
29952993

2994+
// We are comparing types with different invariant lifetimes, so `ptr::eq`
2995+
// won't work for us.
2996+
fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
2997+
t as *const () == u as *const ()
2998+
}
2999+
29963000
pub fn provide(providers: &mut ty::query::Providers<'_>) {
29973001
providers.in_scope_traits_map = |tcx, id| tcx.gcx.trait_map.get(&id).cloned();
29983002
providers.module_exports = |tcx, id| tcx.gcx.export_map.get(&id).cloned();

src/librustc_codegen_ssa/mir/rvalue.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
257257
}
258258
}
259259
}
260-
mir::CastKind::Misc if bx.cx().is_backend_scalar_pair(operand.layout) => {
260+
mir::CastKind::MutToConstPointer
261+
| mir::CastKind::Misc if bx.cx().is_backend_scalar_pair(operand.layout) => {
261262
if let OperandValue::Pair(data_ptr, meta) = operand.val {
262263
if bx.cx().is_backend_scalar_pair(cast) {
263264
let data_cast = bx.pointercast(data_ptr,
@@ -274,7 +275,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
274275
bug!("Unexpected non-Pair operand")
275276
}
276277
}
277-
mir::CastKind::Misc => {
278+
mir::CastKind::MutToConstPointer
279+
| mir::CastKind::Misc => {
278280
assert!(bx.cx().is_backend_immediate(cast));
279281
let ll_t_out = bx.cx().immediate_backend_type(cast);
280282
if operand.layout.abi.is_uninhabited() {

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

+112-1
Original file line numberDiff line numberDiff line change
@@ -1984,7 +1984,118 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
19841984
);
19851985
}
19861986

1987-
CastKind::Misc => {}
1987+
CastKind::MutToConstPointer => {
1988+
let ty_from = match op.ty(mir, tcx).sty {
1989+
ty::RawPtr(ty::TypeAndMut {
1990+
ty: ty_from,
1991+
mutbl: hir::MutMutable,
1992+
}) => ty_from,
1993+
_ => {
1994+
span_mirbug!(
1995+
self,
1996+
rvalue,
1997+
"unexpected base type for cast {:?}",
1998+
ty,
1999+
);
2000+
return;
2001+
}
2002+
};
2003+
let ty_to = match ty.sty {
2004+
ty::RawPtr(ty::TypeAndMut {
2005+
ty: ty_to,
2006+
mutbl: hir::MutImmutable,
2007+
}) => ty_to,
2008+
_ => {
2009+
span_mirbug!(
2010+
self,
2011+
rvalue,
2012+
"unexpected target type for cast {:?}",
2013+
ty,
2014+
);
2015+
return;
2016+
}
2017+
};
2018+
if let Err(terr) = self.sub_types(
2019+
ty_from,
2020+
ty_to,
2021+
location.to_locations(),
2022+
ConstraintCategory::Cast,
2023+
) {
2024+
span_mirbug!(
2025+
self,
2026+
rvalue,
2027+
"relating {:?} with {:?} yields {:?}",
2028+
ty_from,
2029+
ty_to,
2030+
terr
2031+
)
2032+
}
2033+
}
2034+
2035+
CastKind::Misc => {
2036+
if let ty::Ref(_, mut ty_from, _) = op.ty(mir, tcx).sty {
2037+
let (mut ty_to, mutability) = if let ty::RawPtr(ty::TypeAndMut {
2038+
ty: ty_to,
2039+
mutbl,
2040+
}) = ty.sty {
2041+
(ty_to, mutbl)
2042+
} else {
2043+
span_mirbug!(
2044+
self,
2045+
rvalue,
2046+
"invalid cast types {:?} -> {:?}",
2047+
op.ty(mir, tcx),
2048+
ty,
2049+
);
2050+
return;
2051+
};
2052+
2053+
// Handle the direct cast from `&[T; N]` to `*const T` by unwrapping
2054+
// any array we find.
2055+
while let ty::Array(ty_elem_from, _) = ty_from.sty {
2056+
ty_from = ty_elem_from;
2057+
if let ty::Array(ty_elem_to, _) = ty_to.sty {
2058+
ty_to = ty_elem_to;
2059+
} else {
2060+
break;
2061+
}
2062+
}
2063+
2064+
if let hir::MutMutable = mutability {
2065+
if let Err(terr) = self.eq_types(
2066+
ty_from,
2067+
ty_to,
2068+
location.to_locations(),
2069+
ConstraintCategory::Cast,
2070+
) {
2071+
span_mirbug!(
2072+
self,
2073+
rvalue,
2074+
"equating {:?} with {:?} yields {:?}",
2075+
ty_from,
2076+
ty_to,
2077+
terr
2078+
)
2079+
}
2080+
} else {
2081+
if let Err(terr) = self.sub_types(
2082+
ty_from,
2083+
ty_to,
2084+
location.to_locations(),
2085+
ConstraintCategory::Cast,
2086+
) {
2087+
span_mirbug!(
2088+
self,
2089+
rvalue,
2090+
"relating {:?} with {:?} yields {:?}",
2091+
ty_from,
2092+
ty_to,
2093+
terr
2094+
)
2095+
}
2096+
}
2097+
}
2098+
}
19882099
}
19892100
}
19902101

src/librustc_mir/build/expr/as_place.rs

+1
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
196196
| ExprKind::ReifyFnPointer { .. }
197197
| ExprKind::ClosureFnPointer { .. }
198198
| ExprKind::UnsafeFnPointer { .. }
199+
| ExprKind::MutToConstPointer { .. }
199200
| ExprKind::Unsize { .. }
200201
| ExprKind::Repeat { .. }
201202
| ExprKind::Borrow { .. }

src/librustc_mir/build/expr/as_rvalue.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
142142
block.and(Rvalue::Use(Operand::Move(Place::Local(result))))
143143
}
144144
ExprKind::Cast { source } => {
145-
let source = this.hir.mirror(source);
146-
147145
let source = unpack!(block = this.as_operand(block, scope, source));
148146
block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
149147
}
@@ -163,6 +161,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
163161
let source = unpack!(block = this.as_operand(block, scope, source));
164162
block.and(Rvalue::Cast(CastKind::ClosureFnPointer, source, expr.ty))
165163
}
164+
ExprKind::MutToConstPointer { source } => {
165+
let source = unpack!(block = this.as_operand(block, scope, source));
166+
block.and(Rvalue::Cast(CastKind::MutToConstPointer, source, expr.ty))
167+
}
166168
ExprKind::Unsize { source } => {
167169
let source = unpack!(block = this.as_operand(block, scope, source));
168170
block.and(Rvalue::Cast(CastKind::Unsize, source, expr.ty))

src/librustc_mir/build/expr/category.rs

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ impl Category {
6262
| ExprKind::ReifyFnPointer { .. }
6363
| ExprKind::ClosureFnPointer { .. }
6464
| ExprKind::UnsafeFnPointer { .. }
65+
| ExprKind::MutToConstPointer { .. }
6566
| ExprKind::Unsize { .. }
6667
| ExprKind::Repeat { .. }
6768
| ExprKind::Borrow { .. }

src/librustc_mir/build/expr/into.rs

+1
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
383383
| ExprKind::ReifyFnPointer { .. }
384384
| ExprKind::ClosureFnPointer { .. }
385385
| ExprKind::UnsafeFnPointer { .. }
386+
| ExprKind::MutToConstPointer { .. }
386387
| ExprKind::Unsize { .. }
387388
| ExprKind::Repeat { .. }
388389
| ExprKind::Borrow { .. }

src/librustc_mir/hair/cx/expr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
8888
ExprKind::NeverToAny { source: expr.to_ref() }
8989
}
9090
Adjust::MutToConstPointer => {
91-
ExprKind::Cast { source: expr.to_ref() }
91+
ExprKind::MutToConstPointer { source: expr.to_ref() }
9292
}
9393
Adjust::Deref(None) => {
9494
// Adjust the span from the block, to the last expression of the

src/librustc_mir/hair/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ pub enum ExprKind<'tcx> {
190190
UnsafeFnPointer {
191191
source: ExprRef<'tcx>,
192192
},
193+
MutToConstPointer {
194+
source: ExprRef<'tcx>,
195+
},
193196
Unsize {
194197
source: ExprRef<'tcx>,
195198
},

src/librustc_mir/interpret/cast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
3333
self.unsize_into(src, dest)?;
3434
}
3535

36-
Misc => {
36+
Misc | MutToConstPointer => {
3737
let src = self.read_immediate(src)?;
3838

3939
if self.type_is_fat_ptr(src.layout.ty) {

src/librustc_mir/transform/qualify_consts.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
10911091
Rvalue::Cast(CastKind::UnsafeFnPointer, ..) |
10921092
Rvalue::Cast(CastKind::ClosureFnPointer, ..) |
10931093
Rvalue::Cast(CastKind::Unsize, ..) |
1094+
Rvalue::Cast(CastKind::MutToConstPointer, ..) |
10941095
Rvalue::Discriminant(..) |
10951096
Rvalue::Len(_) |
10961097
Rvalue::Ref(..) |

src/librustc_mir/transform/qualify_min_const_fn.rs

+3
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ fn check_rvalue(
152152
_ => check_operand(tcx, mir, operand, span),
153153
}
154154
}
155+
Rvalue::Cast(CastKind::MutToConstPointer, operand, _) => {
156+
check_operand(tcx, mir, operand, span)
157+
}
155158
Rvalue::Cast(CastKind::UnsafeFnPointer, _, _) |
156159
Rvalue::Cast(CastKind::ClosureFnPointer, _, _) |
157160
Rvalue::Cast(CastKind::ReifyFnPointer, _, _) => Err((
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#![feature(nll)]
2+
3+
fn shared_to_const<'a, 'b>(x: &&'a i32) -> *const &'b i32 {
4+
x //~ ERROR
5+
}
6+
7+
fn unique_to_const<'a, 'b>(x: &mut &'a i32) -> *const &'b i32 {
8+
x //~ ERROR
9+
}
10+
11+
fn unique_to_mut<'a, 'b>(x: &mut &'a i32) -> *mut &'b i32 {
12+
// Two errors because *mut is invariant
13+
x //~ ERROR
14+
//~| ERROR
15+
}
16+
17+
fn mut_to_const<'a, 'b>(x: *mut &'a i32) -> *const &'b i32 {
18+
x //~ ERROR
19+
}
20+
21+
fn array_elem<'a, 'b>(x: &'a i32) -> *const &'b i32 {
22+
let z = &[x; 3];
23+
let y = z as *const &i32;
24+
y //~ ERROR
25+
}
26+
27+
fn array_coerce<'a, 'b>(x: &'a i32) -> *const [&'b i32; 3] {
28+
let z = &[x; 3];
29+
let y = z as *const [&i32; 3];
30+
y //~ ERROR
31+
}
32+
33+
fn nested_array<'a, 'b>(x: &'a i32) -> *const [&'b i32; 2] {
34+
let z = &[[x; 2]; 3];
35+
let y = z as *const [&i32; 2];
36+
y //~ ERROR
37+
}
38+
39+
fn main() {}

0 commit comments

Comments
 (0)