diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 5be77cb12e9ef..ccc944813ff18 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -196,6 +196,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Function items are coercible to any closure // type; function pointers are not (that would // require double indirection). + // Additionally, we permit coercion of function + // items to drop the unsafe qualifier. self.coerce_from_fn_item(a, a_f, b) } ty::TyFnPtr(a_f) => { @@ -504,6 +506,24 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { Ok((target, AdjustDerefRef(adjustment))) } + fn coerce_from_safe_fn(&self, + a: Ty<'tcx>, + fn_ty_a: &'tcx ty::BareFnTy<'tcx>, + b: Ty<'tcx>) + -> CoerceResult<'tcx> { + if let ty::TyFnPtr(fn_ty_b) = b.sty { + match (fn_ty_a.unsafety, fn_ty_b.unsafety) { + (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { + let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); + return self.unify_and_identity(unsafe_a, b) + .map(|(ty, _)| (ty, AdjustUnsafeFnPointer)); + } + _ => {} + } + } + self.unify_and_identity(a, b) + } + fn coerce_from_fn_pointer(&self, a: Ty<'tcx>, fn_ty_a: &'tcx ty::BareFnTy<'tcx>, @@ -516,17 +536,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let b = self.shallow_resolve(b); debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); - if let ty::TyFnPtr(fn_ty_b) = b.sty { - match (fn_ty_a.unsafety, fn_ty_b.unsafety) { - (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { - let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); - return self.unify_and_identity(unsafe_a, b) - .map(|(ty, _)| (ty, AdjustUnsafeFnPointer)); - } - _ => {} - } - } - self.unify_and_identity(a, b) + self.coerce_from_safe_fn(a, fn_ty_a, b) } fn coerce_from_fn_item(&self, @@ -544,7 +554,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { match b.sty { ty::TyFnPtr(_) => { let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a); - self.unify_and_identity(a_fn_pointer, b).map(|(ty, _)| (ty, AdjustReifyFnPointer)) + self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b) + .map(|(ty, _)| (ty, AdjustReifyFnPointer)) } _ => self.unify_and_identity(a, b), } diff --git a/src/test/run-pass/typeck-fn-to-unsafe-fn-ptr.rs b/src/test/run-pass/typeck-fn-to-unsafe-fn-ptr.rs new file mode 100644 index 0000000000000..323705f3f955f --- /dev/null +++ b/src/test/run-pass/typeck-fn-to-unsafe-fn-ptr.rs @@ -0,0 +1,21 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This tests reification from safe function to `unsafe fn` pointer + +fn do_nothing() -> () {} + +unsafe fn call_unsafe(func: unsafe fn() -> ()) -> () { + func() +} + +pub fn main() { + unsafe { call_unsafe(do_nothing); } +}