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