Skip to content

Commit 6f65201

Browse files
committed
Auto merge of #113262 - Nilstrieb:rawr-casting, r=lcnr
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. fixes #113257
2 parents 9ab0749 + e8a4814 commit 6f65201

File tree

6 files changed

+77
-37
lines changed

6 files changed

+77
-37
lines changed

compiler/rustc_hir_typeck/src/cast.rs

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

compiler/rustc_mir_build/src/thir/cx/expr.rs

+13-19
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,16 @@ impl<'tcx> Cx<'tcx> {
191191
source: self.mirror_expr(source),
192192
cast: PointerCoercion::ArrayToPointer,
193193
}
194-
} else {
195-
// check whether this is casting an enum variant discriminant
196-
// to prevent cycles, we refer to the discriminant initializer
194+
} else if let hir::ExprKind::Path(ref qpath) = source.kind
195+
&& let res = self.typeck_results().qpath_res(qpath, source.hir_id)
196+
&& let ty = self.typeck_results().node_type(source.hir_id)
197+
&& let ty::Adt(adt_def, args) = ty.kind()
198+
&& let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res
199+
{
200+
// Check whether this is casting an enum variant discriminant.
201+
// To prevent cycles, we refer to the discriminant initializer,
197202
// which is always an integer and thus doesn't need to know the
198-
// enum's layout (or its tag type) to compute it during const eval
203+
// enum's layout (or its tag type) to compute it during const eval.
199204
// Example:
200205
// enum Foo {
201206
// A,
@@ -204,21 +209,6 @@ impl<'tcx> Cx<'tcx> {
204209
// The correct solution would be to add symbolic computations to miri,
205210
// so we wouldn't have to compute and store the actual value
206211

207-
let hir::ExprKind::Path(ref qpath) = source.kind else {
208-
return ExprKind::Cast { source: self.mirror_expr(source) };
209-
};
210-
211-
let res = self.typeck_results().qpath_res(qpath, source.hir_id);
212-
let ty = self.typeck_results().node_type(source.hir_id);
213-
let ty::Adt(adt_def, args) = ty.kind() else {
214-
return ExprKind::Cast { source: self.mirror_expr(source) };
215-
};
216-
217-
let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Const), variant_ctor_id) = res
218-
else {
219-
return ExprKind::Cast { source: self.mirror_expr(source) };
220-
};
221-
222212
let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id);
223213
let (discr_did, discr_offset) = adt_def.discriminant_def_for_variant(idx);
224214

@@ -255,6 +245,10 @@ impl<'tcx> Cx<'tcx> {
255245
};
256246

257247
ExprKind::Cast { source }
248+
} else {
249+
// Default to `ExprKind::Cast` for all explicit casts.
250+
// MIR building then picks the right MIR casts based on the types.
251+
ExprKind::Cast { source: self.mirror_expr(source) }
258252
}
259253
}
260254

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

+12-7
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,27 @@
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>) {
10-
debug x => _3;
11-
let mut _4: *const &u8;
11+
debug x => _4;
12+
let mut _5: *const &u8;
1213
}
1314

1415
bb0: {
1516
StorageLive(_2);
1617
StorageLive(_3);
17-
_3 = _1;
1818
StorageLive(_4);
19-
_4 = _3;
20-
- _2 = move _4 as *const &u8 (PtrToPtr);
21-
+ _2 = move _4;
19+
_4 = _1;
20+
StorageLive(_5);
21+
_5 = _4;
22+
- _3 = move _5 as *const &u8 (PtrToPtr);
23+
+ _3 = move _5;
24+
StorageDead(_5);
2225
StorageDead(_4);
23-
StorageDead(_3);
26+
- _2 = move _3 as *const &u8 (PtrToPtr);
27+
+ _2 = move _3;
2428
_0 = _2;
29+
StorageDead(_3);
2530
StorageDead(_2);
2631
return;
2732
}

tests/mir-opt/instsimplify/casts.roundtrip.InstSimplify.diff

+10-5
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,21 @@
44
fn roundtrip(_1: *const u8) -> *const u8 {
55
debug x => _1;
66
let mut _0: *const u8;
7-
let mut _2: *mut u8;
8-
let mut _3: *const u8;
7+
let mut _2: *const u8;
8+
let mut _3: *mut u8;
9+
let mut _4: *const u8;
910

1011
bb0: {
1112
StorageLive(_2);
1213
StorageLive(_3);
13-
_3 = _1;
14-
_2 = move _3 as *mut u8 (PtrToPtr);
15-
_0 = move _2 as *const u8 (PointerCoercion(MutToConstPointer));
14+
StorageLive(_4);
15+
_4 = _1;
16+
_3 = move _4 as *mut u8 (PtrToPtr);
17+
_2 = move _3 as *const u8 (PointerCoercion(MutToConstPointer));
18+
StorageDead(_4);
1619
StorageDead(_3);
20+
- _0 = move _2 as *const u8 (PtrToPtr);
21+
+ _0 = move _2;
1722
StorageDead(_2);
1823
return;
1924
}

tests/mir-opt/instsimplify/casts.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ pub fn redundant<'a, 'b: 'a>(x: *const &'a u8) -> *const &'a u8 {
1818
// EMIT_MIR casts.roundtrip.InstSimplify.diff
1919
pub fn roundtrip(x: *const u8) -> *const u8 {
2020
// CHECK-LABEL: fn roundtrip(
21-
// CHECK: _3 = _1;
22-
// CHECK: _2 = move _3 as *mut u8 (PtrToPtr);
23-
// CHECK: _0 = move _2 as *const u8 (PointerCoercion(MutToConstPointer));
21+
// CHECK: _4 = _1;
22+
// CHECK: _3 = move _4 as *mut u8 (PtrToPtr);
23+
// CHECK: _2 = move _3 as *const u8 (PointerCoercion(MutToConstPointer));
2424
x as *mut u8 as *const u8
2525
}
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)