Skip to content

Commit d77e212

Browse files
committed
Never consider raw pointer casts to be trival
HIR typeck tries to figure out which casts are trivial by doing them as coercions and seeing whether this works. Since HIR typeck is oblivious of lifetimes, this doesn't work for pointer casts that only change the lifetime of the pointee, which are, as borrowck will tell you, not trivial. This change makes it so that raw pointer casts are never considered trivial. This also incidentally fixes the "trivial cast" lint false positive on the same code. Unfortunately, "trivial cast" lints are now never emitted on raw pointer casts, even if they truly are trivial. This could be fixed by also doing the lint in borrowck for raw pointers specifically.
1 parent ff5664d commit d77e212

File tree

3 files changed

+48
-7
lines changed

3 files changed

+48
-7
lines changed

compiler/rustc_hir_typeck/src/cast.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -661,9 +661,21 @@ impl<'a, 'tcx> CastCheck<'tcx> {
661661
} else {
662662
match self.try_coercion_cast(fcx) {
663663
Ok(()) => {
664-
self.trivial_cast_lint(fcx);
665-
debug!(" -> CoercionCast");
666-
fcx.typeck_results.borrow_mut().set_coercion_cast(self.expr.hir_id.local_id);
664+
if self.expr_ty.is_unsafe_ptr() && self.cast_ty.is_unsafe_ptr() {
665+
// When casting a raw pointer to another raw pointer, we cannot convert the cast into
666+
// a coercion because the pointee types might only differ in regions, which HIR typeck
667+
// cannot distinguish. This would cause us to erroneously discard a cast which will
668+
// lead to a borrowck error like #113257.
669+
// We still did a coercion above to unify inference variables for `ptr as _` casts.
670+
debug!(" -> PointerCast");
671+
// This does cause us to miss some trivial casts in the trival cast lint.
672+
} else {
673+
self.trivial_cast_lint(fcx);
674+
debug!(" -> CoercionCast");
675+
fcx.typeck_results
676+
.borrow_mut()
677+
.set_coercion_cast(self.expr.hir_id.local_id);
678+
}
667679
}
668680
Err(_) => {
669681
match self.do_check(fcx) {

tests/mir-opt/casts.redundant.InstSimplify.diff

+9-4
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,23 @@
66
let mut _0: *const &u8;
77
let mut _2: *const &u8;
88
let mut _3: *const &u8;
9+
let mut _4: *const &u8;
910
scope 1 (inlined generic_cast::<&u8, &u8>) {
1011
debug x => _1;
1112
}
1213

1314
bb0: {
1415
StorageLive(_2);
1516
StorageLive(_3);
16-
_3 = _1;
17-
- _2 = _3 as *const &u8 (PtrToPtr);
18-
+ _2 = _3;
19-
StorageDead(_3);
17+
StorageLive(_4);
18+
_4 = _1;
19+
- _3 = _4 as *const &u8 (PtrToPtr);
20+
+ _3 = _4;
21+
StorageDead(_4);
22+
- _2 = move _3 as *const &u8 (PtrToPtr);
23+
+ _2 = move _3;
2024
_0 = _2;
25+
StorageDead(_3);
2126
StorageDead(_2);
2227
return;
2328
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// check-pass
2+
3+
// https://github.com/rust-lang/rust/issues/113257
4+
5+
#![deny(trivial_casts)] // The casts here are not trivial.
6+
7+
struct Foo<'a> { a: &'a () }
8+
9+
fn extend_lifetime_very_very_safely<'a>(v: *const Foo<'a>) -> *const Foo<'static> {
10+
// This should pass because raw pointer casts can do anything they want.
11+
v as *const Foo<'static>
12+
}
13+
14+
trait Trait {}
15+
16+
fn assert_static<'a>(ptr: *mut (dyn Trait + 'a)) -> *mut (dyn Trait + 'static) {
17+
ptr as _
18+
}
19+
20+
fn main() {
21+
let unit = ();
22+
let foo = Foo { a: &unit };
23+
let _long: *const Foo<'static> = extend_lifetime_very_very_safely(&foo);
24+
}

0 commit comments

Comments
 (0)