From e538c95e4d5c7df475772639e983770e6425da32 Mon Sep 17 00:00:00 2001 From: Geoff Hill Date: Wed, 9 Oct 2013 15:36:26 -0700 Subject: [PATCH] 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 --- src/librustc/middle/ty.rs | 7 +++++++ src/librustc/middle/typeck/check/mod.rs | 12 ++++++++++-- src/test/compile-fail/cast-to-bare-fn.rs | 21 +++++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/cast-to-bare-fn.rs diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 753d4ab700918..081dfe868d610 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2539,6 +2539,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, diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index fad766f5066d2..f535832c6546b 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -2687,10 +2687,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 @@ -3448,6 +3451,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); diff --git a/src/test/compile-fail/cast-to-bare-fn.rs b/src/test/compile-fail/cast-to-bare-fn.rs new file mode 100644 index 0000000000000..8d75c66cb8274 --- /dev/null +++ b/src/test/compile-fail/cast-to-bare-fn.rs @@ -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 or the MIT license +// , 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()); +}