Skip to content

Commit e538c95

Browse files
committed
Typeck: Disallow scalar casts to bare_fn.
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 #8728
1 parent 11d5670 commit e538c95

File tree

3 files changed

+38
-2
lines changed

3 files changed

+38
-2
lines changed

src/librustc/middle/ty.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2539,6 +2539,13 @@ pub fn type_is_char(ty: t) -> bool {
25392539
}
25402540
}
25412541

2542+
pub fn type_is_bare_fn(ty: t) -> bool {
2543+
match get(ty).sty {
2544+
ty_bare_fn(*) => true,
2545+
_ => false
2546+
}
2547+
}
2548+
25422549
pub fn type_is_fp(ty: t) -> bool {
25432550
match get(ty).sty {
25442551
ty_infer(FloatVar(_)) | ty_float(_) => true,

src/librustc/middle/typeck/check/mod.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2687,10 +2687,13 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
26872687

26882688
let t1 = structurally_resolved_type(fcx, e.span, t_1);
26892689
let te = structurally_resolved_type(fcx, e.span, t_e);
2690+
let t_1_is_scalar = type_is_scalar(fcx, expr.span, t_1);
26902691
let t_1_is_char = type_is_char(fcx, expr.span, t_1);
2692+
let t_1_is_bare_fn = type_is_bare_fn(fcx, expr.span, t_1);
26912693

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

26952698
if type_is_c_like_enum(fcx, expr.span, t_e) && t_1_is_trivial {
26962699
// casts from C-like enums are allowed
@@ -3448,6 +3451,11 @@ pub fn type_is_char(fcx: @mut FnCtxt, sp: Span, typ: ty::t) -> bool {
34483451
return ty::type_is_char(typ_s);
34493452
}
34503453

3454+
pub fn type_is_bare_fn(fcx: @mut FnCtxt, sp: Span, typ: ty::t) -> bool {
3455+
let typ_s = structurally_resolved_type(fcx, sp, typ);
3456+
return ty::type_is_bare_fn(typ_s);
3457+
}
3458+
34513459
pub fn type_is_unsafe_ptr(fcx: @mut FnCtxt, sp: Span, typ: ty::t) -> bool {
34523460
let typ_s = structurally_resolved_type(fcx, sp, typ);
34533461
return ty::type_is_unsafe_ptr(typ_s);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn foo(_x: int) { }
12+
13+
#[fixed_stack_segment]
14+
fn main() {
15+
let v: u64 = 5;
16+
let x = foo as extern "C" fn() -> int;
17+
//~^ ERROR non-scalar cast
18+
let y = v as extern "Rust" fn(int) -> (int, int);
19+
//~^ ERROR non-scalar cast
20+
y(x());
21+
}

0 commit comments

Comments
 (0)