]> git.proxmox.com Git - rustc.git/blob - src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
9f7b4cf26e1c47fa60dabc40b6bdc37abb10c293
[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::region;
18 use rustc::middle::ty;
19 use rustc::util::ppaux::Repr;
20 use syntax::ast;
21 use syntax::codemap::Span;
22
23 type R = Result<(),()>;
24
25 pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
26 item_scope: region::CodeExtent,
27 span: Span,
28 cause: euv::LoanCause,
29 cmt: mc::cmt<'tcx>,
30 loan_region: ty::Region,
31 _: ty::BorrowKind)
32 -> Result<(),()> {
33 //! Reports error if `loan_region` is larger than S
34 //! where S is `item_scope` if `cmt` is an upvar,
35 //! and is scope of `cmt` otherwise.
36 debug!("guarantee_lifetime(cmt={}, loan_region={})",
37 cmt.repr(bccx.tcx), loan_region.repr(bccx.tcx));
38 let ctxt = GuaranteeLifetimeContext {bccx: bccx,
39 item_scope: item_scope,
40 span: span,
41 cause: cause,
42 loan_region: loan_region,
43 cmt_original: cmt.clone()};
44 ctxt.check(&cmt, None)
45 }
46
47 ///////////////////////////////////////////////////////////////////////////
48 // Private
49
50 struct GuaranteeLifetimeContext<'a, 'tcx: 'a> {
51 bccx: &'a BorrowckCtxt<'a, 'tcx>,
52
53 // the scope of the function body for the enclosing item
54 item_scope: region::CodeExtent,
55
56 span: Span,
57 cause: euv::LoanCause,
58 loan_region: ty::Region,
59 cmt_original: mc::cmt<'tcx>
60 }
61
62 impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
63
64 fn check(&self, cmt: &mc::cmt<'tcx>, discr_scope: Option<ast::NodeId>) -> R {
65 //! Main routine. Walks down `cmt` until we find the
66 //! "guarantor". Reports an error if `self.loan_region` is
67 //! larger than scope of `cmt`.
68 debug!("guarantee_lifetime.check(cmt={}, loan_region={})",
69 cmt.repr(self.bccx.tcx),
70 self.loan_region.repr(self.bccx.tcx));
71
72 match cmt.cat {
73 mc::cat_rvalue(..) |
74 mc::cat_local(..) | // L-Local
75 mc::cat_upvar(..) |
76 mc::cat_deref(_, _, mc::BorrowedPtr(..)) | // L-Deref-Borrowed
77 mc::cat_deref(_, _, mc::Implicit(..)) |
78 mc::cat_deref(_, _, mc::UnsafePtr(..)) => {
79 self.check_scope(self.scope(cmt))
80 }
81
82 mc::cat_static_item => {
83 Ok(())
84 }
85
86 mc::cat_downcast(ref base, _) |
87 mc::cat_deref(ref base, _, mc::Unique) | // L-Deref-Send
88 mc::cat_interior(ref base, _) => { // L-Field
89 self.check(base, discr_scope)
90 }
91 }
92 }
93
94 fn check_scope(&self, max_scope: ty::Region) -> R {
95 //! Reports an error if `loan_region` is larger than `max_scope`
96
97 if !self.bccx.is_subregion_of(self.loan_region, max_scope) {
98 Err(self.report_error(err_out_of_scope(max_scope, self.loan_region)))
99 } else {
100 Ok(())
101 }
102 }
103
104 fn scope(&self, cmt: &mc::cmt) -> ty::Region {
105 //! Returns the maximal region scope for the which the
106 //! lvalue `cmt` is guaranteed to be valid without any
107 //! rooting etc, and presuming `cmt` is not mutated.
108
109 match cmt.cat {
110 mc::cat_rvalue(temp_scope) => {
111 temp_scope
112 }
113 mc::cat_upvar(..) => {
114 ty::ReScope(self.item_scope)
115 }
116 mc::cat_static_item => {
117 ty::ReStatic
118 }
119 mc::cat_local(local_id) => {
120 ty::ReScope(self.bccx.tcx.region_maps.var_scope(local_id))
121 }
122 mc::cat_deref(_, _, mc::UnsafePtr(..)) => {
123 ty::ReStatic
124 }
125 mc::cat_deref(_, _, mc::BorrowedPtr(_, r)) |
126 mc::cat_deref(_, _, mc::Implicit(_, r)) => {
127 r
128 }
129 mc::cat_downcast(ref cmt, _) |
130 mc::cat_deref(ref cmt, _, mc::Unique) |
131 mc::cat_interior(ref cmt, _) => {
132 self.scope(cmt)
133 }
134 }
135 }
136
137 fn report_error(&self, code: bckerr_code) {
138 self.bccx.report(BckError { cmt: self.cmt_original.clone(),
139 span: self.span,
140 cause: self.cause,
141 code: code });
142 }
143 }