trans: Keep transmutes from fn item types working, but lint them.
This commit is contained in:
parent
eb926dd4b7
commit
3855fa99ca
6 changed files with 140 additions and 14 deletions
|
@ -148,6 +148,12 @@ declare_lint! {
|
||||||
"uses of #[derive] with raw pointers are rarely correct"
|
"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
|
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||||
/// which are used by other parts of the compiler.
|
/// which are used by other parts of the compiler.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
@ -177,7 +183,8 @@ impl LintPass for HardwiredLints {
|
||||||
INVALID_TYPE_PARAM_DEFAULT,
|
INVALID_TYPE_PARAM_DEFAULT,
|
||||||
MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
|
MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
|
||||||
CONST_ERR,
|
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();
|
*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) {
|
pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
|
||||||
|
|
|
@ -171,6 +171,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
||||||
reference: "RFC 218 <https://github.com/rust-lang/rfcs/blob/\
|
reference: "RFC 218 <https://github.com/rust-lang/rfcs/blob/\
|
||||||
master/text/0218-empty-struct-with-braces.md>",
|
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
|
// We have one lint pass defined specially
|
||||||
|
|
|
@ -22,7 +22,7 @@ use trans::adt;
|
||||||
use trans::attributes;
|
use trans::attributes;
|
||||||
use trans::base::*;
|
use trans::base::*;
|
||||||
use trans::build::*;
|
use trans::build::*;
|
||||||
use trans::callee;
|
use trans::callee::{self, Callee};
|
||||||
use trans::cleanup;
|
use trans::cleanup;
|
||||||
use trans::cleanup::CleanupMethods;
|
use trans::cleanup::CleanupMethods;
|
||||||
use trans::common::*;
|
use trans::common::*;
|
||||||
|
@ -45,6 +45,7 @@ use syntax::ast;
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
use syntax::parse::token;
|
use syntax::parse::token;
|
||||||
|
|
||||||
|
use rustc::lint;
|
||||||
use rustc::session::Session;
|
use rustc::session::Session;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
|
|
||||||
|
@ -125,29 +126,41 @@ pub fn check_intrinsics(ccx: &CrateContext) {
|
||||||
transmute_restriction.substituted_to);
|
transmute_restriction.substituted_to);
|
||||||
let from_type_size = machine::llbitsize_of_real(ccx, llfromtype);
|
let from_type_size = machine::llbitsize_of_real(ccx, llfromtype);
|
||||||
let to_type_size = machine::llbitsize_of_real(ccx, lltotype);
|
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 {
|
if from_type_size != to_type_size {
|
||||||
last_failing_id = Some(transmute_restriction.id);
|
last_failing_id = Some(transmute_restriction.id);
|
||||||
|
|
||||||
if transmute_restriction.original_from != transmute_restriction.substituted_from {
|
if transmute_restriction.original_from != transmute_restriction.substituted_from {
|
||||||
span_transmute_size_error(ccx.sess(), transmute_restriction.span,
|
span_transmute_size_error(ccx.sess(), transmute_restriction.span,
|
||||||
&format!("transmute called with differently sized types: \
|
&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,
|
transmute_restriction.original_from,
|
||||||
from_type_size as usize,
|
from_type_size,
|
||||||
if from_type_size == 1 {""} else {"s"},
|
|
||||||
transmute_restriction.original_to,
|
transmute_restriction.original_to,
|
||||||
to_type_size as usize,
|
to_type_size));
|
||||||
if to_type_size == 1 {""} else {"s"}));
|
|
||||||
} else {
|
} else {
|
||||||
span_transmute_size_error(ccx.sess(), transmute_restriction.span,
|
span_transmute_size_error(ccx.sess(), transmute_restriction.span,
|
||||||
&format!("transmute called with differently sized types: \
|
&format!("transmute called with differently sized types: \
|
||||||
{} ({} bit{}) to {} ({} bit{})",
|
{} ({} bits) to {} ({} bits)",
|
||||||
transmute_restriction.original_from,
|
transmute_restriction.original_from,
|
||||||
from_type_size as usize,
|
from_type_size,
|
||||||
if from_type_size == 1 {""} else {"s"},
|
|
||||||
transmute_restriction.original_to,
|
transmute_restriction.original_to,
|
||||||
to_type_size as usize,
|
to_type_size));
|
||||||
if to_type_size == 1 {""} else {"s"}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 foreign_item = tcx.map.expect_foreign_item(node);
|
||||||
let name = foreign_item.name.as_str();
|
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
|
// For `transmute` we can just trans the input expr directly into dest
|
||||||
if name == "transmute" {
|
if name == "transmute" {
|
||||||
let llret_ty = type_of::type_of(ccx, ret_ty.unwrap());
|
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 in_type_size = machine::llbitsize_of_real(ccx, llintype);
|
||||||
let out_type_size = machine::llbitsize_of_real(ccx, llouttype);
|
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
|
// This should be caught by the intrinsicck pass
|
||||||
assert_eq!(in_type_size, out_type_size);
|
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
|
// For `try` we need some custom control flow
|
||||||
if &name[..] == "try" {
|
if &name[..] == "try" {
|
||||||
if let callee::ArgExprs(ref exprs) = args {
|
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…
Add table
Add a link
Reference in a new issue