Skip to content

Commit

Permalink
Allow closure to extern fn pointer coercion
Browse files Browse the repository at this point in the history
  • Loading branch information
jplatte committed Jun 11, 2019
1 parent 8e948df commit 4f096f4
Show file tree
Hide file tree
Showing 11 changed files with 35 additions and 17 deletions.
3 changes: 2 additions & 1 deletion src/librustc/ty/adjustment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -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,
Expand Down
15 changes: 7 additions & 8 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2420,21 +2420,20 @@ 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) => {
params.into_iter().map(|k| k.expect_ty())
}
_ => 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)
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_codegen_ssa/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/borrow_check/nll/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/monomorphize/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/transform/qualify_min_const_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
5 changes: 3 additions & 2 deletions src/librustc_typeck/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
7 changes: 7 additions & 0 deletions src/test/run-pass/typeck-closure-to-extern-c-fn-ptr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fn call_extern_c(func: extern "C" fn()) {
func()
}

pub fn main() {
call_extern_c(|| {});
}
7 changes: 7 additions & 0 deletions src/test/run-pass/typeck-closure-to-unsafe-extern-c-fn-ptr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
unsafe fn call_unsafe_extern_c(func: unsafe extern "C" fn()) {
func()
}

pub fn main() {
unsafe { call_unsafe_extern_c(|| {}); }
}

0 comments on commit 4f096f4

Please sign in to comment.