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.
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 // Verifies that the types and values of static items
12 // are safe. The rules enforced by this module are:
14 // - For each *mutable* static item, it checks that its **type**:
15 // - doesn't have a destructor
16 // - doesn't own an owned pointer
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 has a dtor
23 // Rules Enforced Elsewhere:
24 // - It's not possible to take the address of a static item with unsafe interior. This is enforced
25 // by borrowck::gather_loans
30 use syntax::codemap::Span;
31 use syntax::visit::Visitor;
33 use syntax::print::pprust;
36 fn safe_type_for_static_mut(cx: &ty::ctxt, e: &ast::Expr) -> Option<~str> {
37 let node_ty = ty::node_id_to_type(cx, e.id);
38 let tcontents = ty::type_contents(cx, node_ty);
39 debug!("safe_type_for_static_mut(dtor={}, managed={}, owned={})",
40 tcontents.has_dtor(), tcontents.owns_managed(), tcontents.owns_owned())
42 let suffix = if tcontents.has_dtor() {
44 } else if tcontents.owns_managed() {
46 } else if tcontents.owns_owned() {
52 Some(format!("mutable static items are not allowed to have {}", suffix))
55 struct CheckStaticVisitor<'a> {
59 pub fn check_crate(tcx: &ty::ctxt, krate: &ast::Crate) {
60 visit::walk_crate(&mut CheckStaticVisitor { tcx: tcx }, krate, false)
63 impl<'a> CheckStaticVisitor<'a> {
64 fn report_error(&self, span: Span, result: Option<~str>) -> bool {
68 self.tcx.sess.span_err(span, msg);
75 impl<'a> Visitor<bool> for CheckStaticVisitor<'a> {
77 fn visit_item(&mut self, i: &ast::Item, _is_const: bool) {
78 debug!("visit_item(item={})", pprust::item_to_str(i));
80 ast::ItemStatic(_, mutability, expr) => {
82 ast::MutImmutable => {
83 self.visit_expr(expr, true);
86 self.report_error(expr.span, safe_type_for_static_mut(self.tcx, expr));
90 _ => { visit::walk_item(self, i, false) }
94 /// This method is used to enforce the constraints on
95 /// immutable static items. It walks through the *value*
96 /// of the item walking down the expression and evaluating
97 /// every nested expression. if the expression is not part
98 /// of a static item, this method does nothing but walking
100 fn visit_expr(&mut self, e: &ast::Expr, is_const: bool) {
101 debug!("visit_expr(expr={})", pprust::expr_to_str(e));
104 return visit::walk_expr(self, e, is_const);
108 ast::ExprField(..) | ast::ExprVec(..) |
109 ast::ExprBlock(..) | ast::ExprTup(..) |
110 ast::ExprVstore(_, ast::ExprVstoreSlice) => {
111 visit::walk_expr(self, e, is_const);
113 ast::ExprVstore(_, ast::ExprVstoreMutSlice) => {
114 self.tcx.sess.span_err(e.span,
115 "static items are not allowed to have mutable slices");
117 ast::ExprUnary(ast::UnBox, _) => {
118 self.tcx.sess.span_err(e.span,
119 "static items are not allowed to have managed pointers");
122 ast::ExprUnary(ast::UnUniq, _) |
123 ast::ExprVstore(_, ast::ExprVstoreUniq) => {
124 self.tcx.sess.span_err(e.span,
125 "static items are not allowed to have owned pointers");
128 let node_ty = ty::node_id_to_type(self.tcx, e.id);
130 match ty::get(node_ty).sty {
131 ty::ty_struct(did, _) |
132 ty::ty_enum(did, _) => {
133 if ty::has_dtor(self.tcx, did) {
134 self.report_error(e.span,
135 Some("static items are not allowed to have destructors".to_owned()));
141 visit::walk_expr(self, e, is_const);