Skip to content

Commit

Permalink
rustc_typeck: Allow reification from fn item to unsafe ptr
Browse files Browse the repository at this point in the history
  • Loading branch information
cramertj committed Oct 25, 2016
1 parent 7bd2427 commit 4bb6d4e
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 12 deletions.
35 changes: 23 additions & 12 deletions src/librustc_typeck/check/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 coercin of function
// items to drop the unsafe qualifier.
self.coerce_from_fn_item(a, a_f, b)
}
ty::TyFnPtr(a_f) => {
Expand Down Expand Up @@ -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>,
Expand All @@ -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,
Expand All @@ -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),
}
Expand Down
21 changes: 21 additions & 0 deletions src/test/run-pass/typeck-fn-to-unsafe-fn-ptr.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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); }
}

0 comments on commit 4bb6d4e

Please sign in to comment.