Skip to content

Commit 650b1b1

Browse files
committed
Auto merge of #45016 - pnkfelix:mir-borrowck-gather-and-signal-move-errors, r=nikomatsakis
MIR-borrowck: gather and signal any move errors When building up the `MoveData` structure for a given MIR, also accumulate any erroneous actions, and then report all of those errors when the construction is complete. This PR adds a host of move-related error constructor methods to `trait BorrowckErrors`. I think I got the notes right; but we should plan to audit all of the notes before turning MIR-borrowck on by default. Fix #44830
2 parents ade0b01 + 86ca5cf commit 650b1b1

17 files changed

+557
-379
lines changed

src/librustc/mir/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,19 @@ impl<'tcx> Mir<'tcx> {
260260
debug_assert!(location.statement_index < block.statements.len());
261261
block.statements[location.statement_index].make_nop()
262262
}
263+
264+
/// Returns the source info associated with `location`.
265+
pub fn source_info(&self, location: Location) -> &SourceInfo {
266+
let block = &self[location.block];
267+
let stmts = &block.statements;
268+
let idx = location.statement_index;
269+
if location.statement_index < stmts.len() {
270+
&stmts[idx].source_info
271+
} else {
272+
assert!(location.statement_index == stmts.len());
273+
&block.terminator().source_info
274+
}
275+
}
263276
}
264277

265278
#[derive(Clone, Debug)]

src/librustc_borrowck/borrowck/gather_loans/move_error.rs

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use rustc::middle::mem_categorization::Categorization;
1414
use rustc::middle::mem_categorization::NoteClosureEnv;
1515
use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
1616
use rustc::ty;
17+
use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
1718
use syntax::ast;
1819
use syntax_pos;
1920
use errors::DiagnosticBuilder;
@@ -134,51 +135,29 @@ fn group_errors_with_same_origin<'tcx>(errors: &Vec<MoveError<'tcx>>)
134135
}
135136

