Allow closure to unsafe fn coercion
This commit is contained in:
parent
cee58fdc12
commit
07021e07ed
19 changed files with 50 additions and 27 deletions
|
@ -707,7 +707,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
|
||||||
adjustment::Adjust::NeverToAny |
|
adjustment::Adjust::NeverToAny |
|
||||||
adjustment::Adjust::ReifyFnPointer |
|
adjustment::Adjust::ReifyFnPointer |
|
||||||
adjustment::Adjust::UnsafeFnPointer |
|
adjustment::Adjust::UnsafeFnPointer |
|
||||||
adjustment::Adjust::ClosureFnPointer |
|
adjustment::Adjust::ClosureFnPointer(_) |
|
||||||
adjustment::Adjust::MutToConstPointer |
|
adjustment::Adjust::MutToConstPointer |
|
||||||
adjustment::Adjust::Unsize => {
|
adjustment::Adjust::Unsize => {
|
||||||
// Creating a closure/fn-pointer or unsizing consumes
|
// Creating a closure/fn-pointer or unsizing consumes
|
||||||
|
|
|
@ -621,7 +621,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
|
||||||
adjustment::Adjust::NeverToAny |
|
adjustment::Adjust::NeverToAny |
|
||||||
adjustment::Adjust::ReifyFnPointer |
|
adjustment::Adjust::ReifyFnPointer |
|
||||||
adjustment::Adjust::UnsafeFnPointer |
|
adjustment::Adjust::UnsafeFnPointer |
|
||||||
adjustment::Adjust::ClosureFnPointer |
|
adjustment::Adjust::ClosureFnPointer(_) |
|
||||||
adjustment::Adjust::MutToConstPointer |
|
adjustment::Adjust::MutToConstPointer |
|
||||||
adjustment::Adjust::Borrow(_) |
|
adjustment::Adjust::Borrow(_) |
|
||||||
adjustment::Adjust::Unsize => {
|
adjustment::Adjust::Unsize => {
|
||||||
|
|
|
@ -2247,8 +2247,9 @@ pub enum CastKind {
|
||||||
/// Converts unique, zero-sized type for a fn to fn()
|
/// Converts unique, zero-sized type for a fn to fn()
|
||||||
ReifyFnPointer,
|
ReifyFnPointer,
|
||||||
|
|
||||||
/// Converts non capturing closure to fn()
|
/// Converts non capturing closure to fn() or unsafe fn().
|
||||||
ClosureFnPointer,
|
/// It cannot convert a closure that requires unsafe.
|
||||||
|
ClosureFnPointer(hir::Unsafety),
|
||||||
|
|
||||||
/// Converts safe fn() to unsafe fn()
|
/// Converts safe fn() to unsafe fn()
|
||||||
UnsafeFnPointer,
|
UnsafeFnPointer,
|
||||||
|
|
|
@ -62,8 +62,9 @@ pub enum Adjust<'tcx> {
|
||||||
/// Go from a safe fn pointer to an unsafe fn pointer.
|
/// Go from a safe fn pointer to an unsafe fn pointer.
|
||||||
UnsafeFnPointer,
|
UnsafeFnPointer,
|
||||||
|
|
||||||
/// Go from a non-capturing closure to an fn pointer.
|
/// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer.
|
||||||
ClosureFnPointer,
|
/// It cannot convert a closure that requires unsafe.
|
||||||
|
ClosureFnPointer(hir::Unsafety),
|
||||||
|
|
||||||
/// Go from a mut raw pointer to a const raw pointer.
|
/// Go from a mut raw pointer to a const raw pointer.
|
||||||
MutToConstPointer,
|
MutToConstPointer,
|
||||||
|
|
|
@ -2441,7 +2441,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
/// type with the same signature. Detuples and so forth -- so
|
/// type with the same signature. Detuples and so forth -- so
|
||||||
/// e.g., if we have a sig with `Fn<(u32, i32)>` then you would get
|
/// e.g., if we have a sig with `Fn<(u32, i32)>` then you would get
|
||||||
/// a `fn(u32, i32)`.
|
/// a `fn(u32, i32)`.
|
||||||
pub fn coerce_closure_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
|
/// `unsafety` determines the unsafety of the `fn` type. If you pass
|
||||||
|
/// `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> {
|
||||||
let converted_sig = sig.map_bound(|s| {
|
let converted_sig = sig.map_bound(|s| {
|
||||||
let params_iter = match s.inputs()[0].sty {
|
let params_iter = match s.inputs()[0].sty {
|
||||||
ty::Tuple(params) => {
|
ty::Tuple(params) => {
|
||||||
|
@ -2453,7 +2457,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
params_iter,
|
params_iter,
|
||||||
s.output(),
|
s.output(),
|
||||||
s.c_variadic,
|
s.c_variadic,
|
||||||
hir::Unsafety::Normal,
|
unsafety,
|
||||||
abi::Abi::Rust,
|
abi::Abi::Rust,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
|
@ -630,8 +630,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> {
|
||||||
Some(ty::adjustment::Adjust::ReifyFnPointer),
|
Some(ty::adjustment::Adjust::ReifyFnPointer),
|
||||||
ty::adjustment::Adjust::UnsafeFnPointer =>
|
ty::adjustment::Adjust::UnsafeFnPointer =>
|
||||||
Some(ty::adjustment::Adjust::UnsafeFnPointer),
|
Some(ty::adjustment::Adjust::UnsafeFnPointer),
|
||||||
ty::adjustment::Adjust::ClosureFnPointer =>
|
ty::adjustment::Adjust::ClosureFnPointer(unsafety) =>
|
||||||
Some(ty::adjustment::Adjust::ClosureFnPointer),
|
Some(ty::adjustment::Adjust::ClosureFnPointer(unsafety)),
|
||||||
ty::adjustment::Adjust::MutToConstPointer =>
|
ty::adjustment::Adjust::MutToConstPointer =>
|
||||||
Some(ty::adjustment::Adjust::MutToConstPointer),
|
Some(ty::adjustment::Adjust::MutToConstPointer),
|
||||||
ty::adjustment::Adjust::Unsize =>
|
ty::adjustment::Adjust::Unsize =>
|
||||||
|
@ -1187,7 +1187,7 @@ EnumTypeFoldableImpl! {
|
||||||
(ty::adjustment::Adjust::NeverToAny),
|
(ty::adjustment::Adjust::NeverToAny),
|
||||||
(ty::adjustment::Adjust::ReifyFnPointer),
|
(ty::adjustment::Adjust::ReifyFnPointer),
|
||||||
(ty::adjustment::Adjust::UnsafeFnPointer),
|
(ty::adjustment::Adjust::UnsafeFnPointer),
|
||||||
(ty::adjustment::Adjust::ClosureFnPointer),
|
(ty::adjustment::Adjust::ClosureFnPointer)(a),
|
||||||
(ty::adjustment::Adjust::MutToConstPointer),
|
(ty::adjustment::Adjust::MutToConstPointer),
|
||||||
(ty::adjustment::Adjust::Unsize),
|
(ty::adjustment::Adjust::Unsize),
|
||||||
(ty::adjustment::Adjust::Deref)(a),
|
(ty::adjustment::Adjust::Deref)(a),
|
||||||
|
|
|
@ -193,7 +193,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mir::CastKind::ClosureFnPointer => {
|
mir::CastKind::ClosureFnPointer(_) => {
|
||||||
match operand.layout.ty.sty {
|
match operand.layout.ty.sty {
|
||||||
ty::Closure(def_id, substs) => {
|
ty::Closure(def_id, substs) => {
|
||||||
let instance = monomorphize::resolve_closure(
|
let instance = monomorphize::resolve_closure(
|
||||||
|
|
|
@ -1999,14 +1999,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CastKind::ClosureFnPointer => {
|
CastKind::ClosureFnPointer(unsafety) => {
|
||||||
let sig = match op.ty(mir, tcx).sty {
|
let sig = match op.ty(mir, tcx).sty {
|
||||||
ty::Closure(def_id, substs) => {
|
ty::Closure(def_id, substs) => {
|
||||||
substs.closure_sig_ty(def_id, tcx).fn_sig(tcx)
|
substs.closure_sig_ty(def_id, tcx).fn_sig(tcx)
|
||||||
}
|
}
|
||||||
_ => bug!(),
|
_ => bug!(),
|
||||||
};
|
};
|
||||||
let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig);
|
let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig, *unsafety);
|
||||||
|
|
||||||
if let Err(terr) = self.eq_types(
|
if let Err(terr) = self.eq_types(
|
||||||
ty_fn_ptr_from,
|
ty_fn_ptr_from,
|
||||||
|
|
|
@ -162,9 +162,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
||||||
let source = unpack!(block = this.as_operand(block, scope, source));
|
let source = unpack!(block = this.as_operand(block, scope, source));
|
||||||
block.and(Rvalue::Cast(CastKind::UnsafeFnPointer, source, expr.ty))
|
block.and(Rvalue::Cast(CastKind::UnsafeFnPointer, source, expr.ty))
|
||||||
}
|
}
|
||||||
ExprKind::ClosureFnPointer { source } => {
|
ExprKind::ClosureFnPointer { source, unsafety } => {
|
||||||
let source = unpack!(block = this.as_operand(block, scope, source));
|
let source = unpack!(block = this.as_operand(block, scope, source));
|
||||||
block.and(Rvalue::Cast(CastKind::ClosureFnPointer, source, expr.ty))
|
block.and(Rvalue::Cast(CastKind::ClosureFnPointer(unsafety), source, expr.ty))
|
||||||
}
|
}
|
||||||
ExprKind::MutToConstPointer { source } => {
|
ExprKind::MutToConstPointer { source } => {
|
||||||
let source = unpack!(block = this.as_operand(block, scope, source));
|
let source = unpack!(block = this.as_operand(block, scope, source));
|
||||||
|
|
|
@ -81,8 +81,8 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
|
||||||
Adjust::UnsafeFnPointer => {
|
Adjust::UnsafeFnPointer => {
|
||||||
ExprKind::UnsafeFnPointer { source: expr.to_ref() }
|
ExprKind::UnsafeFnPointer { source: expr.to_ref() }
|
||||||
}
|
}
|
||||||
Adjust::ClosureFnPointer => {
|
Adjust::ClosureFnPointer(unsafety) => {
|
||||||
ExprKind::ClosureFnPointer { source: expr.to_ref() }
|
ExprKind::ClosureFnPointer { source: expr.to_ref(), unsafety }
|
||||||
}
|
}
|
||||||
Adjust::NeverToAny => {
|
Adjust::NeverToAny => {
|
||||||
ExprKind::NeverToAny { source: expr.to_ref() }
|
ExprKind::NeverToAny { source: expr.to_ref() }
|
||||||
|
|
|
@ -185,6 +185,7 @@ pub enum ExprKind<'tcx> {
|
||||||
},
|
},
|
||||||
ClosureFnPointer {
|
ClosureFnPointer {
|
||||||
source: ExprRef<'tcx>,
|
source: ExprRef<'tcx>,
|
||||||
|
unsafety: hir::Unsafety,
|
||||||
},
|
},
|
||||||
UnsafeFnPointer {
|
UnsafeFnPointer {
|
||||||
source: ExprRef<'tcx>,
|
source: ExprRef<'tcx>,
|
||||||
|
|
|
@ -105,7 +105,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ClosureFnPointer => {
|
ClosureFnPointer(_) => {
|
||||||
// The src operand does not matter, just its type
|
// The src operand does not matter, just its type
|
||||||
match src.layout.ty.sty {
|
match src.layout.ty.sty {
|
||||||
ty::Closure(def_id, substs) => {
|
ty::Closure(def_id, substs) => {
|
||||||
|
|
|
@ -563,7 +563,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
visit_fn_use(self.tcx, fn_ty, false, &mut self.output);
|
visit_fn_use(self.tcx, fn_ty, false, &mut self.output);
|
||||||
}
|
}
|
||||||
mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => {
|
mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer(_), ref operand, _) => {
|
||||||
let source_ty = operand.ty(self.mir, self.tcx);
|
let source_ty = operand.ty(self.mir, self.tcx);
|
||||||
let source_ty = self.tcx.subst_and_normalize_erasing_regions(
|
let source_ty = self.tcx.subst_and_normalize_erasing_regions(
|
||||||
self.param_substs,
|
self.param_substs,
|
||||||
|
|
|
@ -1105,7 +1105,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
||||||
Rvalue::CheckedBinaryOp(..) |
|
Rvalue::CheckedBinaryOp(..) |
|
||||||
Rvalue::Cast(CastKind::ReifyFnPointer, ..) |
|
Rvalue::Cast(CastKind::ReifyFnPointer, ..) |
|
||||||
Rvalue::Cast(CastKind::UnsafeFnPointer, ..) |
|
Rvalue::Cast(CastKind::UnsafeFnPointer, ..) |
|
||||||
Rvalue::Cast(CastKind::ClosureFnPointer, ..) |
|
Rvalue::Cast(CastKind::ClosureFnPointer(_), ..) |
|
||||||
Rvalue::Cast(CastKind::Unsize, ..) |
|
Rvalue::Cast(CastKind::Unsize, ..) |
|
||||||
Rvalue::Cast(CastKind::MutToConstPointer, ..) |
|
Rvalue::Cast(CastKind::MutToConstPointer, ..) |
|
||||||
Rvalue::Discriminant(..) |
|
Rvalue::Discriminant(..) |
|
||||||
|
|
|
@ -156,7 +156,7 @@ fn check_rvalue(
|
||||||
check_operand(tcx, mir, operand, span)
|
check_operand(tcx, mir, operand, span)
|
||||||
}
|
}
|
||||||
Rvalue::Cast(CastKind::UnsafeFnPointer, _, _) |
|
Rvalue::Cast(CastKind::UnsafeFnPointer, _, _) |
|
||||||
Rvalue::Cast(CastKind::ClosureFnPointer, _, _) |
|
Rvalue::Cast(CastKind::ClosureFnPointer(_), _, _) |
|
||||||
Rvalue::Cast(CastKind::ReifyFnPointer, _, _) => Err((
|
Rvalue::Cast(CastKind::ReifyFnPointer, _, _) => Err((
|
||||||
span,
|
span,
|
||||||
"function pointer casts are not allowed in const fn".into(),
|
"function pointer casts are not allowed in const fn".into(),
|
||||||
|
|
|
@ -586,7 +586,7 @@ fn check_adjustments<'a, 'tcx>(
|
||||||
Adjust::NeverToAny |
|
Adjust::NeverToAny |
|
||||||
Adjust::ReifyFnPointer |
|
Adjust::ReifyFnPointer |
|
||||||
Adjust::UnsafeFnPointer |
|
Adjust::UnsafeFnPointer |
|
||||||
Adjust::ClosureFnPointer |
|
Adjust::ClosureFnPointer(_) |
|
||||||
Adjust::MutToConstPointer |
|
Adjust::MutToConstPointer |
|
||||||
Adjust::Borrow(_) |
|
Adjust::Borrow(_) |
|
||||||
Adjust::Unsize => {}
|
Adjust::Unsize => {}
|
||||||
|
|
|
@ -225,7 +225,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
ty::Closure(def_id_a, substs_a) => {
|
ty::Closure(def_id_a, substs_a) => {
|
||||||
// Non-capturing closures are coercible to
|
// Non-capturing closures are coercible to
|
||||||
// function pointers
|
// function pointers or unsafe function pointers.
|
||||||
|
// It cannot convert closures that require unsafe.
|
||||||
self.coerce_closure_to_fn(a, def_id_a, substs_a, b)
|
self.coerce_closure_to_fn(a, def_id_a, substs_a, b)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -714,16 +715,19 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
|
||||||
|
|
||||||
let hir_id_a = self.tcx.hir().as_local_hir_id(def_id_a).unwrap();
|
let hir_id_a = self.tcx.hir().as_local_hir_id(def_id_a).unwrap();
|
||||||
match b.sty {
|
match b.sty {
|
||||||
ty::FnPtr(_) if self.tcx.with_freevars(hir_id_a, |v| v.is_empty()) => {
|
ty::FnPtr(fn_ty) if self.tcx.with_freevars(hir_id_a, |v| v.is_empty()) => {
|
||||||
// We coerce the closure, which has fn type
|
// We coerce the closure, which has fn type
|
||||||
// `extern "rust-call" fn((arg0,arg1,...)) -> _`
|
// `extern "rust-call" fn((arg0,arg1,...)) -> _`
|
||||||
// to
|
// to
|
||||||
// `fn(arg0,arg1,...) -> _`
|
// `fn(arg0,arg1,...) -> _`
|
||||||
|
// or
|
||||||
|
// `unsafe fn(arg0,arg1,...) -> _`
|
||||||
let sig = self.closure_sig(def_id_a, substs_a);
|
let sig = self.closure_sig(def_id_a, substs_a);
|
||||||
let pointer_ty = self.tcx.coerce_closure_fn_ty(sig);
|
let unsafety = fn_ty.unsafety();
|
||||||
|
let pointer_ty = self.tcx.coerce_closure_fn_ty(sig, unsafety);
|
||||||
debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})",
|
debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})",
|
||||||
a, b, pointer_ty);
|
a, b, pointer_ty);
|
||||||
self.unify_and(pointer_ty, b, simple(Adjust::ClosureFnPointer))
|
self.unify_and(pointer_ty, b, simple(Adjust::ClosureFnPointer(unsafety)))
|
||||||
}
|
}
|
||||||
_ => self.unify_and(a, b, identity),
|
_ => self.unify_and(a, b, identity),
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
fn main() {
|
||||||
|
let _: unsafe fn() = || { ::std::pin::Pin::new_unchecked(&0_u8); };
|
||||||
|
//~^ ERROR E0133
|
||||||
|
let _: unsafe fn() = || unsafe { ::std::pin::Pin::new_unchecked(&0_u8); }; // OK
|
||||||
|
}
|
7
src/test/run-pass/typeck-closure-to-unsafe-fn-ptr.rs
Normal file
7
src/test/run-pass/typeck-closure-to-unsafe-fn-ptr.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
unsafe fn call_unsafe(func: unsafe fn() -> ()) -> () {
|
||||||
|
func()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
unsafe { call_unsafe(|| {}); }
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue