about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/expr_use_visitor.rs2
-rw-r--r--src/librustc/middle/mem_categorization.rs2
-rw-r--r--src/librustc/mir/mod.rs5
-rw-r--r--src/librustc/ty/adjustment.rs5
-rw-r--r--src/librustc/ty/context.rs8
-rw-r--r--src/librustc/ty/structural_impls.rs6
-rw-r--r--src/librustc_codegen_ssa/mir/rvalue.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs4
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs4
-rw-r--r--src/librustc_mir/hair/cx/expr.rs4
-rw-r--r--src/librustc_mir/hair/mod.rs1
-rw-r--r--src/librustc_mir/interpret/cast.rs2
-rw-r--r--src/librustc_mir/monomorphize/collector.rs2
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs2
-rw-r--r--src/librustc_mir/transform/qualify_min_const_fn.rs2
-rw-r--r--src/librustc_passes/rvalue_promotion.rs2
-rw-r--r--src/librustc_typeck/check/coercion.rs12
-rw-r--r--src/test/compile-fail/coerce-unsafe-closure-to-unsafe-fn-ptr.rs5
-rw-r--r--src/test/run-pass/typeck-closure-to-unsafe-fn-ptr.rs7
19 files changed, 50 insertions, 27 deletions
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 01e57273e54..4f630fe9a39 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -707,7 +707,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                 adjustment::Adjust::NeverToAny |
                 adjustment::Adjust::ReifyFnPointer |
                 adjustment::Adjust::UnsafeFnPointer |
-                adjustment::Adjust::ClosureFnPointer |
+                adjustment::Adjust::ClosureFnPointer(_) |
                 adjustment::Adjust::MutToConstPointer |
                 adjustment::Adjust::Unsize => {
                     // Creating a closure/fn-pointer or unsizing consumes
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 4b169dea06c..1a3fef18404 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -621,7 +621,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             adjustment::Adjust::NeverToAny |
             adjustment::Adjust::ReifyFnPointer |
             adjustment::Adjust::UnsafeFnPointer |
-            adjustment::Adjust::ClosureFnPointer |
+            adjustment::Adjust::ClosureFnPointer(_) |
             adjustment::Adjust::MutToConstPointer |
             adjustment::Adjust::Borrow(_) |
             adjustment::Adjust::Unsize => {
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index d35ee1e57d5..7b419e306db 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -2247,8 +2247,9 @@ pub enum CastKind {
     /// Converts unique, zero-sized type for a fn to fn()
     ReifyFnPointer,
 
-    /// Converts non capturing closure to fn()
-    ClosureFnPointer,
+    /// Converts non capturing closure to fn() or unsafe fn().
+    /// It cannot convert a closure that requires unsafe.
+    ClosureFnPointer(hir::Unsafety),
 
     /// Converts safe fn() to unsafe fn()
     UnsafeFnPointer,
diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs
index f9149ce0f6e..c2ef08c4c40 100644
--- a/src/librustc/ty/adjustment.rs
+++ b/src/librustc/ty/adjustment.rs
@@ -62,8 +62,9 @@ pub enum Adjust<'tcx> {
     /// Go from a safe fn pointer to an unsafe fn pointer.
     UnsafeFnPointer,
 
-    /// Go from a non-capturing closure to an fn pointer.
-    ClosureFnPointer,
+    /// 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),
 
     /// 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 ea003ba1ac7..77330c7a9d1 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -2441,7 +2441,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// 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
     /// 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 params_iter = match s.inputs()[0].sty {
                 ty::Tuple(params) => {
@@ -2453,7 +2457,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 params_iter,
                 s.output(),
                 s.c_variadic,
-                hir::Unsafety::Normal,
+                unsafety,
                 abi::Abi::Rust,
             )
         });
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index cbdda732692..4f1fda3f4e5 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -630,8 +630,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> {
                 Some(ty::adjustment::Adjust::ReifyFnPointer),
             ty::adjustment::Adjust::UnsafeFnPointer =>
                 Some(ty::adjustment::Adjust::UnsafeFnPointer),
-            ty::adjustment::Adjust::ClosureFnPointer =>
-                Some(ty::adjustment::Adjust::ClosureFnPointer),
+            ty::adjustment::Adjust::ClosureFnPointer(unsafety) =>
+                Some(ty::adjustment::Adjust::ClosureFnPointer(unsafety)),
             ty::adjustment::Adjust::MutToConstPointer =>
                 Some(ty::adjustment::Adjust::MutToConstPointer),
             ty::adjustment::Adjust::Unsize =>
@@ -1187,7 +1187,7 @@ EnumTypeFoldableImpl! {
         (ty::adjustment::Adjust::NeverToAny),
         (ty::adjustment::Adjust::ReifyFnPointer),
         (ty::adjustment::Adjust::UnsafeFnPointer),
-        (ty::adjustment::Adjust::ClosureFnPointer),
+        (ty::adjustment::Adjust::ClosureFnPointer)(a),
         (ty::adjustment::Adjust::MutToConstPointer),
         (ty::adjustment::Adjust::Unsize),
         (ty::adjustment::Adjust::Deref)(a),
diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs
index dfb7f37eb4c..53640284a2c 100644
--- a/src/librustc_codegen_ssa/mir/rvalue.rs
+++ b/src/librustc_codegen_ssa/mir/rvalue.rs
@@ -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 {
                             ty::Closure(def_id, substs) => {
                                 let instance = monomorphize::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 a3561515aaa..3b559b28f12 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -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 {
                             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);
+                        let ty_fn_ptr_from = tcx.coerce_closure_fn_ty(sig, *unsafety);
 
                         if let Err(terr) = self.eq_types(
                             ty_fn_ptr_from,
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 9e12a7e6fa9..84f74484e60 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -162,9 +162,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 let source = unpack!(block = this.as_operand(block, scope, source));
                 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));
-                block.and(Rvalue::Cast(CastKind::ClosureFnPointer, source, expr.ty))
+                block.and(Rvalue::Cast(CastKind::ClosureFnPointer(unsafety), source, expr.ty))
             }
             ExprKind::MutToConstPointer { source } => {
                 let source = unpack!(block = this.as_operand(block, scope, source));
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index e4f92f81e9f..91113dc2271 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -81,8 +81,8 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         Adjust::UnsafeFnPointer => {
             ExprKind::UnsafeFnPointer { source: expr.to_ref() }
         }
-        Adjust::ClosureFnPointer => {
-            ExprKind::ClosureFnPointer { source: expr.to_ref() }
+        Adjust::ClosureFnPointer(unsafety) => {
+            ExprKind::ClosureFnPointer { source: expr.to_ref(), unsafety }
         }
         Adjust::NeverToAny => {
             ExprKind::NeverToAny { source: expr.to_ref() }
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 3a38876bb68..a661649db0f 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -185,6 +185,7 @@ pub enum ExprKind<'tcx> {
     },
     ClosureFnPointer {
         source: ExprRef<'tcx>,
+        unsafety: hir::Unsafety,
     },
     UnsafeFnPointer {
         source: ExprRef<'tcx>,
diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs
index ba61b03ea67..fe719bff250 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>
                 }
             }
 
-            ClosureFnPointer => {
+            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 0e8ab2ba2a5..45b346b6413 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -563,7 +563,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::ClosureFnPointer, ref operand, _) => {
+            mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer(_), ref operand, _) => {
                 let source_ty = operand.ty(self.mir, self.tcx);
                 let source_ty = self.tcx.subst_and_normalize_erasing_regions(
                     self.param_substs,
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 0b9ad85e6b1..9bd5fce31f1 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -1105,7 +1105,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
             Rvalue::CheckedBinaryOp(..) |
             Rvalue::Cast(CastKind::ReifyFnPointer, ..) |
             Rvalue::Cast(CastKind::UnsafeFnPointer, ..) |
-            Rvalue::Cast(CastKind::ClosureFnPointer, ..) |
+            Rvalue::Cast(CastKind::ClosureFnPointer(_), ..) |
             Rvalue::Cast(CastKind::Unsize, ..) |
             Rvalue::Cast(CastKind::MutToConstPointer, ..) |
             Rvalue::Discriminant(..) |
diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs
index 8742c5d759c..87459571b52 100644
--- a/src/librustc_mir/transform/qualify_min_const_fn.rs
+++ b/src/librustc_mir/transform/qualify_min_const_fn.rs
@@ -156,7 +156,7 @@ fn check_rvalue(
             check_operand(tcx, mir, operand, span)
         }
         Rvalue::Cast(CastKind::UnsafeFnPointer, _, _) |
-        Rvalue::Cast(CastKind::ClosureFnPointer, _, _) |
+        Rvalue::Cast(CastKind::ClosureFnPointer(_), _, _) |
         Rvalue::Cast(CastKind::ReifyFnPointer, _, _) => Err((
             span,
             "function pointer casts are not allowed in const fn".into(),
diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs
index a0a0d7be1b9..7c37c38f2d7 100644
--- a/src/librustc_passes/rvalue_promotion.rs
+++ b/src/librustc_passes/rvalue_promotion.rs
@@ -586,7 +586,7 @@ fn check_adjustments<'a, 'tcx>(
             Adjust::NeverToAny |
             Adjust::ReifyFnPointer |
             Adjust::UnsafeFnPointer |
-            Adjust::ClosureFnPointer |
+            Adjust::ClosureFnPointer(_) |
             Adjust::MutToConstPointer |
             Adjust::Borrow(_) |
             Adjust::Unsize => {}
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index ac8b639edbf..c470bc09e8c 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -225,7 +225,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
             }
             ty::Closure(def_id_a, substs_a) => {
                 // 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)
             }
             _ => {
@@ -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();
         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
                 //     `extern "rust-call" fn((arg0,arg1,...)) -> _`
                 // to
                 //     `fn(arg0,arg1,...) -> _`
+                // or
+                //     `unsafe fn(arg0,arg1,...) -> _`
                 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={:?})",
                        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),
         }
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
new file mode 100644
index 00000000000..36777693fab
--- /dev/null
+++ b/src/test/compile-fail/coerce-unsafe-closure-to-unsafe-fn-ptr.rs
@@ -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
+}
diff --git a/src/test/run-pass/typeck-closure-to-unsafe-fn-ptr.rs b/src/test/run-pass/typeck-closure-to-unsafe-fn-ptr.rs
new file mode 100644
index 00000000000..fe15b912d60
--- /dev/null
+++ b/src/test/run-pass/typeck-closure-to-unsafe-fn-ptr.rs
@@ -0,0 +1,7 @@
+unsafe fn call_unsafe(func: unsafe fn() -> ()) -> () {
+    func()
+}
+
+pub fn main() {
+    unsafe { call_unsafe(|| {}); }
+}