about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-07-22 08:36:11 +0000
committerbors <bors@rust-lang.org>2017-07-22 08:36:11 +0000
commit066a0ae99b857eb58f536f33a6ef126f0bd9aba0 (patch)
treef1eb0559fbf34de5f1ae1aeb50f249cf3cac119a
parentf0b07cac2f4ff513dcc5f93e97f9528bfe91e622 (diff)
parent18d970164524ae3f51f97b30080d061f2007c046 (diff)
Auto merge of #43343 - petrochenkov:methlife3, r=estebank
Add an extra note to `late_bound_lifetime_arguments` error/lint

Fixes https://github.com/rust-lang/rust/issues/42868#issuecomment-316368538
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs21
-rw-r--r--src/librustc_typeck/collect.rs28
-rw-r--r--src/test/ui/method-call-lifetime-args-lint.rs31
-rw-r--r--src/test/ui/method-call-lifetime-args-lint.stderr31
-rw-r--r--src/test/ui/method-call-lifetime-args.rs25
-rw-r--r--src/test/ui/method-call-lifetime-args.stderr26
7 files changed, 140 insertions, 24 deletions
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 1fee0dd9863..2a11b19f855 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -719,7 +719,7 @@ pub struct Generics {
     pub type_param_to_index: BTreeMap<DefIndex, u32>,
 
     pub has_self: bool,
-    pub has_late_bound_regions: bool,
+    pub has_late_bound_regions: Option<Span>,
 }
 
 impl Generics {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index af11cacb247..b086c427ba5 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -121,7 +121,7 @@ use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::ptr::P;
 use syntax::symbol::{Symbol, InternedString, keywords};
 use syntax::util::lev_distance::find_best_match_for_name;
-use syntax_pos::{self, BytePos, Span};
+use syntax_pos::{self, BytePos, Span, MultiSpan};
 
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
@@ -4689,20 +4689,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Prohibit explicit lifetime arguments if late bound lifetime parameters are present.
         let has_late_bound_lifetime_defs =
-            segment.map_or(false, |(_, generics)| generics.has_late_bound_regions);
-        if has_late_bound_lifetime_defs && !lifetimes.is_empty() {
+            segment.map_or(None, |(_, generics)| generics.has_late_bound_regions);
+        if let (Some(span_late), false) = (has_late_bound_lifetime_defs, lifetimes.is_empty()) {
             // Report this as a lint only if no error was reported previously.
+            let primary_msg = "cannot specify lifetime arguments explicitly \
+                               if late bound lifetime parameters are present";
+            let note_msg = "the late bound lifetime parameter is introduced here";
             if !is_method_call && (lifetimes.len() > lifetime_defs.len() ||
                                    lifetimes.len() < required_len && !infer_lifetimes) {
-                self.tcx.sess.span_err(lifetimes[0].span,
-                                       "cannot specify lifetime arguments explicitly \
-                                        if late bound lifetime parameters are present");
+                let mut err = self.tcx.sess.struct_span_err(lifetimes[0].span, primary_msg);
+                err.span_note(span_late, note_msg);
+                err.emit();
                 *segment = None;
             } else {
+                let mut multispan = MultiSpan::from_span(lifetimes[0].span);
+                multispan.push_span_label(span_late, note_msg.to_string());
                 self.tcx.sess.add_lint(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS,
-                                       lifetimes[0].id, lifetimes[0].span,
-                                       format!("cannot specify lifetime arguments explicitly \
-                                                if late bound lifetime parameters are present"));
+                                       lifetimes[0].id, multispan, primary_msg.to_string());
             }
             return;
         }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 72bd084330d..143079b0a08 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -774,11 +774,11 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
 fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     node: hir_map::Node<'tcx>)
-                                    -> bool {
+                                    -> Option<Span> {
     struct LateBoundRegionsDetector<'a, 'tcx: 'a> {
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
         binder_depth: u32,
-        has_late_bound_regions: bool,
+        has_late_bound_regions: Option<Span>,
     }
 
     impl<'a, 'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'a, 'tcx> {
@@ -787,7 +787,7 @@ fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
 
         fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
-            if self.has_late_bound_regions { return }
+            if self.has_late_bound_regions.is_some() { return }
             match ty.node {
                 hir::TyBareFn(..) => {
                     self.binder_depth += 1;
@@ -801,21 +801,21 @@ fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         fn visit_poly_trait_ref(&mut self,
                                 tr: &'tcx hir::PolyTraitRef,
                                 m: hir::TraitBoundModifier) {
-            if self.has_late_bound_regions { return }
+            if self.has_late_bound_regions.is_some() { return }
             self.binder_depth += 1;
             intravisit::walk_poly_trait_ref(self, tr, m);
             self.binder_depth -= 1;
         }
 
         fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
-            if self.has_late_bound_regions { return }
+            if self.has_late_bound_regions.is_some() { return }
 
             match self.tcx.named_region_map.defs.get(&lt.id).cloned() {
                 Some(rl::Region::Static) | Some(rl::Region::EarlyBound(..)) => {}
                 Some(rl::Region::LateBound(debruijn, _)) |
                 Some(rl::Region::LateBoundAnon(debruijn, _))
                     if debruijn.depth < self.binder_depth => {}
-                _ => self.has_late_bound_regions = true,
+                _ => self.has_late_bound_regions = Some(lt.span),
             }
         }
     }
@@ -823,13 +823,13 @@ fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         generics: &'tcx hir::Generics,
                                         decl: &'tcx hir::FnDecl)
-                                        -> bool {
+                                        -> Option<Span> {
         let mut visitor = LateBoundRegionsDetector {
-            tcx, binder_depth: 1, has_late_bound_regions: false
+            tcx, binder_depth: 1, has_late_bound_regions: None
         };
         for lifetime in &generics.lifetimes {
             if tcx.named_region_map.late_bound.contains(&lifetime.lifetime.id) {
-                return true;
+                return Some(lifetime.lifetime.span);
             }
         }
         visitor.visit_fn_decl(decl);
@@ -840,24 +840,24 @@ fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         hir_map::NodeTraitItem(item) => match item.node {
             hir::TraitItemKind::Method(ref sig, _) =>
                 has_late_bound_regions(tcx, &sig.generics, &sig.decl),
-            _ => false,
+            _ => None,
         },
         hir_map::NodeImplItem(item) => match item.node {
             hir::ImplItemKind::Method(ref sig, _) =>
                 has_late_bound_regions(tcx, &sig.generics, &sig.decl),
-            _ => false,
+            _ => None,
         },
         hir_map::NodeForeignItem(item) => match item.node {
             hir::ForeignItemFn(ref fn_decl, _, ref generics) =>
                 has_late_bound_regions(tcx, generics, fn_decl),
-            _ => false,
+            _ => None,
         },
         hir_map::NodeItem(item) => match item.node {
             hir::ItemFn(ref fn_decl, .., ref generics, _) =>
                 has_late_bound_regions(tcx, generics, fn_decl),
-            _ => false,
+            _ => None,
         },
-        _ => false
+        _ => None
     }
 }
 
diff --git a/src/test/ui/method-call-lifetime-args-lint.rs b/src/test/ui/method-call-lifetime-args-lint.rs
new file mode 100644
index 00000000000..f9a4f712e57
--- /dev/null
+++ b/src/test/ui/method-call-lifetime-args-lint.rs
@@ -0,0 +1,31 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(late_bound_lifetime_arguments)]
+#![allow(unused)]
+
+struct S;
+
+impl S {
+    fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
+    fn late_implicit(self, _: &u8, _: &u8) {}
+}
+
+fn method_call() {
+    S.late::<'static>(&0, &0);
+    //~^ ERROR cannot specify lifetime arguments explicitly
+    //~| WARN this was previously accepted
+
+    S.late_implicit::<'static>(&0, &0);
+    //~^ ERROR cannot specify lifetime arguments explicitly
+    //~| WARN this was previously accepted
+}
+
+fn main() {}
diff --git a/src/test/ui/method-call-lifetime-args-lint.stderr b/src/test/ui/method-call-lifetime-args-lint.stderr
new file mode 100644
index 00000000000..e319b54aa2c
--- /dev/null
+++ b/src/test/ui/method-call-lifetime-args-lint.stderr
@@ -0,0 +1,31 @@
+error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/method-call-lifetime-args-lint.rs:22:14
+   |
+17 |     fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
+   |             -- the late bound lifetime parameter is introduced here
+...
+22 |     S.late::<'static>(&0, &0);
+   |              ^^^^^^^
+   |
+note: lint level defined here
+  --> $DIR/method-call-lifetime-args-lint.rs:11:9
+   |
+11 | #![deny(late_bound_lifetime_arguments)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
+
+error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/method-call-lifetime-args-lint.rs:26:23
+   |
+18 |     fn late_implicit(self, _: &u8, _: &u8) {}
+   |                               - the late bound lifetime parameter is introduced here
+...
+26 |     S.late_implicit::<'static>(&0, &0);
+   |                       ^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/method-call-lifetime-args.rs b/src/test/ui/method-call-lifetime-args.rs
new file mode 100644
index 00000000000..7ce3ebb8bee
--- /dev/null
+++ b/src/test/ui/method-call-lifetime-args.rs
@@ -0,0 +1,25 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct S;
+
+impl S {
+    fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
+    fn late_implicit(self, _: &u8, _: &u8) {}
+}
+
+fn ufcs() {
+    S::late::<'static>(S, &0, &0);
+    //~^ ERROR cannot specify lifetime arguments explicitly
+    S::late_implicit::<'static>(S, &0, &0);
+    //~^ ERROR cannot specify lifetime arguments explicitly
+}
+
+fn main() {}
diff --git a/src/test/ui/method-call-lifetime-args.stderr b/src/test/ui/method-call-lifetime-args.stderr
new file mode 100644
index 00000000000..a6c1b8efe27
--- /dev/null
+++ b/src/test/ui/method-call-lifetime-args.stderr
@@ -0,0 +1,26 @@
+error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/method-call-lifetime-args.rs:19:15
+   |
+19 |     S::late::<'static>(S, &0, &0);
+   |               ^^^^^^^
+   |
+note: the late bound lifetime parameter is introduced here
+  --> $DIR/method-call-lifetime-args.rs:14:13
+   |
+14 |     fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
+   |             ^^
+
+error: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
+  --> $DIR/method-call-lifetime-args.rs:21:24
+   |
+21 |     S::late_implicit::<'static>(S, &0, &0);
+   |                        ^^^^^^^
+   |
+note: the late bound lifetime parameter is introduced here
+  --> $DIR/method-call-lifetime-args.rs:15:31
+   |
+15 |     fn late_implicit(self, _: &u8, _: &u8) {}
+   |                               ^
+
+error: aborting due to 2 previous errors
+