/
lifetime.rs
132 lines (115 loc) · 4.79 KB
/
lifetime.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! This module implements the check that the lifetime of a borrow
//! does not exceed the lifetime of the value being borrowed.
use crate::borrowck::*;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
use rustc::middle::region;
use rustc::ty;
use syntax::ast;
use syntax_pos::Span;
use log::debug;
type R = Result<(),()>;
pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
item_scope: region::Scope,
span: Span,
cause: euv::LoanCause,
cmt: &'a mc::cmt_<'tcx>,
loan_region: ty::Region<'tcx>)
-> Result<(),()> {
//! Reports error if `loan_region` is larger than S
//! where S is `item_scope` if `cmt` is an upvar,
//! and is scope of `cmt` otherwise.
debug!("guarantee_lifetime(cmt={:?}, loan_region={:?})",
cmt, loan_region);
let ctxt = GuaranteeLifetimeContext {bccx: bccx,
item_scope,
span,
cause,
loan_region,
cmt_original: cmt};
ctxt.check(cmt, None)
}
///////////////////////////////////////////////////////////////////////////
// Private
struct GuaranteeLifetimeContext<'a, 'tcx: 'a> {
bccx: &'a BorrowckCtxt<'a, 'tcx>,
// the scope of the function body for the enclosing item
item_scope: region::Scope,
span: Span,
cause: euv::LoanCause,
loan_region: ty::Region<'tcx>,
cmt_original: &'a mc::cmt_<'tcx>
}
impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
fn check(&self, cmt: &mc::cmt_<'tcx>, discr_scope: Option<ast::NodeId>) -> R {
//! Main routine. Walks down `cmt` until we find the
//! "guarantor". Reports an error if `self.loan_region` is
//! larger than scope of `cmt`.
debug!("guarantee_lifetime.check(cmt={:?}, loan_region={:?})",
cmt,
self.loan_region);
match cmt.cat {
Categorization::Rvalue(..) |
Categorization::ThreadLocal(..) |
Categorization::Local(..) | // L-Local
Categorization::Upvar(..) |
Categorization::Deref(_, mc::BorrowedPtr(..)) | // L-Deref-Borrowed
Categorization::Deref(_, mc::UnsafePtr(..)) => {
self.check_scope(self.scope(cmt))
}
Categorization::StaticItem => {
Ok(())
}
Categorization::Downcast(ref base, _) |
Categorization::Deref(ref base, mc::Unique) | // L-Deref-Send
Categorization::Interior(ref base, _) => { // L-Field
self.check(base, discr_scope)
}
}
}
fn check_scope(&self, max_scope: ty::Region<'tcx>) -> R {
//! Reports an error if `loan_region` is larger than `max_scope`
if !self.bccx.is_subregion_of(self.loan_region, max_scope) {
Err(self.report_error(err_out_of_scope(max_scope, self.loan_region, self.cause)))
} else {
Ok(())
}
}
fn scope(&self, cmt: &mc::cmt_<'tcx>) -> ty::Region<'tcx> {
//! Returns the maximal region scope for the which the
//! place `cmt` is guaranteed to be valid without any
//! rooting etc, and presuming `cmt` is not mutated.
match cmt.cat {
Categorization::ThreadLocal(temp_scope) |
Categorization::Rvalue(temp_scope) => {
temp_scope
}
Categorization::Upvar(..) => {
self.bccx.tcx.mk_region(ty::ReScope(self.item_scope))
}
Categorization::Local(hir_id) => {
self.bccx.tcx.mk_region(ty::ReScope(
self.bccx.region_scope_tree.var_scope(hir_id.local_id)))
}
Categorization::StaticItem |
Categorization::Deref(_, mc::UnsafePtr(..)) => {
self.bccx.tcx.types.re_static
}
Categorization::Deref(_, mc::BorrowedPtr(_, r)) => {
r
}
Categorization::Downcast(ref cmt, _) |
Categorization::Deref(ref cmt, mc::Unique) |
Categorization::Interior(ref cmt, _) => {
self.scope(cmt)
}
}
}
fn report_error(&self, code: bckerr_code<'tcx>) {
self.bccx.report(BckError { cmt: self.cmt_original,
span: self.span,
cause: BorrowViolation(self.cause),
code: code });
}
}