diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 857e4f66489ab..009caad51eacb 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1291,14 +1291,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Closure(..) => { Adjust::Pointer(PointerCoercion::ClosureFnPointer(a_sig.safety())) } - ty::FnDef(..) => Adjust::Pointer(PointerCoercion::ReifyFnPointer), + ty::FnDef(def_id, ..) => { + // Intrinsics are not coercible to function pointers + if self.tcx.intrinsic(def_id).is_some() { + return Err(TypeError::IntrinsicCast); + } + Adjust::Pointer(PointerCoercion::ReifyFnPointer) + } _ => span_bug!(cause.span, "should not try to coerce a {prev_ty} to a fn pointer"), }; let next_adjustment = match new_ty.kind() { ty::Closure(..) => { Adjust::Pointer(PointerCoercion::ClosureFnPointer(b_sig.safety())) } - ty::FnDef(..) => Adjust::Pointer(PointerCoercion::ReifyFnPointer), + ty::FnDef(def_id, ..) => { + // Intrinsics are not coercible to function pointers + if self.tcx.intrinsic(def_id).is_some() { + return Err(TypeError::IntrinsicCast); + } + Adjust::Pointer(PointerCoercion::ReifyFnPointer) + } _ => span_bug!(new.span, "should not try to coerce a {new_ty} to a fn pointer"), }; for expr in exprs.iter().map(|e| e.as_coercion_site()) { diff --git a/tests/ui/coercion/intrinsic-in-unifying-coercion-149143.rs b/tests/ui/coercion/intrinsic-in-unifying-coercion-149143.rs new file mode 100644 index 0000000000000..f20a491916f6d --- /dev/null +++ b/tests/ui/coercion/intrinsic-in-unifying-coercion-149143.rs @@ -0,0 +1,25 @@ +// Regression test for #149143. +// The compiler did not check for a coercion from intrinsics +// to fn ptrs in all possible code paths that could lead to such a coercion. +// This caused an ICE during a later sanity check. + +use std::mem::transmute; + +fn main() { + unsafe { + let f = if true { transmute } else { safe_transmute }; + //~^ ERROR `if` and `else` have incompatible type + + let _: i64 = f(5i64); + } + unsafe { + let f = if true { safe_transmute } else { transmute }; + //~^ ERROR `if` and `else` have incompatible type + + let _: i64 = f(5i64); + } +} + +unsafe fn safe_transmute(x: A) -> B { + panic!() +} diff --git a/tests/ui/coercion/intrinsic-in-unifying-coercion-149143.stderr b/tests/ui/coercion/intrinsic-in-unifying-coercion-149143.stderr new file mode 100644 index 0000000000000..43fc194deea2b --- /dev/null +++ b/tests/ui/coercion/intrinsic-in-unifying-coercion-149143.stderr @@ -0,0 +1,27 @@ +error[E0308]: `if` and `else` have incompatible types + --> $DIR/intrinsic-in-unifying-coercion-149143.rs:10:46 + | +LL | let f = if true { transmute } else { safe_transmute }; + | --------- ^^^^^^^^^^^^^^ cannot coerce intrinsics to function pointers + | | + | expected because of this + | + = note: expected fn item `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` + found fn item `unsafe fn(_) -> _ {safe_transmute::<_, _>}` + = note: different fn items have unique types, even if their signatures are the same + +error[E0308]: `if` and `else` have incompatible types + --> $DIR/intrinsic-in-unifying-coercion-149143.rs:16:51 + | +LL | let f = if true { safe_transmute } else { transmute }; + | -------------- ^^^^^^^^^ cannot coerce intrinsics to function pointers + | | + | expected because of this + | + = note: expected fn item `unsafe fn(_) -> _ {safe_transmute::<_, _>}` + found fn item `unsafe fn(_) -> _ {std::intrinsics::transmute::<_, _>}` + = note: different fn items have unique types, even if their signatures are the same + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`.