(index<- )        ./librustc/middle/check_static.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Sat Apr 19 11:22:39 2014
   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 has a dtor
  22  //
  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
  26  
  27  use middle::ty;
  28  
  29  use syntax::ast;
  30  use syntax::codemap::Span;
  31  use syntax::visit::Visitor;
  32  use syntax::visit;
  33  use syntax::print::pprust;
  34  
  35  
  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())
  41  
  42      let suffix = if tcontents.has_dtor() {
  43          "destructors"
  44      } else if tcontents.owns_managed() {
  45          "managed pointers"
  46      } else if tcontents.owns_owned() {
  47          "owned pointers"
  48      } else {
  49          return None;
  50      };
  51  
  52      Some(format!("mutable static items are not allowed to have {}", suffix))
  53  }
  54  
  55  struct CheckStaticVisitor<'a> {
  56      tcx: &'a ty::ctxt,
  57  }
  58  
  59  pub fn check_crate(tcx: &ty::ctxt, krate: &ast::Crate) {
  60      visit::walk_crate(&mut CheckStaticVisitor { tcx: tcx }, krate, false)
  61  }
  62  
  63  impl<'a> CheckStaticVisitor<'a> {
  64      fn report_error(&self, spanSpan, resultOption<~str>) -> bool {
  65          match result {
  66              None => { false }
  67              Some(msg) => {
  68                  self.tcx.sess.span_err(span, msg);
  69                  true
  70              }
  71          }
  72      }
  73  }
  74  
  75  impl<'a> Visitor<bool> for CheckStaticVisitor<'a> {
  76  
  77      fn visit_item(&mut self, i&ast::Item, _is_constbool) {
  78          debug!("visit_item(item={})", pprust::item_to_str(i));
  79          match i.node {
  80              ast::ItemStatic(_, mutability, expr) => {
  81                  match mutability {
  82                      ast::MutImmutable => {
  83                          self.visit_expr(expr, true);
  84                      }
  85                      ast::MutMutable => {
  86                          self.report_error(expr.span, safe_type_for_static_mut(self.tcx, expr));
  87                      }
  88                  }
  89              }
  90              _ => { visit::walk_item(self, i, false) }
  91          }
  92      }
  93  
  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
  99      /// down through it.
 100      fn visit_expr(&mut self, e&ast::Expr, is_constbool) {
 101          debug!("visit_expr(expr={})", pprust::expr_to_str(e));
 102  
 103          if !is_const {
 104              return visit::walk_expr(self, e, is_const);
 105          }
 106  
 107          match e.node {
 108              ast::ExprField(..) | ast::ExprVec(..) |
 109              ast::ExprBlock(..) | ast::ExprTup(..) |
 110              ast::ExprVstore(_, ast::ExprVstoreSlice) => {
 111                  visit::walk_expr(self, e, is_const);
 112              }
 113              ast::ExprVstore(_, ast::ExprVstoreMutSlice) => {
 114                  self.tcx.sess.span_err(e.span,
 115                                         "static items are not allowed to have mutable slices");
 116             },
 117              ast::ExprUnary(ast::UnBox, _) => {
 118                  self.tcx.sess.span_err(e.span,
 119                                     "static items are not allowed to have managed pointers");
 120              }
 121              ast::ExprBox(..) |
 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");
 126              }
 127              _ => {
 128                  let node_ty = ty::node_id_to_type(self.tcx, e.id);
 129  
 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()));
 136                              return;
 137                          }
 138                      }
 139                      _ => {}
 140                  }
 141                  visit::walk_expr(self, e, is_const);
 142              }
 143          }
 144      }
 145  }