(index<- )        ./librustc/middle/borrowck/gather_loans/restrictions.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2012 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  /*!
  12   * Computes the restrictions that result from a borrow.
  13   */
  14  
  15  use middle::borrowck::*;
  16  use euv = middle::expr_use_visitor;
  17  use mc = middle::mem_categorization;
  18  use middle::ty;
  19  use syntax::codemap::Span;
  20  use util::ppaux::Repr;
  21  
  22  use std::rc::Rc;
  23  
  24  pub enum RestrictionResult {
  25      Safe,
  26      SafeIf(Rc<LoanPath>, Vec<Restriction>)
  27  }
  28  
  29  pub fn compute_restrictions(bccx: &BorrowckCtxt,
  30                              spanSpan,
  31                              causeeuv::LoanCause,
  32                              cmtmc::cmt,
  33                              loan_regionty::Region,
  34                              restrRestrictionSet) -> RestrictionResult {
  35      let ctxt = RestrictionsContext {
  36          bccx: bccx,
  37          span: span,
  38          cause: cause,
  39          cmt_original: cmt.clone(),
  40          loan_region: loan_region,
  41      };
  42  
  43      ctxt.restrict(cmt, restr)
  44  }
  45  
  46  ///////////////////////////////////////////////////////////////////////////
  47  // Private
  48  
  49  struct RestrictionsContext<'a> {
  50      bccx: &'a BorrowckCtxt<'a>,
  51      span: Span,
  52      cmt_original: mc::cmt,
  53      loan_region: ty::Region,
  54      cause: euv::LoanCause,
  55  }
  56  
  57  impl<'a> RestrictionsContext<'a> {
  58      fn restrict(&self,
  59                  cmtmc::cmt,
  60                  restrictionsRestrictionSet) -> RestrictionResult {
  61          debug!("restrict(cmt={}, restrictions={})",
  62                 cmt.repr(self.bccx.tcx),
  63                 restrictions.repr(self.bccx.tcx));
  64  
  65          match cmt.cat.clone() {
  66              mc::cat_rvalue(..) => {
  67                  // Effectively, rvalues are stored into a
  68                  // non-aliasable temporary on the stack. Since they
  69                  // are inherently non-aliasable, they can only be
  70                  // accessed later through the borrow itself and hence
  71                  // must inherently comply with its terms.
  72                  Safe
  73              }
  74  
  75              mc::cat_local(local_id) |
  76              mc::cat_arg(local_id) |
  77              mc::cat_upvar(ty::UpvarId {var_id: local_id, ..}, _) => {
  78                  // R-Variable
  79                  let lp = Rc::new(LpVar(local_id));
  80                  SafeIf(lp.clone(), vec!(Restriction {
  81                      loan_path: lp,
  82                      set: restrictions
  83                  }))
  84              }
  85  
  86              mc::cat_downcast(cmt_base) => {
  87                  // When we borrow the interior of an enum, we have to
  88                  // ensure the enum itself is not mutated, because that
  89                  // could cause the type of the memory to change.
  90                  self.restrict(
  91                      cmt_base,
  92                      restrictions | RESTR_MUTATE)
  93              }
  94  
  95              mc::cat_interior(cmt_base, i) => {
  96                  // R-Field
  97                  //
  98                  // Overwriting the base would not change the type of
  99                  // the memory, so no additional restrictions are
 100                  // needed.
 101                  let result = self.restrict(cmt_base, restrictions);
 102                  self.extend(result, cmt.mutbl, LpInterior(i), restrictions)
 103              }
 104  
 105              mc::cat_deref(cmt_base, _, pk @ mc::OwnedPtr) |
 106              mc::cat_deref(cmt_base, _, pk @ mc::GcPtr) => {
 107                  // R-Deref-Send-Pointer
 108                  //
 109                  // When we borrow the interior of an owned pointer, we
 110                  // cannot permit the base to be mutated, because that
 111                  // would cause the unique pointer to be freed.
 112                  //
 113                  // For a managed pointer, the rules are basically the
 114                  // same, because this could be the last ref.
 115                  // Eventually we should make these non-special and
 116                  // just rely on Deref<T> implementation.
 117                  let result = self.restrict(
 118                      cmt_base,
 119                      restrictions | RESTR_MUTATE);
 120                  self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
 121              }
 122  
 123              mc::cat_copied_upvar(..) | // FIXME(#2152) allow mutation of upvars
 124              mc::cat_static_item(..) => {
 125                  Safe
 126              }
 127  
 128              mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::ImmBorrow, lt)) |
 129              mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::UniqueImmBorrow, lt)) => {
 130                  // R-Deref-Imm-Borrowed
 131                  if !self.bccx.is_subregion_of(self.loan_region, lt) {
 132                      self.bccx.report(
 133                          BckError {
 134                              span: self.span,
 135                              cause: self.cause,
 136                              cmt: cmt_base,
 137                              code: err_borrowed_pointer_too_short(
 138                                  self.loan_region, lt, restrictions)});
 139                      return Safe;
 140                  }
 141                  Safe
 142              }
 143  
 144              mc::cat_deref(cmt_base, _, pk @ mc::BorrowedPtr(ty::MutBorrow, lt)) => {
 145                  // R-Deref-Mut-Borrowed
 146                  if !self.bccx.is_subregion_of(self.loan_region, lt) {
 147                      self.bccx.report(
 148                          BckError {
 149                              span: self.span,
 150                              cause: self.cause,
 151                              cmt: cmt_base,
 152                              code: err_borrowed_pointer_too_short(
 153                                  self.loan_region, lt, restrictions)});
 154                      return Safe;
 155                  }
 156  
 157                  let result = self.restrict(cmt_base, restrictions);
 158                  self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
 159              }
 160  
 161              mc::cat_deref(_, _, mc::UnsafePtr(..)) => {
 162                  // We are very trusting when working with unsafe pointers.
 163                  Safe
 164              }
 165  
 166              mc::cat_discr(cmt_base, _) => {
 167                  self.restrict(cmt_base, restrictions)
 168              }
 169          }
 170      }
 171  
 172      fn extend(&self,
 173                resultRestrictionResult,
 174                mcmc::MutabilityCategory,
 175                elemLoanPathElem,
 176                restrictionsRestrictionSet) -> RestrictionResult {
 177          match result {
 178              Safe => Safe,
 179              SafeIf(base_lp, mut base_vec) => {
 180                  let lp = Rc::new(LpExtend(base_lp, mc, elem));
 181                  base_vec.push(Restriction {
 182                      loan_path: lp.clone(),
 183                      set: restrictions
 184                  });
 185                  SafeIf(lp, base_vec)
 186              }
 187          }
 188      }
 189  }