]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/util/borrowck_errors.rs
Rollup merge of #51765 - jonas-schievink:patch-1, r=KodrAus
[rust.git] / src / librustc_mir / util / borrowck_errors.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use rustc::session::config::BorrowckMode;
12 use rustc::ty::{self, TyCtxt};
13 use rustc_errors::{DiagnosticBuilder, DiagnosticId};
14 use syntax_pos::{MultiSpan, Span};
15
16 use std::fmt;
17
18 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
19 pub enum Origin {
20     Ast,
21     Mir,
22 }
23
24 impl fmt::Display for Origin {
25     fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
26         // If the user passed `-Z borrowck=compare`, then include
27         // origin info as part of the error report,
28         // otherwise
29         let display_origin = ty::tls::with_opt(|opt_tcx| {
30             if let Some(tcx) = opt_tcx {
31                 tcx.sess.opts.borrowck_mode == BorrowckMode::Compare
32             } else {
33                 false
34             }
35         });
36         if display_origin {
37             match *self {
38                 Origin::Mir => write!(w, " (Mir)"),
39                 Origin::Ast => write!(w, " (Ast)"),
40             }
41         } else {
42             // Print no origin info
43             Ok(())
44         }
45     }
46 }
47
48 impl Origin {
49     /// Whether we should emit errors for the origin in the given mode
50     pub fn should_emit_errors(self, mode: BorrowckMode) -> bool {
51         match self {
52             Origin::Ast => mode.use_ast(),
53             Origin::Mir => mode.use_mir(),
54         }
55     }
56 }
57
58 pub trait BorrowckErrors<'cx>: Sized + Copy {
59     fn struct_span_err_with_code<S: Into<MultiSpan>>(
60         self,
61         sp: S,
62         msg: &str,
63         code: DiagnosticId,
64     ) -> DiagnosticBuilder<'cx>;
65
66     fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'cx>;
67
68     /// Cancels the given error if we shouldn't emit errors for a given
69     /// origin in the current mode.
70     ///
71     /// Always make sure that the error gets passed through this function
72     /// before you return it.
73     fn cancel_if_wrong_origin(
74         self,
75         diag: DiagnosticBuilder<'cx>,
76         o: Origin,
77     ) -> DiagnosticBuilder<'cx>;
78
79     fn cannot_move_when_borrowed(
80         self,
81         span: Span,
82         desc: &str,
83         o: Origin,
84     ) -> DiagnosticBuilder<'cx> {
85         let err = struct_span_err!(
86             self,
87             span,
88             E0505,
89             "cannot move out of `{}` because it is borrowed{OGN}",
90             desc,
91             OGN = o
92         );
93         self.cancel_if_wrong_origin(err, o)
94     }
95
96     fn cannot_use_when_mutably_borrowed(
97         self,
98         span: Span,
99         desc: &str,
100         borrow_span: Span,
101         borrow_desc: &str,
102         o: Origin,
103     ) -> DiagnosticBuilder<'cx> {
104         let mut err = struct_span_err!(
105             self,
106             span,
107             E0503,
108             "cannot use `{}` because it was mutably borrowed{OGN}",
109             desc,
110             OGN = o
111         );
112
113         err.span_label(
114             borrow_span,
115             format!("borrow of `{}` occurs here", borrow_desc),
116         );
117         err.span_label(span, format!("use of borrowed `{}`", borrow_desc));
118
119         self.cancel_if_wrong_origin(err, o)
120     }
121
122     fn cannot_act_on_uninitialized_variable(
123         self,
124         span: Span,
125         verb: &str,
126         desc: &str,
127         o: Origin,
128     ) -> DiagnosticBuilder<'cx> {
129         let err = struct_span_err!(
130             self,
131             span,
132             E0381,
133             "{} of possibly uninitialized variable: `{}`{OGN}",
134             verb,
135             desc,
136             OGN = o
137         );
138         self.cancel_if_wrong_origin(err, o)
139     }
140
141     fn cannot_mutably_borrow_multiply(
142         self,
143         new_loan_span: Span,
144         desc: &str,
145         opt_via: &str,
146         old_loan_span: Span,
147         old_opt_via: &str,
148         old_load_end_span: Option<Span>,
149         o: Origin,
150     ) -> DiagnosticBuilder<'cx> {
151         let mut err = struct_span_err!(
152             self,
153             new_loan_span,
154             E0499,
155             "cannot borrow `{}`{} as mutable more than once at a time{OGN}",
156             desc,
157             opt_via,
158             OGN = o
159         );
160         if old_loan_span == new_loan_span {
161             // Both borrows are happening in the same place
162             // Meaning the borrow is occurring in a loop
163             err.span_label(
164                 new_loan_span,
165                 format!(
166                     "mutable borrow starts here in previous \
167                      iteration of loop{}",
168                     opt_via
169                 ),
170             );
171             if let Some(old_load_end_span) = old_load_end_span {
172                 err.span_label(old_load_end_span, "mutable borrow ends here");
173             }
174         } else {
175             err.span_label(
176                 old_loan_span,
177                 format!("first mutable borrow occurs here{}", old_opt_via),
178             );
179             err.span_label(
180                 new_loan_span,
181                 format!("second mutable borrow occurs here{}", opt_via),
182             );
183             if let Some(old_load_end_span) = old_load_end_span {
184                 err.span_label(old_load_end_span, "first borrow ends here");
185             }
186         }
187         self.cancel_if_wrong_origin(err, o)
188     }
189
190     fn cannot_uniquely_borrow_by_two_closures(
191         self,
192         new_loan_span: Span,
193         desc: &str,
194         old_loan_span: Span,
195         old_load_end_span: Option<Span>,
196         o: Origin,
197     ) -> DiagnosticBuilder<'cx> {
198         let mut err = struct_span_err!(
199             self,
200             new_loan_span,
201             E0524,
202             "two closures require unique access to `{}` at the same time{OGN}",
203             desc,
204             OGN = o
205         );
206         err.span_label(old_loan_span, "first closure is constructed here");
207         err.span_label(new_loan_span, "second closure is constructed here");
208         if let Some(old_load_end_span) = old_load_end_span {
209             err.span_label(old_load_end_span, "borrow from first closure ends here");
210         }
211         self.cancel_if_wrong_origin(err, o)
212     }
213
214     fn cannot_uniquely_borrow_by_one_closure(
215         self,
216         new_loan_span: Span,
217         desc_new: &str,
218         opt_via: &str,
219         old_loan_span: Span,
220         noun_old: &str,
221         old_opt_via: &str,
222         previous_end_span: Option<Span>,
223         o: Origin,
224     ) -> DiagnosticBuilder<'cx> {
225         let mut err = struct_span_err!(
226             self,
227             new_loan_span,
228             E0500,
229             "closure requires unique access to `{}` but {} is already borrowed{}{OGN}",
230             desc_new,
231             noun_old,
232             old_opt_via,
233             OGN = o
234         );
235         err.span_label(
236             new_loan_span,
237             format!("closure construction occurs here{}", opt_via),
238         );
239         err.span_label(old_loan_span, format!("borrow occurs here{}", old_opt_via));
240         if let Some(previous_end_span) = previous_end_span {
241             err.span_label(previous_end_span, "borrow ends here");
242         }
243         self.cancel_if_wrong_origin(err, o)
244     }
245
246     fn cannot_reborrow_already_uniquely_borrowed(
247         self,
248         new_loan_span: Span,
249         desc_new: &str,
250         opt_via: &str,
251         kind_new: &str,
252         old_loan_span: Span,
253         old_opt_via: &str,
254         previous_end_span: Option<Span>,
255         o: Origin,
256     ) -> DiagnosticBuilder<'cx> {
257         let mut err = struct_span_err!(
258             self,
259             new_loan_span,
260             E0501,
261             "cannot borrow `{}`{} as {} because previous closure \
262              requires unique access{OGN}",
263             desc_new,
264             opt_via,
265             kind_new,
266             OGN = o
267         );
268         err.span_label(new_loan_span, format!("borrow occurs here{}", opt_via));
269         err.span_label(
270             old_loan_span,
271             format!("closure construction occurs here{}", old_opt_via),
272         );
273         if let Some(previous_end_span) = previous_end_span {
274             err.span_label(previous_end_span, "borrow from closure ends here");
275         }
276         self.cancel_if_wrong_origin(err, o)
277     }
278
279     fn cannot_reborrow_already_borrowed(
280         self,
281         span: Span,
282         desc_new: &str,
283         msg_new: &str,
284         kind_new: &str,
285         old_span: Span,
286         noun_old: &str,
287         kind_old: &str,
288         msg_old: &str,
289         old_load_end_span: Option<Span>,
290         o: Origin,
291     ) -> DiagnosticBuilder<'cx> {
292         let mut err = struct_span_err!(
293             self,
294             span,
295             E0502,
296             "cannot borrow `{}`{} as {} because {} is also borrowed as {}{}{OGN}",
297             desc_new,
298             msg_new,
299             kind_new,
300             noun_old,
301             kind_old,
302             msg_old,
303             OGN = o
304         );
305         err.span_label(span, format!("{} borrow occurs here{}", kind_new, msg_new));
306         err.span_label(
307             old_span,
308             format!("{} borrow occurs here{}", kind_old, msg_old),
309         );
310         if let Some(old_load_end_span) = old_load_end_span {
311             err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old));
312         }
313         self.cancel_if_wrong_origin(err, o)
314     }
315
316     fn cannot_assign_to_borrowed(
317         self,
318         span: Span,
319         borrow_span: Span,
320         desc: &str,
321         o: Origin,
322     ) -> DiagnosticBuilder<'cx> {
323         let mut err = struct_span_err!(
324             self,
325             span,
326             E0506,
327             "cannot assign to `{}` because it is borrowed{OGN}",
328             desc,
329             OGN = o
330         );
331
332         err.span_label(borrow_span, format!("borrow of `{}` occurs here", desc));
333         err.span_label(
334             span,
335             format!("assignment to borrowed `{}` occurs here", desc),
336         );
337
338         self.cancel_if_wrong_origin(err, o)
339     }
340
341     fn cannot_move_into_closure(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
342         let err = struct_span_err!(
343             self,
344             span,
345             E0504,
346             "cannot move `{}` into closure because it is borrowed{OGN}",
347             desc,
348             OGN = o
349         );
350
351         self.cancel_if_wrong_origin(err, o)
352     }
353
354     fn cannot_reassign_immutable(
355         self,
356         span: Span,
357         desc: &str,
358         is_arg: bool,
359         o: Origin,
360     ) -> DiagnosticBuilder<'cx> {
361         let msg = if is_arg {
362             "to immutable argument"
363         } else {
364             "twice to immutable variable"
365         };
366         let err = struct_span_err!(
367             self,
368             span,
369             E0384,
370             "cannot assign {} `{}`{OGN}",
371             msg,
372             desc,
373             OGN = o
374         );
375
376         self.cancel_if_wrong_origin(err, o)
377     }
378
379     fn cannot_assign(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
380         let err = struct_span_err!(self, span, E0594, "cannot assign to {}{OGN}", desc, OGN = o);
381         self.cancel_if_wrong_origin(err, o)
382     }
383
384     fn cannot_assign_static(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
385         self.cannot_assign(span, &format!("immutable static item `{}`", desc), o)
386     }
387
388     fn cannot_move_out_of(
389         self,
390         move_from_span: Span,
391         move_from_desc: &str,
392         o: Origin,
393     ) -> DiagnosticBuilder<'cx> {
394         let mut err = struct_span_err!(
395             self,
396             move_from_span,
397             E0507,
398             "cannot move out of {}{OGN}",
399             move_from_desc,
400             OGN = o
401         );
402         err.span_label(
403             move_from_span,
404             format!("cannot move out of {}", move_from_desc),
405         );
406
407         self.cancel_if_wrong_origin(err, o)
408     }
409
410     /// Signal an error due to an attempt to move out of the interior
411     /// of an array or slice. `is_index` is None when error origin
412     /// didn't capture whether there was an indexing operation or not.
413     fn cannot_move_out_of_interior_noncopy(
414         self,
415         move_from_span: Span,
416         ty: ty::Ty,
417         is_index: Option<bool>,
418         o: Origin,
419     ) -> DiagnosticBuilder<'cx> {
420         let type_name = match (&ty.sty, is_index) {
421             (&ty::TyArray(_, _), Some(true)) | (&ty::TyArray(_, _), None) => "array",
422             (&ty::TySlice(_), _) => "slice",
423             _ => span_bug!(move_from_span, "this path should not cause illegal move"),
424         };
425         let mut err = struct_span_err!(
426             self,
427             move_from_span,
428             E0508,
429             "cannot move out of type `{}`, \
430              a non-copy {}{OGN}",
431             ty,
432             type_name,
433             OGN = o
434         );
435         err.span_label(move_from_span, "cannot move out of here");
436
437         self.cancel_if_wrong_origin(err, o)
438     }
439
440     fn cannot_move_out_of_interior_of_drop(
441         self,
442         move_from_span: Span,
443         container_ty: ty::Ty,
444         o: Origin,
445     ) -> DiagnosticBuilder<'cx> {
446         let mut err = struct_span_err!(
447             self,
448             move_from_span,
449             E0509,
450             "cannot move out of type `{}`, \
451              which implements the `Drop` trait{OGN}",
452             container_ty,
453             OGN = o
454         );
455         err.span_label(move_from_span, "cannot move out of here");
456
457         self.cancel_if_wrong_origin(err, o)
458     }
459
460     fn cannot_act_on_moved_value(
461         self,
462         use_span: Span,
463         verb: &str,
464         optional_adverb_for_moved: &str,
465         moved_path: Option<String>,
466         o: Origin,
467     ) -> DiagnosticBuilder<'cx> {
468         let moved_path = moved_path
469             .map(|mp| format!(": `{}`", mp))
470             .unwrap_or("".to_owned());
471
472         let err = struct_span_err!(
473             self,
474             use_span,
475             E0382,
476             "{} of {}moved value{}{OGN}",
477             verb,
478             optional_adverb_for_moved,
479             moved_path,
480             OGN = o
481         );
482
483         self.cancel_if_wrong_origin(err, o)
484     }
485
486     fn cannot_partially_reinit_an_uninit_struct(
487         self,
488         span: Span,
489         uninit_path: &str,
490         o: Origin,
491     ) -> DiagnosticBuilder<'cx> {
492         let err = struct_span_err!(
493             self,
494             span,
495             E0383,
496             "partial reinitialization of uninitialized structure `{}`{OGN}",
497             uninit_path,
498             OGN = o
499         );
500
501         self.cancel_if_wrong_origin(err, o)
502     }
503
504     fn closure_cannot_assign_to_borrowed(
505         self,
506         span: Span,
507         descr: &str,
508         o: Origin,
509     ) -> DiagnosticBuilder<'cx> {
510         let err = struct_span_err!(
511             self,
512             span,
513             E0595,
514             "closure cannot assign to {}{OGN}",
515             descr,
516             OGN = o
517         );
518
519         self.cancel_if_wrong_origin(err, o)
520     }
521
522     fn cannot_borrow_path_as_mutable(
523         self,
524         span: Span,
525         path: &str,
526         o: Origin,
527     ) -> DiagnosticBuilder<'cx> {
528         let err = struct_span_err!(
529             self,
530             span,
531             E0596,
532             "cannot borrow {} as mutable{OGN}",
533             path,
534             OGN = o
535         );
536
537         self.cancel_if_wrong_origin(err, o)
538     }
539
540     fn cannot_borrow_across_generator_yield(
541         self,
542         span: Span,
543         yield_span: Span,
544         o: Origin,
545     ) -> DiagnosticBuilder<'cx> {
546         let mut err = struct_span_err!(
547             self,
548             span,
549             E0626,
550             "borrow may still be in use when generator yields{OGN}",
551             OGN = o
552         );
553         err.span_label(yield_span, "possible yield occurs here");
554
555         self.cancel_if_wrong_origin(err, o)
556     }
557
558     fn path_does_not_live_long_enough(
559         self,
560         span: Span,
561         path: &str,
562         o: Origin,
563     ) -> DiagnosticBuilder<'cx> {
564         let err = struct_span_err!(
565             self,
566             span,
567             E0597,
568             "{} does not live long enough{OGN}",
569             path,
570             OGN = o
571         );
572
573         self.cancel_if_wrong_origin(err, o)
574     }
575
576     fn lifetime_too_short_for_reborrow(
577         self,
578         span: Span,
579         path: &str,
580         o: Origin,
581     ) -> DiagnosticBuilder<'cx> {
582         let err = struct_span_err!(
583             self,
584             span,
585             E0598,
586             "lifetime of {} is too short to guarantee \
587              its contents can be safely reborrowed{OGN}",
588             path,
589             OGN = o
590         );
591
592         self.cancel_if_wrong_origin(err, o)
593     }
594
595     fn cannot_act_on_capture_in_sharable_fn(
596         self,
597         span: Span,
598         bad_thing: &str,
599         help: (Span, &str),
600         o: Origin,
601     ) -> DiagnosticBuilder<'cx> {
602         let (help_span, help_msg) = help;
603         let mut err = struct_span_err!(
604             self,
605             span,
606             E0387,
607             "{} in a captured outer variable in an `Fn` closure{OGN}",
608             bad_thing,
609             OGN = o
610         );
611         err.span_help(help_span, help_msg);
612
613         self.cancel_if_wrong_origin(err, o)
614     }
615
616     fn cannot_assign_into_immutable_reference(
617         self,
618         span: Span,
619         bad_thing: &str,
620         o: Origin,
621     ) -> DiagnosticBuilder<'cx> {
622         let mut err = struct_span_err!(
623             self,
624             span,
625             E0389,
626             "{} in a `&` reference{OGN}",
627             bad_thing,
628             OGN = o
629         );
630         err.span_label(span, "assignment into an immutable reference");
631
632         self.cancel_if_wrong_origin(err, o)
633     }
634
635     fn cannot_capture_in_long_lived_closure(
636         self,
637         closure_span: Span,
638         borrowed_path: &str,
639         capture_span: Span,
640         o: Origin,
641     ) -> DiagnosticBuilder<'cx> {
642         let mut err = struct_span_err!(
643             self,
644             closure_span,
645             E0373,
646             "closure may outlive the current function, \
647              but it borrows {}, \
648              which is owned by the current function{OGN}",
649             borrowed_path,
650             OGN = o
651         );
652         err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
653             .span_label(
654                 closure_span,
655                 format!("may outlive borrowed value {}", borrowed_path),
656             );
657
658         self.cancel_if_wrong_origin(err, o)
659     }
660 }
661
662 impl<'cx, 'gcx, 'tcx> BorrowckErrors<'cx> for TyCtxt<'cx, 'gcx, 'tcx> {
663     fn struct_span_err_with_code<S: Into<MultiSpan>>(
664         self,
665         sp: S,
666         msg: &str,
667         code: DiagnosticId,
668     ) -> DiagnosticBuilder<'cx> {
669         self.sess.struct_span_err_with_code(sp, msg, code)
670     }
671
672     fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'cx> {
673         self.sess.struct_span_err(sp, msg)
674     }
675
676     fn cancel_if_wrong_origin(
677         self,
678         mut diag: DiagnosticBuilder<'cx>,
679         o: Origin,
680     ) -> DiagnosticBuilder<'cx> {
681         if !o.should_emit_errors(self.borrowck_mode()) {
682             self.sess.diagnostic().cancel(&mut diag);
683         }
684         diag
685     }
686 }