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.
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 //! This module implements the check that the lifetime of a borrow
12 //! does not exceed the lifetime of the value being borrowed.
15 use rustc::middle::expr_use_visitor as euv;
16 use rustc::middle::mem_categorization as mc;
17 use rustc::middle::mem_categorization::Categorization;
18 use rustc::middle::region;
24 type R = Result<(),()>;
26 pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
27 item_scope: region::Scope,
29 cause: euv::LoanCause,
31 loan_region: ty::Region<'tcx>,
34 //! Reports error if `loan_region` is larger than S
35 //! where S is `item_scope` if `cmt` is an upvar,
36 //! and is scope of `cmt` otherwise.
37 debug!("guarantee_lifetime(cmt={:?}, loan_region={:?})",
39 let ctxt = GuaranteeLifetimeContext {bccx: bccx,
44 cmt_original: cmt.clone()};
45 ctxt.check(&cmt, None)
48 ///////////////////////////////////////////////////////////////////////////
51 struct GuaranteeLifetimeContext<'a, 'tcx: 'a> {
52 bccx: &'a BorrowckCtxt<'a, 'tcx>,
54 // the scope of the function body for the enclosing item
55 item_scope: region::Scope,
58 cause: euv::LoanCause,
59 loan_region: ty::Region<'tcx>,
60 cmt_original: mc::cmt<'tcx>
63 impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
65 fn check(&self, cmt: &mc::cmt<'tcx>, discr_scope: Option<ast::NodeId>) -> R {
66 //! Main routine. Walks down `cmt` until we find the
67 //! "guarantor". Reports an error if `self.loan_region` is
68 //! larger than scope of `cmt`.
69 debug!("guarantee_lifetime.check(cmt={:?}, loan_region={:?})",
74 Categorization::Rvalue(..) |
75 Categorization::Local(..) | // L-Local
76 Categorization::Upvar(..) |
77 Categorization::Deref(_, mc::BorrowedPtr(..)) | // L-Deref-Borrowed
78 Categorization::Deref(_, mc::Implicit(..)) |
79 Categorization::Deref(_, mc::UnsafePtr(..)) => {
80 self.check_scope(self.scope(cmt))
83 Categorization::StaticItem => {
87 Categorization::Downcast(ref base, _) |
88 Categorization::Deref(ref base, mc::Unique) | // L-Deref-Send
89 Categorization::Interior(ref base, _) => { // L-Field
90 self.check(base, discr_scope)
95 fn check_scope(&self, max_scope: ty::Region<'tcx>) -> R {
96 //! Reports an error if `loan_region` is larger than `max_scope`
98 if !self.bccx.is_subregion_of(self.loan_region, max_scope) {
99 Err(self.report_error(err_out_of_scope(max_scope, self.loan_region, self.cause)))
105 fn scope(&self, cmt: &mc::cmt<'tcx>) -> ty::Region<'tcx> {
106 //! Returns the maximal region scope for the which the
107 //! place `cmt` is guaranteed to be valid without any
108 //! rooting etc, and presuming `cmt` is not mutated.
111 Categorization::Rvalue(temp_scope) => {
114 Categorization::Upvar(..) => {
115 self.bccx.tcx.mk_region(ty::ReScope(self.item_scope))
117 Categorization::Local(local_id) => {
118 let hir_id = self.bccx.tcx.hir.node_to_hir_id(local_id);
119 self.bccx.tcx.mk_region(ty::ReScope(
120 self.bccx.region_scope_tree.var_scope(hir_id.local_id)))
122 Categorization::StaticItem |
123 Categorization::Deref(_, mc::UnsafePtr(..)) => {
124 self.bccx.tcx.types.re_static
126 Categorization::Deref(_, mc::BorrowedPtr(_, r)) |
127 Categorization::Deref(_, mc::Implicit(_, r)) => {
130 Categorization::Downcast(ref cmt, _) |
131 Categorization::Deref(ref cmt, mc::Unique) |
132 Categorization::Interior(ref cmt, _) => {
138 fn report_error(&self, code: bckerr_code<'tcx>) {
139 self.bccx.report(BckError { cmt: self.cmt_original.clone(),
141 cause: BorrowViolation(self.cause),