Skip to content

Commit d191caf

Browse files
committed
Do not merge fn pointer casts.
1 parent 8963a53 commit d191caf

File tree

5 files changed

+272
-3
lines changed

5 files changed

+272
-3
lines changed

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ use rustc_index::IndexVec;
9292
use rustc_macros::newtype_index;
9393
use rustc_middle::mir::visit::*;
9494
use rustc_middle::mir::*;
95+
use rustc_middle::ty::adjustment::PointerCoercion;
9596
use rustc_middle::ty::layout::LayoutOf;
9697
use rustc_middle::ty::{self, Ty, TyCtxt, TypeAndMut};
9798
use rustc_span::def_id::DefId;
@@ -761,6 +762,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
761762
Rvalue::Cast(kind, ref mut value, to) => {
762763
let from = value.ty(self.local_decls, self.tcx);
763764
let value = self.simplify_operand(value, location)?;
765+
if let CastKind::PointerCoercion(
766+
PointerCoercion::ReifyFnPointer | PointerCoercion::ClosureFnPointer(_),
767+
) = kind
768+
{
769+
// Each reification of a generic fn may get a different pointer.
770+
// Do not try to merge them.
771+
return self.new_opaque();
772+
}
764773
Value::Cast { kind, value, from, to }
765774
}
766775
Rvalue::BinaryOp(op, box (ref mut lhs, ref mut rhs)) => {

src/tools/miri/tests/pass/function_pointers.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,8 @@ fn main() {
8080
// but Miri currently uses a fixed address for monomorphic functions.
8181
assert!(return_fn_ptr(i) == i);
8282
assert!(return_fn_ptr(i) as unsafe fn() -> i32 == i as fn() -> i32 as unsafe fn() -> i32);
83-
// We don't check anything for `f`. Miri gives it many different addresses
84-
// but mir-opts can turn them into the same address.
85-
let _val = return_fn_ptr(f) != f;
83+
// Miri gives it many different addresses to different reifications of a generic function.
84+
assert!(return_fn_ptr(f) != f);
8685
// However, if we only turn `f` into a function pointer and use that pointer,
8786
// it is equal to itself.
8887
let f2 = f as fn() -> i32;
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
- // MIR for `fn_pointers` before GVN
2+
+ // MIR for `fn_pointers` after GVN
3+
4+
fn fn_pointers() -> () {
5+
let mut _0: ();
6+
let _1: fn(u8) -> u8;
7+
let _2: ();
8+
let mut _3: fn(u8) -> u8;
9+
let _5: ();
10+
let mut _6: fn(u8) -> u8;
11+
let mut _9: {closure@$DIR/gvn.rs:591:19: 591:21};
12+
let _10: ();
13+
let mut _11: fn();
14+
let mut _13: {closure@$DIR/gvn.rs:591:19: 591:21};
15+
let _14: ();
16+
let mut _15: fn();
17+
scope 1 {
18+
debug f => _1;
19+
let _4: fn(u8) -> u8;
20+
scope 2 {
21+
debug g => _4;
22+
let _7: {closure@$DIR/gvn.rs:591:19: 591:21};
23+
scope 3 {
24+
debug closure => _7;
25+
let _8: fn();
26+
scope 4 {
27+
debug cf => _8;
28+
let _12: fn();
29+
scope 5 {
30+
debug cg => _12;
31+
}
32+
}
33+
}
34+
}
35+
}
36+
37+
bb0: {
38+
- StorageLive(_1);
39+
+ nop;
40+
_1 = identity::<u8> as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer));
41+
StorageLive(_2);
42+
StorageLive(_3);
43+
_3 = _1;
44+
- _2 = opaque::<fn(u8) -> u8>(move _3) -> [return: bb1, unwind unreachable];
45+
+ _2 = opaque::<fn(u8) -> u8>(_1) -> [return: bb1, unwind unreachable];
46+
}
47+
48+
bb1: {
49+
StorageDead(_3);
50+
StorageDead(_2);
51+
- StorageLive(_4);
52+
+ nop;
53+
_4 = identity::<u8> as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer));
54+
StorageLive(_5);
55+
StorageLive(_6);
56+
_6 = _4;
57+
- _5 = opaque::<fn(u8) -> u8>(move _6) -> [return: bb2, unwind unreachable];
58+
+ _5 = opaque::<fn(u8) -> u8>(_4) -> [return: bb2, unwind unreachable];
59+
}
60+
61+
bb2: {
62+
StorageDead(_6);
63+
StorageDead(_5);
64+
- StorageLive(_7);
65+
- _7 = {closure@$DIR/gvn.rs:591:19: 591:21};
66+
- StorageLive(_8);
67+
+ nop;
68+
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
69+
+ nop;
70+
StorageLive(_9);
71+
- _9 = _7;
72+
- _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
73+
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
74+
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
75+
StorageDead(_9);
76+
StorageLive(_10);
77+
StorageLive(_11);
78+
_11 = _8;
79+
- _10 = opaque::<fn()>(move _11) -> [return: bb3, unwind unreachable];
80+
+ _10 = opaque::<fn()>(_8) -> [return: bb3, unwind unreachable];
81+
}
82+
83+
bb3: {
84+
StorageDead(_11);
85+
StorageDead(_10);
86+
- StorageLive(_12);
87+
+ nop;
88+
StorageLive(_13);
89+
- _13 = _7;
90+
- _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
91+
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
92+
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
93+
StorageDead(_13);
94+
StorageLive(_14);
95+
StorageLive(_15);
96+
_15 = _12;
97+
- _14 = opaque::<fn()>(move _15) -> [return: bb4, unwind unreachable];
98+
+ _14 = opaque::<fn()>(_12) -> [return: bb4, unwind unreachable];
99+
}
100+
101+
bb4: {
102+
StorageDead(_15);
103+
StorageDead(_14);
104+
_0 = const ();
105+
- StorageDead(_12);
106+
- StorageDead(_8);
107+
- StorageDead(_7);
108+
- StorageDead(_4);
109+
- StorageDead(_1);
110+
+ nop;
111+
+ nop;
112+
+ nop;
113+
+ nop;
114+
+ nop;
115+
return;
116+
}
117+
}
118+
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
- // MIR for `fn_pointers` before GVN
2+
+ // MIR for `fn_pointers` after GVN
3+
4+
fn fn_pointers() -> () {
5+
let mut _0: ();
6+
let _1: fn(u8) -> u8;
7+
let _2: ();
8+
let mut _3: fn(u8) -> u8;
9+
let _5: ();
10+
let mut _6: fn(u8) -> u8;
11+
let mut _9: {closure@$DIR/gvn.rs:591:19: 591:21};
12+
let _10: ();
13+
let mut _11: fn();
14+
let mut _13: {closure@$DIR/gvn.rs:591:19: 591:21};
15+
let _14: ();
16+
let mut _15: fn();
17+
scope 1 {
18+
debug f => _1;
19+
let _4: fn(u8) -> u8;
20+
scope 2 {
21+
debug g => _4;
22+
let _7: {closure@$DIR/gvn.rs:591:19: 591:21};
23+
scope 3 {
24+
debug closure => _7;
25+
let _8: fn();
26+
scope 4 {
27+
debug cf => _8;
28+
let _12: fn();
29+
scope 5 {
30+
debug cg => _12;
31+
}
32+
}
33+
}
34+
}
35+
}
36+
37+
bb0: {
38+
- StorageLive(_1);
39+
+ nop;
40+
_1 = identity::<u8> as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer));
41+
StorageLive(_2);
42+
StorageLive(_3);
43+
_3 = _1;
44+
- _2 = opaque::<fn(u8) -> u8>(move _3) -> [return: bb1, unwind continue];
45+
+ _2 = opaque::<fn(u8) -> u8>(_1) -> [return: bb1, unwind continue];
46+
}
47+
48+
bb1: {
49+
StorageDead(_3);
50+
StorageDead(_2);
51+
- StorageLive(_4);
52+
+ nop;
53+
_4 = identity::<u8> as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer));
54+
StorageLive(_5);
55+
StorageLive(_6);
56+
_6 = _4;
57+
- _5 = opaque::<fn(u8) -> u8>(move _6) -> [return: bb2, unwind continue];
58+
+ _5 = opaque::<fn(u8) -> u8>(_4) -> [return: bb2, unwind continue];
59+
}
60+
61+
bb2: {
62+
StorageDead(_6);
63+
StorageDead(_5);
64+
- StorageLive(_7);
65+
- _7 = {closure@$DIR/gvn.rs:591:19: 591:21};
66+
- StorageLive(_8);
67+
+ nop;
68+
+ _7 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
69+
+ nop;
70+
StorageLive(_9);
71+
- _9 = _7;
72+
- _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
73+
+ _9 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
74+
+ _8 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
75+
StorageDead(_9);
76+
StorageLive(_10);
77+
StorageLive(_11);
78+
_11 = _8;
79+
- _10 = opaque::<fn()>(move _11) -> [return: bb3, unwind continue];
80+
+ _10 = opaque::<fn()>(_8) -> [return: bb3, unwind continue];
81+
}
82+
83+
bb3: {
84+
StorageDead(_11);
85+
StorageDead(_10);
86+
- StorageLive(_12);
87+
+ nop;
88+
StorageLive(_13);
89+
- _13 = _7;
90+
- _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
91+
+ _13 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21};
92+
+ _12 = const ZeroSized: {closure@$DIR/gvn.rs:591:19: 591:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
93+
StorageDead(_13);
94+
StorageLive(_14);
95+
StorageLive(_15);
96+
_15 = _12;
97+
- _14 = opaque::<fn()>(move _15) -> [return: bb4, unwind continue];
98+
+ _14 = opaque::<fn()>(_12) -> [return: bb4, unwind continue];
99+
}
100+
101+
bb4: {
102+
StorageDead(_15);
103+
StorageDead(_14);
104+
_0 = const ();
105+
- StorageDead(_12);
106+
- StorageDead(_8);
107+
- StorageDead(_7);
108+
- StorageDead(_4);
109+
- StorageDead(_1);
110+
+ nop;
111+
+ nop;
112+
+ nop;
113+
+ nop;
114+
+ nop;
115+
return;
116+
}
117+
}
118+

