]> git.proxmox.com Git - rustc.git/blob - src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_borrowck / borrowck / gather_loans / lifetime.rs
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 //! This module implements the check that the lifetime of a borrow
12 //! does not exceed the lifetime of the value being borrowed.
13
14 use borrowck::*;
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;
19 use rustc::ty;
20
21 use syntax::ast;
22 use syntax::codemap::Span;
23
24 type R = Result<(),()>;
25
26 pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
27 item_scope: region::CodeExtent,
28 span: Span,
29 cause: euv::LoanCause,
30 cmt: mc::cmt<'tcx>,
31 loan_region: ty::Region,
32 _: ty::BorrowKind)
33 -> Result<(),()> {
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={:?})",
38 cmt, loan_region);
39 let ctxt = GuaranteeLifetimeContext {bccx: bccx,
40 item_scope: item_scope,
41 span: span,
42 cause: cause,
43 loan_region: loan_region,
44 cmt_original: cmt.clone()};
45 ctxt.check(&cmt, None)
46 }
47
48 ///////////////////////////////////////////////////////////////////////////
49 // Private
50
51 struct GuaranteeLifetimeContext<'a, 'tcx: 'a> {
52 bccx: &'a BorrowckCtxt<'a, 'tcx>,
53
54 // the scope of the function body for the enclosing item
55 item_scope: region::CodeExtent,
56
57 span: Span,
58 cause: euv::LoanCause,
59 loan_region: ty::Region,
60 cmt_original: mc::cmt<'tcx>
61 }
62
63 impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
64
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={:?})",
70 cmt,
71 self.loan_region);
72
73 match cmt.cat {
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))
81 }
82
83 Categorization::StaticItem => {
84 Ok(())
85 }
86
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)
91 }
92 }
93 }
94
95 fn check_scope(&self, max_scope: ty::Region) -> R {
96 //! Reports an error if `loan_region` is larger than `max_scope`
97
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)))
100 } else {
101 Ok(())
102 }
103 }
104
105 fn scope(&self, cmt: &mc::cmt) -> ty::Region {
106 //! Returns the maximal region scope for the which the
107 //! lvalue `cmt` is guaranteed to be valid without any
108 //! rooting etc, and presuming `cmt` is not mutated.
109
110 match cmt.cat {
111 Categorization::Rvalue(temp_scope) => {
112 temp_scope
113 }
114 Categorization::Upvar(..) => {
115 ty::ReScope(self.item_scope)
116 }
117 Categorization::StaticItem => {
118 ty::ReStatic
119 }
120 Categorization::Local(local_id) => {
121 ty::ReScope(self.bccx.tcx.region_maps.var_scope(local_id))
122 }
123 Categorization::Deref(_, _, mc::UnsafePtr(..)) => {
124 ty::ReStatic
125 }
126 Categorization::Deref(_, _, mc::BorrowedPtr(_, r)) |
127 Categorization::Deref(_, _, mc::Implicit(_, r)) => {
128 r
129 }
130 Categorization::Downcast(ref cmt, _) |
131 Categorization::Deref(ref cmt, _, mc::Unique) |
132 Categorization::Interior(ref cmt, _) => {
133 self.scope(cmt)
134 }
135 }
136 }
137
138 fn report_error(&self, code: bckerr_code) {
139 self.bccx.report(BckError { cmt: self.cmt_original.clone(),
140 span: self.span,
141 cause: BorrowViolation(self.cause),
142 code: code });
143 }
144 }