]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs
Suggest `mem::forget` if `mem::ManuallyDrop::new` isn't used
[rust.git] / src / librustc_mir / borrow_check / diagnostics / conflict_errors.rs
1 use either::Either;
2 use rustc_data_structures::fx::FxHashSet;
3 use rustc_errors::{Applicability, DiagnosticBuilder};
4 use rustc_hir as hir;
5 use rustc_hir::def_id::DefId;
6 use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
7 use rustc_index::vec::Idx;
8 use rustc_middle::mir::{
9     self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
10     FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
11     ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
12 };
13 use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
14 use rustc_span::source_map::DesugaringKind;
15 use rustc_span::Span;
16
17 use crate::dataflow::drop_flag_effects;
18 use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex};
19 use crate::util::borrowck_errors;
20
21 use crate::borrow_check::{
22     borrow_set::BorrowData, prefixes::IsPrefixOf, InitializationRequiringAction, MirBorrowckCtxt,
23     PrefixSet, WriteKind,
24 };
25
26 use super::{
27     explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName,
28     RegionNameSource, UseSpans,
29 };
30
31 #[derive(Debug)]
32 struct MoveSite {
33     /// Index of the "move out" that we found. The `MoveData` can
34     /// then tell us where the move occurred.
35     moi: MoveOutIndex,
36
37     /// `true` if we traversed a back edge while walking from the point
38     /// of error to the move site.
39     traversed_back_edge: bool,
40 }
41
42 /// Which case a StorageDeadOrDrop is for.
43 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
44 enum StorageDeadOrDrop<'tcx> {
45     LocalStorageDead,
46     BoxedStorageDead,
47     Destructor(Ty<'tcx>),
48 }
49
50 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
51     pub(in crate::borrow_check) fn report_use_of_moved_or_uninitialized(
52         &mut self,
53         location: Location,
54         desired_action: InitializationRequiringAction,
55         (moved_place, used_place, span): (PlaceRef<'tcx>, PlaceRef<'tcx>, Span),
56         mpi: MovePathIndex,
57     ) {
58         debug!(
59             "report_use_of_moved_or_uninitialized: location={:?} desired_action={:?} \
60              moved_place={:?} used_place={:?} span={:?} mpi={:?}",
61             location, desired_action, moved_place, used_place, span, mpi
62         );
63
64         let use_spans =
65             self.move_spans(moved_place, location).or_else(|| self.borrow_spans(span, location));
66         let span = use_spans.args_or_use();
67
68         let move_site_vec = self.get_moved_indexes(location, mpi);
69         debug!("report_use_of_moved_or_uninitialized: move_site_vec={:?}", move_site_vec);
70         let move_out_indices: Vec<_> =
71             move_site_vec.iter().map(|move_site| move_site.moi).collect();
72
73         if move_out_indices.is_empty() {
74             let root_place = PlaceRef { projection: &[], ..used_place };
75
76             if !self.uninitialized_error_reported.insert(root_place) {
77                 debug!(
78                     "report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
79                     root_place
80                 );
81                 return;
82             }
83
84             let item_msg =
85                 match self.describe_place_with_options(used_place, IncludingDowncast(true)) {
86                     Some(name) => format!("`{}`", name),
87                     None => "value".to_owned(),
88                 };
89             let mut err = self.cannot_act_on_uninitialized_variable(
90                 span,
91                 desired_action.as_noun(),
92                 &self
93                     .describe_place_with_options(moved_place, IncludingDowncast(true))
94                     .unwrap_or_else(|| "_".to_owned()),
95             );
96             err.span_label(span, format!("use of possibly-uninitialized {}", item_msg));
97
98             use_spans.var_span_label(
99                 &mut err,
100                 format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
101             );
102
103             err.buffer(&mut self.errors_buffer);
104         } else {
105             if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {
106                 if self.prefixes(*reported_place, PrefixSet::All).any(|p| p == used_place) {
107                     debug!(
108                         "report_use_of_moved_or_uninitialized place: error suppressed \
109                          mois={:?}",
110                         move_out_indices
111                     );
112                     return;
113                 }
114             }
115
116             let msg = ""; //FIXME: add "partially " or "collaterally "
117
118             let mut err = self.cannot_act_on_moved_value(
119                 span,
120                 desired_action.as_noun(),
121                 msg,
122                 self.describe_place_with_options(moved_place, IncludingDowncast(true)),
123             );
124
125             self.add_moved_or_invoked_closure_note(location, used_place, &mut err);
126
127             let mut is_loop_move = false;
128             let is_partial_move = move_site_vec.iter().any(|move_site| {
129                 let move_out = self.move_data.moves[(*move_site).moi];
130                 let moved_place = &self.move_data.move_paths[move_out.path].place;
131                 used_place != moved_place.as_ref() && used_place.is_prefix_of(moved_place.as_ref())
132             });
133             for move_site in &move_site_vec {
134                 let move_out = self.move_data.moves[(*move_site).moi];
135                 let moved_place = &self.move_data.move_paths[move_out.path].place;
136
137                 let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
138                 let move_span = move_spans.args_or_use();
139
140                 let move_msg = if move_spans.for_closure() { " into closure" } else { "" };
141
142                 if location == move_out.source {
143                     err.span_label(
144                         span,
145                         format!("value moved{} here, in previous iteration of loop", move_msg),
146                     );
147                     is_loop_move = true;
148                 } else if move_site.traversed_back_edge {
149                     err.span_label(
150                         move_span,
151                         format!("value moved{} here, in previous iteration of loop", move_msg),
152                     );
153                 } else {
154                     if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } =
155                         move_spans
156                     {
157                         let place_name = self
158                             .describe_place(moved_place.as_ref())
159                             .map(|n| format!("`{}`", n))
160                             .unwrap_or_else(|| "value".to_owned());
161                         match kind {
162                             FnSelfUseKind::FnOnceCall => {
163                                 err.span_label(
164                                     fn_call_span,
165                                     &format!("{} moved due to this call", place_name),
166                                 );
167                                 err.span_note(
168                                     var_span,
169                                     "this value implements `FnOnce`, which causes it to be moved when called",
170                                 );
171                             }
172                             FnSelfUseKind::Operator { self_arg } => {
173                                 err.span_label(
174                                     fn_call_span,
175                                     &format!("{} moved due to usage in operator", place_name),
176                                 );
177                                 if self.fn_self_span_reported.insert(fn_span) {
178                                     err.span_note(
179                                         self_arg.span,
180                                         "calling this operator moves the left-hand side",
181                                     );
182                                 }
183                             }
184                             FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
185                                 if implicit_into_iter {
186                                     err.span_label(
187                                         fn_call_span,
188                                         &format!(
189                                             "{} moved due to this implicit call to `.into_iter()`",
190                                             place_name
191                                         ),
192                                     );
193                                 } else {
194                                     err.span_label(
195                                         fn_call_span,
196                                         &format!("{} moved due to this method call", place_name),
197                                     );
198                                 }
199                                 // Avoid pointing to the same function in multiple different
200                                 // error messages
201                                 if self.fn_self_span_reported.insert(self_arg.span) {
202                                     err.span_note(
203                                         self_arg.span,
204                                         &format!("this function consumes the receiver `self` by taking ownership of it, which moves {}", place_name)
205                                     );
206                                 }
207                             }
208                         }
209                     } else {
210                         err.span_label(move_span, format!("value moved{} here", move_msg));
211                         move_spans.var_span_label(
212                             &mut err,
213                             format!("variable moved due to use{}", move_spans.describe()),
214                         );
215                     }
216                 }
217                 if let UseSpans::PatUse(span) = move_spans {
218                     err.span_suggestion_verbose(
219                         span.shrink_to_lo(),
220                         &format!(
221                             "borrow this field in the pattern to avoid moving {}",
222                             self.describe_place(moved_place.as_ref())
223                                 .map(|n| format!("`{}`", n))
224                                 .unwrap_or_else(|| "the value".to_string())
225                         ),
226                         "ref ".to_string(),
227                         Applicability::MachineApplicable,
228                     );
229                 }
230
231                 if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
232                     let sess = self.infcx.tcx.sess;
233                     if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
234                         err.span_suggestion(
235                             move_span,
236                             "consider borrowing to avoid moving into the for loop",
237                             format!("&{}", snippet),
238                             Applicability::MaybeIncorrect,
239                         );
240                     }
241                 }
242             }
243
244             use_spans.var_span_label(
245                 &mut err,
246                 format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
247             );
248
249             if !is_loop_move {
250                 err.span_label(
251                     span,
252                     format!(
253                         "value {} here {}",
254                         desired_action.as_verb_in_past_tense(),
255                         if is_partial_move { "after partial move" } else { "after move" },
256                     ),
257                 );
258             }
259
260             let ty =
261                 Place::ty_from(used_place.local, used_place.projection, self.body, self.infcx.tcx)
262                     .ty;
263             let needs_note = match ty.kind {
264                 ty::Closure(id, _) => {
265                     let tables = self.infcx.tcx.typeck(id.expect_local());
266                     let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(id.expect_local());
267
268                     tables.closure_kind_origins().get(hir_id).is_none()
269                 }
270                 _ => true,
271             };
272
273             let mpi = self.move_data.moves[move_out_indices[0]].path;
274             let place = &self.move_data.move_paths[mpi].place;
275             let ty = place.ty(self.body, self.infcx.tcx).ty;
276
277             if is_loop_move {
278                 if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind {
279                     // We have a `&mut` ref, we need to reborrow on each iteration (#62112).
280                     err.span_suggestion_verbose(
281                         span.shrink_to_lo(),
282                         &format!(
283                             "consider creating a fresh reborrow of {} here",
284                             self.describe_place(moved_place)
285                                 .map(|n| format!("`{}`", n))
286                                 .unwrap_or_else(|| "the mutable reference".to_string()),
287                         ),
288                         "&mut *".to_string(),
289                         Applicability::MachineApplicable,
290                     );
291                 }
292             }
293
294             if needs_note {
295                 let opt_name =
296                     self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
297                 let note_msg = match opt_name {
298                     Some(ref name) => format!("`{}`", name),
299                     None => "value".to_owned(),
300                 };
301                 if let ty::Param(param_ty) = ty.kind {
302                     let tcx = self.infcx.tcx;
303                     let generics = tcx.generics_of(self.mir_def_id);
304                     let param = generics.type_param(&param_ty, tcx);
305                     if let Some(generics) =
306                         tcx.hir().get_generics(tcx.closure_base_def_id(self.mir_def_id.to_def_id()))
307                     {
308                         suggest_constraining_type_param(
309                             tcx,
310                             generics,
311                             &mut err,
312                             &param.name.as_str(),
313                             "Copy",
314                             None,
315                         );
316                     }
317                 }
318                 let span = if let Some(local) = place.as_local() {
319                     let decl = &self.body.local_decls[local];
320                     Some(decl.source_info.span)
321                 } else {
322                     None
323                 };
324                 self.note_type_does_not_implement_copy(&mut err, &note_msg, ty, span);
325             }
326
327             if let Some((_, mut old_err)) =
328                 self.move_error_reported.insert(move_out_indices, (used_place, err))
329             {
330                 // Cancel the old error so it doesn't ICE.
331                 old_err.cancel();
332             }
333         }
334     }
335
336     pub(in crate::borrow_check) fn report_move_out_while_borrowed(
337         &mut self,
338         location: Location,
339         (place, span): (Place<'tcx>, Span),
340         borrow: &BorrowData<'tcx>,
341     ) {
342         debug!(
343             "report_move_out_while_borrowed: location={:?} place={:?} span={:?} borrow={:?}",
344             location, place, span, borrow
345         );
346         let value_msg = self.describe_any_place(place.as_ref());
347         let borrow_msg = self.describe_any_place(borrow.borrowed_place.as_ref());
348
349         let borrow_spans = self.retrieve_borrow_spans(borrow);
350         let borrow_span = borrow_spans.args_or_use();
351
352         let move_spans = self.move_spans(place.as_ref(), location);
353         let span = move_spans.args_or_use();
354
355         let mut err =
356             self.cannot_move_when_borrowed(span, &self.describe_any_place(place.as_ref()));
357         err.span_label(borrow_span, format!("borrow of {} occurs here", borrow_msg));
358         err.span_label(span, format!("move out of {} occurs here", value_msg));
359
360         borrow_spans.var_span_label(
361             &mut err,
362             format!("borrow occurs due to use{}", borrow_spans.describe()),
363         );
364
365         move_spans
366             .var_span_label(&mut err, format!("move occurs due to use{}", move_spans.describe()));
367
368         self.explain_why_borrow_contains_point(location, borrow, None)
369             .add_explanation_to_diagnostic(
370                 self.infcx.tcx,
371                 &self.body,
372                 &self.local_names,
373                 &mut err,
374                 "",
375                 Some(borrow_span),
376             );
377         err.buffer(&mut self.errors_buffer);
378     }
379
380     pub(in crate::borrow_check) fn report_use_while_mutably_borrowed(
381         &mut self,
382         location: Location,
383         (place, _span): (Place<'tcx>, Span),
384         borrow: &BorrowData<'tcx>,
385     ) -> DiagnosticBuilder<'cx> {
386         let borrow_spans = self.retrieve_borrow_spans(borrow);
387         let borrow_span = borrow_spans.args_or_use();
388
389         // Conflicting borrows are reported separately, so only check for move
390         // captures.
391         let use_spans = self.move_spans(place.as_ref(), location);
392         let span = use_spans.var_or_use();
393
394         let mut err = self.cannot_use_when_mutably_borrowed(
395             span,
396             &self.describe_any_place(place.as_ref()),
397             borrow_span,
398             &self.describe_any_place(borrow.borrowed_place.as_ref()),
399         );
400
401         borrow_spans.var_span_label(&mut err, {
402             let place = &borrow.borrowed_place;
403             let desc_place = self.describe_any_place(place.as_ref());
404             format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe())
405         });
406
407         self.explain_why_borrow_contains_point(location, borrow, None)
408             .add_explanation_to_diagnostic(
409                 self.infcx.tcx,
410                 &self.body,
411                 &self.local_names,
412                 &mut err,
413                 "",
414                 None,
415             );
416         err
417     }
418
419     pub(in crate::borrow_check) fn report_conflicting_borrow(
420         &mut self,
421         location: Location,
422         (place, span): (Place<'tcx>, Span),
423         gen_borrow_kind: BorrowKind,
424         issued_borrow: &BorrowData<'tcx>,
425     ) -> DiagnosticBuilder<'cx> {
426         let issued_spans = self.retrieve_borrow_spans(issued_borrow);
427         let issued_span = issued_spans.args_or_use();
428
429         let borrow_spans = self.borrow_spans(span, location);
430         let span = borrow_spans.args_or_use();
431
432         let container_name = if issued_spans.for_generator() || borrow_spans.for_generator() {
433             "generator"
434         } else {
435             "closure"
436         };
437
438         let (desc_place, msg_place, msg_borrow, union_type_name) =
439             self.describe_place_for_conflicting_borrow(place, issued_borrow.borrowed_place);
440
441         let explanation = self.explain_why_borrow_contains_point(location, issued_borrow, None);
442         let second_borrow_desc = if explanation.is_explained() { "second " } else { "" };
443
444         // FIXME: supply non-"" `opt_via` when appropriate
445         let first_borrow_desc;
446         let mut err = match (gen_borrow_kind, issued_borrow.kind) {
447             (BorrowKind::Shared, BorrowKind::Mut { .. }) => {
448                 first_borrow_desc = "mutable ";
449                 self.cannot_reborrow_already_borrowed(
450                     span,
451                     &desc_place,
452                     &msg_place,
453                     "immutable",
454                     issued_span,
455                     "it",
456                     "mutable",
457                     &msg_borrow,
458                     None,
459                 )
460             }
461             (BorrowKind::Mut { .. }, BorrowKind::Shared) => {
462                 first_borrow_desc = "immutable ";
463                 self.cannot_reborrow_already_borrowed(
464                     span,
465                     &desc_place,
466                     &msg_place,
467                     "mutable",
468                     issued_span,
469                     "it",
470                     "immutable",
471                     &msg_borrow,
472                     None,
473                 )
474             }
475
476             (BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
477                 first_borrow_desc = "first ";
478                 let mut err = self.cannot_mutably_borrow_multiply(
479                     span,
480                     &desc_place,
481                     &msg_place,
482                     issued_span,
483                     &msg_borrow,
484                     None,
485                 );
486                 self.suggest_split_at_mut_if_applicable(
487                     &mut err,
488                     place,
489                     issued_borrow.borrowed_place,
490                 );
491                 err
492             }
493
494             (BorrowKind::Unique, BorrowKind::Unique) => {
495                 first_borrow_desc = "first ";
496                 self.cannot_uniquely_borrow_by_two_closures(span, &desc_place, issued_span, None)
497             }
498
499             (BorrowKind::Mut { .. } | BorrowKind::Unique, BorrowKind::Shallow) => {
500                 if let Some(immutable_section_description) =
501                     self.classify_immutable_section(issued_borrow.assigned_place)
502                 {
503                     let mut err = self.cannot_mutate_in_immutable_section(
504                         span,
505                         issued_span,
506                         &desc_place,
507                         immutable_section_description,
508                         "mutably borrow",
509                     );
510                     borrow_spans.var_span_label(
511                         &mut err,
512                         format!(
513                             "borrow occurs due to use of {}{}",
514                             desc_place,
515                             borrow_spans.describe(),
516                         ),
517                     );
518
519                     return err;
520                 } else {
521                     first_borrow_desc = "immutable ";
522                     self.cannot_reborrow_already_borrowed(
523                         span,
524                         &desc_place,
525                         &msg_place,
526                         "mutable",
527                         issued_span,
528                         "it",
529                         "immutable",
530                         &msg_borrow,
531                         None,
532                     )
533                 }
534             }
535
536             (BorrowKind::Unique, _) => {
537                 first_borrow_desc = "first ";
538                 self.cannot_uniquely_borrow_by_one_closure(
539                     span,
540                     container_name,
541                     &desc_place,
542                     "",
543                     issued_span,
544                     "it",
545                     "",
546                     None,
547                 )
548             }
549
550             (BorrowKind::Shared, BorrowKind::Unique) => {
551                 first_borrow_desc = "first ";
552                 self.cannot_reborrow_already_uniquely_borrowed(
553                     span,
554                     container_name,
555                     &desc_place,
556                     "",
557                     "immutable",
558                     issued_span,
559                     "",
560                     None,
561                     second_borrow_desc,
562                 )
563             }
564
565             (BorrowKind::Mut { .. }, BorrowKind::Unique) => {
566                 first_borrow_desc = "first ";
567                 self.cannot_reborrow_already_uniquely_borrowed(
568                     span,
569                     container_name,
570                     &desc_place,
571                     "",
572                     "mutable",
573                     issued_span,
574                     "",
575                     None,
576                     second_borrow_desc,
577                 )
578             }
579
580             (BorrowKind::Shared, BorrowKind::Shared | BorrowKind::Shallow)
581             | (
582                 BorrowKind::Shallow,
583                 BorrowKind::Mut { .. }
584                 | BorrowKind::Unique
585                 | BorrowKind::Shared
586                 | BorrowKind::Shallow,
587             ) => unreachable!(),
588         };
589
590         if issued_spans == borrow_spans {
591             borrow_spans.var_span_label(
592                 &mut err,
593                 format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe()),
594             );
595         } else {
596             let borrow_place = &issued_borrow.borrowed_place;
597             let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
598             issued_spans.var_span_label(
599                 &mut err,
600                 format!(
601                     "first borrow occurs due to use of {}{}",
602                     borrow_place_desc,
603                     issued_spans.describe(),
604                 ),
605             );
606
607             borrow_spans.var_span_label(
608                 &mut err,
609                 format!(
610                     "second borrow occurs due to use of {}{}",
611                     desc_place,
612                     borrow_spans.describe(),
613                 ),
614             );
615         }
616
617         if union_type_name != "" {
618             err.note(&format!(
619                 "{} is a field of the union `{}`, so it overlaps the field {}",
620                 msg_place, union_type_name, msg_borrow,
621             ));
622         }
623
624         explanation.add_explanation_to_diagnostic(
625             self.infcx.tcx,
626             &self.body,
627             &self.local_names,
628             &mut err,
629             first_borrow_desc,
630             None,
631         );
632
633         err
634     }
635
636     fn suggest_split_at_mut_if_applicable(
637         &self,
638         err: &mut DiagnosticBuilder<'_>,
639         place: Place<'tcx>,
640         borrowed_place: Place<'tcx>,
641     ) {
642         if let ([ProjectionElem::Index(_)], [ProjectionElem::Index(_)]) =
643             (&place.projection[..], &borrowed_place.projection[..])
644         {
645             err.help(
646                 "consider using `.split_at_mut(position)` or similar method to obtain \
647                      two mutable non-overlapping sub-slices",
648             );
649         }
650     }
651
652     /// Returns the description of the root place for a conflicting borrow and the full
653     /// descriptions of the places that caused the conflict.
654     ///
655     /// In the simplest case, where there are no unions involved, if a mutable borrow of `x` is
656     /// attempted while a shared borrow is live, then this function will return:
657     ///
658     ///     ("x", "", "")
659     ///
660     /// In the simple union case, if a mutable borrow of a union field `x.z` is attempted while
661     /// a shared borrow of another field `x.y`, then this function will return:
662     ///
663     ///     ("x", "x.z", "x.y")
664     ///
665     /// In the more complex union case, where the union is a field of a struct, then if a mutable
666     /// borrow of a union field in a struct `x.u.z` is attempted while a shared borrow of
667     /// another field `x.u.y`, then this function will return:
668     ///
669     ///     ("x.u", "x.u.z", "x.u.y")
670     ///
671     /// This is used when creating error messages like below:
672     ///
673     /// ```text
674     /// cannot borrow `a.u` (via `a.u.z.c`) as immutable because it is also borrowed as
675     /// mutable (via `a.u.s.b`) [E0502]
676     /// ```
677     pub(in crate::borrow_check) fn describe_place_for_conflicting_borrow(
678         &self,
679         first_borrowed_place: Place<'tcx>,
680         second_borrowed_place: Place<'tcx>,
681     ) -> (String, String, String, String) {
682         // Define a small closure that we can use to check if the type of a place
683         // is a union.
684         let union_ty = |place_base, place_projection| {
685             let ty = Place::ty_from(place_base, place_projection, self.body, self.infcx.tcx).ty;
686             ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty)
687         };
688
689         // Start with an empty tuple, so we can use the functions on `Option` to reduce some
690         // code duplication (particularly around returning an empty description in the failure
691         // case).
692         Some(())
693             .filter(|_| {
694                 // If we have a conflicting borrow of the same place, then we don't want to add
695                 // an extraneous "via x.y" to our diagnostics, so filter out this case.
696                 first_borrowed_place != second_borrowed_place
697             })
698             .and_then(|_| {
699                 // We're going to want to traverse the first borrowed place to see if we can find
700                 // field access to a union. If we find that, then we will keep the place of the
701                 // union being accessed and the field that was being accessed so we can check the
702                 // second borrowed place for the same union and a access to a different field.
703                 let Place { local, projection } = first_borrowed_place;
704
705                 let mut cursor = projection.as_ref();
706                 while let [proj_base @ .., elem] = cursor {
707                     cursor = proj_base;
708
709                     match elem {
710                         ProjectionElem::Field(field, _) if union_ty(local, proj_base).is_some() => {
711                             return Some((PlaceRef { local, projection: proj_base }, field));
712                         }
713                         _ => {}
714                     }
715                 }
716                 None
717             })
718             .and_then(|(target_base, target_field)| {
719                 // With the place of a union and a field access into it, we traverse the second
720                 // borrowed place and look for a access to a different field of the same union.
721                 let Place { local, ref projection } = second_borrowed_place;
722
723                 let mut cursor = &projection[..];
724                 while let [proj_base @ .., elem] = cursor {
725                     cursor = proj_base;
726
727                     if let ProjectionElem::Field(field, _) = elem {
728                         if let Some(union_ty) = union_ty(local, proj_base) {
729                             if field != target_field
730                                 && local == target_base.local
731                                 && proj_base == target_base.projection
732                             {
733                                 return Some((
734                                     self.describe_any_place(PlaceRef {
735                                         local,
736                                         projection: proj_base,
737                                     }),
738                                     self.describe_any_place(first_borrowed_place.as_ref()),
739                                     self.describe_any_place(second_borrowed_place.as_ref()),
740                                     union_ty.to_string(),
741                                 ));
742                             }
743                         }
744                     }
745                 }
746                 None
747             })
748             .unwrap_or_else(|| {
749                 // If we didn't find a field access into a union, or both places match, then
750                 // only return the description of the first place.
751                 (
752                     self.describe_any_place(first_borrowed_place.as_ref()),
753                     "".to_string(),
754                     "".to_string(),
755                     "".to_string(),
756                 )
757             })
758     }
759
760     /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
761     ///
762     /// This means that some data referenced by `borrow` needs to live
763     /// past the point where the StorageDeadOrDrop of `place` occurs.
764     /// This is usually interpreted as meaning that `place` has too
765     /// short a lifetime. (But sometimes it is more useful to report
766     /// it as a more direct conflict between the execution of a
767     /// `Drop::drop` with an aliasing borrow.)
768     pub(in crate::borrow_check) fn report_borrowed_value_does_not_live_long_enough(
769         &mut self,
770         location: Location,
771         borrow: &BorrowData<'tcx>,
772         place_span: (Place<'tcx>, Span),
773         kind: Option<WriteKind>,
774     ) {
775         debug!(
776             "report_borrowed_value_does_not_live_long_enough(\
777              {:?}, {:?}, {:?}, {:?}\
778              )",
779             location, borrow, place_span, kind
780         );
781
782         let drop_span = place_span.1;
783         let root_place =
784             self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
785
786         let borrow_spans = self.retrieve_borrow_spans(borrow);
787         let borrow_span = borrow_spans.var_or_use();
788
789         assert!(root_place.projection.is_empty());
790         let proper_span = self.body.local_decls[root_place.local].source_info.span;
791
792         let root_place_projection = self.infcx.tcx.intern_place_elems(root_place.projection);
793
794         if self.access_place_error_reported.contains(&(
795             Place { local: root_place.local, projection: root_place_projection },
796             borrow_span,
797         )) {
798             debug!(
799                 "suppressing access_place error when borrow doesn't live long enough for {:?}",
800                 borrow_span
801             );
802             return;
803         }
804
805         self.access_place_error_reported.insert((
806             Place { local: root_place.local, projection: root_place_projection },
807             borrow_span,
808         ));
809
810         let borrowed_local = borrow.borrowed_place.local;
811         if self.body.local_decls[borrowed_local].is_ref_to_thread_local() {
812             let err =
813                 self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
814             err.buffer(&mut self.errors_buffer);
815             return;
816         }
817
818         if let StorageDeadOrDrop::Destructor(dropped_ty) =
819             self.classify_drop_access_kind(borrow.borrowed_place.as_ref())
820         {
821             // If a borrow of path `B` conflicts with drop of `D` (and
822             // we're not in the uninteresting case where `B` is a
823             // prefix of `D`), then report this as a more interesting
824             // destructor conflict.
825             if !borrow.borrowed_place.as_ref().is_prefix_of(place_span.0.as_ref()) {
826                 self.report_borrow_conflicts_with_destructor(
827                     location, borrow, place_span, kind, dropped_ty,
828                 );
829                 return;
830             }
831         }
832
833         let place_desc = self.describe_place(borrow.borrowed_place.as_ref());
834
835         let kind_place = kind.filter(|_| place_desc.is_some()).map(|k| (k, place_span.0));
836         let explanation = self.explain_why_borrow_contains_point(location, &borrow, kind_place);
837
838         debug!(
839             "report_borrowed_value_does_not_live_long_enough(place_desc: {:?}, explanation: {:?})",
840             place_desc, explanation
841         );
842         let err = match (place_desc, explanation) {
843             // If the outlives constraint comes from inside the closure,
844             // for example:
845             //
846             // let x = 0;
847             // let y = &x;
848             // Box::new(|| y) as Box<Fn() -> &'static i32>
849             //
850             // then just use the normal error. The closure isn't escaping
851             // and `move` will not help here.
852             (
853                 Some(ref name),
854                 BorrowExplanation::MustBeValidFor {
855                     category:
856                         category
857                         @
858                         (ConstraintCategory::Return(_)
859                         | ConstraintCategory::CallArgument
860                         | ConstraintCategory::OpaqueType),
861                     from_closure: false,
862                     ref region_name,
863                     span,
864                     ..
865                 },
866             ) if borrow_spans.for_generator() | borrow_spans.for_closure() => self
867                 .report_escaping_closure_capture(
868                     borrow_spans,
869                     borrow_span,
870                     region_name,
871                     category,
872                     span,
873                     &format!("`{}`", name),
874                 ),
875             (
876                 ref name,
877                 BorrowExplanation::MustBeValidFor {
878                     category: ConstraintCategory::Assignment,
879                     from_closure: false,
880                     region_name:
881                         RegionName {
882                             source:
883                                 RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name),
884                             ..
885                         },
886                     span,
887                     ..
888                 },
889             ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span),
890             (Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
891                 location,
892                 &name,
893                 &borrow,
894                 drop_span,
895                 borrow_spans,
896                 explanation,
897             ),
898             (None, explanation) => self.report_temporary_value_does_not_live_long_enough(
899                 location,
900                 &borrow,
901                 drop_span,
902                 borrow_spans,
903                 proper_span,
904                 explanation,
905             ),
906         };
907
908         err.buffer(&mut self.errors_buffer);
909     }
910
911     fn report_local_value_does_not_live_long_enough(
912         &mut self,
913         location: Location,
914         name: &str,
915         borrow: &BorrowData<'tcx>,
916         drop_span: Span,
917         borrow_spans: UseSpans,
918         explanation: BorrowExplanation,
919     ) -> DiagnosticBuilder<'cx> {
920         debug!(
921             "report_local_value_does_not_live_long_enough(\
922              {:?}, {:?}, {:?}, {:?}, {:?}\
923              )",
924             location, name, borrow, drop_span, borrow_spans
925         );
926
927         let borrow_span = borrow_spans.var_or_use();
928         if let BorrowExplanation::MustBeValidFor {
929             category,
930             span,
931             ref opt_place_desc,
932             from_closure: false,
933             ..
934         } = explanation
935         {
936             if let Some(diag) = self.try_report_cannot_return_reference_to_local(
937                 borrow,
938                 borrow_span,
939                 span,
940                 category,
941                 opt_place_desc.as_ref(),
942             ) {
943                 return diag;
944             }
945         }
946
947         let mut err = self.path_does_not_live_long_enough(borrow_span, &format!("`{}`", name));
948
949         if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) {
950             let region_name = annotation.emit(self, &mut err);
951
952             err.span_label(
953                 borrow_span,
954                 format!("`{}` would have to be valid for `{}`...", name, region_name),
955             );
956
957             let fn_hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(self.mir_def_id);
958             err.span_label(
959                 drop_span,
960                 format!(
961                     "...but `{}` will be dropped here, when the {} returns",
962                     name,
963                     self.infcx
964                         .tcx
965                         .hir()
966                         .opt_name(fn_hir_id)
967                         .map(|name| format!("function `{}`", name))
968                         .unwrap_or_else(|| {
969                             match &self.infcx.tcx.typeck(self.mir_def_id).node_type(fn_hir_id).kind
970                             {
971                                 ty::Closure(..) => "enclosing closure",
972                                 ty::Generator(..) => "enclosing generator",
973                                 kind => bug!("expected closure or generator, found {:?}", kind),
974                             }
975                             .to_string()
976                         })
977                 ),
978             );
979
980             err.note(
981                 "functions cannot return a borrow to data owned within the function's scope, \
982                     functions can only return borrows to data passed as arguments",
983             );
984             err.note(
985                 "to learn more, visit <https://doc.rust-lang.org/book/ch04-02-\
986                     references-and-borrowing.html#dangling-references>",
987             );
988
989             if let BorrowExplanation::MustBeValidFor { .. } = explanation {
990             } else {
991                 explanation.add_explanation_to_diagnostic(
992                     self.infcx.tcx,
993                     &self.body,
994                     &self.local_names,
995                     &mut err,
996                     "",
997                     None,
998                 );
999             }
1000         } else {
1001             err.span_label(borrow_span, "borrowed value does not live long enough");
1002             err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name));
1003
1004             let within = if borrow_spans.for_generator() { " by generator" } else { "" };
1005
1006             borrow_spans.args_span_label(&mut err, format!("value captured here{}", within));
1007
1008             explanation.add_explanation_to_diagnostic(
1009                 self.infcx.tcx,
1010                 &self.body,
1011                 &self.local_names,
1012                 &mut err,
1013                 "",
1014                 None,
1015             );
1016         }
1017
1018         err
1019     }
1020
1021     fn report_borrow_conflicts_with_destructor(
1022         &mut self,
1023         location: Location,
1024         borrow: &BorrowData<'tcx>,
1025         (place, drop_span): (Place<'tcx>, Span),
1026         kind: Option<WriteKind>,
1027         dropped_ty: Ty<'tcx>,
1028     ) {
1029         debug!(
1030             "report_borrow_conflicts_with_destructor(\
1031              {:?}, {:?}, ({:?}, {:?}), {:?}\
1032              )",
1033             location, borrow, place, drop_span, kind,
1034         );
1035
1036         let borrow_spans = self.retrieve_borrow_spans(borrow);
1037         let borrow_span = borrow_spans.var_or_use();
1038
1039         let mut err = self.cannot_borrow_across_destructor(borrow_span);
1040
1041         let what_was_dropped = match self.describe_place(place.as_ref()) {
1042             Some(name) => format!("`{}`", name),
1043             None => String::from("temporary value"),
1044         };
1045
1046         let label = match self.describe_place(borrow.borrowed_place.as_ref()) {
1047             Some(borrowed) => format!(
1048                 "here, drop of {D} needs exclusive access to `{B}`, \
1049                  because the type `{T}` implements the `Drop` trait",
1050                 D = what_was_dropped,
1051                 T = dropped_ty,
1052                 B = borrowed
1053             ),
1054             None => format!(
1055                 "here is drop of {D}; whose type `{T}` implements the `Drop` trait",
1056                 D = what_was_dropped,
1057                 T = dropped_ty
1058             ),
1059         };
1060         err.span_label(drop_span, label);
1061
1062         // Only give this note and suggestion if they could be relevant.
1063         let explanation =
1064             self.explain_why_borrow_contains_point(location, borrow, kind.map(|k| (k, place)));
1065         match explanation {
1066             BorrowExplanation::UsedLater { .. }
1067             | BorrowExplanation::UsedLaterWhenDropped { .. } => {
1068                 err.note("consider using a `let` binding to create a longer lived value");
1069             }
1070             _ => {}
1071         }
1072
1073         explanation.add_explanation_to_diagnostic(
1074             self.infcx.tcx,
1075             &self.body,
1076             &self.local_names,
1077             &mut err,
1078             "",
1079             None,
1080         );
1081
1082         err.buffer(&mut self.errors_buffer);
1083     }
1084
1085     fn report_thread_local_value_does_not_live_long_enough(
1086         &mut self,
1087         drop_span: Span,
1088         borrow_span: Span,
1089     ) -> DiagnosticBuilder<'cx> {
1090         debug!(
1091             "report_thread_local_value_does_not_live_long_enough(\
1092              {:?}, {:?}\
1093              )",
1094             drop_span, borrow_span
1095         );
1096
1097         let mut err = self.thread_local_value_does_not_live_long_enough(borrow_span);
1098
1099         err.span_label(
1100             borrow_span,
1101             "thread-local variables cannot be borrowed beyond the end of the function",
1102         );
1103         err.span_label(drop_span, "end of enclosing function is here");
1104
1105         err
1106     }
1107
1108     fn report_temporary_value_does_not_live_long_enough(
1109         &mut self,
1110         location: Location,
1111         borrow: &BorrowData<'tcx>,
1112         drop_span: Span,
1113         borrow_spans: UseSpans,
1114         proper_span: Span,
1115         explanation: BorrowExplanation,
1116     ) -> DiagnosticBuilder<'cx> {
1117         debug!(
1118             "report_temporary_value_does_not_live_long_enough(\
1119              {:?}, {:?}, {:?}, {:?}\
1120              )",
1121             location, borrow, drop_span, proper_span
1122         );
1123
1124         if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
1125             explanation
1126         {
1127             if let Some(diag) = self.try_report_cannot_return_reference_to_local(
1128                 borrow,
1129                 proper_span,
1130                 span,
1131                 category,
1132                 None,
1133             ) {
1134                 return diag;
1135             }
1136         }
1137
1138         let mut err = self.temporary_value_borrowed_for_too_long(proper_span);
1139         err.span_label(proper_span, "creates a temporary which is freed while still in use");
1140         err.span_label(drop_span, "temporary value is freed at the end of this statement");
1141
1142         match explanation {
1143             BorrowExplanation::UsedLater(..)
1144             | BorrowExplanation::UsedLaterInLoop(..)
1145             | BorrowExplanation::UsedLaterWhenDropped { .. } => {
1146                 // Only give this note and suggestion if it could be relevant.
1147                 err.note("consider using a `let` binding to create a longer lived value");
1148             }
1149             _ => {}
1150         }
1151         explanation.add_explanation_to_diagnostic(
1152             self.infcx.tcx,
1153             &self.body,
1154             &self.local_names,
1155             &mut err,
1156             "",
1157             None,
1158         );
1159
1160         let within = if borrow_spans.for_generator() { " by generator" } else { "" };
1161
1162         borrow_spans.args_span_label(&mut err, format!("value captured here{}", within));
1163
1164         err
1165     }
1166
1167     fn try_report_cannot_return_reference_to_local(
1168         &self,
1169         borrow: &BorrowData<'tcx>,
1170         borrow_span: Span,
1171         return_span: Span,
1172         category: ConstraintCategory,
1173         opt_place_desc: Option<&String>,
1174     ) -> Option<DiagnosticBuilder<'cx>> {
1175         let return_kind = match category {
1176             ConstraintCategory::Return(_) => "return",
1177             ConstraintCategory::Yield => "yield",
1178             _ => return None,
1179         };
1180
1181         // FIXME use a better heuristic than Spans
1182         let reference_desc = if return_span == self.body.source_info(borrow.reserve_location).span {
1183             "reference to"
1184         } else {
1185             "value referencing"
1186         };
1187
1188         let (place_desc, note) = if let Some(place_desc) = opt_place_desc {
1189             let local_kind = if let Some(local) = borrow.borrowed_place.as_local() {
1190                 match self.body.local_kind(local) {
1191                     LocalKind::ReturnPointer | LocalKind::Temp => {
1192                         bug!("temporary or return pointer with a name")
1193                     }
1194                     LocalKind::Var => "local variable ",
1195                     LocalKind::Arg if !self.upvars.is_empty() && local == Local::new(1) => {
1196                         "variable captured by `move` "
1197                     }
1198                     LocalKind::Arg => "function parameter ",
1199                 }
1200             } else {
1201                 "local data "
1202             };
1203             (
1204                 format!("{}`{}`", local_kind, place_desc),
1205                 format!("`{}` is borrowed here", place_desc),
1206             )
1207         } else {
1208             let root_place =
1209                 self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap();
1210             let local = root_place.local;
1211             match self.body.local_kind(local) {
1212                 LocalKind::ReturnPointer | LocalKind::Temp => {
1213                     ("temporary value".to_string(), "temporary value created here".to_string())
1214                 }
1215                 LocalKind::Arg => (
1216                     "function parameter".to_string(),
1217                     "function parameter borrowed here".to_string(),
1218                 ),
1219                 LocalKind::Var => {
1220                     ("local binding".to_string(), "local binding introduced here".to_string())
1221                 }
1222             }
1223         };
1224
1225         let mut err = self.cannot_return_reference_to_local(
1226             return_span,
1227             return_kind,
1228             reference_desc,
1229             &place_desc,
1230         );
1231
1232         if return_span != borrow_span {
1233             err.span_label(borrow_span, note);
1234         }
1235
1236         Some(err)
1237     }
1238
1239     fn report_escaping_closure_capture(
1240         &mut self,
1241         use_span: UseSpans,
1242         var_span: Span,
1243         fr_name: &RegionName,
1244         category: ConstraintCategory,
1245         constraint_span: Span,
1246         captured_var: &str,
1247     ) -> DiagnosticBuilder<'cx> {
1248         let tcx = self.infcx.tcx;
1249         let args_span = use_span.args_or_use();
1250
1251         let suggestion = match tcx.sess.source_map().span_to_snippet(args_span) {
1252             Ok(mut string) => {
1253                 if string.starts_with("async ") {
1254                     string.insert_str(6, "move ");
1255                 } else if string.starts_with("async|") {
1256                     string.insert_str(5, " move");
1257                 } else {
1258                     string.insert_str(0, "move ");
1259                 };
1260                 string
1261             }
1262             Err(_) => "move |<args>| <body>".to_string(),
1263         };
1264         let kind = match use_span.generator_kind() {
1265             Some(generator_kind) => match generator_kind {
1266                 GeneratorKind::Async(async_kind) => match async_kind {
1267                     AsyncGeneratorKind::Block => "async block",
1268                     AsyncGeneratorKind::Closure => "async closure",
1269                     _ => bug!("async block/closure expected, but async function found."),
1270                 },
1271                 GeneratorKind::Gen => "generator",
1272             },
1273             None => "closure",
1274         };
1275
1276         let mut err =
1277             self.cannot_capture_in_long_lived_closure(args_span, kind, captured_var, var_span);
1278         err.span_suggestion(
1279             args_span,
1280             &format!(
1281                 "to force the {} to take ownership of {} (and any \
1282                  other referenced variables), use the `move` keyword",
1283                 kind, captured_var
1284             ),
1285             suggestion,
1286             Applicability::MachineApplicable,
1287         );
1288
1289         let msg = match category {
1290             ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => {
1291                 format!("{} is returned here", kind)
1292             }
1293             ConstraintCategory::CallArgument => {
1294                 fr_name.highlight_region_name(&mut err);
1295                 format!("function requires argument type to outlive `{}`", fr_name)
1296             }
1297             _ => bug!(
1298                 "report_escaping_closure_capture called with unexpected constraint \
1299                  category: `{:?}`",
1300                 category
1301             ),
1302         };
1303         err.span_note(constraint_span, &msg);
1304         err
1305     }
1306
1307     fn report_escaping_data(
1308         &mut self,
1309         borrow_span: Span,
1310         name: &Option<String>,
1311         upvar_span: Span,
1312         upvar_name: &str,
1313         escape_span: Span,
1314     ) -> DiagnosticBuilder<'cx> {
1315         let tcx = self.infcx.tcx;
1316
1317         let (_, escapes_from) = tcx.article_and_description(self.mir_def_id.to_def_id());
1318
1319         let mut err =
1320             borrowck_errors::borrowed_data_escapes_closure(tcx, escape_span, escapes_from);
1321
1322         err.span_label(
1323             upvar_span,
1324             format!("`{}` declared here, outside of the {} body", upvar_name, escapes_from),
1325         );
1326
1327         err.span_label(borrow_span, format!("borrow is only valid in the {} body", escapes_from));
1328
1329         if let Some(name) = name {
1330             err.span_label(
1331                 escape_span,
1332                 format!("reference to `{}` escapes the {} body here", name, escapes_from),
1333             );
1334         } else {
1335             err.span_label(
1336                 escape_span,
1337                 format!("reference escapes the {} body here", escapes_from),
1338             );
1339         }
1340
1341         err
1342     }
1343
1344     fn get_moved_indexes(&mut self, location: Location, mpi: MovePathIndex) -> Vec<MoveSite> {
1345         fn predecessor_locations(
1346             body: &'a mir::Body<'tcx>,
1347             location: Location,
1348         ) -> impl Iterator<Item = Location> + 'a {
1349             if location.statement_index == 0 {
1350                 let predecessors = body.predecessors()[location.block].to_vec();
1351                 Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb)))
1352             } else {
1353                 Either::Right(std::iter::once(Location {
1354                     statement_index: location.statement_index - 1,
1355                     ..location
1356                 }))
1357             }
1358         }
1359
1360         let mut stack = Vec::new();
1361         stack.extend(predecessor_locations(self.body, location).map(|predecessor| {
1362             let is_back_edge = location.dominates(predecessor, &self.dominators);
1363             (predecessor, is_back_edge)
1364         }));
1365
1366         let mut visited = FxHashSet::default();
1367         let mut result = vec![];
1368
1369         'dfs: while let Some((location, is_back_edge)) = stack.pop() {
1370             debug!(
1371                 "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})",
1372                 location, is_back_edge
1373             );
1374
1375             if !visited.insert(location) {
1376                 continue;
1377             }
1378
1379             // check for moves
1380             let stmt_kind =
1381                 self.body[location.block].statements.get(location.statement_index).map(|s| &s.kind);
1382             if let Some(StatementKind::StorageDead(..)) = stmt_kind {
1383                 // this analysis only tries to find moves explicitly
1384                 // written by the user, so we ignore the move-outs
1385                 // created by `StorageDead` and at the beginning
1386                 // of a function.
1387             } else {
1388                 // If we are found a use of a.b.c which was in error, then we want to look for
1389                 // moves not only of a.b.c but also a.b and a.
1390                 //
1391                 // Note that the moves data already includes "parent" paths, so we don't have to
1392                 // worry about the other case: that is, if there is a move of a.b.c, it is already
1393                 // marked as a move of a.b and a as well, so we will generate the correct errors
1394                 // there.
1395                 let mut mpis = vec![mpi];
1396                 let move_paths = &self.move_data.move_paths;
1397                 mpis.extend(move_paths[mpi].parents(move_paths).map(|(mpi, _)| mpi));
1398
1399                 for moi in &self.move_data.loc_map[location] {
1400                     debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
1401                     if mpis.contains(&self.move_data.moves[*moi].path) {
1402                         debug!("report_use_of_moved_or_uninitialized: found");
1403                         result.push(MoveSite { moi: *moi, traversed_back_edge: is_back_edge });
1404
1405                         // Strictly speaking, we could continue our DFS here. There may be
1406                         // other moves that can reach the point of error. But it is kind of
1407                         // confusing to highlight them.
1408                         //
1409                         // Example:
1410                         //
1411                         // ```
1412                         // let a = vec![];
1413                         // let b = a;
1414                         // let c = a;
1415                         // drop(a); // <-- current point of error
1416                         // ```
1417                         //
1418                         // Because we stop the DFS here, we only highlight `let c = a`,
1419                         // and not `let b = a`. We will of course also report an error at
1420                         // `let c = a` which highlights `let b = a` as the move.
1421                         continue 'dfs;
1422                     }
1423                 }
1424             }
1425
1426             // check for inits
1427             let mut any_match = false;
1428             drop_flag_effects::for_location_inits(
1429                 self.infcx.tcx,
1430                 &self.body,
1431                 self.move_data,
1432                 location,
1433                 |m| {
1434                     if m == mpi {
1435                         any_match = true;
1436                     }
1437                 },
1438             );
1439             if any_match {
1440                 continue 'dfs;
1441             }
1442
1443             stack.extend(predecessor_locations(self.body, location).map(|predecessor| {
1444                 let back_edge = location.dominates(predecessor, &self.dominators);
1445                 (predecessor, is_back_edge || back_edge)
1446             }));
1447         }
1448
1449         result
1450     }
1451
1452     pub(in crate::borrow_check) fn report_illegal_mutation_of_borrowed(
1453         &mut self,
1454         location: Location,
1455         (place, span): (Place<'tcx>, Span),
1456         loan: &BorrowData<'tcx>,
1457     ) {
1458         let loan_spans = self.retrieve_borrow_spans(loan);
1459         let loan_span = loan_spans.args_or_use();
1460
1461         let descr_place = self.describe_any_place(place.as_ref());
1462         if loan.kind == BorrowKind::Shallow {
1463             if let Some(section) = self.classify_immutable_section(loan.assigned_place) {
1464                 let mut err = self.cannot_mutate_in_immutable_section(
1465                     span,
1466                     loan_span,
1467                     &descr_place,
1468                     section,
1469                     "assign",
1470                 );
1471                 loan_spans.var_span_label(
1472                     &mut err,
1473                     format!("borrow occurs due to use{}", loan_spans.describe()),
1474                 );
1475
1476                 err.buffer(&mut self.errors_buffer);
1477
1478                 return;
1479             }
1480         }
1481
1482         let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
1483
1484         loan_spans
1485             .var_span_label(&mut err, format!("borrow occurs due to use{}", loan_spans.describe()));
1486
1487         self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic(
1488             self.infcx.tcx,
1489             &self.body,
1490             &self.local_names,
1491             &mut err,
1492             "",
1493             None,
1494         );
1495
1496         err.buffer(&mut self.errors_buffer);
1497     }
1498
1499     /// Reports an illegal reassignment; for example, an assignment to
1500     /// (part of) a non-`mut` local that occurs potentially after that
1501     /// local has already been initialized. `place` is the path being
1502     /// assigned; `err_place` is a place providing a reason why
1503     /// `place` is not mutable (e.g., the non-`mut` local `x` in an
1504     /// assignment to `x.f`).
1505     pub(in crate::borrow_check) fn report_illegal_reassignment(
1506         &mut self,
1507         _location: Location,
1508         (place, span): (Place<'tcx>, Span),
1509         assigned_span: Span,
1510         err_place: Place<'tcx>,
1511     ) {
1512         let (from_arg, local_decl, local_name) = match err_place.as_local() {
1513             Some(local) => (
1514                 self.body.local_kind(local) == LocalKind::Arg,
1515                 Some(&self.body.local_decls[local]),
1516                 self.local_names[local],
1517             ),
1518             None => (false, None, None),
1519         };
1520
1521         // If root local is initialized immediately (everything apart from let
1522         // PATTERN;) then make the error refer to that local, rather than the
1523         // place being assigned later.
1524         let (place_description, assigned_span) = match local_decl {
1525             Some(LocalDecl {
1526                 local_info:
1527                     Some(box LocalInfo::User(
1528                         ClearCrossCrate::Clear
1529                         | ClearCrossCrate::Set(BindingForm::Var(VarBindingForm {
1530                             opt_match_place: None,
1531                             ..
1532                         })),
1533                     ))
1534                     | Some(box LocalInfo::StaticRef { .. })
1535                     | None,
1536                 ..
1537             })
1538             | None => (self.describe_any_place(place.as_ref()), assigned_span),
1539             Some(decl) => (self.describe_any_place(err_place.as_ref()), decl.source_info.span),
1540         };
1541
1542         let mut err = self.cannot_reassign_immutable(span, &place_description, from_arg);
1543         let msg = if from_arg {
1544             "cannot assign to immutable argument"
1545         } else {
1546             "cannot assign twice to immutable variable"
1547         };
1548         if span != assigned_span {
1549             if !from_arg {
1550                 err.span_label(assigned_span, format!("first assignment to {}", place_description));
1551             }
1552         }
1553         if let Some(decl) = local_decl {
1554             if let Some(name) = local_name {
1555                 if decl.can_be_made_mutable() {
1556                     err.span_suggestion(
1557                         decl.source_info.span,
1558                         "make this binding mutable",
1559                         format!("mut {}", name),
1560                         Applicability::MachineApplicable,
1561                     );
1562                 }
1563             }
1564         }
1565         err.span_label(span, msg);
1566         err.buffer(&mut self.errors_buffer);
1567     }
1568
1569     fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> {
1570         let tcx = self.infcx.tcx;
1571         match place.projection {
1572             [] => StorageDeadOrDrop::LocalStorageDead,
1573             [proj_base @ .., elem] => {
1574                 // FIXME(spastorino) make this iterate
1575                 let base_access = self.classify_drop_access_kind(PlaceRef {
1576                     local: place.local,
1577                     projection: proj_base,
1578                 });
1579                 match elem {
1580                     ProjectionElem::Deref => match base_access {
1581                         StorageDeadOrDrop::LocalStorageDead
1582                         | StorageDeadOrDrop::BoxedStorageDead => {
1583                             assert!(
1584                                 Place::ty_from(place.local, proj_base, self.body, tcx).ty.is_box(),
1585                                 "Drop of value behind a reference or raw pointer"
1586                             );
1587                             StorageDeadOrDrop::BoxedStorageDead
1588                         }
1589                         StorageDeadOrDrop::Destructor(_) => base_access,
1590                     },
1591                     ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
1592                         let base_ty = Place::ty_from(place.local, proj_base, self.body, tcx).ty;
1593                         match base_ty.kind {
1594                             ty::Adt(def, _) if def.has_dtor(tcx) => {
1595                                 // Report the outermost adt with a destructor
1596                                 match base_access {
1597                                     StorageDeadOrDrop::Destructor(_) => base_access,
1598                                     StorageDeadOrDrop::LocalStorageDead
1599                                     | StorageDeadOrDrop::BoxedStorageDead => {
1600                                         StorageDeadOrDrop::Destructor(base_ty)
1601                                     }
1602                                 }
1603                             }
1604                             _ => base_access,
1605                         }
1606                     }
1607
1608                     ProjectionElem::ConstantIndex { .. }
1609                     | ProjectionElem::Subslice { .. }
1610                     | ProjectionElem::Index(_) => base_access,
1611                 }
1612             }
1613         }
1614     }
1615
1616     /// Describe the reason for the fake borrow that was assigned to `place`.
1617     fn classify_immutable_section(&self, place: Place<'tcx>) -> Option<&'static str> {
1618         use rustc_middle::mir::visit::Visitor;
1619         struct FakeReadCauseFinder<'tcx> {
1620             place: Place<'tcx>,
1621             cause: Option<FakeReadCause>,
1622         }
1623         impl<'tcx> Visitor<'tcx> for FakeReadCauseFinder<'tcx> {
1624             fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) {
1625                 match statement {
1626                     Statement { kind: StatementKind::FakeRead(cause, box place), .. }
1627                         if *place == self.place =>
1628                     {
1629                         self.cause = Some(*cause);
1630                     }
1631                     _ => (),
1632                 }
1633             }
1634         }
1635         let mut visitor = FakeReadCauseFinder { place, cause: None };
1636         visitor.visit_body(&self.body);
1637         match visitor.cause {
1638             Some(FakeReadCause::ForMatchGuard) => Some("match guard"),
1639             Some(FakeReadCause::ForIndex) => Some("indexing expression"),
1640             _ => None,
1641         }
1642     }
1643
1644     /// Annotate argument and return type of function and closure with (synthesized) lifetime for
1645     /// borrow of local value that does not live long enough.
1646     fn annotate_argument_and_return_for_borrow(
1647         &self,
1648         borrow: &BorrowData<'tcx>,
1649     ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
1650         // Define a fallback for when we can't match a closure.
1651         let fallback = || {
1652             let is_closure = self.infcx.tcx.is_closure(self.mir_def_id.to_def_id());
1653             if is_closure {
1654                 None
1655             } else {
1656                 let ty = self.infcx.tcx.type_of(self.mir_def_id);
1657                 match ty.kind {
1658                     ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig(
1659                         self.mir_def_id.to_def_id(),
1660                         self.infcx.tcx.fn_sig(self.mir_def_id),
1661                     ),
1662                     _ => None,
1663                 }
1664             }
1665         };
1666
1667         // In order to determine whether we need to annotate, we need to check whether the reserve
1668         // place was an assignment into a temporary.
1669         //
1670         // If it was, we check whether or not that temporary is eventually assigned into the return
1671         // place. If it was, we can add annotations about the function's return type and arguments
1672         // and it'll make sense.
1673         let location = borrow.reserve_location;
1674         debug!("annotate_argument_and_return_for_borrow: location={:?}", location);
1675         if let Some(&Statement { kind: StatementKind::Assign(box (ref reservation, _)), .. }) =
1676             &self.body[location.block].statements.get(location.statement_index)
1677         {
1678             debug!("annotate_argument_and_return_for_borrow: reservation={:?}", reservation);
1679             // Check that the initial assignment of the reserve location is into a temporary.
1680             let mut target = match reservation.as_local() {
1681                 Some(local) if self.body.local_kind(local) == LocalKind::Temp => local,
1682                 _ => return None,
1683             };
1684
1685             // Next, look through the rest of the block, checking if we are assigning the
1686             // `target` (that is, the place that contains our borrow) to anything.
1687             let mut annotated_closure = None;
1688             for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
1689                 debug!(
1690                     "annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
1691                     target, stmt
1692                 );
1693                 if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
1694                     if let Some(assigned_to) = place.as_local() {
1695                         debug!(
1696                             "annotate_argument_and_return_for_borrow: assigned_to={:?} \
1697                              rvalue={:?}",
1698                             assigned_to, rvalue
1699                         );
1700                         // Check if our `target` was captured by a closure.
1701                         if let Rvalue::Aggregate(
1702                             box AggregateKind::Closure(def_id, substs),
1703                             operands,
1704                         ) = rvalue
1705                         {
1706                             for operand in operands {
1707                                 let assigned_from = match operand {
1708                                     Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
1709                                         assigned_from
1710                                     }
1711                                     _ => continue,
1712                                 };
1713                                 debug!(
1714                                     "annotate_argument_and_return_for_borrow: assigned_from={:?}",
1715                                     assigned_from
1716                                 );
1717
1718                                 // Find the local from the operand.
1719                                 let assigned_from_local = match assigned_from.local_or_deref_local()
1720                                 {
1721                                     Some(local) => local,
1722                                     None => continue,
1723                                 };
1724
1725                                 if assigned_from_local != target {
1726                                     continue;
1727                                 }
1728
1729                                 // If a closure captured our `target` and then assigned
1730                                 // into a place then we should annotate the closure in
1731                                 // case it ends up being assigned into the return place.
1732                                 annotated_closure =
1733                                     self.annotate_fn_sig(*def_id, substs.as_closure().sig());
1734                                 debug!(
1735                                     "annotate_argument_and_return_for_borrow: \
1736                                      annotated_closure={:?} assigned_from_local={:?} \
1737                                      assigned_to={:?}",
1738                                     annotated_closure, assigned_from_local, assigned_to
1739                                 );
1740
1741                                 if assigned_to == mir::RETURN_PLACE {
1742                                     // If it was assigned directly into the return place, then
1743                                     // return now.
1744                                     return annotated_closure;
1745                                 } else {
1746                                     // Otherwise, update the target.
1747                                     target = assigned_to;
1748                                 }
1749                             }
1750
1751                             // If none of our closure's operands matched, then skip to the next
1752                             // statement.
1753                             continue;
1754                         }
1755
1756                         // Otherwise, look at other types of assignment.
1757                         let assigned_from = match rvalue {
1758                             Rvalue::Ref(_, _, assigned_from) => assigned_from,
1759                             Rvalue::Use(operand) => match operand {
1760                                 Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
1761                                     assigned_from
1762                                 }
1763                                 _ => continue,
1764                             },
1765                             _ => continue,
1766                         };
1767                         debug!(
1768                             "annotate_argument_and_return_for_borrow: \
1769                              assigned_from={:?}",
1770                             assigned_from,
1771                         );
1772
1773                         // Find the local from the rvalue.
1774                         let assigned_from_local = match assigned_from.local_or_deref_local() {
1775                             Some(local) => local,
1776                             None => continue,
1777                         };
1778                         debug!(
1779                             "annotate_argument_and_return_for_borrow: \
1780                              assigned_from_local={:?}",
1781                             assigned_from_local,
1782                         );
1783
1784                         // Check if our local matches the target - if so, we've assigned our
1785                         // borrow to a new place.
1786                         if assigned_from_local != target {
1787                             continue;
1788                         }
1789
1790                         // If we assigned our `target` into a new place, then we should
1791                         // check if it was the return place.
1792                         debug!(
1793                             "annotate_argument_and_return_for_borrow: \
1794                              assigned_from_local={:?} assigned_to={:?}",
1795                             assigned_from_local, assigned_to
1796                         );
1797                         if assigned_to == mir::RETURN_PLACE {
1798                             // If it was then return the annotated closure if there was one,
1799                             // else, annotate this function.
1800                             return annotated_closure.or_else(fallback);
1801                         }
1802
1803                         // If we didn't assign into the return place, then we just update
1804                         // the target.
1805                         target = assigned_to;
1806                     }
1807                 }
1808             }
1809
1810             // Check the terminator if we didn't find anything in the statements.
1811             let terminator = &self.body[location.block].terminator();
1812             debug!(
1813                 "annotate_argument_and_return_for_borrow: target={:?} terminator={:?}",
1814                 target, terminator
1815             );
1816             if let TerminatorKind::Call { destination: Some((place, _)), args, .. } =
1817                 &terminator.kind
1818             {
1819                 if let Some(assigned_to) = place.as_local() {
1820                     debug!(
1821                         "annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
1822                         assigned_to, args
1823                     );
1824                     for operand in args {
1825                         let assigned_from = match operand {
1826                             Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
1827                                 assigned_from
1828                             }
1829                             _ => continue,
1830                         };
1831                         debug!(
1832                             "annotate_argument_and_return_for_borrow: assigned_from={:?}",
1833                             assigned_from,
1834                         );
1835
1836                         if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
1837                             debug!(
1838                                 "annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
1839                                 assigned_from_local,
1840                             );
1841
1842                             if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
1843                                 return annotated_closure.or_else(fallback);
1844                             }
1845                         }
1846                     }
1847                 }
1848             }
1849         }
1850
1851         // If we haven't found an assignment into the return place, then we need not add
1852         // any annotations.
1853         debug!("annotate_argument_and_return_for_borrow: none found");
1854         None
1855     }
1856
1857     /// Annotate the first argument and return type of a function signature if they are
1858     /// references.
1859     fn annotate_fn_sig(
1860         &self,
1861         did: DefId,
1862         sig: ty::PolyFnSig<'tcx>,
1863     ) -> Option<AnnotatedBorrowFnSignature<'tcx>> {
1864         debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig);
1865         let is_closure = self.infcx.tcx.is_closure(did);
1866         let fn_hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did.as_local()?);
1867         let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?;
1868
1869         // We need to work out which arguments to highlight. We do this by looking
1870         // at the return type, where there are three cases:
1871         //
1872         // 1. If there are named arguments, then we should highlight the return type and
1873         //    highlight any of the arguments that are also references with that lifetime.
1874         //    If there are no arguments that have the same lifetime as the return type,
1875         //    then don't highlight anything.
1876         // 2. The return type is a reference with an anonymous lifetime. If this is
1877         //    the case, then we can take advantage of (and teach) the lifetime elision
1878         //    rules.
1879         //
1880         //    We know that an error is being reported. So the arguments and return type
1881         //    must satisfy the elision rules. Therefore, if there is a single argument
1882         //    then that means the return type and first (and only) argument have the same
1883         //    lifetime and the borrow isn't meeting that, we can highlight the argument
1884         //    and return type.
1885         //
1886         //    If there are multiple arguments then the first argument must be self (else
1887         //    it would not satisfy the elision rules), so we can highlight self and the
1888         //    return type.
1889         // 3. The return type is not a reference. In this case, we don't highlight
1890         //    anything.
1891         let return_ty = sig.output();
1892         match return_ty.skip_binder().kind {
1893             ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => {
1894                 // This is case 1 from above, return type is a named reference so we need to
1895                 // search for relevant arguments.
1896                 let mut arguments = Vec::new();
1897                 for (index, argument) in sig.inputs().skip_binder().iter().enumerate() {
1898                     if let ty::Ref(argument_region, _, _) = argument.kind {
1899                         if argument_region == return_region {
1900                             // Need to use the `rustc_middle::ty` types to compare against the
1901                             // `return_region`. Then use the `rustc_hir` type to get only
1902                             // the lifetime span.
1903                             if let hir::TyKind::Rptr(lifetime, _) = &fn_decl.inputs[index].kind {
1904                                 // With access to the lifetime, we can get
1905                                 // the span of it.
1906                                 arguments.push((*argument, lifetime.span));
1907                             } else {
1908                                 bug!("ty type is a ref but hir type is not");
1909                             }
1910                         }
1911                     }
1912                 }
1913
1914                 // We need to have arguments. This shouldn't happen, but it's worth checking.
1915                 if arguments.is_empty() {
1916                     return None;
1917                 }
1918
1919                 // We use a mix of the HIR and the Ty types to get information
1920                 // as the HIR doesn't have full types for closure arguments.
1921                 let return_ty = sig.output().skip_binder();
1922                 let mut return_span = fn_decl.output.span();
1923                 if let hir::FnRetTy::Return(ty) = &fn_decl.output {
1924                     if let hir::TyKind::Rptr(lifetime, _) = ty.kind {
1925                         return_span = lifetime.span;
1926                     }
1927                 }
1928
1929                 Some(AnnotatedBorrowFnSignature::NamedFunction {
1930                     arguments,
1931                     return_ty,
1932                     return_span,
1933                 })
1934             }
1935             ty::Ref(_, _, _) if is_closure => {
1936                 // This is case 2 from above but only for closures, return type is anonymous
1937                 // reference so we select
1938                 // the first argument.
1939                 let argument_span = fn_decl.inputs.first()?.span;
1940                 let argument_ty = sig.inputs().skip_binder().first()?;
1941
1942                 // Closure arguments are wrapped in a tuple, so we need to get the first
1943                 // from that.
1944                 if let ty::Tuple(elems) = argument_ty.kind {
1945                     let argument_ty = elems.first()?.expect_ty();
1946                     if let ty::Ref(_, _, _) = argument_ty.kind {
1947                         return Some(AnnotatedBorrowFnSignature::Closure {
1948                             argument_ty,
1949                             argument_span,
1950                         });
1951                     }
1952                 }
1953
1954                 None
1955             }
1956             ty::Ref(_, _, _) => {
1957                 // This is also case 2 from above but for functions, return type is still an
1958                 // anonymous reference so we select the first argument.
1959                 let argument_span = fn_decl.inputs.first()?.span;
1960                 let argument_ty = sig.inputs().skip_binder().first()?;
1961
1962                 let return_span = fn_decl.output.span();
1963                 let return_ty = sig.output().skip_binder();
1964
1965                 // We expect the first argument to be a reference.
1966                 match argument_ty.kind {
1967                     ty::Ref(_, _, _) => {}
1968                     _ => return None,
1969                 }
1970
1971                 Some(AnnotatedBorrowFnSignature::AnonymousFunction {
1972                     argument_ty,
1973                     argument_span,
1974                     return_ty,
1975                     return_span,
1976                 })
1977             }
1978             _ => {
1979                 // This is case 3 from above, return type is not a reference so don't highlight
1980                 // anything.
1981                 None
1982             }
1983         }
1984     }
1985 }
1986
1987 #[derive(Debug)]
1988 enum AnnotatedBorrowFnSignature<'tcx> {
1989     NamedFunction {
1990         arguments: Vec<(Ty<'tcx>, Span)>,
1991         return_ty: Ty<'tcx>,
1992         return_span: Span,
1993     },
1994     AnonymousFunction {
1995         argument_ty: Ty<'tcx>,
1996         argument_span: Span,
1997         return_ty: Ty<'tcx>,
1998         return_span: Span,
1999     },
2000     Closure {
2001         argument_ty: Ty<'tcx>,
2002         argument_span: Span,
2003     },
2004 }
2005
2006 impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
2007     /// Annotate the provided diagnostic with information about borrow from the fn signature that
2008     /// helps explain.
2009     pub(in crate::borrow_check) fn emit(
2010         &self,
2011         cx: &mut MirBorrowckCtxt<'_, 'tcx>,
2012         diag: &mut DiagnosticBuilder<'_>,
2013     ) -> String {
2014         match self {
2015             AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => {
2016                 diag.span_label(
2017                     *argument_span,
2018                     format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)),
2019                 );
2020
2021                 cx.get_region_name_for_ty(argument_ty, 0)
2022             }
2023             AnnotatedBorrowFnSignature::AnonymousFunction {
2024                 argument_ty,
2025                 argument_span,
2026                 return_ty,
2027                 return_span,
2028             } => {
2029                 let argument_ty_name = cx.get_name_for_ty(argument_ty, 0);
2030                 diag.span_label(*argument_span, format!("has type `{}`", argument_ty_name));
2031
2032                 let return_ty_name = cx.get_name_for_ty(return_ty, 0);
2033                 let types_equal = return_ty_name == argument_ty_name;
2034                 diag.span_label(
2035                     *return_span,
2036                     format!(
2037                         "{}has type `{}`",
2038                         if types_equal { "also " } else { "" },
2039                         return_ty_name,
2040                     ),
2041                 );
2042
2043                 diag.note(
2044                     "argument and return type have the same lifetime due to lifetime elision rules",
2045                 );
2046                 diag.note(
2047                     "to learn more, visit <https://doc.rust-lang.org/book/ch10-03-\
2048                      lifetime-syntax.html#lifetime-elision>",
2049                 );
2050
2051                 cx.get_region_name_for_ty(return_ty, 0)
2052             }
2053             AnnotatedBorrowFnSignature::NamedFunction { arguments, return_ty, return_span } => {
2054                 // Region of return type and arguments checked to be the same earlier.
2055                 let region_name = cx.get_region_name_for_ty(return_ty, 0);
2056                 for (_, argument_span) in arguments {
2057                     diag.span_label(*argument_span, format!("has lifetime `{}`", region_name));
2058                 }
2059
2060                 diag.span_label(*return_span, format!("also has lifetime `{}`", region_name,));
2061
2062                 diag.help(&format!(
2063                     "use data from the highlighted arguments which match the `{}` lifetime of \
2064                      the return type",
2065                     region_name,
2066                 ));
2067
2068                 region_name
2069             }
2070         }
2071     }
2072 }