tests/mir-opt/gvn.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,29 @@ fn repeat() {
574574
let array = [val, val, val, val, val, val, val, val, val, val];
575575
}
576576

577+
/// Verify that we do not merge fn pointers created by casts.
578+
fn fn_pointers() {
579+
// CHECK-LABEL: fn fn_pointers(
580+
// CHECK: [[f:_.*]] = identity::<u8> as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer
581+
// CHECK: opaque::<fn(u8) -> u8>([[f]])
582+
let f = identity as fn(u8) -> u8;
583+
opaque(f);
584+
// CHECK: [[g:_.*]] = identity::<u8> as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer
585+
// CHECK: opaque::<fn(u8) -> u8>([[g]])
586+
let g = identity as fn(u8) -> u8;
587+
opaque(g);
588+
589+
// CHECK: [[cf:_.*]] = const {{.*}} as fn() (PointerCoercion(ClosureFnPointer
590+
// CHECK: opaque::<fn()>([[cf]])
591+
let closure = || {};
592+
let cf = closure as fn();
593+
opaque(cf);
594+
// CHECK: [[cg:_.*]] = const {{.*}} as fn() (PointerCoercion(ClosureFnPointer
595+
// CHECK: opaque::<fn()>([[cg]])
596+
let cg = closure as fn();
597+
opaque(cg);
598+
}
599+
577600
fn main() {
578601
subexpression_elimination(2, 4, 5);
579602
wrap_unwrap(5);
@@ -590,6 +613,7 @@ fn main() {
590613
let (direct, indirect) = duplicate_slice();
591614
assert_eq!(direct, indirect);
592615
repeat();
616+
fn_pointers();
593617
}
594618

595619
#[inline(never)]
@@ -614,3 +638,4 @@ fn identity<T>(x: T) -> T {
614638
// EMIT_MIR gvn.slices.GVN.diff
615639
// EMIT_MIR gvn.duplicate_slice.GVN.diff
616640
// EMIT_MIR gvn.repeat.GVN.diff
641+
// EMIT_MIR gvn.fn_pointers.GVN.diff

0 commit comments

Comments
 (0)