|
1 | 1 | use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
|
2 | 2 | use rustc_middle::mir::*;
|
3 |
| -use rustc_middle::ty; |
4 |
| -use rustc_mir_dataflow::move_paths::{ |
5 |
| - IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex, |
6 |
| -}; |
| 3 | +use rustc_middle::ty::{self, Ty}; |
| 4 | +use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex}; |
7 | 5 | use rustc_span::{BytePos, Span};
|
8 | 6 |
|
9 | 7 | use crate::diagnostics::CapturedMessageOpt;
|
10 | 8 | use crate::diagnostics::{DescribePlaceOpt, UseSpans};
|
11 | 9 | use crate::prefixes::PrefixSet;
|
12 | 10 | use crate::MirBorrowckCtxt;
|
13 | 11 |
|
| 12 | +#[derive(Debug)] |
| 13 | +pub enum IllegalMoveOriginKind<'tcx> { |
| 14 | + /// Illegal move due to attempt to move from behind a reference. |
| 15 | + BorrowedContent { |
| 16 | + /// The place the reference refers to: if erroneous code was trying to |
| 17 | + /// move from `(*x).f` this will be `*x`. |
| 18 | + target_place: Place<'tcx>, |
| 19 | + }, |
| 20 | + |
| 21 | + /// Illegal move due to attempt to move from field of an ADT that |
| 22 | + /// implements `Drop`. Rust maintains invariant that all `Drop` |
| 23 | + /// ADT's remain fully-initialized so that user-defined destructor |
| 24 | + /// can safely read from all of the ADT's fields. |
| 25 | + InteriorOfTypeWithDestructor { container_ty: Ty<'tcx> }, |
| 26 | + |
| 27 | + /// Illegal move due to attempt to move out of a slice or array. |
| 28 | + InteriorOfSliceOrArray { ty: Ty<'tcx>, is_index: bool }, |
| 29 | +} |
| 30 | + |
| 31 | +#[derive(Debug)] |
| 32 | +pub(crate) struct MoveError<'tcx> { |
| 33 | + place: Place<'tcx>, |
| 34 | + location: Location, |
| 35 | + kind: IllegalMoveOriginKind<'tcx>, |
| 36 | +} |
| 37 | + |
| 38 | +impl<'tcx> MoveError<'tcx> { |
| 39 | + pub(crate) fn new( |
| 40 | + place: Place<'tcx>, |
| 41 | + location: Location, |
| 42 | + kind: IllegalMoveOriginKind<'tcx>, |
| 43 | + ) -> Self { |
| 44 | + MoveError { place, location, kind } |
| 45 | + } |
| 46 | +} |
| 47 | + |
14 | 48 | // Often when desugaring a pattern match we may have many individual moves in
|
15 | 49 | // MIR that are all part of one operation from the user's point-of-view. For
|
16 | 50 | // example:
|
@@ -53,87 +87,77 @@ enum GroupedMoveError<'tcx> {
|
53 | 87 | }
|
54 | 88 |
|
55 | 89 | impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
56 |
| - pub(crate) fn report_move_errors(&mut self, move_errors: Vec<(Place<'tcx>, MoveError<'tcx>)>) { |
57 |
| - let grouped_errors = self.group_move_errors(move_errors); |
| 90 | + pub(crate) fn report_move_errors(&mut self) { |
| 91 | + let grouped_errors = self.group_move_errors(); |
58 | 92 | for error in grouped_errors {
|
59 | 93 | self.report(error);
|
60 | 94 | }
|
61 | 95 | }
|
62 | 96 |
|
63 |
| - fn group_move_errors( |
64 |
| - &self, |
65 |
| - errors: Vec<(Place<'tcx>, MoveError<'tcx>)>, |
66 |
| - ) -> Vec<GroupedMoveError<'tcx>> { |
| 97 | + fn group_move_errors(&mut self) -> Vec<GroupedMoveError<'tcx>> { |
67 | 98 | let mut grouped_errors = Vec::new();
|
68 |
| - for (original_path, error) in errors { |
69 |
| - self.append_to_grouped_errors(&mut grouped_errors, original_path, error); |
| 99 | + let errors = std::mem::take(&mut self.move_errors); |
| 100 | + for error in errors { |
| 101 | + self.append_to_grouped_errors(&mut grouped_errors, error); |
70 | 102 | }
|
71 | 103 | grouped_errors
|
72 | 104 | }
|
73 | 105 |
|
74 | 106 | fn append_to_grouped_errors(
|
75 | 107 | &self,
|
76 | 108 | grouped_errors: &mut Vec<GroupedMoveError<'tcx>>,
|
77 |
| - original_path: Place<'tcx>, |
78 | 109 | error: MoveError<'tcx>,
|
79 | 110 | ) {
|
80 |
| - match error { |
81 |
| - MoveError::UnionMove { .. } => { |
82 |
| - unimplemented!("don't know how to report union move errors yet.") |
83 |
| - } |
84 |
| - MoveError::IllegalMove { cannot_move_out_of: IllegalMoveOrigin { location, kind } } => { |
85 |
| - // Note: that the only time we assign a place isn't a temporary |
86 |
| - // to a user variable is when initializing it. |
87 |
| - // If that ever stops being the case, then the ever initialized |
88 |
| - // flow could be used. |
89 |
| - if let Some(StatementKind::Assign(box ( |
90 |
| - place, |
91 |
| - Rvalue::Use(Operand::Move(move_from)), |
92 |
| - ))) = self.body.basic_blocks[location.block] |
93 |
| - .statements |
94 |
| - .get(location.statement_index) |
95 |
| - .map(|stmt| &stmt.kind) |
| 111 | + let MoveError { place: original_path, location, kind } = error; |
| 112 | + |
| 113 | + // Note: that the only time we assign a place isn't a temporary |
| 114 | + // to a user variable is when initializing it. |
| 115 | + // If that ever stops being the case, then the ever initialized |
| 116 | + // flow could be used. |
| 117 | + if let Some(StatementKind::Assign(box (place, Rvalue::Use(Operand::Move(move_from))))) = |
| 118 | + self.body.basic_blocks[location.block] |
| 119 | + .statements |
| 120 | + .get(location.statement_index) |
| 121 | + .map(|stmt| &stmt.kind) |
| 122 | + { |
| 123 | + if let Some(local) = place.as_local() { |
| 124 | + let local_decl = &self.body.local_decls[local]; |
| 125 | + // opt_match_place is the |
| 126 | + // match_span is the span of the expression being matched on |
| 127 | + // match *x.y { ... } match_place is Some(*x.y) |
| 128 | + // ^^^^ match_span is the span of *x.y |
| 129 | + // |
| 130 | + // opt_match_place is None for let [mut] x = ... statements, |
| 131 | + // whether or not the right-hand side is a place expression |
| 132 | + if let LocalInfo::User(BindingForm::Var(VarBindingForm { |
| 133 | + opt_match_place: Some((opt_match_place, match_span)), |
| 134 | + binding_mode: _, |
| 135 | + opt_ty_info: _, |
| 136 | + pat_span: _, |
| 137 | + })) = *local_decl.local_info() |
96 | 138 | {
|
97 |
| - if let Some(local) = place.as_local() { |
98 |
| - let local_decl = &self.body.local_decls[local]; |
99 |
| - // opt_match_place is the |
100 |
| - // match_span is the span of the expression being matched on |
101 |
| - // match *x.y { ... } match_place is Some(*x.y) |
102 |
| - // ^^^^ match_span is the span of *x.y |
103 |
| - // |
104 |
| - // opt_match_place is None for let [mut] x = ... statements, |
105 |
| - // whether or not the right-hand side is a place expression |
106 |
| - if let LocalInfo::User(BindingForm::Var(VarBindingForm { |
107 |
| - opt_match_place: Some((opt_match_place, match_span)), |
108 |
| - binding_mode: _, |
109 |
| - opt_ty_info: _, |
110 |
| - pat_span: _, |
111 |
| - })) = *local_decl.local_info() |
112 |
| - { |
113 |
| - let stmt_source_info = self.body.source_info(location); |
114 |
| - self.append_binding_error( |
115 |
| - grouped_errors, |
116 |
| - kind, |
117 |
| - original_path, |
118 |
| - *move_from, |
119 |
| - local, |
120 |
| - opt_match_place, |
121 |
| - match_span, |
122 |
| - stmt_source_info.span, |
123 |
| - ); |
124 |
| - return; |
125 |
| - } |
126 |
| - } |
| 139 | + let stmt_source_info = self.body.source_info(location); |
| 140 | + self.append_binding_error( |
| 141 | + grouped_errors, |
| 142 | + kind, |
| 143 | + original_path, |
| 144 | + *move_from, |
| 145 | + local, |
| 146 | + opt_match_place, |
| 147 | + match_span, |
| 148 | + stmt_source_info.span, |
| 149 | + ); |
| 150 | + return; |
127 | 151 | }
|
128 |
| - |
129 |
| - let move_spans = self.move_spans(original_path.as_ref(), location); |
130 |
| - grouped_errors.push(GroupedMoveError::OtherIllegalMove { |
131 |
| - use_spans: move_spans, |
132 |
| - original_path, |
133 |
| - kind, |
134 |
| - }); |
135 | 152 | }
|
136 | 153 | }
|
| 154 | + |
| 155 | + let move_spans = self.move_spans(original_path.as_ref(), location); |
| 156 | + grouped_errors.push(GroupedMoveError::OtherIllegalMove { |
| 157 | + use_spans: move_spans, |
| 158 | + original_path, |
| 159 | + kind, |
| 160 | + }); |
137 | 161 | }
|
138 | 162 |
|
139 | 163 | fn append_binding_error(
|
|
0 commit comments