]> git.lizzy.rs Git - rust.git/commitdiff
Prohibit lifetime arguments in path segments with late bound lifetime parameters
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Fri, 23 Jun 2017 21:56:25 +0000 (00:56 +0300)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Mon, 17 Jul 2017 21:12:48 +0000 (00:12 +0300)
12 files changed:
src/librustc/ich/impls_ty.rs
src/librustc/lint/builtin.rs
src/librustc/ty/mod.rs
src/librustc_lint/lib.rs
src/librustc_typeck/check/method/confirm.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/collect.rs
src/test/compile-fail/E0088.rs
src/test/compile-fail/method-call-lifetime-args-lint.rs [new file with mode: 0644]
src/test/compile-fail/method-call-lifetime-args.rs
src/test/incremental/hashes/inherent_impls.rs
src/test/incremental/hashes/trait_defs.rs

index a1dd2caf786c207951ab26e97024d7e13734be44..3e227872848efb36efcd10ac1cde8ef167f5787e 100644 (file)
@@ -346,6 +346,7 @@ fn hash_stable<W: StableHasherResult>(&self,
             // `def_id.index` (`def_id.krate` is the same as the item's).
             type_param_to_index: _, // Don't hash this
             has_self,
+            has_late_bound_regions,
         } = *self;
 
         parent.hash_stable(hcx, hasher);
@@ -354,6 +355,7 @@ fn hash_stable<W: StableHasherResult>(&self,
         regions.hash_stable(hcx, hasher);
         types.hash_stable(hcx, hasher);
         has_self.hash_stable(hcx, hasher);
+        has_late_bound_regions.hash_stable(hcx, hasher);
     }
 }
 
index 2d088c4f6d1727729aaccd4d065e33b28669f985..3e71ac539a3417f6b512a0bc34421255e4ef2fac 100644 (file)
     "detects parenthesized generic parameters in type and module names"
 }
 
+declare_lint! {
+    pub LATE_BOUND_LIFETIME_ARGUMENTS,
+    Deny,
+    "detects generic lifetime arguments in path segments with late bound lifetime parameters"
+}
+
 declare_lint! {
     pub DEPRECATED,
     Warn,
@@ -249,6 +255,7 @@ fn get_lints(&self) -> LintArray {
             LEGACY_CONSTRUCTOR_VISIBILITY,
             MISSING_FRAGMENT_SPECIFIER,
             PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
+            LATE_BOUND_LIFETIME_ARGUMENTS,
             DEPRECATED
         )
     }
index 5aaba526e265f8a40b5494f0a49cb7dc592de58d..1fee0dd98634ae3af07784b751bb122348240322 100644 (file)
@@ -719,6 +719,7 @@ pub struct Generics {
     pub type_param_to_index: BTreeMap<DefIndex, u32>,
 
     pub has_self: bool,
+    pub has_late_bound_regions: bool,
 }
 
 impl Generics {
index a03f12c3dfbca09dd054c2f732c4a6cda7bcd5f9..21dca7f6c61c413234671a38817e6aabba2c9231 100644 (file)
@@ -235,7 +235,11 @@ macro_rules! add_lint_group {
         FutureIncompatibleInfo {
             id: LintId::of(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES),
             reference: "issue #42238 <https://github.com/rust-lang/rust/issues/42238>",
-        }
+        },
+        FutureIncompatibleInfo {
+            id: LintId::of(LATE_BOUND_LIFETIME_ARGUMENTS),
+            reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>",
+        },
         ]);
 
     // Register renamed and removed lints
