From 4f096f4ee03e0211c776f918f4b5bf895f43cf25 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 4 Jun 2019 22:59:59 +0200 Subject: [PATCH] Allow closure to extern fn pointer coercion --- src/librustc/ty/adjustment.rs | 3 ++- src/librustc/ty/context.rs | 15 +++++++-------- src/librustc_codegen_ssa/mir/rvalue.rs | 2 +- .../borrow_check/nll/type_check/mod.rs | 4 ++-- src/librustc_mir/interpret/cast.rs | 2 +- src/librustc_mir/monomorphize/collector.rs | 2 +- .../transform/qualify_min_const_fn.rs | 2 +- src/librustc_typeck/check/coercion.rs | 5 +++-- .../coerce-unsafe-closure-to-unsafe-fn-ptr.rs | 3 +++ .../run-pass/typeck-closure-to-extern-c-fn-ptr.rs | 7 +++++++ .../typeck-closure-to-unsafe-extern-c-fn-ptr.rs | 7 +++++++ 11 files changed, 35 insertions(+), 17 deletions(-) create mode 100644 src/test/run-pass/typeck-closure-to-extern-c-fn-ptr.rs create mode 100644 src/test/run-pass/typeck-closure-to-unsafe-extern-c-fn-ptr.rs diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 11aad87b70dd3..4ed97d64d9cf9 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -3,6 +3,7 @@ use crate::hir::def_id::DefId; use crate::ty::{self, Ty, TyCtxt}; use crate::ty::subst::SubstsRef; use rustc_macros::HashStable; +use rustc_target::spec::abi; #[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable)] @@ -15,7 +16,7 @@ pub enum PointerCast { /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer. /// It cannot convert a closure that requires unsafe. - ClosureFnPointer(hir::Unsafety), + ClosureFnPointer(hir::Unsafety, abi::Abi), /// Go from a mut raw pointer to a const raw pointer. MutToConstPointer, diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e60022033cc54..f4f90c109280c 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2420,7 +2420,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// `hir::Unsafety::Unsafe` in the previous example, then you would get /// an `unsafe fn (u32, i32)`. /// It cannot convert a closure that requires unsafe. - pub fn coerce_closure_fn_ty(self, sig: PolyFnSig<'tcx>, unsafety: hir::Unsafety) -> Ty<'tcx> { + pub fn coerce_closure_fn_ty( + self, + sig: PolyFnSig<'tcx>, + unsafety: hir::Unsafety, + abi: abi::Abi, + ) -> Ty<'tcx> { let converted_sig = sig.map_bound(|s| { let params_iter = match s.inputs()[0].sty { ty::Tuple(params) => { @@ -2428,13 +2433,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } _ => bug!(), }; - self.mk_fn_sig( - params_iter, - s.output(), - s.c_variadic, - unsafety, - abi::Abi::Rust, - ) + self.mk_fn_sig(params_iter, s.output(), s.c_variadic, unsafety, abi) }); self.mk_fn_ptr(converted_sig) diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 7a2bd18df4ec9..1764d71df71d8 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -192,7 +192,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } - mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)) => { + mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_, _)) => { match operand.layout.ty.sty { ty::Closure(def_id, substs) => { let instance = Instance::resolve_closure( diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index d6da42c24cee4..7c3a8b24667fe 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -2011,14 +2011,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - CastKind::Pointer(PointerCast::ClosureFnPointer(unsafety)) => { + CastKind::Pointer(PointerCast::ClosureFnPointer(unsafety, abi)) => { let sig = match op.ty(body, tcx).sty { ty::Closure(def_id, substs) => { substs.closure_sig_ty(def_id, tcx).fn_sig(tcx) } _ => bug!(), }; - let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig, *unsafety); + let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig, *unsafety, *abi); if let Err(terr) = self.eq_types( ty_fn_ptr_from, diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 6392e0996aec2..ac5e0a928620d 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -104,7 +104,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> } } - Pointer(PointerCast::ClosureFnPointer(_)) => { + Pointer(PointerCast::ClosureFnPointer(_, _)) => { // The src operand does not matter, just its type match src.layout.ty.sty { ty::Closure(def_id, substs) => { diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index f084919ac057c..b74a034e56a8f 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -569,7 +569,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { visit_fn_use(self.tcx, fn_ty, false, &mut self.output); } mir::Rvalue::Cast( - mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)), ref operand, _ + mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_, _)), ref operand, _ ) => { let source_ty = operand.ty(self.body, self.tcx); let source_ty = self.tcx.subst_and_normalize_erasing_regions( diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index f96675864562f..ad22e1b0049d2 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -160,7 +160,7 @@ fn check_rvalue( check_operand(operand, span) } Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), _, _) | - Rvalue::Cast(CastKind::Pointer(PointerCast::ClosureFnPointer(_)), _, _) | + Rvalue::Cast(CastKind::Pointer(PointerCast::ClosureFnPointer(_, _)), _, _) | Rvalue::Cast(CastKind::Pointer(PointerCast::ReifyFnPointer), _, _) => Err(( span, "function pointer casts are not allowed in const fn".into(), diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index f95021f0cb088..28d592f777fd6 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -739,11 +739,12 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // `unsafe fn(arg0,arg1,...) -> _` let sig = self.closure_sig(def_id_a, substs_a); let unsafety = fn_ty.unsafety(); - let pointer_ty = self.tcx.coerce_closure_fn_ty(sig, unsafety); + let abi = fn_ty.abi(); + let pointer_ty = self.tcx.coerce_closure_fn_ty(sig, unsafety, abi); debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty); self.unify_and(pointer_ty, b, simple( - Adjust::Pointer(PointerCast::ClosureFnPointer(unsafety)) + Adjust::Pointer(PointerCast::ClosureFnPointer(unsafety, abi)) )) } _ => self.unify_and(a, b, identity), diff --git a/src/test/compile-fail/coerce-unsafe-closure-to-unsafe-fn-ptr.rs b/src/test/compile-fail/coerce-unsafe-closure-to-unsafe-fn-ptr.rs index 36777693faba0..f7345826da8cf 100644 --- a/src/test/compile-fail/coerce-unsafe-closure-to-unsafe-fn-ptr.rs +++ b/src/test/compile-fail/coerce-unsafe-closure-to-unsafe-fn-ptr.rs @@ -1,5 +1,8 @@ fn main() { let _: unsafe fn() = || { ::std::pin::Pin::new_unchecked(&0_u8); }; //~^ ERROR E0133 + let _: unsafe extern "C" fn() = || { ::std::pin::Pin::new_unchecked(&0_u8); }; + //~^ ERROR E0133 let _: unsafe fn() = || unsafe { ::std::pin::Pin::new_unchecked(&0_u8); }; // OK + let _: unsafe extern "C" fn() = || unsafe { ::std::pin::Pin::new_unchecked(&0_u8); }; // OK } diff --git a/src/test/run-pass/typeck-closure-to-extern-c-fn-ptr.rs b/src/test/run-pass/typeck-closure-to-extern-c-fn-ptr.rs new file mode 100644 index 0000000000000..277ff7adaeedb --- /dev/null +++ b/src/test/run-pass/typeck-closure-to-extern-c-fn-ptr.rs @@ -0,0 +1,7 @@ +fn call_extern_c(func: extern "C" fn()) { + func() +} + +pub fn main() { + call_extern_c(|| {}); +} diff --git a/src/test/run-pass/typeck-closure-to-unsafe-extern-c-fn-ptr.rs b/src/test/run-pass/typeck-closure-to-unsafe-extern-c-fn-ptr.rs new file mode 100644 index 0000000000000..f252e45389e68 --- /dev/null +++ b/src/test/run-pass/typeck-closure-to-unsafe-extern-c-fn-ptr.rs @@ -0,0 +1,7 @@ +unsafe fn call_unsafe_extern_c(func: unsafe extern "C" fn()) { + func() +} + +pub fn main() { + unsafe { call_unsafe_extern_c(|| {}); } +}