1 // Copyright 2012-2014 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.
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.
11 use metadata::csearch;
12 use middle::def::DefFn;
13 use middle::subst::Subst;
14 use middle::ty::{TransmuteRestriction, ctxt, ty_bare_fn};
17 use syntax::abi::RustIntrinsic;
18 use syntax::ast::DefId;
20 use syntax::ast_map::NodeForeignItem;
21 use syntax::codemap::Span;
22 use syntax::parse::token;
23 use syntax::visit::Visitor;
26 fn type_size_is_affected_by_type_parameters(tcx: &ty::ctxt, typ: ty::t)
28 let mut result = false;
29 ty::maybe_walk_ty(typ, |typ| {
30 match ty::get(typ).sty {
31 ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_ptr(_) |
32 ty::ty_rptr(..) | ty::ty_bare_fn(..) | ty::ty_closure(..) => {
37 // No need to continue; we now know the result.
40 ty::ty_enum(did, ref substs) => {
41 for enum_variant in (*ty::enum_variants(tcx, did)).iter() {
42 for argument_type in enum_variant.args.iter() {
43 let argument_type = argument_type.subst(tcx, substs);
45 type_size_is_affected_by_type_parameters(
51 // Don't traverse substitutions.
54 ty::ty_struct(did, ref substs) => {
55 for field in ty::struct_fields(tcx, did, substs).iter() {
57 type_size_is_affected_by_type_parameters(tcx,
61 // Don't traverse substitutions.
70 struct IntrinsicCheckingVisitor<'a, 'tcx: 'a> {
74 impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
75 fn def_id_is_transmute(&self, def_id: DefId) -> bool {
76 let intrinsic = match ty::get(ty::lookup_item_type(self.tcx, def_id).ty).sty {
77 ty::ty_bare_fn(ref bfty) => bfty.abi == RustIntrinsic,
80 if def_id.krate == ast::LOCAL_CRATE {
81 match self.tcx.map.get(def_id.node) {
82 NodeForeignItem(ref item) if intrinsic => {
83 token::get_ident(item.ident) ==
84 token::intern_and_get_ident("transmute")
89 match csearch::get_item_path(self.tcx, def_id).last() {
90 Some(ref last) if intrinsic => {
91 token::get_name(last.name()) ==
92 token::intern_and_get_ident("transmute")
99 fn check_transmute(&self, span: Span, from: ty::t, to: ty::t, id: ast::NodeId) {
100 if type_size_is_affected_by_type_parameters(self.tcx, from) {
101 span_err!(self.tcx.sess, span, E0139,
102 "cannot transmute from a type that contains type parameters");
104 if type_size_is_affected_by_type_parameters(self.tcx, to) {
105 span_err!(self.tcx.sess, span, E0140,
106 "cannot transmute to a type that contains type parameters");
109 let restriction = TransmuteRestriction {
115 self.tcx.transmute_restrictions.borrow_mut().push(restriction);
119 impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> {
120 fn visit_expr(&mut self, expr: &ast::Expr) {
122 ast::ExprPath(..) => {
123 match ty::resolve_expr(self.tcx, expr) {
124 DefFn(did, _, _) if self.def_id_is_transmute(did) => {
125 let typ = ty::node_id_to_type(self.tcx, expr.id);
126 match ty::get(typ).sty {
127 ty_bare_fn(ref bare_fn_ty)
128 if bare_fn_ty.abi == RustIntrinsic => {
129 let from = *bare_fn_ty.sig.inputs.get(0);
130 let to = bare_fn_ty.sig.output;
131 self.check_transmute(expr.span, from, to, expr.id);
137 "transmute wasn't a bare fn?!");
147 visit::walk_expr(self, expr);
151 pub fn check_crate(tcx: &ctxt) {
152 visit::walk_crate(&mut IntrinsicCheckingVisitor { tcx: tcx },