]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/check_static.rs
auto merge of #12616 : alexcrichton/rust/size, r=huonw
[rust.git] / src / librustc / middle / check_static.rs
1 // Copyright 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 // Verifies that the types and values of static items
12 // are safe. The rules enforced by this module are:
13 //
14 // - For each *mutable* static item, it checks that its **type**:
15 //     - doesn't have a destructor
16 //     - doesn't own an owned pointer
17 //
18 // - For each *immutable* static item, it checks that its **value**:
19 //       - doesn't own owned, managed pointers
20 //       - doesn't contain a struct literal or a call to an enum variant / struct constructor where
21 //           - the type of the struct/enum is not freeze
22 //           - the type of the struct/enum has a dtor
23
24 use middle::ty;
25
26 use syntax::ast;
27 use syntax::codemap::Span;
28 use syntax::visit::Visitor;
29 use syntax::visit;
30 use syntax::print::pprust;
31
32
33 fn safe_type_for_static_mut(cx: ty::ctxt, e: &ast::Expr) -> Option<~str> {
34     let node_ty = ty::node_id_to_type(cx, e.id);
35     let tcontents = ty::type_contents(cx, node_ty);
36     debug!("safe_type_for_static_mut(dtor={}, managed={}, owned={})",
37            tcontents.has_dtor(), tcontents.owns_managed(), tcontents.owns_owned())
38
39     let suffix = if tcontents.has_dtor() {
40         "destructors"
41     } else if tcontents.owns_managed() {
42         "managed pointers"
43     } else if tcontents.owns_owned() {
44         "owned pointers"
45     } else {
46         return None;
47     };
48
49     Some(format!("mutable static items are not allowed to have {}", suffix))
50 }
51
52 struct CheckStaticVisitor {
53     tcx: ty::ctxt,
54 }
55
56 pub fn check_crate(tcx: ty::ctxt, krate: &ast::Crate) {
57     visit::walk_crate(&mut CheckStaticVisitor { tcx: tcx }, krate, false)
58 }
59
60 impl CheckStaticVisitor {
61
62     fn report_error(&self, span: Span, result: Option<~str>) -> bool {
63         match result {
64             None => { false }
65             Some(msg) => {
66                 self.tcx.sess.span_err(span, msg);
67                 true
68             }
69         }
70     }
71 }
72
73 impl Visitor<bool> for CheckStaticVisitor {
74
75     fn visit_item(&mut self, i: &ast::Item, _is_const: bool) {
76         debug!("visit_item(item={})", pprust::item_to_str(i));
77         match i.node {
78             ast::ItemStatic(_, mutability, expr) => {
79                 match mutability {
80                     ast::MutImmutable => {
81                         self.visit_expr(expr, true);
82                     }
83                     ast::MutMutable => {
84                         self.report_error(expr.span, safe_type_for_static_mut(self.tcx, expr));
85                     }
86                 }
87             }
88             _ => { visit::walk_item(self, i, false) }
89         }
90     }
91
92     /// This method is used to enforce the constraints on
93     /// immutable static items. It walks through the *value*
94     /// of the item walking down the expression and evaluating
95     /// every nested expression. if the expression is not part
96     /// of a static item, this method does nothing but walking
97     /// down through it.
98     fn visit_expr(&mut self, e: &ast::Expr, is_const: bool) {
99         debug!("visit_expr(expr={})", pprust::expr_to_str(e));
100
101         if !is_const {
102             return visit::walk_expr(self, e, is_const);
103         }
104
105         match e.node {
106             ast::ExprField(..) | ast::ExprVec(..) |
107             ast::ExprBlock(..) | ast::ExprTup(..) |
108             ast::ExprVstore(_, ast::ExprVstoreSlice) => {
109                 visit::walk_expr(self, e, is_const);
110             }
111             ast::ExprUnary(ast::UnBox, _) => {
112                 self.tcx.sess.span_err(e.span,
113                                    "static items are not allowed to have managed pointers");
114             }
115             ast::ExprBox(..) |
116             ast::ExprUnary(ast::UnUniq, _) |
117             ast::ExprVstore(_, ast::ExprVstoreUniq) => {
118                 self.tcx.sess.span_err(e.span,
119                                    "static items are not allowed to have owned pointers");
120             }
121             ast::ExprProc(..) => {
122                 self.report_error(e.span,
123                                   Some(~"immutable static items must be `Freeze`"));
124                 return;
125             }
126             ast::ExprAddrOf(mutability, _) => {
127                 match mutability {
128                     ast::MutMutable => {
129                         self.report_error(e.span,
130                                   Some(~"immutable static items must be `Freeze`"));
131                         return;
132                     }
133                     _ => {}
134                 }
135             }
136             _ => {
137                 let node_ty = ty::node_id_to_type(self.tcx, e.id);
138
139                 match ty::get(node_ty).sty {
140                     ty::ty_struct(did, _) |
141                     ty::ty_enum(did, _) => {
142                         if ty::has_dtor(self.tcx, did) {
143                             self.report_error(e.span,
144                                      Some(~"static items are not allowed to have destructors"));
145                             return;
146                         }
147                         if Some(did) == self.tcx.lang_items.no_freeze_bound() {
148                             self.report_error(e.span,
149                                               Some(~"immutable static items must be `Freeze`"));
150                             return;
151                         }
152                     }
153                     _ => {}
154                 }
155                 visit::walk_expr(self, e, is_const);
156             }
157         }
158     }
159 }