Skip to content

Commit 1909a03

Browse files
authored
Rollup merge of #59580 - taiki-e:coerce-closure, r=oli-obk
Allow closure to unsafe fn coercion Closes #57883
2 parents 0171fe5 + 07021e0 commit 1909a03

File tree

19 files changed

+50
-27
lines changed

19 files changed

+50
-27
lines changed

src/librustc/middle/expr_use_visitor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
707707
adjustment::Adjust::NeverToAny |
708708
adjustment::Adjust::ReifyFnPointer |
709709
adjustment::Adjust::UnsafeFnPointer |
710-
adjustment::Adjust::ClosureFnPointer |
710+
adjustment::Adjust::ClosureFnPointer(_) |
711711
adjustment::Adjust::MutToConstPointer |
712712
adjustment::Adjust::Unsize => {
713713
// Creating a closure/fn-pointer or unsizing consumes

src/librustc/middle/mem_categorization.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
621621
adjustment::Adjust::NeverToAny |
622622
adjustment::Adjust::ReifyFnPointer |
623623
adjustment::Adjust::UnsafeFnPointer |
624-
adjustment::Adjust::ClosureFnPointer |
624+
adjustment::Adjust::ClosureFnPointer(_) |
625625
adjustment::Adjust::MutToConstPointer |
626626
adjustment::Adjust::Borrow(_) |
627627
adjustment::Adjust::Unsize => {

src/librustc/mir/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -2247,8 +2247,9 @@ pub enum CastKind {
22472247
/// Converts unique, zero-sized type for a fn to fn()
22482248
ReifyFnPointer,
22492249

2250-
/// Converts non capturing closure to fn()
2251-
ClosureFnPointer,
2250+
/// Converts non capturing closure to fn() or unsafe fn().
2251+
/// It cannot convert a closure that requires unsafe.
2252+
ClosureFnPointer(hir::Unsafety),
22522253

22532254
/// Converts safe fn() to unsafe fn()
22542255
UnsafeFnPointer,

src/librustc/ty/adjustment.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,9 @@ pub enum Adjust<'tcx> {
6262
/// Go from a safe fn pointer to an unsafe fn pointer.
6363
UnsafeFnPointer,
6464

65-
/// Go from a non-capturing closure to an fn pointer.
66-
ClosureFnPointer,
65+
/// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer.
66+
/// It cannot convert a closure that requires unsafe.
67+
ClosureFnPointer(hir::Unsafety),
6768

6869
/// Go from a mut raw pointer to a const raw pointer.
6970
MutToConstPointer,

src/librustc/ty/context.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -2441,7 +2441,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
24412441
/// type with the same signature. Detuples and so forth -- so
24422442
/// e.g., if we have a sig with `Fn<(u32, i32)>` then you would get
24432443
/// a `fn(u32, i32)`.
2444-
pub fn coerce_closure_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
2444+
/// `unsafety` determines the unsafety of the `fn` type. If you pass
2445+
/// `hir::Unsafety::Unsafe` in the previous example, then you would get
2446+
/// an `unsafe fn (u32, i32)`.
2447+
/// It cannot convert a closure that requires unsafe.
2448+
pub fn coerce_closure_fn_ty(self, sig: PolyFnSig<'tcx>, unsafety: hir::Unsafety) -> Ty<'tcx> {
24452449
let converted_sig = sig.map_bound(|s| {
24462450
let params_iter = match s.inputs()[0].sty {
24472451
ty::Tuple(params) => {
@@ -2453,7 +2457,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
24532457
params_iter,
24542458
s.output(),
24552459
s.c_variadic,
2456-
hir::Unsafety::Normal,
2460+
unsafety,
24572461
abi::Abi::Rust,
24582462
)
24592463
});

src/librustc/ty/structural_impls.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -630,8 +630,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> {
630630
Some(ty::adjustment::Adjust::ReifyFnPointer),
631631
ty::adjustment::Adjust::UnsafeFnPointer =>
632632
Some(ty::adjustment::Adjust::UnsafeFnPointer),
633-
ty::adjustment::Adjust::ClosureFnPointer =>
634-
Some(ty::adjustment::Adjust::ClosureFnPointer),
633+
ty::adjustment::Adjust::ClosureFnPointer(unsafety) =>
634+
Some(ty::adjustment::Adjust::ClosureFnPointer(unsafety)),
635635
ty::adjustment::Adjust::MutToConstPointer =>
636636
Some(ty::adjustment::Adjust::MutToConstPointer),
637637
ty::adjustment::Adjust::Unsize =>
@@ -1187,7 +1187,7 @@ EnumTypeFoldableImpl! {
11871187
(ty::adjustment::Adjust::NeverToAny),
11881188
(ty::adjustment::Adjust::ReifyFnPointer),
11891189
(ty::adjustment::Adjust::UnsafeFnPointer),
1190-
(ty::adjustment::Adjust::ClosureFnPointer),
1190+
(ty::adjustment::Adjust::ClosureFnPointer)(a),
11911191
(ty::adjustment::Adjust::MutToConstPointer),
11921192
(ty::adjustment::Adjust::Unsize),
11931193
(ty::adjustment::Adjust::Deref)(a),

src/librustc_codegen_ssa/mir/rvalue.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
193193
}
194194
}
195195
}
196-
mir::CastKind::ClosureFnPointer => {
196+
mir::CastKind::ClosureFnPointer(_) => {
197197
match operand.layout.ty.sty {
198198
ty::Closure(def_id, substs) => {
199199
let instance = monomorphize::resolve_closure(

src/librustc_mir/borrow_check/nll/type_check/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1999,14 +1999,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
19991999
}
20002000
}
20012001

2002-
CastKind::ClosureFnPointer => {
2002+
CastKind::ClosureFnPointer(unsafety) => {
20032003
let sig = match op.ty(mir, tcx).sty {
20042004
ty::Closure(def_id, substs) => {
20052005
substs.closure_sig_ty(def_id, tcx).fn_sig(tcx)
20062006
}
20072007
_ => bug!(),
20082008
};
2009-
let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig);
2009+
let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig, *unsafety);
20102010

20112011
if let Err(terr) = self.eq_types(
20122012
ty_fn_ptr_from,

src/librustc_mir/build/expr/as_rvalue.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
162162
let source = unpack!(block = this.as_operand(block, scope, source));
163163
block.and(Rvalue::Cast(CastKind::UnsafeFnPointer, source, expr.ty))
164164
}
165-
ExprKind::ClosureFnPointer { source } => {
165+
ExprKind::ClosureFnPointer { source, unsafety } => {
166166
let source = unpack!(block = this.as_operand(block, scope, source));
167-
block.and(Rvalue::Cast(CastKind::ClosureFnPointer, source, expr.ty))
167+
block.and(Rvalue::Cast(CastKind::ClosureFnPointer(unsafety), source, expr.ty))
168168
}
169169
ExprKind::MutToConstPointer { source } => {
170170
let source = unpack!(block = this.as_operand(block, scope, source));

src/librustc_mir/hair/cx/expr.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
8181
Adjust::UnsafeFnPointer => {
8282
ExprKind::UnsafeFnPointer { source: expr.to_ref() }
8383
}
84-
Adjust::ClosureFnPointer => {
85-
ExprKind::ClosureFnPointer { source: expr.to_ref() }
84+
Adjust::ClosureFnPointer(unsafety) => {
85+
ExprKind::ClosureFnPointer { source: expr.to_ref(), unsafety }
8686
}
8787
Adjust::NeverToAny => {
8888
ExprKind::NeverToAny { source: expr.to_ref() }

src/librustc_mir/hair/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ pub enum ExprKind<'tcx> {
185185
},
186186
ClosureFnPointer {
187187
source: ExprRef<'tcx>,
188+
unsafety: hir::Unsafety,
188189
},
189190
UnsafeFnPointer {
190191
source: ExprRef<'tcx>,

src/librustc_mir/interpret/cast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
104104
}
105105
}
106106

107-
ClosureFnPointer => {
107+
ClosureFnPointer(_) => {
108108
// The src operand does not matter, just its type
109109
match src.layout.ty.sty {
110110
ty::Closure(def_id, substs) => {

src/librustc_mir/monomorphize/collector.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
563563
);
564564
visit_fn_use(self.tcx, fn_ty, false, &mut self.output);
565565
}
566-
mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => {
566+
mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer(_), ref operand, _) => {
567567
let source_ty = operand.ty(self.mir, self.tcx);
568568
let source_ty = self.tcx.subst_and_normalize_erasing_regions(
569569
self.param_substs,

src/librustc_mir/transform/qualify_consts.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1105,7 +1105,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
11051105
Rvalue::CheckedBinaryOp(..) |
11061106
Rvalue::Cast(CastKind::ReifyFnPointer, ..) |
11071107
Rvalue::Cast(CastKind::UnsafeFnPointer, ..) |
1108-
Rvalue::Cast(CastKind::ClosureFnPointer, ..) |
1108+
Rvalue::Cast(CastKind::ClosureFnPointer(_), ..) |
11091109
Rvalue::Cast(CastKind::Unsize, ..) |
11101110
Rvalue::Cast(CastKind::MutToConstPointer, ..) |
11111111
Rvalue::Discriminant(..) |

src/librustc_mir/transform/qualify_min_const_fn.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ fn check_rvalue(
156156
check_operand(tcx, mir, operand, span)
157157
}
158158
Rvalue::Cast(CastKind::UnsafeFnPointer, _, _) |
159-
Rvalue::Cast(CastKind::ClosureFnPointer, _, _) |
159+
Rvalue::Cast(CastKind::ClosureFnPointer(_), _, _) |
160160
Rvalue::Cast(CastKind::ReifyFnPointer, _, _) => Err((
161161
span,
162162
"function pointer casts are not allowed in const fn".into(),

src/librustc_passes/rvalue_promotion.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ fn check_adjustments<'a, 'tcx>(
586586
Adjust::NeverToAny |
587587
Adjust::ReifyFnPointer |
588588
Adjust::UnsafeFnPointer |
589-
Adjust::ClosureFnPointer |
589+
Adjust::ClosureFnPointer(_) |
590590
Adjust::MutToConstPointer |
591591
Adjust::Borrow(_) |
592592
Adjust::Unsize => {}

src/librustc_typeck/check/coercion.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
225225
}
226226
ty::Closure(def_id_a, substs_a) => {
227227
// Non-capturing closures are coercible to
228-
// function pointers
228+
// function pointers or unsafe function pointers.
229+
// It cannot convert closures that require unsafe.
229230
self.coerce_closure_to_fn(a, def_id_a, substs_a, b)
230231
}
231232
_ => {
@@ -714,16 +715,19 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
714715

715716
let hir_id_a = self.tcx.hir().as_local_hir_id(def_id_a).unwrap();
716717
match b.sty {
717-
ty::FnPtr(_) if self.tcx.with_freevars(hir_id_a, |v| v.is_empty()) => {
718+
ty::FnPtr(fn_ty) if self.tcx.with_freevars(hir_id_a, |v| v.is_empty()) => {
718719
// We coerce the closure, which has fn type
719720
// `extern "rust-call" fn((arg0,arg1,...)) -> _`
720721
// to
721722
// `fn(arg0,arg1,...) -> _`
723+
// or
724+
// `unsafe fn(arg0,arg1,...) -> _`
722725
let sig = self.closure_sig(def_id_a, substs_a);
723-
let pointer_ty = self.tcx.coerce_closure_fn_ty(sig);
726+
let unsafety = fn_ty.unsafety();
727+
let pointer_ty = self.tcx.coerce_closure_fn_ty(sig, unsafety);
724728
debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})",
725729
a, b, pointer_ty);
726-
self.unify_and(pointer_ty, b, simple(Adjust::ClosureFnPointer))
730+
self.unify_and(pointer_ty, b, simple(Adjust::ClosureFnPointer(unsafety)))
727731
}
728732
_ => self.unify_and(a, b, identity),
729733
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fn main() {
2+
let _: unsafe fn() = || { ::std::pin::Pin::new_unchecked(&0_u8); };
3+
//~^ ERROR E0133
4+
let _: unsafe fn() = || unsafe { ::std::pin::Pin::new_unchecked(&0_u8); }; // OK
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
unsafe fn call_unsafe(func: unsafe fn() -> ()) -> () {
2+
func()
3+
}
4+
5+
pub fn main() {
6+
unsafe { call_unsafe(|| {}); }
7+
}

0 commit comments

Comments
 (0)