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