Skip to content

Commit

Permalink
auto merge of rust-lang#9788 : geoffhill/rust/bare-fn-cast, r=pnkfelix
Browse files Browse the repository at this point in the history
Bare functions are another example of a scalar but non-numeric
type (like char) that should be handled separately in casts.
This disallows expressions like `0 as extern "Rust" fn() -> int;`.

It might be advantageous to allow casts between bare functions
and raw pointers in unsafe code in the future, to pass function
pointers between Rust and C.

Closes rust-lang#8728
  • Loading branch information
bors committed Nov 14, 2013
2 parents f9cea4b + e538c95 commit af62adf
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 2 deletions.
7 changes: 7 additions & 0 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2423,6 +2423,13 @@ pub fn type_is_char(ty: t) -> bool {
}
}

pub fn type_is_bare_fn(ty: t) -> bool {
match get(ty).sty {
ty_bare_fn(*) => true,
_ => false
}
}

pub fn type_is_fp(ty: t) -> bool {
match get(ty).sty {
ty_infer(FloatVar(_)) | ty_float(_) => true,
Expand Down
12 changes: 10 additions & 2 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3022,10 +3022,13 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,

let t1 = structurally_resolved_type(fcx, e.span, t_1);
let te = structurally_resolved_type(fcx, e.span, t_e);
let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
let t_1_is_char = type_is_char(fcx, expr.span, t_1);
let t_1_is_bare_fn = type_is_bare_fn(fcx, expr.span, t_1);

// casts to scalars other than `char` are allowed
let t_1_is_trivial = type_is_scalar(fcx, expr.span, t_1) && !t_1_is_char;
// casts to scalars other than `char` and `bare fn` are trivial
let t_1_is_trivial = t_1_is_scalar &&
!t_1_is_char && !t_1_is_bare_fn;

if type_is_c_like_enum(fcx, expr.span, t_e) && t_1_is_trivial {
// casts from C-like enums are allowed
Expand Down Expand Up @@ -3825,6 +3828,11 @@ pub fn type_is_char(fcx: @mut FnCtxt, sp: Span, typ: ty::t) -> bool {
return ty::type_is_char(typ_s);
}

pub fn type_is_bare_fn(fcx: @mut FnCtxt, sp: Span, typ: ty::t) -> bool {
let typ_s = structurally_resolved_type(fcx, sp, typ);
return ty::type_is_bare_fn(typ_s);
}

pub fn type_is_unsafe_ptr(fcx: @mut FnCtxt, sp: Span, typ: ty::t) -> bool {
let typ_s = structurally_resolved_type(fcx, sp, typ);
return ty::type_is_unsafe_ptr(typ_s);
Expand Down
21 changes: 21 additions & 0 deletions src/test/compile-fail/cast-to-bare-fn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2013 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.

fn foo(_x: int) { }

#[fixed_stack_segment]
fn main() {
let v: u64 = 5;
let x = foo as extern "C" fn() -> int;
//~^ ERROR non-scalar cast
let y = v as extern "Rust" fn(int) -> (int, int);
//~^ ERROR non-scalar cast
y(x());
}

0 comments on commit af62adf

Please sign in to comment.