]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/util/borrowck_errors.rs
Give an error number for "borrowed data escapes outside of closure"
[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         if old_loan_span == new_loan_span {
207             err.span_label(
208                 old_loan_span,
209                 "closures are constructed here in different iterations of loop"
210             );
211         } else {
212             err.span_label(old_loan_span, "first closure is constructed here");
213             err.span_label(new_loan_span, "second closure is constructed here");
214         }
215         if let Some(old_load_end_span) = old_load_end_span {
216             err.span_label(old_load_end_span, "borrow from first closure ends here");
217         }
218         self.cancel_if_wrong_origin(err, o)
219     }
220
221     fn cannot_uniquely_borrow_by_one_closure(
222         self,
223         new_loan_span: Span,
224         container_name: &str,
225         desc_new: &str,
226         opt_via: &str,
227         old_loan_span: Span,
228         noun_old: &str,
229         old_opt_via: &str,
230         previous_end_span: Option<Span>,
231         o: Origin,
232     ) -> DiagnosticBuilder<'cx> {
233         let mut err = struct_span_err!(
234             self,
235             new_loan_span,
236             E0500,
237             "closure requires unique access to `{}` but {} is already borrowed{}{OGN}",
238             desc_new,
239             noun_old,
240             old_opt_via,
241             OGN = o
242         );
243         err.span_label(
244             new_loan_span,
245             format!("{} construction occurs here{}", container_name, opt_via),
246         );
247         err.span_label(old_loan_span, format!("borrow occurs here{}", old_opt_via));
248         if let Some(previous_end_span) = previous_end_span {
249             err.span_label(previous_end_span, "borrow ends here");
250         }
251         self.cancel_if_wrong_origin(err, o)
252     }
253
254     fn cannot_reborrow_already_uniquely_borrowed(
255         self,
256         new_loan_span: Span,
257         container_name: &str,
258         desc_new: &str,
259         opt_via: &str,
260         kind_new: &str,
261         old_loan_span: Span,
262         old_opt_via: &str,
263         previous_end_span: Option<Span>,
264         o: Origin,
265     ) -> DiagnosticBuilder<'cx> {
266         let mut err = struct_span_err!(
267             self,
268             new_loan_span,
269             E0501,
270             "cannot borrow `{}`{} as {} because previous closure \
271              requires unique access{OGN}",
272             desc_new,
273             opt_via,
274             kind_new,
275             OGN = o
276         );
277         err.span_label(new_loan_span, format!("borrow occurs here{}", opt_via));
278         err.span_label(
279             old_loan_span,
280             format!("{} construction occurs here{}", container_name, old_opt_via),
281         );
282         if let Some(previous_end_span) = previous_end_span {
283             err.span_label(previous_end_span, "borrow from closure ends here");
284         }
285         self.cancel_if_wrong_origin(err, o)
286     }
287
288     fn cannot_reborrow_already_borrowed(
289         self,
290         span: Span,
291         desc_new: &str,
292         msg_new: &str,
293         kind_new: &str,
294         old_span: Span,
295         noun_old: &str,
296         kind_old: &str,
297         msg_old: &str,
298         old_load_end_span: Option<Span>,
299         o: Origin,
300     ) -> DiagnosticBuilder<'cx> {
301         let mut err = struct_span_err!(
302             self,
303             span,
304             E0502,
305             "cannot borrow `{}`{} as {} because {} is also borrowed as {}{}{OGN}",
306             desc_new,
307             msg_new,
308             kind_new,
309             noun_old,
310             kind_old,
311             msg_old,
312             OGN = o
313         );
314         err.span_label(span, format!("{} borrow occurs here{}", kind_new, msg_new));
315         err.span_label(
316             old_span,
317             format!("{} borrow occurs here{}", kind_old, msg_old),
318         );
319         if let Some(old_load_end_span) = old_load_end_span {
320             err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old));
321         }
322         self.cancel_if_wrong_origin(err, o)
323     }
324
325     fn cannot_assign_to_borrowed(
326         self,
327         span: Span,
328         borrow_span: Span,
329         desc: &str,
330         o: Origin,
331     ) -> DiagnosticBuilder<'cx> {
332         let mut err = struct_span_err!(
333             self,
334             span,
335             E0506,
336             "cannot assign to `{}` because it is borrowed{OGN}",
337             desc,
338             OGN = o
339         );
340
341         err.span_label(borrow_span, format!("borrow of `{}` occurs here", desc));
342         err.span_label(
343             span,
344             format!("assignment to borrowed `{}` occurs here", desc),
345         );
346
347         self.cancel_if_wrong_origin(err, o)
348     }
349
350     fn cannot_move_into_closure(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
351         let err = struct_span_err!(
352             self,
353             span,
354             E0504,
355             "cannot move `{}` into closure because it is borrowed{OGN}",
356             desc,
357             OGN = o
358         );
359
360         self.cancel_if_wrong_origin(err, o)
361     }
362
363     fn cannot_reassign_immutable(
364         self,
365         span: Span,
366         desc: &str,
367         is_arg: bool,
368         o: Origin,
369     ) -> DiagnosticBuilder<'cx> {
370         let msg = if is_arg {
371             "to immutable argument"
372         } else {
373             "twice to immutable variable"
374         };
375         let err = struct_span_err!(
376             self,
377             span,
378             E0384,
379             "cannot assign {} `{}`{OGN}",
380             msg,
381             desc,
382             OGN = o
383         );
384
385         self.cancel_if_wrong_origin(err, o)
386     }
387
388     fn cannot_assign(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
389         let err = struct_span_err!(self, span, E0594, "cannot assign to {}{OGN}", desc, OGN = o);
390         self.cancel_if_wrong_origin(err, o)
391     }
392
393     fn cannot_assign_static(self, span: Span, desc: &str, o: Origin) -> DiagnosticBuilder<'cx> {
394         self.cannot_assign(span, &format!("immutable static item `{}`", desc), o)
395     }
396
397     fn cannot_move_out_of(
398         self,
399         move_from_span: Span,
400         move_from_desc: &str,
401         o: Origin,
402     ) -> DiagnosticBuilder<'cx> {
403         let mut err = struct_span_err!(
404             self,
405             move_from_span,
406             E0507,
407             "cannot move out of {}{OGN}",
408             move_from_desc,
409             OGN = o
410         );
411         err.span_label(
412             move_from_span,
413             format!("cannot move out of {}", move_from_desc),
414         );
415
416         self.cancel_if_wrong_origin(err, o)
417     }
418
419     /// Signal an error due to an attempt to move out of the interior
420     /// of an array or slice. `is_index` is None when error origin
421     /// didn't capture whether there was an indexing operation or not.
422     fn cannot_move_out_of_interior_noncopy(
423         self,
424         move_from_span: Span,
425         ty: ty::Ty,
426         is_index: Option<bool>,
427         o: Origin,
428     ) -> DiagnosticBuilder<'cx> {
429         let type_name = match (&ty.sty, is_index) {
430             (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array",
431             (&ty::Slice(_), _) => "slice",
432             _ => span_bug!(move_from_span, "this path should not cause illegal move"),
433         };
434         let mut err = struct_span_err!(
435             self,
436             move_from_span,
437             E0508,
438             "cannot move out of type `{}`, \
439              a non-copy {}{OGN}",
440             ty,
441             type_name,
442             OGN = o
443         );
444         err.span_label(move_from_span, "cannot move out of here");
445
446         self.cancel_if_wrong_origin(err, o)
447     }
448
449     fn cannot_move_out_of_interior_of_drop(
450         self,
451         move_from_span: Span,
452         container_ty: ty::Ty,
453         o: Origin,
454     ) -> DiagnosticBuilder<'cx> {
455         let mut err = struct_span_err!(
456             self,
457             move_from_span,
458             E0509,
459             "cannot move out of type `{}`, \
460              which implements the `Drop` trait{OGN}",
461             container_ty,
462             OGN = o
463         );
464         err.span_label(move_from_span, "cannot move out of here");
465
466         self.cancel_if_wrong_origin(err, o)
467     }
468
469     fn cannot_act_on_moved_value(
470         self,
471         use_span: Span,
472         verb: &str,
473         optional_adverb_for_moved: &str,
474         moved_path: Option<String>,
475         o: Origin,
476     ) -> DiagnosticBuilder<'cx> {
477         let moved_path = moved_path
478             .map(|mp| format!(": `{}`", mp))
479             .unwrap_or_default();
480
481         let err = struct_span_err!(
482             self,
483             use_span,
484             E0382,
485             "{} of {}moved value{}{OGN}",
486             verb,
487             optional_adverb_for_moved,
488             moved_path,
489             OGN = o
490         );
491
492         self.cancel_if_wrong_origin(err, o)
493     }
494
495     fn cannot_partially_reinit_an_uninit_struct(
496         self,
497         span: Span,
498         uninit_path: &str,
499         o: Origin,
500     ) -> DiagnosticBuilder<'cx> {
501         let err = struct_span_err!(
502             self,
503             span,
504             E0383,
505             "partial reinitialization of uninitialized structure `{}`{OGN}",
506             uninit_path,
507             OGN = o
508         );
509
510         self.cancel_if_wrong_origin(err, o)
511     }
512
513     fn closure_cannot_assign_to_borrowed(
514         self,
515         span: Span,
516         descr: &str,
517         o: Origin,
518     ) -> DiagnosticBuilder<'cx> {
519         let err = struct_span_err!(
520             self,
521             span,
522             E0595,
523             "closure cannot assign to {}{OGN}",
524             descr,
525             OGN = o
526         );
527
528         self.cancel_if_wrong_origin(err, o)
529     }
530
531     fn cannot_borrow_path_as_mutable_because(
532         self,
533         span: Span,
534         path: &str,
535         reason: &str,
536         o: Origin,
537     ) -> DiagnosticBuilder<'cx> {
538         let err = struct_span_err!(
539             self,
540             span,
541             E0596,
542             "cannot borrow {} as mutable{}{OGN}",
543             path,
544             reason,
545             OGN = o,
546         );
547
548         self.cancel_if_wrong_origin(err, o)
549     }
550
551     fn cannot_borrow_path_as_mutable(
552         self,
553         span: Span,
554         path: &str,
555         o: Origin,
556     ) -> DiagnosticBuilder<'cx> {
557         self.cannot_borrow_path_as_mutable_because(span, path, "", o)
558     }
559
560     fn cannot_mutate_in_match_guard(
561         self,
562         mutate_span: Span,
563         match_span: Span,
564         match_place: &str,
565         action: &str,
566         o: Origin,
567     ) -> DiagnosticBuilder<'cx> {
568         let mut err = struct_span_err!(
569             self,
570             mutate_span,
571             E0510,
572             "cannot {} `{}` in match guard{OGN}",
573             action,
574             match_place,
575             OGN = o
576         );
577         err.span_label(mutate_span, format!("cannot {}", action));
578         err.span_label(match_span, format!("value is immutable in match guard"));
579
580         self.cancel_if_wrong_origin(err, o)
581     }
582
583     fn cannot_borrow_across_generator_yield(
584         self,
585         span: Span,
586         yield_span: Span,
587         o: Origin,
588     ) -> DiagnosticBuilder<'cx> {
589         let mut err = struct_span_err!(
590             self,
591             span,
592             E0626,
593             "borrow may still be in use when generator yields{OGN}",
594             OGN = o
595         );
596         err.span_label(yield_span, "possible yield occurs here");
597
598         self.cancel_if_wrong_origin(err, o)
599     }
600
601     fn cannot_borrow_across_destructor(
602         self,
603         borrow_span: Span,
604         o: Origin,
605     ) -> DiagnosticBuilder<'cx> {
606         let err = struct_span_err!(
607             self,
608             borrow_span,
609             E0713,
610             "borrow may still be in use when destructor runs{OGN}",
611             OGN = o
612         );
613
614         self.cancel_if_wrong_origin(err, o)
615     }
616
617     fn path_does_not_live_long_enough(
618         self,
619         span: Span,
620         path: &str,
621         o: Origin,
622     ) -> DiagnosticBuilder<'cx> {
623         let err = struct_span_err!(
624             self,
625             span,
626             E0597,
627             "{} does not live long enough{OGN}",
628             path,
629             OGN = o
630         );
631
632         self.cancel_if_wrong_origin(err, o)
633     }
634
635     fn lifetime_too_short_for_reborrow(
636         self,
637         span: Span,
638         path: &str,
639         o: Origin,
640     ) -> DiagnosticBuilder<'cx> {
641         let err = struct_span_err!(
642             self,
643             span,
644             E0598,
645             "lifetime of {} is too short to guarantee \
646              its contents can be safely reborrowed{OGN}",
647             path,
648             OGN = o
649         );
650
651         self.cancel_if_wrong_origin(err, o)
652     }
653
654     fn cannot_act_on_capture_in_sharable_fn(
655         self,
656         span: Span,
657         bad_thing: &str,
658         help: (Span, &str),
659         o: Origin,
660     ) -> DiagnosticBuilder<'cx> {
661         let (help_span, help_msg) = help;
662         let mut err = struct_span_err!(
663             self,
664             span,
665             E0387,
666             "{} in a captured outer variable in an `Fn` closure{OGN}",
667             bad_thing,
668             OGN = o
669         );
670         err.span_help(help_span, help_msg);
671
672         self.cancel_if_wrong_origin(err, o)
673     }
674
675     fn cannot_assign_into_immutable_reference(
676         self,
677         span: Span,
678         bad_thing: &str,
679         o: Origin,
680     ) -> DiagnosticBuilder<'cx> {
681         let mut err = struct_span_err!(
682             self,
683             span,
684             E0389,
685             "{} in a `&` reference{OGN}",
686             bad_thing,
687             OGN = o
688         );
689         err.span_label(span, "assignment into an immutable reference");
690
691         self.cancel_if_wrong_origin(err, o)
692     }
693
694     fn cannot_capture_in_long_lived_closure(
695         self,
696         closure_span: Span,
697         borrowed_path: &str,
698         capture_span: Span,
699         o: Origin,
700     ) -> DiagnosticBuilder<'cx> {
701         let mut err = struct_span_err!(
702             self,
703             closure_span,
704             E0373,
705             "closure may outlive the current function, \
706              but it borrows {}, \
707              which is owned by the current function{OGN}",
708             borrowed_path,
709             OGN = o
710         );
711         err.span_label(capture_span, format!("{} is borrowed here", borrowed_path))
712             .span_label(
713                 closure_span,
714                 format!("may outlive borrowed value {}", borrowed_path),
715             );
716
717         self.cancel_if_wrong_origin(err, o)
718     }
719
720     fn borrowed_data_escapes_closure(
721         self,
722         escape_span: Span,
723         escapes_from: &str,
724         o: Origin,
725     ) -> DiagnosticBuilder<'cx> {
726         let err = struct_span_err!(
727             self,
728             escape_span,
729             E0521,
730             "borrowed data escapes outside of {}{OGN}",
731             escapes_from,
732             OGN = o
733         );
734
735         self.cancel_if_wrong_origin(err, o)
736     }
737
738     fn thread_local_value_does_not_live_long_enough(
739         self,
740         span: Span,
741         o: Origin,
742     ) -> DiagnosticBuilder<'cx> {
743         let err = struct_span_err!(
744             self,
745             span,
746             E0712,
747             "thread-local variable borrowed past end of function{OGN}",
748             OGN = o
749         );
750
751         self.cancel_if_wrong_origin(err, o)
752     }
753
754     fn temporary_value_borrowed_for_too_long(
755         self,
756         span: Span,
757         o: Origin,
758     ) -> DiagnosticBuilder<'cx> {
759         let err = struct_span_err!(
760             self,
761             span,
762             E0716,
763             "temporary value dropped while borrowed{OGN}",
764             OGN = o
765         );
766
767         self.cancel_if_wrong_origin(err, o)
768     }
769 }
770
771 impl<'cx, 'gcx, 'tcx> BorrowckErrors<'cx> for TyCtxt<'cx, 'gcx, 'tcx> {
772     fn struct_span_err_with_code<S: Into<MultiSpan>>(
773         self,
774         sp: S,
775         msg: &str,
776         code: DiagnosticId,
777     ) -> DiagnosticBuilder<'cx> {
778         self.sess.struct_span_err_with_code(sp, msg, code)
779     }
780
781     fn struct_span_err<S: Into<MultiSpan>>(self, sp: S, msg: &str) -> DiagnosticBuilder<'cx> {
782         self.sess.struct_span_err(sp, msg)
783     }
784
785     fn cancel_if_wrong_origin(
786         self,
787         mut diag: DiagnosticBuilder<'cx>,
788         o: Origin,
789     ) -> DiagnosticBuilder<'cx> {
790         if !o.should_emit_errors(self.borrowck_mode()) {
791             self.sess.diagnostic().cancel(&mut diag);
792         }
793         diag
794     }
795 }