136137
// (keep in sync with gather_moves::check_and_get_illegal_move_origin )
137-
fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
138+
fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>,
138139
move_from: mc::cmt<'tcx>)
139140
-> DiagnosticBuilder<'a> {
140141
match move_from.cat {
141142
Categorization::Deref(_, mc::BorrowedPtr(..)) |
142143
Categorization::Deref(_, mc::Implicit(..)) |
143144
Categorization::Deref(_, mc::UnsafePtr(..)) |
144145
Categorization::StaticItem => {
145-
let mut err = struct_span_err!(bccx, move_from.span, E0507,
146-
"cannot move out of {}",
147-
move_from.descriptive_string(bccx.tcx));
148-
err.span_label(
149-
move_from.span,
150-
format!("cannot move out of {}", move_from.descriptive_string(bccx.tcx))
151-
);
152-
err
146+
bccx.cannot_move_out_of(
147+
move_from.span, &move_from.descriptive_string(bccx.tcx), Origin::Ast)
153148
}
154-
155149
Categorization::Interior(ref b, mc::InteriorElement(ik)) => {
156-
let type_name = match (&b.ty.sty, ik) {
157-
(&ty::TyArray(_, _), Kind::Index) => "array",
158-
(&ty::TySlice(_), _) => "slice",
159-
_ => {
160-
span_bug!(move_from.span, "this path should not cause illegal move");
161-
},
162-
};
163-
let mut err = struct_span_err!(bccx, move_from.span, E0508,
164-
"cannot move out of type `{}`, \
165-
a non-copy {}",
166-
b.ty, type_name);
167-
err.span_label(move_from.span, "cannot move out of here");
168-
err
150+
bccx.cannot_move_out_of_interior_noncopy(
151+
move_from.span, b.ty, ik == Kind::Index, Origin::Ast)
169152
}
170153

171154
Categorization::Downcast(ref b, _) |
172155
Categorization::Interior(ref b, mc::InteriorField(_)) => {
173156
match b.ty.sty {
174157
ty::TyAdt(def, _) if def.has_dtor(bccx.tcx) => {
175-
let mut err = struct_span_err!(bccx, move_from.span, E0509,
176-
"cannot move out of type `{}`, \
177-
which implements the `Drop` trait",
178-
b.ty);
179-
err.span_label(move_from.span, "cannot move out of here");
180-
err
181-
},
158+
bccx.cannot_move_out_of_interior_of_drop(
159+
move_from.span, b.ty, Origin::Ast)
160+
}
182161
_ => {
183162
span_bug!(move_from.span, "this path should not cause illegal move");
184163
}

src/librustc_borrowck/diagnostics.rs

Lines changed: 0 additions & 266 deletions
Original file line numberDiff line numberDiff line change
@@ -317,272 +317,6 @@ fn main() {
317317
```
318318
"##,
319319

320-
E0507: r##"
321-
You tried to move out of a value which was borrowed. Erroneous code example:
322-
323-
```compile_fail,E0507
324-
use std::cell::RefCell;
325-
326-
struct TheDarkKnight;
327-
328-
impl TheDarkKnight {
329-
fn nothing_is_true(self) {}
330-
}
331-
332-
fn main() {
333-
let x = RefCell::new(TheDarkKnight);
334-
335-
x.borrow().nothing_is_true(); // error: cannot move out of borrowed content
336-
}
337-
```
338-
339-
Here, the `nothing_is_true` method takes the ownership of `self`. However,
340-
`self` cannot be moved because `.borrow()` only provides an `&TheDarkKnight`,
341-
which is a borrow of the content owned by the `RefCell`. To fix this error,
342-
you have three choices:
343-
344-
* Try to avoid moving the variable.
345-
* Somehow reclaim the ownership.
346-
* Implement the `Copy` trait on the type.
347-
348-
Examples:
349-
350-
```
351-
use std::cell::RefCell;
352-
353-
struct TheDarkKnight;
354-
355-
impl TheDarkKnight {
356-
fn nothing_is_true(&self) {} // First case, we don't take ownership
357-
}
358-
359-
fn main() {
360-
let x = RefCell::new(TheDarkKnight);
361-
362-
x.borrow().nothing_is_true(); // ok!
363-
}
364-
```
365-
366-
Or:
367-
368-
```
369-
use std::cell::RefCell;
370-
371-
struct TheDarkKnight;
372-
373-
impl TheDarkKnight {
374-
fn nothing_is_true(self) {}
375-
}
376-
377-
fn main() {
378-
let x = RefCell::new(TheDarkKnight);
379-
let x = x.into_inner(); // we get back ownership
380-
381-
x.nothing_is_true(); // ok!
382-
}
383-
```
384-
385-
Or:
386-
387-
```
388-
use std::cell::RefCell;
389-
390-
#[derive(Clone, Copy)] // we implement the Copy trait
391-
struct TheDarkKnight;
392-
393-
impl TheDarkKnight {
394-
fn nothing_is_true(self) {}
395-
}
396-
397-
fn main() {
398-
let x = RefCell::new(TheDarkKnight);
399-
400-
x.borrow().nothing_is_true(); // ok!
401-
}
402-
```
403-
404-
Moving a member out of a mutably borrowed struct will also cause E0507 error:
405-
406-
```compile_fail,E0507
407-
struct TheDarkKnight;
408-
409-
impl TheDarkKnight {
410-
fn nothing_is_true(self) {}
411-
}
412-
413-
struct Batcave {
414-
knight: TheDarkKnight
415-
}
416-
417-
fn main() {
418-
let mut cave = Batcave {
419-
knight: TheDarkKnight
420-
};
421-
let borrowed = &mut cave;
422-
423-
borrowed.knight.nothing_is_true(); // E0507
424-
}
425-
```
426-
427-
It is fine only if you put something back. `mem::replace` can be used for that:
428-
429-
```
430-
# struct TheDarkKnight;
431-
# impl TheDarkKnight { fn nothing_is_true(self) {} }
432-
# struct Batcave { knight: TheDarkKnight }
433-
use std::mem;
434-
435-
let mut cave = Batcave {
436-
knight: TheDarkKnight
437-
};
438-
let borrowed = &mut cave;
439-
440-
mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok!
441-
```
442-
443-
You can find more information about borrowing in the rust-book:
444-
http://doc.rust-lang.org/book/first-edition/references-and-borrowing.html
445-
"##,
446-
447-
E0508: r##"
448-
A value was moved out of a non-copy fixed-size array.
449-
450-
Example of erroneous code:
451-
452-
```compile_fail,E0508
453-
struct NonCopy;
454-
455-
fn main() {
456-
let array = [NonCopy; 1];
457-
let _value = array[0]; // error: cannot move out of type `[NonCopy; 1]`,
458-
// a non-copy fixed-size array
459-
}
460-
```
461-
462-
The first element was moved out of the array, but this is not
463-
possible because `NonCopy` does not implement the `Copy` trait.
464-
465-
Consider borrowing the element instead of moving it:
466-
467-
```
468-
struct NonCopy;
469-
470-
fn main() {
471-
let array = [NonCopy; 1];
472-
let _value = &array[0]; // Borrowing is allowed, unlike moving.
473-
}
474-
```
475-
476-
Alternatively, if your type implements `Clone` and you need to own the value,
477-
consider borrowing and then cloning:
478-
479-
```
480-
#[derive(Clone)]
481-
struct NonCopy;
482-
483-
fn main() {
484-
let array = [NonCopy; 1];
485-
// Now you can clone the array element.
486-
let _value = array[0].clone();
487-
}
488-
```
489-
"##,
490-
491-
E0509: r##"
492-
This error occurs when an attempt is made to move out of a value whose type
493-
implements the `Drop` trait.
494-
495-
Example of erroneous code:
496-
497-
```compile_fail,E0509
498-
struct FancyNum {
499-
num: usize
500-
}
501-
502-
struct DropStruct {
503-
fancy: FancyNum
504-
}
505-
506-
impl Drop for DropStruct {
507-
fn drop(&mut self) {
508-
// Destruct DropStruct, possibly using FancyNum
509-
}
510-
}
511-
512-
fn main() {
513-
let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
514-
let fancy_field = drop_struct.fancy; // Error E0509
515-
println!("Fancy: {}", fancy_field.num);
516-
// implicit call to `drop_struct.drop()` as drop_struct goes out of scope
517-
}
518-
```
519-
520-
Here, we tried to move a field out of a struct of type `DropStruct` which
521-
implements the `Drop` trait. However, a struct cannot be dropped if one or
522-
more of its fields have been moved.
523-
524-
Structs implementing the `Drop` trait have an implicit destructor that gets
525-
called when they go out of scope. This destructor may use the fields of the
526-
struct, so moving out of the struct could make it impossible to run the
527-
destructor. Therefore, we must think of all values whose type implements the
528-
`Drop` trait as single units whose fields cannot be moved.
529-
530-
This error can be fixed by creating a reference to the fields of a struct,
531-
enum, or tuple using the `ref` keyword:
532-
533-
```
534-
struct FancyNum {
535-
num: usize
536-
}
537-
538-
struct DropStruct {
539-
fancy: FancyNum
540-
}
541-
542-
impl Drop for DropStruct {
543-
fn drop(&mut self) {
544-
// Destruct DropStruct, possibly using FancyNum
545-
}
546-
}
547-
548-
fn main() {
549-
let drop_struct = DropStruct{fancy: FancyNum{num: 5}};
550-
let ref fancy_field = drop_struct.fancy; // No more errors!
551-
println!("Fancy: {}", fancy_field.num);
552-
// implicit call to `drop_struct.drop()` as drop_struct goes out of scope
553-
}
554-
```
555-
556-
Note that this technique can also be used in the arms of a match expression:
557-
558-
```
559-
struct FancyNum {
560-
num: usize
561-
}
562-
563-
enum DropEnum {
564-
Fancy(FancyNum)
565-
}
566-
567-
impl Drop for DropEnum {
568-
fn drop(&mut self) {
569-
// Destruct DropEnum, possibly using FancyNum
570-
}
571-
}
572-
573-
fn main() {
574-
// Creates and enum of type `DropEnum`, which implements `Drop`
575-
let drop_enum = DropEnum::Fancy(FancyNum{num: 10});
576-
match drop_enum {
577-
// Creates a reference to the inside of `DropEnum::Fancy`
578-
DropEnum::Fancy(ref fancy_field) => // No error!
579-
println!("It was fancy-- {}!", fancy_field.num),
580-
}
581-
// implicit call to `drop_enum.drop()` as drop_enum goes out of scope
582-
}
583-
```
584-
"##,
585-
586320
E0595: r##"
587321
Closures cannot mutate immutable captured variables.
588322

0 commit comments

Comments
 (0)