trans: Keep transmutes from fn item types working, but lint them.
This commit is contained in:
parent
eb926dd4b7
commit
3855fa99ca
@ -148,6 +148,12 @@
|
||||
"uses of #[derive] with raw pointers are rarely correct"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub TRANSMUTE_FROM_FN_ITEM_TYPES,
|
||||
Warn,
|
||||
"transmute from function item type to pointer-sized type erroneously allowed"
|
||||
}
|
||||
|
||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||
/// which are used by other parts of the compiler.
|
||||
#[derive(Copy, Clone)]
|
||||
@ -177,7 +183,8 @@ fn get_lints(&self) -> LintArray {
|
||||
INVALID_TYPE_PARAM_DEFAULT,
|
||||
MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
|
||||
CONST_ERR,
|
||||
RAW_POINTER_DERIVE
|
||||
RAW_POINTER_DERIVE,
|
||||
TRANSMUTE_FROM_FN_ITEM_TYPES
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1287,6 +1287,9 @@ pub fn check_crate(tcx: &TyCtxt, access_levels: &AccessLevels) {
|
||||
}
|
||||
|
||||
*tcx.node_lint_levels.borrow_mut() = cx.node_levels.into_inner();
|
||||
|
||||
// Put the lint store back in the session.
|
||||
mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), cx.lints);
|
||||
}
|
||||
|
||||
pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
|
||||
|
@ -171,6 +171,10 @@ macro_rules! add_lint_group {
|
||||
reference: "RFC 218 <https://github.com/rust-lang/rfcs/blob/\
|
||||
master/text/0218-empty-struct-with-braces.md>",
|
||||
},
|
||||
FutureIncompatibleInfo {
|
||||
id: LintId::of(TRANSMUTE_FROM_FN_ITEM_TYPES),
|
||||
reference: "issue #19925 <https://github.com/rust-lang/rust/issues/19925>",
|
||||
},
|
||||
]);
|
||||
|
||||
// We have one lint pass defined specially
|
||||
|
@ -22,7 +22,7 @@
|
||||
use trans::attributes;
|
||||
use trans::base::*;
|
||||
use trans::build::*;
|
||||
use trans::callee;
|
||||
use trans::callee::{self, Callee};
|
||||
use trans::cleanup;
|
||||
use trans::cleanup::CleanupMethods;
|
||||
use trans::common::*;
|
||||
@ -45,6 +45,7 @@
|
||||
use syntax::ptr::P;
|
||||
use syntax::parse::token;
|
||||
|
||||
use rustc::lint;
|
||||
use rustc::session::Session;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
@ -125,29 +126,41 @@ pub fn check_intrinsics(ccx: &CrateContext) {
|
||||
transmute_restriction.substituted_to);
|
||||
let from_type_size = machine::llbitsize_of_real(ccx, llfromtype);
|
||||
let to_type_size = machine::llbitsize_of_real(ccx, lltotype);
|
||||
|
||||
if let ty::TyFnDef(..) = transmute_restriction.substituted_from.sty {
|
||||
if to_type_size == machine::llbitsize_of_real(ccx, ccx.int_type()) {
|
||||
// FIXME #19925 Remove this warning after a release cycle.
|
||||
lint::raw_emit_lint(&ccx.tcx().sess,
|
||||
&ccx.tcx().sess.lint_store.borrow(),
|
||||
lint::builtin::TRANSMUTE_FROM_FN_ITEM_TYPES,
|
||||
(lint::Warn, lint::LintSource::Default),
|
||||
Some(transmute_restriction.span),
|
||||
&format!("`{}` is now zero-sized and has to be cast \
|
||||
to a pointer before transmuting to `{}`",
|
||||
transmute_restriction.substituted_from,
|
||||
transmute_restriction.substituted_to));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if from_type_size != to_type_size {
|
||||
last_failing_id = Some(transmute_restriction.id);
|
||||
|
||||
if transmute_restriction.original_from != transmute_restriction.substituted_from {
|
||||
span_transmute_size_error(ccx.sess(), transmute_restriction.span,
|
||||
&format!("transmute called with differently sized types: \
|
||||
{} (could be {} bit{}) to {} (could be {} bit{})",
|
||||
{} (could be {} bits) to {} (could be {} bits)",
|
||||
transmute_restriction.original_from,
|
||||
from_type_size as usize,
|
||||
if from_type_size == 1 {""} else {"s"},
|
||||
from_type_size,
|
||||
transmute_restriction.original_to,
|
||||
to_type_size as usize,
|
||||
if to_type_size == 1 {""} else {"s"}));
|
||||
to_type_size));
|
||||
} else {
|
||||
span_transmute_size_error(ccx.sess(), transmute_restriction.span,
|
||||
&format!("transmute called with differently sized types: \
|
||||
{} ({} bit{}) to {} ({} bit{})",
|
||||
{} ({} bits) to {} ({} bits)",
|
||||
transmute_restriction.original_from,
|
||||
from_type_size as usize,
|
||||
if from_type_size == 1 {""} else {"s"},
|
||||
from_type_size,
|
||||
transmute_restriction.original_to,
|
||||
to_type_size as usize,
|
||||
if to_type_size == 1 {""} else {"s"}));
|
||||
to_type_size));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -179,6 +192,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||
let foreign_item = tcx.map.expect_foreign_item(node);
|
||||
let name = foreign_item.name.as_str();
|
||||
|
||||
let call_debug_location = DebugLoc::At(call_info.id, call_info.span);
|
||||
|
||||
// For `transmute` we can just trans the input expr directly into dest
|
||||
if name == "transmute" {
|
||||
let llret_ty = type_of::type_of(ccx, ret_ty.unwrap());
|
||||
@ -194,6 +209,27 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||
let in_type_size = machine::llbitsize_of_real(ccx, llintype);
|
||||
let out_type_size = machine::llbitsize_of_real(ccx, llouttype);
|
||||
|
||||
if let ty::TyFnDef(def_id, substs, _) = in_type.sty {
|
||||
if out_type_size != 0 {
|
||||
// FIXME #19925 Remove this hack after a release cycle.
|
||||
let _ = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0]));
|
||||
let llfn = Callee::def(ccx, def_id, substs, in_type).reify(ccx).val;
|
||||
let llfnty = val_ty(llfn);
|
||||
let llresult = match dest {
|
||||
expr::SaveIn(d) => d,
|
||||
expr::Ignore => alloc_ty(bcx, out_type, "ret")
|
||||
};
|
||||
Store(bcx, llfn, PointerCast(bcx, llresult, llfnty.ptr_to()));
|
||||
if dest == expr::Ignore {
|
||||
bcx = glue::drop_ty(bcx, llresult, out_type,
|
||||
call_debug_location);
|
||||
}
|
||||
fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
|
||||
fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope);
|
||||
return Result::new(bcx, llresult);
|
||||
}
|
||||
}
|
||||
|
||||
// This should be caught by the intrinsicck pass
|
||||
assert_eq!(in_type_size, out_type_size);
|
||||
|
||||
@ -311,8 +347,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
let call_debug_location = DebugLoc::At(call_info.id, call_info.span);
|
||||
|
||||
// For `try` we need some custom control flow
|
||||
if &name[..] == "try" {
|
||||
if let callee::ArgExprs(ref exprs) = args {
|
||||
|
51
src/test/compile-fail/transmute-from-fn-item-types-lint.rs
Normal file
51
src/test/compile-fail/transmute-from-fn-item-types-lint.rs
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
use std::mem;
|
||||
|
||||
unsafe fn foo() -> (isize, *const (), Option<fn()>) {
|
||||
let i = mem::transmute(bar);
|
||||
//~^ WARN is now zero-sized and has to be cast to a pointer before transmuting
|
||||
//~^^ WARN was previously accepted
|
||||
|
||||
let p = mem::transmute(foo);
|
||||
//~^ WARN is now zero-sized and has to be cast to a pointer before transmuting
|
||||
//~^^ WARN was previously accepted
|
||||
|
||||
let of = mem::transmute(main);
|
||||
//~^ WARN is now zero-sized and has to be cast to a pointer before transmuting
|
||||
//~^^ WARN was previously accepted
|
||||
|
||||
(i, p, of)
|
||||
}
|
||||
|
||||
unsafe fn bar() {
|
||||
mem::transmute::<_, *mut ()>(foo);
|
||||
//~^ WARN is now zero-sized and has to be cast to a pointer before transmuting
|
||||
//~^^ WARN was previously accepted
|
||||
|
||||
mem::transmute::<_, fn()>(bar);
|
||||
//~^ WARN is now zero-sized and has to be cast to a pointer before transmuting
|
||||
//~^^ WARN was previously accepted
|
||||
|
||||
// No error if a coercion would otherwise occur.
|
||||
mem::transmute::<fn(), usize>(main);
|
||||
|
||||
// Error, still, if the resulting type is not pointer-sized.
|
||||
mem::transmute::<_, u8>(main);
|
||||
//~^ ERROR transmute called with differently sized types
|
||||
}
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
foo();
|
||||
bar();
|
||||
}
|
||||
}
|
27
src/test/run-pass/transmute-from-fn-item-types.rs
Normal file
27
src/test/run-pass/transmute-from-fn-item-types.rs
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
#![allow(transmute_from_fn_item_types)]
|
||||
|
||||
use std::mem;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let u = mem::transmute(main);
|
||||
let p = mem::transmute(main);
|
||||
let f = mem::transmute(main);
|
||||
let tuple: (usize, *mut (), fn()) = (u, p, f);
|
||||
assert_eq!(mem::transmute::<_, [usize; 3]>(tuple), [main as usize; 3]);
|
||||
|
||||
mem::transmute::<_, usize>(main);
|
||||
mem::transmute::<_, *mut ()>(main);
|
||||
mem::transmute::<_, fn()>(main);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user