index a647a8bf6f86c9aee24d33b1ea85af4bb7eddeab..c28ddf876b3cda242b37a13ac25e5b8fe935c334 100644 (file)
@@ -288,7 +288,7 @@ fn instantiate_method_substs(&mut self,
         // variables.
         let method_generics = self.tcx.generics_of(pick.item.def_id);
         let mut fn_segment = Some((segment, method_generics));
-        self.fcx.check_path_parameter_count(self.span, &mut fn_segment);
+        self.fcx.check_path_parameter_count(self.span, &mut fn_segment, true);
 
         // Create subst for early-bound lifetime parameters, combining
         // parameters from the type and those from the method.
index cdbe5e14e90948fabb469189226f1d6465283578..917bffbc22f00ae8271fcc254d821966125ac51e 100644 (file)
@@ -4491,8 +4491,8 @@ pub fn instantiate_value_path(&self,
         // variables. If the user provided some types, we may still need
         // to add defaults. If the user provided *too many* types, that's
         // a problem.
-        self.check_path_parameter_count(span, &mut type_segment);
-        self.check_path_parameter_count(span, &mut fn_segment);
+        self.check_path_parameter_count(span, &mut type_segment, false);
+        self.check_path_parameter_count(span, &mut fn_segment, false);
 
         let (fn_start, has_self) = match (type_segment, fn_segment) {
             (_, Some((_, generics))) => {
@@ -4618,7 +4618,8 @@ pub fn instantiate_value_path(&self,
     /// Report errors if the provided parameters are too few or too many.
     fn check_path_parameter_count(&self,
                                   span: Span,
-                                  segment: &mut Option<(&hir::PathSegment, &ty::Generics)>) {
+                                  segment: &mut Option<(&hir::PathSegment, &ty::Generics)>,
+                                  is_method_call: bool) {
         let (lifetimes, types, infer_types, bindings) = {
             match segment.map(|(s, _)| &s.parameters) {
                 Some(&hir::AngleBracketedParameters(ref data)) => {
@@ -4632,6 +4633,7 @@ fn check_path_parameter_count(&self,
                 None => (&[][..], &[][..], true, &[][..])
             }
         };
+        let infer_lifetimes = lifetimes.len() == 0;
 
         let count_lifetime_params = |n| {
             format!("{} lifetime parameter{}", n, if n == 1 { "" } else { "s" })
@@ -4640,32 +4642,6 @@ fn check_path_parameter_count(&self,
             format!("{} type parameter{}", n, if n == 1 { "" } else { "s" })
         };
 
-        // Check provided lifetime parameters.
-        let lifetime_defs = segment.map_or(&[][..], |(_, generics)| &generics.regions);
-        if lifetimes.len() > lifetime_defs.len() {
-            let expected_text = count_lifetime_params(lifetime_defs.len());
-            let actual_text = count_lifetime_params(lifetimes.len());
-            struct_span_err!(self.tcx.sess, span, E0088,
-                             "too many lifetime parameters provided: \
-                              expected at most {}, found {}",
-                             expected_text, actual_text)
-                .span_label(span, format!("expected {}", expected_text))
-                .emit();
-        } else if lifetimes.len() > 0 && lifetimes.len() < lifetime_defs.len() {
-            let expected_text = count_lifetime_params(lifetime_defs.len());
-            let actual_text = count_lifetime_params(lifetimes.len());
-            struct_span_err!(self.tcx.sess, span, E0090,
-                             "too few lifetime parameters provided: \
-                              expected {}, found {}",
-                             expected_text, actual_text)
-                .span_label(span, format!("expected {}", expected_text))
-                .emit();
-        }
-
-        // The case where there is not enough lifetime parameters is not checked,
-        // because this is not possible - a function never takes lifetime parameters.
-        // See discussion for Pull Request 36208.
-
         // Check provided type parameters.
         let type_defs = segment.map_or(&[][..], |(_, generics)| {
             if generics.parent.is_none() {
@@ -4690,7 +4666,7 @@ fn check_path_parameter_count(&self,
             // type parameters, we force instantiate_value_path to
             // use inference variables instead of the provided types.
             *segment = None;
-        } else if !infer_types && types.len() < required_len {
+        } else if types.len() < required_len && !infer_types {
             let expected_text = count_type_params(required_len);
             let actual_text = count_type_params(types.len());
             struct_span_err!(self.tcx.sess, span, E0089,
@@ -4706,6 +4682,51 @@ fn check_path_parameter_count(&self,
                       "unexpected binding of associated item in expression path \
                        (only allowed in type paths)");
         }
+
+        // Check provided lifetime parameters.
+        let lifetime_defs = segment.map_or(&[][..], |(_, generics)| &generics.regions);
+        let required_len = lifetime_defs.len();
+
+        // 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() {
+            // Report this as a lint only if no error was reported previously.
+            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");
+            } else {
+                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"));
+            }
+            *segment = None;
+            return;
+        }
+
+        if lifetimes.len() > lifetime_defs.len() {
+            let span = lifetimes[lifetime_defs.len()].span;
+            let expected_text = count_lifetime_params(lifetime_defs.len());
+            let actual_text = count_lifetime_params(lifetimes.len());
+            struct_span_err!(self.tcx.sess, span, E0088,
+                             "too many lifetime parameters provided: \
+                              expected at most {}, found {}",
+                             expected_text, actual_text)
+                .span_label(span, format!("expected {}", expected_text))
+                .emit();
+        } else if lifetimes.len() < required_len && !infer_lifetimes {
+            let expected_text = count_lifetime_params(lifetime_defs.len());
+            let actual_text = count_lifetime_params(lifetimes.len());
+            struct_span_err!(self.tcx.sess, span, E0090,
+                             "too few lifetime parameters provided: \
+                              expected {}, found {}",
+                             expected_text, actual_text)
+                .span_label(span, format!("expected {}", expected_text))
+                .emit();
+        }
     }
 
     fn structurally_resolve_type_or_else<F>(&self, sp: Span, ty: Ty<'tcx>, f: F)
index 002a148c459a3be506f7196e64ee7b91b8ab3f1b..25707229dbc5af7f83c8ccefb9309d898a0e44e4 100644 (file)
@@ -876,11 +876,13 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let has_self = opt_self.is_some();
     let mut parent_has_self = false;
+    let mut parent_has_late_bound_regions = false;
     let mut own_start = has_self as u32;
     let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| {
         let generics = tcx.generics_of(def_id);
         assert_eq!(has_self, false);
         parent_has_self = generics.has_self;
+        parent_has_late_bound_regions = generics.has_late_bound_regions;
         own_start = generics.count() as u32;
         (generics.parent_regions + generics.regions.len() as u32,
             generics.parent_types + generics.types.len() as u32)
@@ -898,6 +900,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
     }).collect::<Vec<_>>();
 
+    let has_late_bound_regions = regions.len() != ast_generics.lifetimes.len();
     let object_lifetime_defaults =
         tcx.named_region_map.object_lifetime_defaults.get(&node_id);
 
@@ -959,7 +962,8 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         regions: regions,
         types: types,
         type_param_to_index: type_param_to_index,
-        has_self: has_self || parent_has_self
+        has_self: has_self || parent_has_self,
+        has_late_bound_regions: has_late_bound_regions || parent_has_late_bound_regions,
     })
 }
 
index de188677a1121ba4513916fa06d8313b6dd92902..db84a4edc487c98914f839dd8e9f92415f2d8a65 100644 (file)
@@ -9,14 +9,9 @@
 // except according to those terms.
 
 fn f() {}
-fn g<'a>() {}
+fn g<'a>() -> &'a u8 { loop {} }
 
 fn main() {
-    f::<'static>();
-    //~^ ERROR expected at most 0 lifetime parameters, found 1 lifetime parameter [E0088]
-    //~| NOTE expected 0 lifetime parameters
-
-    g::<'static, 'static>();
-    //~^ ERROR expected at most 0 lifetime parameters, found 2 lifetime parameters [E0088]
-    //~| NOTE expected 0 lifetime parameters
+    f::<'static>(); //~ ERROR E0088
+    g::<'static, 'static>(); //~ ERROR E0088
 }
diff --git a/src/test/compile-fail/method-call-lifetime-args-lint.rs b/src/test/compile-fail/method-call-lifetime-args-lint.rs
new file mode 100644 (file)
index 0000000..28f1035
--- /dev/null
@@ -0,0 +1,76 @@
+// 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.
+
+#![allow(unused)]
+
+struct S;
+
+impl S {
+    fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
+    fn late_implicit(self, _: &u8, _: &u8) {}
+    fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} }
+    fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} }
+}
+
+fn method_call() {
+    S.late(&0, &0); // OK
+    S.late::<'static>(&0, &0);
+    //~^ ERROR cannot specify lifetime arguments explicitly
+    //~| WARN this was previously accepted
+    S.late::<'static, 'static>(&0, &0);
+    //~^ ERROR cannot specify lifetime arguments explicitly
+    //~| WARN this was previously accepted
+    S.late::<'static, 'static, 'static>(&0, &0);
+    //~^ ERROR cannot specify lifetime arguments explicitly
+    //~| WARN this was previously accepted
+    S.late_early(&0); // OK
+    S.late_early::<'static>(&0);
+    //~^ ERROR cannot specify lifetime arguments explicitly
+    //~| WARN this was previously accepted
+    S.late_early::<'static, 'static>(&0);
+    //~^ ERROR cannot specify lifetime arguments explicitly
+    //~| WARN this was previously accepted
+    S.late_early::<'static, 'static, 'static>(&0);
+    //~^ ERROR cannot specify lifetime arguments explicitly
+    //~| WARN this was previously accepted
+
+    S.late_implicit(&0, &0); // OK
+    // S.late_implicit::<'static>(&0, &0);
+    //FIXME ERROR cannot specify lifetime arguments explicitly
+    //FIXME WARN this was previously accepted
+    // S.late_implicit::<'static, 'static>(&0, &0);
+    //FIXME ERROR cannot specify lifetime arguments explicitly
+    //FIXME WARN this was previously accepted
+    // S.late_implicit::<'static, 'static, 'static>(&0, &0);
+    //FIXME ERROR cannot specify lifetime arguments explicitly
+    //FIXME WARN this was previously accepted
+    S.late_implicit_early(&0); // OK
+    S.late_implicit_early::<'static>(&0);
+    //FIXME ERROR cannot specify lifetime arguments explicitly
+    //FIXME WARN this was previously accepted
+    // S.late_implicit_early::<'static, 'static>(&0);
+    //FIXME ERROR cannot specify lifetime arguments explicitly
+    //FIXME WARN this was previously accepted
+    // S.late_implicit_early::<'static, 'static, 'static>(&0);
+    //FIXME ERROR cannot specify lifetime arguments explicitly
+    //FIXME WARN this was previously accepted
+}
+
+fn ufcs() {
+    S::late_early::<'static>(S, &0);
+    //~^ ERROR cannot specify lifetime arguments explicitly
+    //~| WARN this was previously accepted
+
+    S::late_implicit_early::<'static>(S, &0);
+    //FIXME ERROR cannot specify lifetime arguments explicitly
+    //FIXME WARN this was previously accepted
+}
+
+fn main() {}
index 75c469ecd3268373b8df288897c699f8ab424abf..00c03c3c8599a72394eb77655618db977ecfced5 100644 (file)
 
 impl S {
     fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
+    fn late_implicit(self, _: &u8, _: &u8) {}
     fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} }
-    fn life_and_type<'a, T>(&self) -> &'a T { loop {} }
+    fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} }
+    fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} }
+    fn life_and_type<'a, T>(self) -> &'a T { loop {} }
 }
 
