// `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);
regions.hash_stable(hcx, hasher);
types.hash_stable(hcx, hasher);
has_self.hash_stable(hcx, hasher);
+ has_late_bound_regions.hash_stable(hcx, hasher);
}
}
"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,
LEGACY_CONSTRUCTOR_VISIBILITY,
MISSING_FRAGMENT_SPECIFIER,
PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
+ LATE_BOUND_LIFETIME_ARGUMENTS,
DEPRECATED
)
}
pub type_param_to_index: BTreeMap<DefIndex, u32>,
pub has_self: bool,
+ pub has_late_bound_regions: bool,
}
impl Generics {
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
// 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.
// 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))) => {
/// 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)) => {
None => (&[][..], &[][..], true, &[][..])
}
};
+ let infer_lifetimes = lifetimes.len() == 0;
let count_lifetime_params = |n| {
format!("{} lifetime parameter{}", n, if n == 1 { "" } else { "s" })
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() {
// 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,
"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)
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)
}
}).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);
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,
})
}
// 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
}
--- /dev/null
+// 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() {}
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
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() {}
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) { }
}
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>();
}