]> git.lizzy.rs Git - rust.git/commitdiff
Modified to output intended error.
authorDavid Wood <david@davidtw.co>
Fri, 17 Nov 2017 00:09:18 +0000 (00:09 +0000)
committerDavid Wood <david@davidtw.co>
Fri, 17 Nov 2017 00:09:18 +0000 (00:09 +0000)
src/librustc_mir/borrow_check.rs

index 1c2289c758defabf76636f18b17e58f87c6456ec..6ba3f5054797419487e94010698ace5184c03086 100644 (file)
@@ -25,7 +25,7 @@
 use rustc_data_structures::indexed_vec::{Idx};
 
 use syntax::ast::{self};
-use syntax_pos::{DUMMY_SP, Span};
+use syntax_pos::{DUMMY_SP, Span, MultiSpan};
 
 use dataflow::{do_dataflow};
 use dataflow::{MoveDataParamEnv};
@@ -287,11 +287,14 @@ fn visit_statement_entry(&mut self,
             }
 
             StatementKind::StorageDead(local) => {
-                if self.storage_drop_or_dead_error_reported.insert(local) {
-                    self.access_lvalue(ContextKind::StorageDead.new(location),
-                                       (&Lvalue::Local(local), span),
-                                       (Shallow(None), Write(WriteKind::StorageDead)),
-                                       flow_state);
+                if !self.storage_drop_or_dead_error_reported.contains(&local) {
+                    let error_reported = self.access_lvalue(ContextKind::StorageDead.new(location),
+                        (&Lvalue::Local(local), span),
+                        (Shallow(None), Write(WriteKind::StorageDeadOrDrop)), flow_state);
+
+                    if error_reported {
+                        self.storage_drop_or_dead_error_reported.insert(local);
+                    }
                 }
             }
         }