-fn main() {
-    S.late(&0, &0); // OK
-    S.late::<'static>(&0, &0);
-    //~^ ERROR expected at most 0 lifetime parameters, found 1 lifetime parameter
-    S.late::<'static, 'static, 'static>(&0, &0);
-    //~^ ERROR expected at most 0 lifetime parameters, found 3 lifetime parameter
+fn method_call() {
     S.early(); // OK
     S.early::<'static>();
     //~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter
@@ -31,3 +29,47 @@ fn main() {
     S.life_and_type::<u8>();
     S.life_and_type::<'static, u8>();
 }
+
+fn ufcs() {
+    S::late(S, &0, &0); // OK
+    S::late::<'static>(S, &0, &0);
+    //~^ ERROR cannot specify lifetime arguments explicitly
+    S::late::<'static, 'static>(S, &0, &0);
+    //~^ ERROR cannot specify lifetime arguments explicitly
+    S::late::<'static, 'static, 'static>(S, &0, &0);
+    //~^ ERROR cannot specify lifetime arguments explicitly
+    S::late_early(S, &0); // OK
+    S::late_early::<'static, 'static>(S, &0);
+    //~^ ERROR cannot specify lifetime arguments explicitly
+    S::late_early::<'static, 'static, 'static>(S, &0);
+    //~^ ERROR cannot specify lifetime arguments explicitly
+
+    S::late_implicit(S, &0, &0); // OK
+    S::late_implicit::<'static>(S, &0, &0);
+    //~^ ERROR expected at most 0 lifetime parameters, found 1 lifetime parameter
+    //FIXME ERROR cannot specify lifetime arguments explicitly
+    S::late_implicit::<'static, 'static>(S, &0, &0);
+    //~^ ERROR expected at most 0 lifetime parameters, found 2 lifetime parameters
+    //FIXME ERROR cannot specify lifetime arguments explicitly
+    S::late_implicit::<'static, 'static, 'static>(S, &0, &0);
+    //~^ ERROR expected at most 0 lifetime parameters, found 3 lifetime parameters
+    //FIXME ERROR cannot specify lifetime arguments explicitly
+    S::late_implicit_early(S, &0); // OK
+    S::late_implicit_early::<'static, 'static>(S, &0);
+    //~^ ERROR expected at most 1 lifetime parameter, found 2 lifetime parameters
+    //FIXME ERROR cannot specify lifetime arguments explicitly
+    S::late_implicit_early::<'static, 'static, 'static>(S, &0);
+    //~^ ERROR expected at most 1 lifetime parameter, found 3 lifetime parameters
+    //FIXME ERROR cannot specify lifetime arguments explicitly
+
+    S::early(S); // OK
+    S::early::<'static>(S);
+    //~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter
+    S::early::<'static, 'static, 'static>(S);
+    //~^ ERROR expected at most 2 lifetime parameters, found 3 lifetime parameters
+    let _: &u8 = S::life_and_type::<'static>(S);
+    S::life_and_type::<u8>(S);
+    S::life_and_type::<'static, u8>(S);
+}
+
+fn main() {}
index 899aefa24a033b0e3d4eeeb666b96c7e3b9c86d2..370e07ba6c9e9f9f1897bf82fefab17bff63995b 100644 (file)
@@ -369,7 +369,7 @@ pub fn add_lifetime_parameter_to_method(&self) { }
 impl Foo {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_clean(cfg="cfail2")] // Apparently unused lifetimes don't show up in the type.
+    #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     pub fn add_lifetime_parameter_to_method<'a>(&self) { }
 }
index e47556a790b62652835cc525e652fb5e69536da2..44950ee8a601f90865698e22d955bc9a07344bf5 100644 (file)
@@ -448,7 +448,7 @@ trait TraitAddLifetimeParameterToMethod {
 trait TraitAddLifetimeParameterToMethod {
     #[rustc_dirty(label="Hir", cfg="cfail2")]
     #[rustc_clean(label="Hir", cfg="cfail3")]
-    #[rustc_metadata_clean(cfg="cfail2")] // Unused lifetimes don't seem to show up in type?
+    #[rustc_metadata_dirty(cfg="cfail2")]
     #[rustc_metadata_clean(cfg="cfail3")]
     fn method<'a>();
 }