Skip to content

Commit ebf1c38

Browse files
committed
Check for intrinsic to fn ptr casts in unified coercions
Ensures that when coercing multiple expressions to a unified type, the same "intrinsic to fn ptr" check is applied as for other coercions.
1 parent 2c0f486 commit ebf1c38

File tree

3 files changed

+66
-2
lines changed

3 files changed

+66
-2
lines changed

compiler/rustc_hir_typeck/src/coercion.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,14 +1291,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12911291
ty::Closure(..) => {
12921292
Adjust::Pointer(PointerCoercion::ClosureFnPointer(a_sig.safety()))
12931293
}
1294-
ty::FnDef(..) => Adjust::Pointer(PointerCoercion::ReifyFnPointer),
1294+
ty::FnDef(def_id, ..) => {
1295+
// Intrinsics are not coercible to function pointers
1296+
if self.tcx.intrinsic(def_id).is_some() {
1297+
return Err(TypeError::IntrinsicCast);
1298+
}
1299+
Adjust::Pointer(PointerCoercion::ReifyFnPointer)
1300+
}
12951301
_ => span_bug!(cause.span, "should not try to coerce a {prev_ty} to a fn pointer"),
12961302
};
12971303
let next_adjustment = match new_ty.kind() {
12981304
ty::Closure(..) => {
12991305
Adjust::Pointer(PointerCoercion::ClosureFnPointer(b_sig.safety()))
13001306
}
1301-
ty::FnDef(..) => Adjust::Pointer(PointerCoercion::ReifyFnPointer),
1307+
ty::FnDef(def_id, ..) => {
1308+
// Intrinsics are not coercible to function pointers
1309+
if self.tcx.intrinsic(def_id).is_some() {
1310+
return Err(TypeError::IntrinsicCast);
1311+
}
1312+
Adjust::Pointer(PointerCoercion::ReifyFnPointer)
1313+
}
13021314
_ => span_bug!(new.span, "should not try to coerce a {new_ty} to a fn pointer"),
13031315
};
13041316
for expr in exprs.iter().map(|e| e.as_coercion_site()) {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Regression test for #149143.
2+
// The compiler did not check for a coercion from intrinsics
3+
// to fn ptrs in all possible code paths that could lead to such a coercion.
4+
// This caused an ICE during a later sanity check.
5+
6+
use std::mem::transmute;
7+
8+
fn main() {
9+
unsafe {
10+
let f = if true { transmute } else { safe_transmute };
11+
//~^ ERROR `if` and `else` have incompatible type
12+
13+
let _: i64 = f(5i64);
14+
}
15+
unsafe {
16+
let f = if true { safe_transmute } else { transmute };
17+
//~^ ERROR `if` and `else` have incompatible type
18+
19+
let _: i64 = f(5i64);
20+
}
21+
}
22+
23+
unsafe fn safe_transmute<A, B>(x: A) -> B {
24+
panic!()
25+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0308]: `if` and `else` have incompatible types
2+
--> $DIR/intrinsic-in-unifying-coercion-149143.rs:10:46
3+
|
4+
LL | let f = if true { transmute } else { safe_transmute };
5+
| --------- ^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers
6+
| |
7+
| expected because of this
8+
|
9+
= note: expected fn item `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}`
10+
found fn item `unsafe fn(_) -> _ {safe_transmute::<_, _>}`
11+
= note: different fn items have unique types, even if their signatures are the same
12+
13+
error[E0308]: `if` and `else` have incompatible types
14+
--> $DIR/intrinsic-in-unifying-coercion-149143.rs:16:51
15+
|
16+
LL | let f = if true { safe_transmute } else { transmute };
17+
| -------------- ^^^^^^^^^ cannot coerce intrinsics to function pointers
18+
| |
19+
| expected because of this
20+
|
21+
= note: expected fn item `unsafe fn(_) -> _ {safe_transmute::<_, _>}`
22+
found fn item `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}`
23+
= note: different fn items have unique types, even if their signatures are the same
24+
25+
error: aborting due to 2 previous errors
26+
27+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)