@@ -435,24 +438,30 @@ enum ReadKind {
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 enum WriteKind {
-    StorageDead,
+    StorageDeadOrDrop,
     MutableBorrow(BorrowKind),
     Mutate,
     Move,
 }
 
 impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
+    /// Checks an access to the given lvalue to see if it is allowed. Examines the set of borrows
+    /// that are in scope, as well as which paths have been initialized, to ensure that (a) the
+    /// lvalue is initialized and (b) it is not borrowed in some way that would prevent this
+    /// access.
+    ///
+    /// Returns true if an error is reported, false otherwise.
     fn access_lvalue(&mut self,
                      context: Context,
                      lvalue_span: (&Lvalue<'tcx>, Span),
                      kind: (ShallowOrDeep, ReadOrWrite),
-                     flow_state: &InProgress<'cx, 'gcx, 'tcx>) {
-
+                     flow_state: &InProgress<'cx, 'gcx, 'tcx>) -> bool {
         let (sd, rw) = kind;
 
         // Check permissions
         self.check_access_permissions(lvalue_span, rw);
 
+        let mut error_reported = false;
         self.each_borrow_involving_path(
             context, (sd, lvalue_span.0), flow_state, |this, _index, borrow, common_prefix| {
                 match (rw, borrow.kind) {
@@ -462,13 +471,16 @@ fn access_lvalue(&mut self,
                     (Read(kind), BorrowKind::Unique) |
                     (Read(kind), BorrowKind::Mut) => {
                         match kind {
-                            ReadKind::Copy =>
+                            ReadKind::Copy => {
+                                error_reported = true;
                                 this.report_use_while_mutably_borrowed(
-                                    context, lvalue_span, borrow),
+                                    context, lvalue_span, borrow)
+                            },
                             ReadKind::Borrow(bk) => {
                                 let end_issued_loan_span =
                                     flow_state.borrows.base_results.operator().opt_region_end_span(
                                         &borrow.region);
+                                error_reported = true;
                                 this.report_conflicting_borrow(
                                     context, common_prefix, lvalue_span, bk,
                                     &borrow, end_issued_loan_span)
@@ -482,22 +494,35 @@ fn access_lvalue(&mut self,
                                 let end_issued_loan_span =
                                     flow_state.borrows.base_results.operator().opt_region_end_span(
                                         &borrow.region);
+                                error_reported = true;
                                 this.report_conflicting_borrow(
                                     context, common_prefix, lvalue_span, bk,
                                     &borrow, end_issued_loan_span)
                             }
-                            WriteKind::StorageDead |
-                            WriteKind::Mutate =>
+                             WriteKind::StorageDeadOrDrop => {
+                                let end_span =
+                                    flow_state.borrows.base_results.operator().opt_region_end_span(
+                                        &borrow.region);
+                                error_reported = true;
+                                this.report_borrowed_value_does_not_live_long_enough(
+                                    context, lvalue_span, end_span)
+                            },
+                            WriteKind::Mutate => {
+                                error_reported = true;
                                 this.report_illegal_mutation_of_borrowed(
-                                    context, lvalue_span, borrow),
-                            WriteKind::Move =>
+                                    context, lvalue_span, borrow)
+                            },
+                            WriteKind::Move => {
+                                error_reported = true;
                                 this.report_move_out_while_borrowed(
-                                    context, lvalue_span, &borrow),
+                                    context, lvalue_span, &borrow)
+                            },
                         }
                         Control::Break
                     }
                 }
             });
+        error_reported
     }
 
     fn mutate_lvalue(&mut self,
@@ -614,20 +639,34 @@ fn consume_lvalue(&mut self,
 
         // Check if error has already been reported to stop duplicate reporting.
         let has_storage_drop_or_dead_error_reported = match *lvalue {
-            Lvalue::Local(local) => self.storage_drop_or_dead_error_reported.insert(local),
+            Lvalue::Local(local) => self.storage_drop_or_dead_error_reported.contains(&local),
             _ => false,
         };
 
+        // If the error has been reported already, then we don't need the access_lvalue call and we
+        // can set error_reported to false.
         if !has_storage_drop_or_dead_error_reported {
+            let error_reported;
+
             if moves_by_default {
+                let kind = match consume_via_drop {
+                    ConsumeKind::Drop => WriteKind::StorageDeadOrDrop,
+                    _ => WriteKind::Move,
+                };
                 // move of lvalue: check if this is move of already borrowed path
-                self.access_lvalue(context, lvalue_span, (Deep, Write(WriteKind::Move)),
-                                   flow_state);
+                error_reported = self.access_lvalue(context, lvalue_span,
+                                                    (Deep, Write(kind)), flow_state);
             } else {
                 // copy of lvalue: check if this is "copy of frozen path"
                 // (FIXME: see check_loans.rs)
-                self.access_lvalue(context, lvalue_span, (Deep, Read(ReadKind::Copy)),
-                                   flow_state);
+                error_reported = self.access_lvalue(context, lvalue_span,
+                                                    (Deep, Read(ReadKind::Copy)), flow_state);
+            }
+
+            if error_reported {
+                if let Lvalue::Local(local) = *lvalue {
+                    self.storage_drop_or_dead_error_reported.insert(local);
+                }
             }
         }
 
@@ -1477,6 +1516,29 @@ fn report_conflicting_borrow(&mut self,
         err.emit();
     }
 
+    fn report_borrowed_value_does_not_live_long_enough(&mut self,
+                                                       _: Context,
+                                                       (lvalue, span): (&Lvalue, Span),
+                                                       end_span: Option<Span>) {
+        let proper_span = match *lvalue {
+            Lvalue::Local(local) => self.mir.local_decls[local].source_info.span,
+            _ => span
+        };
+
+        let mut err = self.tcx.path_does_not_live_long_enough(proper_span,
+                                                              "borrowed value", Origin::Mir);
+        err.span = MultiSpan::from_span(proper_span);
+        err.span_label(proper_span, "temporary value created here");
+        err.span_label(span, "temporary value dropped here while still borrowed");
+        err.note("consider using a `let` binding to increase its lifetime");
+
+        if let Some(end) = end_span {
+            err.span_label(end, "temporary value needs to live until here");
+        }
+
+        err.emit();
+    }
+
     fn report_illegal_mutation_of_borrowed(&mut self,
                                            _: Context,
                                            (lvalue, span): (&Lvalue<'tcx>, Span),