]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/intrinsicck.rs
auto merge of #17654 : gereeter/rust/no-unnecessary-cell, r=alexcrichton
[rust.git] / src / librustc / middle / intrinsicck.rs
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.
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 use metadata::csearch;
12 use middle::def::DefFn;
13 use middle::subst::Subst;
14 use middle::ty::{TransmuteRestriction, ctxt, ty_bare_fn};
15 use middle::ty;
16
17 use syntax::abi::RustIntrinsic;
18 use syntax::ast::DefId;
19 use syntax::ast;
20 use syntax::ast_map::NodeForeignItem;
21 use syntax::codemap::Span;
22 use syntax::parse::token;
23 use syntax::visit::Visitor;
24 use syntax::visit;
25
26 fn type_size_is_affected_by_type_parameters(tcx: &ty::ctxt, typ: ty::t)
27                                             -> bool {
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(..) => {
33                 false
34             }
35             ty::ty_param(_) => {
36                 result = true;
37                 // No need to continue; we now know the result.
38                 false
39             }
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);
44                         result = result ||
45                             type_size_is_affected_by_type_parameters(
46                                 tcx,
47                                 argument_type);
48                     }
49                 }
50
51                 // Don't traverse substitutions.
52                 false
53             }
54             ty::ty_struct(did, ref substs) => {
55                 for field in ty::struct_fields(tcx, did, substs).iter() {
56                     result = result ||
57                         type_size_is_affected_by_type_parameters(tcx,
58                                                                  field.mt.ty);
59                 }
60
61                 // Don't traverse substitutions.
62                 false
63             }
64             _ => true,
65         }
66     });
67     result
68 }
69
70 struct IntrinsicCheckingVisitor<'a, 'tcx: 'a> {
71     tcx: &'a ctxt<'tcx>,
72 }
73
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,
78             _ => return false
79         };
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")
85                 }
86                 _ => false,
87             }
88         } else {
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")
93                 }
94                 _ => false,
95             }
96         }
97     }
98
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");
103         }
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");
107         }
108
109         let restriction = TransmuteRestriction {
110             span: span,
111             from: from,
112             to: to,
113             id: id,
114         };
115         self.tcx.transmute_restrictions.borrow_mut().push(restriction);
116     }
117 }
118
119 impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> {
120     fn visit_expr(&mut self, expr: &ast::Expr) {
121         match expr.node {
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);
132                             }
133                             _ => {
134                                 self.tcx
135                                     .sess
136                                     .span_bug(expr.span,
137                                               "transmute wasn't a bare fn?!");
138                             }
139                         }
140                     }
141                     _ => {}
142                 }
143             }
144             _ => {}
145         }
146
147         visit::walk_expr(self, expr);
148     }
149 }
150
151 pub fn check_crate(tcx: &ctxt) {
152     visit::walk_crate(&mut IntrinsicCheckingVisitor { tcx: tcx },
153                       tcx.map.krate());
154 }
155