]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_typeck/src/check/regionck.rs
New upstream version 1.62.1+dfsg1
[rustc.git] / compiler / rustc_typeck / src / check / regionck.rs
CommitLineData
1a4d82fc
JJ
1//! The region check is a final pass that runs over the AST after we have
2//! inferred the type constraints but before we have actually finalized
9fa01778 3//! the types. Its purpose is to embed a variety of region constraints.
1a4d82fc
JJ
4//! Inserting these constraints as a separate pass is good because (1) it
5//! localizes the code that has to do with region inference and (2) often
6//! we cannot know what constraints are needed until the basic types have
7//! been inferred.
8//!
9//! ### Interaction with the borrow checker
10//!
11//! In general, the job of the borrowck module (which runs later) is to
12//! check that all soundness criteria are met, given a particular set of
13//! regions. The job of *this* module is to anticipate the needs of the
14//! borrow checker and infer regions that will satisfy its requirements.
15//! It is generally true that the inference doesn't need to be sound,
16//! meaning that if there is a bug and we inferred bad regions, the borrow
17//! checker should catch it. This is not entirely true though; for
18//! example, the borrow checker doesn't check subtyping, and it doesn't
19//! check that region pointers are always live when they are used. It
20//! might be worthwhile to fix this so that borrowck serves as a kind of
21//! verification step -- that would add confidence in the overall
22//! correctness of the compiler, at the cost of duplicating some type
23//! checks and effort.
24//!
25//! ### Inferring the duration of borrows, automatic and otherwise
26//!
27//! Whenever we introduce a borrowed pointer, for example as the result of
28//! a borrow expression `let x = &data`, the lifetime of the pointer `x`
29//! is always specified as a region inference variable. `regionck` has the
30//! job of adding constraints such that this inference variable is as
31//! narrow as possible while still accommodating all uses (that is, every
32//! dereference of the resulting pointer must be within the lifetime).
33//!
34//! #### Reborrows
35//!
36//! Generally speaking, `regionck` does NOT try to ensure that the data
9fa01778 37//! `data` will outlive the pointer `x`. That is the job of borrowck. The
1a4d82fc
JJ
38//! one exception is when "re-borrowing" the contents of another borrowed
39//! pointer. For example, imagine you have a borrowed pointer `b` with
9fa01778
XL
40//! lifetime `L1` and you have an expression `&*b`. The result of this
41//! expression will be another borrowed pointer with lifetime `L2` (which is
1a4d82fc 42//! an inference variable). The borrow checker is going to enforce the
9fa01778
XL
43//! constraint that `L2 < L1`, because otherwise you are re-borrowing data
44//! for a lifetime larger than the original loan. However, without the
1a4d82fc 45//! routines in this module, the region inferencer would not know of this
9fa01778
XL
46//! dependency and thus it might infer the lifetime of `L2` to be greater
47//! than `L1` (issue #3148).
1a4d82fc
JJ
48//!
49//! There are a number of troublesome scenarios in the tests
50//! `region-dependent-*.rs`, but here is one example:
51//!
92a42be0 52//! struct Foo { i: i32 }
1a4d82fc 53//! struct Bar { foo: Foo }
9cc50fc6 54//! fn get_i<'a>(x: &'a Bar) -> &'a i32 {
1a4d82fc
JJ
55//! let foo = &x.foo; // Lifetime L1
56//! &foo.i // Lifetime L2
57//! }
58//!
59//! Note that this comes up either with `&` expressions, `ref`
60//! bindings, and `autorefs`, which are the three ways to introduce
61//! a borrow.
62//!
63//! The key point here is that when you are borrowing a value that
64//! is "guaranteed" by a borrowed pointer, you must link the
9fa01778
XL
65//! lifetime of that borrowed pointer (`L1`, here) to the lifetime of
66//! the borrow itself (`L2`). What do I mean by "guaranteed" by a
1a4d82fc
JJ
67//! borrowed pointer? I mean any data that is reached by first
68//! dereferencing a borrowed pointer and then either traversing
9fa01778 69//! interior offsets or boxes. We say that the guarantor
b039eaaf 70//! of such data is the region of the borrowed pointer that was
9fa01778 71//! traversed. This is essentially the same as the ownership
1a4d82fc
JJ
72//! relation, except that a borrowed pointer never owns its
73//! contents.
74
9fa01778
XL
75use crate::check::dropck;
76use crate::check::FnCtxt;
60c5eb7d 77use crate::mem_categorization as mc;
9fa01778 78use crate::middle::region;
c295e0f8
XL
79use crate::outlives::outlives_bounds::InferCtxtExt as _;
80use rustc_data_structures::stable_set::FxHashSet;
dfeec247 81use rustc_hir as hir;
f9f354fc 82use rustc_hir::def_id::LocalDefId;
5099ac24 83use rustc_hir::intravisit::{self, Visitor};
dfeec247 84use rustc_hir::PatKind;
74b04a01 85use rustc_infer::infer::outlives::env::OutlivesEnvironment;
c295e0f8 86use rustc_infer::infer::{self, InferCtxt, RegionObligation, RegionckMode};
3dfed10e 87use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId};
ba9703b0 88use rustc_middle::ty::adjustment;
ba9703b0 89use rustc_middle::ty::{self, Ty};
dfeec247 90use rustc_span::Span;
a7813a04 91use std::ops::Deref;
1a4d82fc 92
1a4d82fc
JJ
93// a variation on try that just returns unit
94macro_rules! ignore_err {
0bf4aa26
XL
95 ($e:expr) => {
96 match $e {
97 Ok(e) => e,
98 Err(_) => {
99 debug!("ignoring mem-categorization error!");
100 return ();
101 }
102 }
103 };
1a4d82fc
JJ
104}
105
3c0e092e 106pub(crate) trait OutlivesEnvironmentExt<'tcx> {
c295e0f8
XL
107 fn add_implied_bounds(
108 &mut self,
a2a8927a 109 infcx: &InferCtxt<'_, 'tcx>,
c295e0f8
XL
110 fn_sig_tys: FxHashSet<Ty<'tcx>>,
111 body_id: hir::HirId,
112 span: Span,
113 );
114}
115
116impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> {
117 /// This method adds "implied bounds" into the outlives environment.
118 /// Implied bounds are outlives relationships that we can deduce
119 /// on the basis that certain types must be well-formed -- these are
120 /// either the types that appear in the function signature or else
121 /// the input types to an impl. For example, if you have a function
122 /// like
123 ///
124 /// ```
125 /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { }
126 /// ```
127 ///
128 /// we can assume in the caller's body that `'b: 'a` and that `T:
129 /// 'b` (and hence, transitively, that `T: 'a`). This method would
130 /// add those assumptions into the outlives-environment.
131 ///
132 /// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs`
a2a8927a 133 fn add_implied_bounds<'a>(
c295e0f8
XL
134 &mut self,
135 infcx: &InferCtxt<'a, 'tcx>,
136 fn_sig_tys: FxHashSet<Ty<'tcx>>,
137 body_id: hir::HirId,
138 span: Span,
139 ) {
140 debug!("add_implied_bounds()");
141
142 for ty in fn_sig_tys {
143 let ty = infcx.resolve_vars_if_possible(ty);
144 debug!("add_implied_bounds: ty = {}", ty);
145 let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span);
146 self.add_outlives_bounds(Some(infcx), implied_bounds)
147 }
148 }
149}
150
1a4d82fc
JJ
151///////////////////////////////////////////////////////////////////////////
152// PUBLIC ENTRY POINTS
153
dc9dc135 154impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
dfeec247 155 pub fn regionck_expr(&self, body: &'tcx hir::Body<'tcx>) {
f9f354fc 156 let subject = self.tcx.hir().body_owner_def_id(body.id());
9fa01778 157 let id = body.value.hir_id;
f9f354fc 158 let mut rcx = RegionCtxt::new(self, id, Subject(subject), self.param_env);
0bf4aa26
XL
159
160 // There are no add'l implied bounds when checking a
161 // standalone expr (e.g., the `E` in a type like `[u32; E]`).
162 rcx.outlives_environment.save_implied_bounds(id);
163
dc9dc135 164 if !self.errors_reported_since_creation() {
a7813a04 165 // regionck assumes typeck succeeded
32a655c1
SL
166 rcx.visit_body(body);
167 rcx.visit_region_obligations(id);
a7813a04 168 }
ba9703b0 169 rcx.resolve_regions_and_report_errors(RegionckMode::for_item_body(self.tcx));
1a4d82fc 170 }
1a4d82fc 171
a7813a04
XL
172 /// Region checking during the WF phase for items. `wf_tys` are the
173 /// types from which we should derive implied bounds, if any.
04454e1e 174 #[instrument(level = "debug", skip(self))]
c295e0f8 175 pub fn regionck_item(&self, item_id: hir::HirId, span: Span, wf_tys: FxHashSet<Ty<'tcx>>) {
416331ca 176 let subject = self.tcx.hir().local_def_id(item_id);
f9f354fc 177 let mut rcx = RegionCtxt::new(self, item_id, Subject(subject), self.param_env);
dfeec247 178 rcx.outlives_environment.add_implied_bounds(self, wf_tys, item_id, span);
0bf4aa26 179 rcx.outlives_environment.save_implied_bounds(item_id);
a7813a04 180 rcx.visit_region_obligations(item_id);
ba9703b0 181 rcx.resolve_regions_and_report_errors(RegionckMode::default());
1a4d82fc
JJ
182 }
183
abe05a73
XL
184 /// Region check a function body. Not invoked on closures, but
185 /// only on the "root" fn item (in which closures may be
186 /// embedded). Walks the function body and adds various add'l
187 /// constraints that are needed for region inference. This is
188 /// separated both to isolate "pure" region constraints from the
189 /// rest of type check and because sometimes we need type
190 /// inference to have completed before we can determine which
191 /// constraints to add.
94222f64
XL
192 pub(crate) fn regionck_fn(
193 &self,
194 fn_id: hir::HirId,
195 body: &'tcx hir::Body<'tcx>,
196 span: Span,
c295e0f8 197 wf_tys: FxHashSet<Ty<'tcx>>,
94222f64 198 ) {
a7813a04 199 debug!("regionck_fn(id={})", fn_id);
f9f354fc 200 let subject = self.tcx.hir().body_owner_def_id(body.id());
9fa01778 201 let hir_id = body.value.hir_id;
f9f354fc 202 let mut rcx = RegionCtxt::new(self, hir_id, Subject(subject), self.param_env);
94222f64
XL
203 // We need to add the implied bounds from the function signature
204 rcx.outlives_environment.add_implied_bounds(self, wf_tys, fn_id, span);
205 rcx.outlives_environment.save_implied_bounds(fn_id);
a7813a04 206
dc9dc135 207 if !self.errors_reported_since_creation() {
a7813a04 208 // regionck assumes typeck succeeded
dc9dc135 209 rcx.visit_fn_body(fn_id, body, self.tcx.hir().span(fn_id));
a7813a04
XL
210 }
211
ba9703b0 212 rcx.resolve_regions_and_report_errors(RegionckMode::for_item_body(self.tcx));
a7813a04 213 }
1a4d82fc
JJ
214}
215
1a4d82fc
JJ
216///////////////////////////////////////////////////////////////////////////
217// INTERNALS
218
dc9dc135
XL
219pub struct RegionCtxt<'a, 'tcx> {
220 pub fcx: &'a FnCtxt<'a, 'tcx>,
1a4d82fc 221
dc9dc135 222 pub region_scope_tree: &'tcx region::ScopeTree,
7cac9316 223
abe05a73 224 outlives_environment: OutlivesEnvironment<'tcx>,
bd371182 225
85aaf69f 226 // id of innermost fn body id
9fa01778 227 body_id: hir::HirId,
f9f354fc 228 body_owner: LocalDefId,
1a4d82fc
JJ
229
230 // id of AST node being analyzed (the subject of the analysis).
f9f354fc 231 subject_def_id: LocalDefId,
7cac9316 232}
85aaf69f 233
dc9dc135
XL
234impl<'a, 'tcx> Deref for RegionCtxt<'a, 'tcx> {
235 type Target = FnCtxt<'a, 'tcx>;
a7813a04 236 fn deref(&self) -> &Self::Target {
c295e0f8 237 self.fcx
a7813a04
XL
238 }
239}
240
f9f354fc 241pub struct Subject(LocalDefId);
1a4d82fc 242
dc9dc135 243impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
0bf4aa26 244 pub fn new(
dc9dc135 245 fcx: &'a FnCtxt<'a, 'tcx>,
9fa01778 246 initial_body_id: hir::HirId,
0bf4aa26
XL
247 Subject(subject): Subject,
248 param_env: ty::ParamEnv<'tcx>,
dc9dc135 249 ) -> RegionCtxt<'a, 'tcx> {
ea8adc8c 250 let region_scope_tree = fcx.tcx.region_scope_tree(subject);
abe05a73 251 let outlives_environment = OutlivesEnvironment::new(param_env);
a7813a04 252 RegionCtxt {
3b2f2976 253 fcx,
ea8adc8c 254 region_scope_tree,
a7813a04 255 body_id: initial_body_id,
dc9dc135 256 body_owner: subject,
7cac9316 257 subject_def_id: subject,
abe05a73 258 outlives_environment,
85aaf69f 259 }
1a4d82fc
JJ
260 }
261
9fa01778 262 /// Try to resolve the type for the given node, returning `t_err` if an error results. Note that
1a4d82fc
JJ
263 /// we never care about the details of the error, the same error will be detected and reported
264 /// in the writeback phase.
265 ///
9fa01778 266 /// Note one important point: we do not attempt to resolve *region variables* here. This is
1a4d82fc
JJ
267 /// because regionck is essentially adding constraints to those region variables and so may yet
268 /// influence how they are resolved.
269 ///
270 /// Consider this silly example:
271 ///
04454e1e 272 /// ```ignore UNSOLVED (does replacing @i32 with Box<i32> preserve the desired semantics for the example?)
92a42be0
SL
273 /// fn borrow(x: &i32) -> &i32 {x}
274 /// fn foo(x: @i32) -> i32 { // block: B
1a4d82fc
JJ
275 /// let b = borrow(x); // region: <R0>
276 /// *b
277 /// }
278 /// ```
279 ///
9fa01778
XL
280 /// Here, the region of `b` will be `<R0>`. `<R0>` is constrained to be some subregion of the
281 /// block B and some superregion of the call. If we forced it now, we'd choose the smaller
282 /// region (the call). But that would make the *b illegal. Since we don't resolve, the type
92a42be0 283 /// of b will be `&<R0>.i32` and then `*b` will require that `<R0>` be bigger than the let and
1a4d82fc
JJ
284 /// the `*b` expression, so we will effectively resolve `<R0>` to be the block B.
285 pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> {
fc512014 286 self.resolve_vars_if_possible(unresolved_ty)
1a4d82fc
JJ
287 }
288
289 /// Try to resolve the type for the given node.
3b2f2976 290 fn resolve_node_type(&self, id: hir::HirId) -> Ty<'tcx> {
a7813a04 291 let t = self.node_ty(id);
1a4d82fc
JJ
292 self.resolve_type(t)
293 }
294
f9f354fc
XL
295 /// This is the "main" function when region-checking a function item or a
296 /// closure within a function item. It begins by updating various fields
297 /// (e.g., `outlives_environment`) to be appropriate to the function and
298 /// then adds constraints derived from the function body.
abe05a73
XL
299 ///
300 /// Note that it does **not** restore the state of the fields that
301 /// it updates! This is intentional, since -- for the main
302 /// function -- we wish to be able to read the final
303 /// `outlives_environment` and other fields from the caller. For
304 /// closures, however, we save and restore any "scoped state"
305 /// before we invoke this function. (See `visit_fn` in the
306 /// `intravisit::Visitor` impl below.)
0bf4aa26
XL
307 fn visit_fn_body(
308 &mut self,
9fa01778 309 id: hir::HirId, // the id of the fn itself
dfeec247 310 body: &'tcx hir::Body<'tcx>,
0bf4aa26
XL
311 span: Span,
312 ) {
1a4d82fc 313 // When we enter a function, we can derive
9fa01778 314 debug!("visit_fn_body(id={:?})", id);
1a4d82fc 315
32a655c1 316 let body_id = body.id();
9fa01778 317 self.body_id = body_id.hir_id;
f9f354fc 318 self.body_owner = self.tcx.hir().body_owner_def_id(body_id);
9cc50fc6 319
04454e1e
FG
320 let Some(fn_sig) = self.typeck_results.borrow().liberated_fn_sigs().get(id) else {
321 bug!("No fn-sig entry for id={:?}", id);
1a4d82fc
JJ
322 };
323
92a42be0
SL
324 // Collect the types from which we create inferred bounds.
325 // For the return type, if diverging, substitute `bool` just
326 // because it will have no effect.
327 //
9cc50fc6 328 // FIXME(#27579) return types should not be implied bounds
c295e0f8 329 let fn_sig_tys: FxHashSet<_> =
dfeec247 330 fn_sig.inputs().iter().cloned().chain(Some(fn_sig.output())).collect();
476ff2be 331
c295e0f8 332 self.outlives_environment.add_implied_bounds(self.fcx, fn_sig_tys, body_id.hir_id, span);
dfeec247 333 self.outlives_environment.save_implied_bounds(body_id.hir_id);
c295e0f8 334 self.link_fn_params(body.params);
32a655c1 335 self.visit_body(body);
9fa01778 336 self.visit_region_obligations(body_id.hir_id);
3c0e092e
XL
337 }
338
339 fn visit_inline_const(&mut self, id: hir::HirId, body: &'tcx hir::Body<'tcx>) {
340 debug!("visit_inline_const(id={:?})", id);
341
342 // Save state of current function. We will restore afterwards.
343 let old_body_id = self.body_id;
344 let old_body_owner = self.body_owner;
345 let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
bd371182 346
3c0e092e
XL
347 let body_id = body.id();
348 self.body_id = body_id.hir_id;
349 self.body_owner = self.tcx.hir().body_owner_def_id(body_id);
350
351 self.outlives_environment.save_implied_bounds(body_id.hir_id);
352
353 self.visit_body(body);
354 self.visit_region_obligations(body_id.hir_id);
355
356 // Restore state from previous function.
357 self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
358 self.body_id = old_body_id;
359 self.body_owner = old_body_owner;
1a4d82fc
JJ
360 }
361
9fa01778
XL
362 fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
363 debug!("visit_region_obligations: hir_id={:?}", hir_id);
85aaf69f
SL
364
365 // region checking can introduce new pending obligations
366 // which, when processed, might generate new region
367 // obligations. So make sure we process those.
a7813a04 368 self.select_all_obligations_or_error();
0bf4aa26 369 }
85aaf69f 370
ba9703b0 371 fn resolve_regions_and_report_errors(&self, mode: RegionckMode) {
abe05a73 372 self.infcx.process_registered_region_obligations(
0bf4aa26 373 self.outlives_environment.region_bound_pairs_map(),
f9652781 374 Some(self.tcx.lifetimes.re_root_empty),
abe05a73 375 self.param_env,
0bf4aa26 376 );
ff7c6d11 377
0bf4aa26 378 self.fcx.resolve_regions_and_report_errors(
f9f354fc 379 self.subject_def_id.to_def_id(),
0bf4aa26 380 &self.outlives_environment,
ba9703b0 381 mode,
0bf4aa26 382 );
a7813a04
XL
383 }
384
dfeec247 385 fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat<'_>) {
a7813a04 386 debug!("regionck::visit_pat(pat={:?})", pat);
94b46f34 387 pat.each_binding(|_, hir_id, span, _| {
3b2f2976 388 let typ = self.resolve_node_type(hir_id);
0531ce1d 389 let body_id = self.body_id;
5869c6ff 390 dropck::check_drop_obligations(self, typ, span, body_id);
a7813a04 391 })
1a4d82fc
JJ
392 }
393}
394
dc9dc135 395impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> {
1a4d82fc
JJ
396 // (..) FIXME(#3238) should use visit_pat, not visit_arm/visit_local,
397 // However, right now we run into an issue whereby some free
398 // regions are not properly related if they appear within the
399 // types of arguments that must be inferred. This could be
400 // addressed by deferring the construction of the region
401 // hierarchy, and in particular the relationships between free
402 // regions, until regionck, as described in #3238.
403
0bf4aa26
XL
404 fn visit_fn(
405 &mut self,
dc9dc135 406 fk: intravisit::FnKind<'tcx>,
dfeec247 407 _: &'tcx hir::FnDecl<'tcx>,
0bf4aa26
XL
408 body_id: hir::BodyId,
409 span: Span,
9fa01778 410 hir_id: hir::HirId,
0bf4aa26
XL
411 ) {
412 assert!(
6a06907d 413 matches!(fk, intravisit::FnKind::Closure),
0bf4aa26
XL
414 "visit_fn invoked for something other than a closure"
415 );
abe05a73
XL
416
417 // Save state of current function before invoking
418 // `visit_fn_body`. We will restore afterwards.
419 let old_body_id = self.body_id;
dc9dc135 420 let old_body_owner = self.body_owner;
3c0e092e 421 let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
abe05a73 422
0731742a 423 let body = self.tcx.hir().body(body_id);
9fa01778 424 self.visit_fn_body(hir_id, body, span);
abe05a73
XL
425
426 // Restore state from previous function.
3c0e092e 427 self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
abe05a73 428 self.body_id = old_body_id;
dc9dc135 429 self.body_owner = old_body_owner;
1a4d82fc
JJ
430 }
431
1a4d82fc
JJ
432 //visit_pat: visit_pat, // (..) see above
433
dfeec247 434 fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
a7813a04 435 // see above
c295e0f8 436 self.constrain_bindings_in_pat(arm.pat);
a7813a04 437 intravisit::walk_arm(self, arm);
1a4d82fc
JJ
438 }
439
dfeec247 440 fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
a7813a04 441 // see above
c295e0f8 442 self.constrain_bindings_in_pat(l.pat);
a7813a04
XL
443 self.link_local(l);
444 intravisit::walk_local(self, l);
445 }
1a4d82fc 446
dfeec247 447 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
a7813a04 448 // Check any autoderefs or autorefs that appear.
7cac9316 449 let cmt_result = self.constrain_adjustments(expr);
85aaf69f 450
a7813a04
XL
451 // If necessary, constrain destructors in this expression. This will be
452 // the adjusted form if there is an adjustment.
85aaf69f
SL
453 match cmt_result {
454 Ok(head_cmt) => {
83c7162d 455 self.check_safety_of_rvalue_destructor_if_necessary(&head_cmt, expr.span);
85aaf69f
SL
456 }
457 Err(..) => {
a7813a04 458 self.tcx.sess.delay_span_bug(expr.span, "cat_expr Errd");
85aaf69f
SL
459 }
460 }
85aaf69f 461
e74abb32 462 match expr.kind {
60c5eb7d 463 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref base) => {
c295e0f8 464 self.link_addr_of(expr, m, base);
a7813a04 465
a7813a04
XL
466 intravisit::walk_expr(self, expr);
467 }
1a4d82fc 468
c295e0f8
XL
469 hir::ExprKind::Match(ref discr, arms, _) => {
470 self.link_match(discr, arms);
1a4d82fc 471
a7813a04
XL
472 intravisit::walk_expr(self, expr);
473 }
1a4d82fc 474
3c0e092e
XL
475 hir::ExprKind::ConstBlock(anon_const) => {
476 let body = self.tcx.hir().body(anon_const.body);
477 self.visit_inline_const(anon_const.hir_id, body);
478 }
479
f9f354fc 480 _ => intravisit::walk_expr(self, expr),
1a4d82fc
JJ
481 }
482 }
483}
484
dc9dc135 485impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
9fa01778 486 /// Creates a temporary `MemCategorizationContext` and pass it to the closure.
041b39d2 487 fn with_mc<F, R>(&self, f: F) -> R
0bf4aa26 488 where
dc9dc135 489 F: for<'b> FnOnce(mc::MemCategorizationContext<'b, 'tcx>) -> R,
041b39d2 490 {
60c5eb7d 491 f(mc::MemCategorizationContext::new(
0bf4aa26 492 &self.infcx,
416331ca 493 self.outlives_environment.param_env,
dc9dc135 494 self.body_owner,
3dfed10e 495 &self.typeck_results.borrow(),
0bf4aa26 496 ))
041b39d2
XL
497 }
498
7cac9316 499 /// Invoked on any adjustments that occur. Checks that if this is a region pointer being
a7813a04 500 /// dereferenced, the lifetime of the pointer includes the deref expr.
f035d41b
XL
501 fn constrain_adjustments(
502 &mut self,
503 expr: &hir::Expr<'_>,
3dfed10e 504 ) -> mc::McResult<PlaceWithHirId<'tcx>> {
7cac9316 505 debug!("constrain_adjustments(expr={:?})", expr);
1a4d82fc 506
f9f354fc 507 let mut place = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?;
7cac9316 508
3dfed10e 509 let typeck_results = self.typeck_results.borrow();
c295e0f8 510 let adjustments = typeck_results.expr_adjustments(expr);
7cac9316 511 if adjustments.is_empty() {
f9f354fc 512 return Ok(place);
7cac9316
XL
513 }
514
515 debug!("constrain_adjustments: adjustments={:?}", adjustments);
1a4d82fc 516
7cac9316
XL
517 // If necessary, constrain destructors in the unadjusted form of this
518 // expression.
f9f354fc 519 self.check_safety_of_rvalue_destructor_if_necessary(&place, expr.span);
7cac9316 520
7cac9316 521 for adjustment in adjustments {
f9f354fc 522 debug!("constrain_adjustments: adjustment={:?}, place={:?}", adjustment, place);
7cac9316
XL
523
524 if let adjustment::Adjust::Deref(Some(deref)) = adjustment.kind {
0bf4aa26
XL
525 self.link_region(
526 expr.span,
527 deref.region,
528 ty::BorrowKind::from_mutbl(deref.mutbl),
f9f354fc 529 &place,
0bf4aa26 530 );
7cac9316
XL
531 }
532
533 if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind {
f9f354fc 534 self.link_autoref(expr, &place, autoref);
7cac9316
XL
535 }
536
c295e0f8 537 place = self.with_mc(|mc| mc.cat_expr_adjusted(expr, place, adjustment))?;
1a4d82fc 538 }
7cac9316 539
f9f354fc 540 Ok(place)
a7813a04 541 }
1a4d82fc 542
60c5eb7d
XL
543 fn check_safety_of_rvalue_destructor_if_necessary(
544 &mut self,
3dfed10e 545 place_with_id: &PlaceWithHirId<'tcx>,
60c5eb7d
XL
546 span: Span,
547 ) {
3dfed10e 548 if let PlaceBase::Rvalue = place_with_id.place.base {
f035d41b
XL
549 if place_with_id.place.projections.is_empty() {
550 let typ = self.resolve_type(place_with_id.place.ty());
60c5eb7d 551 let body_id = self.body_id;
5869c6ff 552 dropck::check_drop_obligations(self, typ, span, body_id);
60c5eb7d 553 }
85aaf69f 554 }
85aaf69f 555 }
abe05a73
XL
556 /// Adds constraints to inference such that `T: 'a` holds (or
557 /// reports an error if it cannot).
558 ///
559 /// # Parameters
560 ///
561 /// - `origin`, the reason we need this constraint
562 /// - `ty`, the type `T`
563 /// - `region`, the region `'a`
0bf4aa26
XL
564 pub fn type_must_outlive(
565 &self,
566 origin: infer::SubregionOrigin<'tcx>,
567 ty: Ty<'tcx>,
568 region: ty::Region<'tcx>,
569 ) {
570 self.infcx.register_region_obligation(
571 self.body_id,
dfeec247 572 RegionObligation { sub_region: region, sup_type: ty, origin },
0bf4aa26 573 );
abe05a73
XL
574 }
575
a7813a04
XL
576 /// Computes the guarantor for an expression `&base` and then ensures that the lifetime of the
577 /// resulting pointer is linked to the lifetime of its guarantor (if any).
dfeec247
XL
578 fn link_addr_of(
579 &mut self,
580 expr: &hir::Expr<'_>,
581 mutability: hir::Mutability,
582 base: &hir::Expr<'_>,
583 ) {
a7813a04 584 debug!("link_addr_of(expr={:?}, base={:?})", expr, base);
1a4d82fc 585
041b39d2 586 let cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(base)));
1a4d82fc 587
a7813a04 588 debug!("link_addr_of: cmt={:?}", cmt);
1a4d82fc 589
83c7162d 590 self.link_region_from_node_type(expr.span, expr.hir_id, mutability, &cmt);
a7813a04 591 }
1a4d82fc 592
a7813a04
XL
593 /// Computes the guarantors for any ref bindings in a `let` and
594 /// then ensures that the lifetime of the resulting pointer is
595 /// linked to the lifetime of the initialization expression.
dfeec247 596 fn link_local(&self, local: &hir::Local<'_>) {
a7813a04
XL
597 debug!("regionck::for_local()");
598 let init_expr = match local.init {
0bf4aa26
XL
599 None => {
600 return;
601 }
c295e0f8 602 Some(expr) => &*expr,
a7813a04 603 };
60c5eb7d 604 let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr)));
c295e0f8 605 self.link_pattern(discr_cmt, local.pat);
a7813a04 606 }
1a4d82fc 607
a7813a04
XL
608 /// Computes the guarantors for any ref bindings in a match and
609 /// then ensures that the lifetime of the resulting pointer is
610 /// linked to the lifetime of its guarantor (if any).
dfeec247 611 fn link_match(&self, discr: &hir::Expr<'_>, arms: &[hir::Arm<'_>]) {
a7813a04 612 debug!("regionck::for_match()");
60c5eb7d 613 let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(discr)));
a7813a04
XL
614 debug!("discr_cmt={:?}", discr_cmt);
615 for arm in arms {
c295e0f8 616 self.link_pattern(discr_cmt.clone(), arm.pat);
1a4d82fc
JJ
617 }
618 }
1a4d82fc 619
a7813a04
XL
620 /// Computes the guarantors for any ref bindings in a match and
621 /// then ensures that the lifetime of the resulting pointer is
622 /// linked to the lifetime of its guarantor (if any).
dfeec247 623 fn link_fn_params(&self, params: &[hir::Param<'_>]) {
e1599b0c
XL
624 for param in params {
625 let param_ty = self.node_ty(param.hir_id);
dfeec247
XL
626 let param_cmt =
627 self.with_mc(|mc| mc.cat_rvalue(param.hir_id, param.pat.span, param_ty));
e1599b0c 628 debug!("param_ty={:?} param_cmt={:?} param={:?}", param_ty, param_cmt, param);
c295e0f8 629 self.link_pattern(param_cmt, param.pat);
a7813a04 630 }
1a4d82fc 631 }
1a4d82fc 632
a7813a04
XL
633 /// Link lifetimes of any ref bindings in `root_pat` to the pointers found
634 /// in the discriminant, if needed.
3dfed10e 635 fn link_pattern(&self, discr_cmt: PlaceWithHirId<'tcx>, root_pat: &hir::Pat<'_>) {
dfeec247 636 debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat);
5d61e2ac 637 ignore_err!(self.with_mc(|mc| {
29967ef6 638 mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, hir::Pat { kind, span, hir_id, .. }| {
0bf4aa26 639 // `ref x` pattern
04454e1e
FG
640 if let PatKind::Binding(..) = kind
641 && let Some(ty::BindByReference(mutbl)) = mc.typeck_results.extract_binding_mode(self.tcx.sess, *hir_id, *span) {
642 self.link_region_from_node_type(*span, *hir_id, mutbl, sub_cmt);
1a4d82fc 643 }
041b39d2 644 })
5d61e2ac 645 }));
a7813a04 646 }
1a4d82fc 647
a7813a04
XL
648 /// Link lifetime of borrowed pointer resulting from autoref to lifetimes in the value being
649 /// autoref'd.
0bf4aa26
XL
650 fn link_autoref(
651 &self,
dfeec247 652 expr: &hir::Expr<'_>,
3dfed10e 653 expr_cmt: &PlaceWithHirId<'tcx>,
0bf4aa26
XL
654 autoref: &adjustment::AutoBorrow<'tcx>,
655 ) {
dfeec247 656 debug!("link_autoref(autoref={:?}, expr_cmt={:?})", autoref, expr_cmt);
a7813a04
XL
657
658 match *autoref {
c30ab7b3 659 adjustment::AutoBorrow::Ref(r, m) => {
83c7162d 660 self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m.into()), expr_cmt);
a7813a04 661 }
1a4d82fc 662
f9f354fc 663 adjustment::AutoBorrow::RawPtr(_) => {}
9346a6ac 664 }
1a4d82fc 665 }
1a4d82fc 666
a7813a04
XL
667 /// Like `link_region()`, except that the region is extracted from the type of `id`,
668 /// which must be some reference (`&T`, `&str`, etc).
0bf4aa26
XL
669 fn link_region_from_node_type(
670 &self,
671 span: Span,
672 id: hir::HirId,
673 mutbl: hir::Mutability,
3dfed10e 674 cmt_borrowed: &PlaceWithHirId<'tcx>,
0bf4aa26
XL
675 ) {
676 debug!(
677 "link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})",
678 id, mutbl, cmt_borrowed
679 );
a7813a04
XL
680
681 let rptr_ty = self.resolve_node_type(id);
1b1a35ee 682 if let ty::Ref(r, _, _) = rptr_ty.kind() {
0bf4aa26 683 debug!("rptr_ty={}", rptr_ty);
5099ac24 684 self.link_region(span, *r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed);
a7813a04 685 }
1a4d82fc 686 }
1a4d82fc 687
a7813a04
XL
688 /// Informs the inference engine that `borrow_cmt` is being borrowed with
689 /// kind `borrow_kind` and lifetime `borrow_region`.
690 /// In order to ensure borrowck is satisfied, this may create constraints
691 /// between regions, as explained in `link_reborrowed_region()`.
0bf4aa26
XL
692 fn link_region(
693 &self,
694 span: Span,
695 borrow_region: ty::Region<'tcx>,
696 borrow_kind: ty::BorrowKind,
3dfed10e 697 borrow_place: &PlaceWithHirId<'tcx>,
0bf4aa26 698 ) {
f035d41b
XL
699 let origin = infer::DataBorrowed(borrow_place.place.ty(), span);
700 self.type_must_outlive(origin, borrow_place.place.ty(), borrow_region);
a7813a04 701
f035d41b 702 for pointer_ty in borrow_place.place.deref_tys() {
0bf4aa26 703 debug!(
60c5eb7d
XL
704 "link_region(borrow_region={:?}, borrow_kind={:?}, pointer_ty={:?})",
705 borrow_region, borrow_kind, borrow_place
0bf4aa26 706 );
1b1a35ee 707 match *pointer_ty.kind() {
60c5eb7d
XL
708 ty::RawPtr(_) => return,
709 ty::Ref(ref_region, _, ref_mutability) => {
dfeec247
XL
710 if self.link_reborrowed_region(span, borrow_region, ref_region, ref_mutability)
711 {
60c5eb7d 712 return;
a7813a04 713 }
a7813a04 714 }
dfeec247 715 _ => assert!(pointer_ty.is_box(), "unexpected built-in deref type {}", pointer_ty),
a7813a04
XL
716 }
717 }
3dfed10e 718 if let PlaceBase::Upvar(upvar_id) = borrow_place.place.base {
60c5eb7d
XL
719 self.link_upvar_region(span, borrow_region, upvar_id);
720 }
a7813a04
XL
721 }
722
723 /// This is the most complicated case: the path being borrowed is
724 /// itself the referent of a borrowed pointer. Let me give an
725 /// example fragment of code to make clear(er) the situation:
726 ///
f9f354fc
XL
727 /// ```ignore (incomplete Rust code)
728 /// let r: &'a mut T = ...; // the original reference "r" has lifetime 'a
729 /// ...
730 /// &'z *r // the reborrow has lifetime 'z
731 /// ```
a7813a04
XL
732 ///
733 /// Now, in this case, our primary job is to add the inference
734 /// constraint that `'z <= 'a`. Given this setup, let's clarify the
735 /// parameters in (roughly) terms of the example:
736 ///
83c7162d 737 /// ```plain,ignore (pseudo-Rust)
f9f354fc
XL
738 /// A borrow of: `& 'z bk * r` where `r` has type `& 'a bk T`
739 /// borrow_region ^~ ref_region ^~
740 /// borrow_kind ^~ ref_kind ^~
741 /// ref_cmt ^
83c7162d 742 /// ```
a7813a04
XL
743 ///
744 /// Here `bk` stands for some borrow-kind (e.g., `mut`, `uniq`, etc).
745 ///
60c5eb7d
XL
746 /// There is a complication beyond the simple scenario I just painted: there
747 /// may in fact be more levels of reborrowing. In the example, I said the
748 /// borrow was like `&'z *r`, but it might in fact be a borrow like
749 /// `&'z **q` where `q` has type `&'a &'b mut T`. In that case, we want to
750 /// ensure that `'z <= 'a` and `'z <= 'b`.
a7813a04 751 ///
60c5eb7d
XL
752 /// The return value of this function indicates whether we *don't* need to
753 /// the recurse to the next reference up.
a7813a04 754 ///
60c5eb7d 755 /// This is explained more below.
0bf4aa26
XL
756 fn link_reborrowed_region(
757 &self,
758 span: Span,
759 borrow_region: ty::Region<'tcx>,
0bf4aa26 760 ref_region: ty::Region<'tcx>,
60c5eb7d
XL
761 ref_mutability: hir::Mutability,
762 ) -> bool {
dfeec247 763 debug!("link_reborrowed_region: {:?} <= {:?}", borrow_region, ref_region);
60c5eb7d 764 self.sub_regions(infer::Reborrow(span), borrow_region, ref_region);
a7813a04
XL
765
766 // Decide whether we need to recurse and link any regions within
767 // the `ref_cmt`. This is concerned for the case where the value
768 // being reborrowed is in fact a borrowed pointer found within
769 // another borrowed pointer. For example:
770 //
771 // let p: &'b &'a mut T = ...;
772 // ...
773 // &'z **p
774 //
775 // What makes this case particularly tricky is that, if the data
776 // being borrowed is a `&mut` or `&uniq` borrow, borrowck requires
777 // not only that `'z <= 'a`, (as before) but also `'z <= 'b`
778 // (otherwise the user might mutate through the `&mut T` reference
779 // after `'b` expires and invalidate the borrow we are looking at
780 // now).
781 //
782 // So let's re-examine our parameters in light of this more
783 // complicated (possible) scenario:
784 //
785 // A borrow of: `& 'z bk * * p` where `p` has type `&'b bk & 'a bk T`
786 // borrow_region ^~ ref_region ^~
787 // borrow_kind ^~ ref_kind ^~
788 // ref_cmt ^~~
789 //
790 // (Note that since we have not examined `ref_cmt.cat`, we don't
791 // know whether this scenario has occurred; but I wanted to show
792 // how all the types get adjusted.)
60c5eb7d 793 match ref_mutability {
dfeec247 794 hir::Mutability::Not => {
b7449926 795 // The reference being reborrowed is a shareable ref of
a7813a04
XL
796 // type `&'a T`. In this case, it doesn't matter where we
797 // *found* the `&T` pointer, the memory it references will
798 // be valid and immutable for `'a`. So we can stop here.
60c5eb7d
XL
799 true
800 }
801
dfeec247 802 hir::Mutability::Mut => {
60c5eb7d
XL
803 // The reference being reborrowed is either an `&mut T`. This is
804 // the case where recursion is needed.
805 false
1a4d82fc 806 }
60c5eb7d
XL
807 }
808 }
1a4d82fc 809
60c5eb7d
XL
810 /// An upvar may be behind up to 2 references:
811 ///
812 /// * One can come from the reference to a "by-reference" upvar.
813 /// * Another one can come from the reference to the closure itself if it's
814 /// a `FnMut` or `Fn` closure.
815 ///
816 /// This function links the lifetimes of those references to the lifetime
f9f354fc 817 /// of the borrow that's provided. See [RegionCtxt::link_reborrowed_region] for some
60c5eb7d
XL
818 /// more explanation of this in the general case.
819 ///
820 /// We also supply a *cause*, and in this case we set the cause to
821 /// indicate that the reference being "reborrowed" is itself an upvar. This
822 /// provides a nicer error message should something go wrong.
823 fn link_upvar_region(
824 &self,
825 span: Span,
826 borrow_region: ty::Region<'tcx>,
827 upvar_id: ty::UpvarId,
828 ) {
829 debug!("link_upvar_region(borrorw_region={:?}, upvar_id={:?}", borrow_region, upvar_id);
830 // A by-reference upvar can't be borrowed for longer than the
831 // upvar is borrowed from the environment.
6a06907d
XL
832 let closure_local_def_id = upvar_id.closure_expr_id;
833 let mut all_captures_are_imm_borrow = true;
834 for captured_place in self
835 .typeck_results
836 .borrow()
837 .closure_min_captures
838 .get(&closure_local_def_id.to_def_id())
839 .and_then(|root_var_min_cap| root_var_min_cap.get(&upvar_id.var_path.hir_id))
840 .into_iter()
841 .flatten()
842 {
843 match captured_place.info.capture_kind {
844 ty::UpvarCapture::ByRef(upvar_borrow) => {
845 self.sub_regions(
846 infer::ReborrowUpvar(span, upvar_id),
847 borrow_region,
5099ac24 848 captured_place.region.unwrap(),
6a06907d 849 );
5099ac24 850 if let ty::ImmBorrow = upvar_borrow {
6a06907d
XL
851 debug!("link_upvar_region: capture by shared ref");
852 } else {
853 all_captures_are_imm_borrow = false;
854 }
855 }
5099ac24 856 ty::UpvarCapture::ByValue => {
6a06907d 857 all_captures_are_imm_borrow = false;
60c5eb7d
XL
858 }
859 }
60c5eb7d 860 }
6a06907d
XL
861 if all_captures_are_imm_borrow {
862 return;
863 }
864 let fn_hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_local_def_id);
60c5eb7d
XL
865 let ty = self.resolve_node_type(fn_hir_id);
866 debug!("link_upvar_region: ty={:?}", ty);
867
868 // A closure capture can't be borrowed for longer than the
869 // reference to the closure.
1b1a35ee 870 if let ty::Closure(_, substs) = ty.kind() {
ba9703b0
XL
871 match self.infcx.closure_kind(substs) {
872 Some(ty::ClosureKind::Fn | ty::ClosureKind::FnMut) => {
60c5eb7d
XL
873 // Region of environment pointer
874 let env_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
875 scope: upvar_id.closure_expr_id.to_def_id(),
dfeec247 876 bound_region: ty::BrEnv,
60c5eb7d
XL
877 }));
878 self.sub_regions(
879 infer::ReborrowUpvar(span, upvar_id),
880 borrow_region,
881 env_region,
882 );
883 }
884 Some(ty::ClosureKind::FnOnce) => {}
885 None => {
886 span_bug!(span, "Have not inferred closure kind before regionck");
887 }
1a4d82fc
JJ
888 }
889 }
890 }
85aaf69f 891}