Auto merge of #138677 - shepmaster:consistent-elided-lifetime-syntax, r=traviscross,jieyouxu
Add a new `mismatched-lifetime-syntaxes` lint The lang-team [discussed this](https://hackmd.io/nf4ZUYd7Rp6rq-1svJZSaQ) and I attempted to [summarize](https://github.com/rust-lang/rust/pull/120808#issuecomment-2701863833) their decision. The summary-of-the-summary is: - Using two different kinds of syntax for elided lifetimes is confusing. In rare cases, it may even [lead to unsound code](https://github.com/rust-lang/rust/issues/48686)! Some examples: ```rust // Lint will warn about these fn(v: ContainsLifetime) -> ContainsLifetime<'_>; fn(&'static u8) -> &u8; ``` - Matching up references with no lifetime syntax, references with anonymous lifetime syntax, and paths with anonymous lifetime syntax is an exception to the simplest possible rule: ```rust // Lint will not warn about these fn(&u8) -> &'_ u8; fn(&'_ u8) -> &u8; fn(&u8) -> ContainsLifetime<'_>; ``` - Having a lint for consistent syntax of elided lifetimes will make the [future goal](https://github.com/rust-lang/rust/issues/91639) of warning-by-default for paths participating in elision much simpler. --- This new lint attempts to accomplish the goal of enforcing consistent syntax. In the process, it supersedes and replaces the existing `elided-named-lifetimes` lint, which means it starts out life as warn-by-default.
This commit is contained in:
commit
ccf3198de3
117 changed files with 1948 additions and 677 deletions
|
|
@ -1406,7 +1406,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
};
|
||||
let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi();
|
||||
let region = Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id };
|
||||
(region, LifetimeSyntax::Hidden)
|
||||
(region, LifetimeSyntax::Implicit)
|
||||
}
|
||||
};
|
||||
self.lower_lifetime(®ion, LifetimeSource::Reference, syntax)
|
||||
|
|
@ -1790,7 +1790,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
id,
|
||||
Ident::new(kw::UnderscoreLifetime, span),
|
||||
LifetimeSource::Path { angle_brackets },
|
||||
LifetimeSyntax::Hidden,
|
||||
LifetimeSyntax::Implicit,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -2422,7 +2422,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
Ident::new(kw::UnderscoreLifetime, self.lower_span(span)),
|
||||
hir::LifetimeKind::ImplicitObjectLifetimeDefault,
|
||||
LifetimeSource::Other,
|
||||
LifetimeSyntax::Hidden,
|
||||
LifetimeSyntax::Implicit,
|
||||
);
|
||||
debug!("elided_dyn_bound: r={:?}", r);
|
||||
self.arena.alloc(r)
|
||||
|
|
|
|||
|
|
@ -852,12 +852,7 @@ pub enum LifetimeRes {
|
|||
/// late resolution. Those lifetimes will be inferred by typechecking.
|
||||
Infer,
|
||||
/// `'static` lifetime.
|
||||
Static {
|
||||
/// We do not want to emit `elided_named_lifetimes`
|
||||
/// when we are inside of a const item or a static,
|
||||
/// because it would get too annoying.
|
||||
suppress_elision_warning: bool,
|
||||
},
|
||||
Static,
|
||||
/// Resolution failure.
|
||||
Error,
|
||||
/// HACK: This is used to recover the NodeId of an elided lifetime.
|
||||
|
|
|
|||
|
|
@ -72,13 +72,13 @@ pub enum LifetimeSource {
|
|||
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
|
||||
pub enum LifetimeSyntax {
|
||||
/// E.g. `&Type`, `ContainsLifetime`
|
||||
Hidden,
|
||||
Implicit,
|
||||
|
||||
/// E.g. `&'_ Type`, `ContainsLifetime<'_>`, `impl Trait + '_`, `impl Trait + use<'_>`
|
||||
Anonymous,
|
||||
ExplicitAnonymous,
|
||||
|
||||
/// E.g. `&'a Type`, `ContainsLifetime<'a>`, `impl Trait + 'a`, `impl Trait + use<'a>`
|
||||
Named,
|
||||
ExplicitBound,
|
||||
}
|
||||
|
||||
impl From<Ident> for LifetimeSyntax {
|
||||
|
|
@ -88,10 +88,10 @@ impl From<Ident> for LifetimeSyntax {
|
|||
if name == sym::empty {
|
||||
unreachable!("A lifetime name should never be empty");
|
||||
} else if name == kw::UnderscoreLifetime {
|
||||
LifetimeSyntax::Anonymous
|
||||
LifetimeSyntax::ExplicitAnonymous
|
||||
} else {
|
||||
debug_assert!(name.as_str().starts_with('\''));
|
||||
LifetimeSyntax::Named
|
||||
LifetimeSyntax::ExplicitBound
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -102,48 +102,48 @@ impl From<Ident> for LifetimeSyntax {
|
|||
///
|
||||
/// ```
|
||||
/// #[repr(C)]
|
||||
/// struct S<'a>(&'a u32); // res=Param, name='a, source=Reference, syntax=Named
|
||||
/// struct S<'a>(&'a u32); // res=Param, name='a, source=Reference, syntax=ExplicitBound
|
||||
/// unsafe extern "C" {
|
||||
/// fn f1(s: S); // res=Param, name='_, source=Path, syntax=Hidden
|
||||
/// fn f2(s: S<'_>); // res=Param, name='_, source=Path, syntax=Anonymous
|
||||
/// fn f3<'a>(s: S<'a>); // res=Param, name='a, source=Path, syntax=Named
|
||||
/// fn f1(s: S); // res=Param, name='_, source=Path, syntax=Implicit
|
||||
/// fn f2(s: S<'_>); // res=Param, name='_, source=Path, syntax=ExplicitAnonymous
|
||||
/// fn f3<'a>(s: S<'a>); // res=Param, name='a, source=Path, syntax=ExplicitBound
|
||||
/// }
|
||||
///
|
||||
/// struct St<'a> { x: &'a u32 } // res=Param, name='a, source=Reference, syntax=Named
|
||||
/// struct St<'a> { x: &'a u32 } // res=Param, name='a, source=Reference, syntax=ExplicitBound
|
||||
/// fn f() {
|
||||
/// _ = St { x: &0 }; // res=Infer, name='_, source=Path, syntax=Hidden
|
||||
/// _ = St::<'_> { x: &0 }; // res=Infer, name='_, source=Path, syntax=Anonymous
|
||||
/// _ = St { x: &0 }; // res=Infer, name='_, source=Path, syntax=Implicit
|
||||
/// _ = St::<'_> { x: &0 }; // res=Infer, name='_, source=Path, syntax=ExplicitAnonymous
|
||||
/// }
|
||||
///
|
||||
/// struct Name<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=Named
|
||||
/// const A: Name = Name("a"); // res=Static, name='_, source=Path, syntax=Hidden
|
||||
/// const B: &str = ""; // res=Static, name='_, source=Reference, syntax=Hidden
|
||||
/// static C: &'_ str = ""; // res=Static, name='_, source=Reference, syntax=Anonymous
|
||||
/// static D: &'static str = ""; // res=Static, name='static, source=Reference, syntax=Named
|
||||
/// struct Name<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=ExplicitBound
|
||||
/// const A: Name = Name("a"); // res=Static, name='_, source=Path, syntax=Implicit
|
||||
/// const B: &str = ""; // res=Static, name='_, source=Reference, syntax=Implicit
|
||||
/// static C: &'_ str = ""; // res=Static, name='_, source=Reference, syntax=ExplicitAnonymous
|
||||
/// static D: &'static str = ""; // res=Static, name='static, source=Reference, syntax=ExplicitBound
|
||||
///
|
||||
/// trait Tr {}
|
||||
/// fn tr(_: Box<dyn Tr>) {} // res=ImplicitObjectLifetimeDefault, name='_, source=Other, syntax=Hidden
|
||||
/// fn tr(_: Box<dyn Tr>) {} // res=ImplicitObjectLifetimeDefault, name='_, source=Other, syntax=Implicit
|
||||
///
|
||||
/// fn capture_outlives<'a>() ->
|
||||
/// impl FnOnce() + 'a // res=Param, ident='a, source=OutlivesBound, syntax=Named
|
||||
/// impl FnOnce() + 'a // res=Param, ident='a, source=OutlivesBound, syntax=ExplicitBound
|
||||
/// {
|
||||
/// || {}
|
||||
/// }
|
||||
///
|
||||
/// fn capture_precise<'a>() ->
|
||||
/// impl FnOnce() + use<'a> // res=Param, ident='a, source=PreciseCapturing, syntax=Named
|
||||
/// impl FnOnce() + use<'a> // res=Param, ident='a, source=PreciseCapturing, syntax=ExplicitBound
|
||||
/// {
|
||||
/// || {}
|
||||
/// }
|
||||
///
|
||||
/// // (commented out because these cases trigger errors)
|
||||
/// // struct S1<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=Named
|
||||
/// // struct S2(S1); // res=Error, name='_, source=Path, syntax=Hidden
|
||||
/// // struct S3(S1<'_>); // res=Error, name='_, source=Path, syntax=Anonymous
|
||||
/// // struct S4(S1<'a>); // res=Error, name='a, source=Path, syntax=Named
|
||||
/// // struct S1<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=ExplicitBound
|
||||
/// // struct S2(S1); // res=Error, name='_, source=Path, syntax=Implicit
|
||||
/// // struct S3(S1<'_>); // res=Error, name='_, source=Path, syntax=ExplicitAnonymous
|
||||
/// // struct S4(S1<'a>); // res=Error, name='a, source=Path, syntax=ExplicitBound
|
||||
/// ```
|
||||
///
|
||||
/// Some combinations that cannot occur are `LifetimeSyntax::Hidden` with
|
||||
/// Some combinations that cannot occur are `LifetimeSyntax::Implicit` with
|
||||
/// `LifetimeSource::OutlivesBound` or `LifetimeSource::PreciseCapturing`
|
||||
/// — there's no way to "elide" these lifetimes.
|
||||
#[derive(Debug, Copy, Clone, HashStable_Generic)]
|
||||
|
|
@ -206,7 +206,7 @@ impl ParamName {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
|
||||
pub enum LifetimeKind {
|
||||
/// User-given names or fresh (synthetic) names.
|
||||
Param(LocalDefId),
|
||||
|
|
@ -287,12 +287,8 @@ impl Lifetime {
|
|||
self.ident.name == kw::UnderscoreLifetime
|
||||
}
|
||||
|
||||
pub fn is_syntactically_hidden(&self) -> bool {
|
||||
matches!(self.syntax, LifetimeSyntax::Hidden)
|
||||
}
|
||||
|
||||
pub fn is_syntactically_anonymous(&self) -> bool {
|
||||
matches!(self.syntax, LifetimeSyntax::Anonymous)
|
||||
pub fn is_implicit(&self) -> bool {
|
||||
matches!(self.syntax, LifetimeSyntax::Implicit)
|
||||
}
|
||||
|
||||
pub fn is_static(&self) -> bool {
|
||||
|
|
@ -307,28 +303,28 @@ impl Lifetime {
|
|||
|
||||
match (self.syntax, self.source) {
|
||||
// The user wrote `'a` or `'_`.
|
||||
(Named | Anonymous, _) => (self.ident.span, format!("{new_lifetime}")),
|
||||
(ExplicitBound | ExplicitAnonymous, _) => (self.ident.span, format!("{new_lifetime}")),
|
||||
|
||||
// The user wrote `Path<T>`, and omitted the `'_,`.
|
||||
(Hidden, Path { angle_brackets: AngleBrackets::Full }) => {
|
||||
(Implicit, Path { angle_brackets: AngleBrackets::Full }) => {
|
||||
(self.ident.span, format!("{new_lifetime}, "))
|
||||
}
|
||||
|
||||
// The user wrote `Path<>`, and omitted the `'_`..
|
||||
(Hidden, Path { angle_brackets: AngleBrackets::Empty }) => {
|
||||
(Implicit, Path { angle_brackets: AngleBrackets::Empty }) => {
|
||||
(self.ident.span, format!("{new_lifetime}"))
|
||||
}
|
||||
|
||||
// The user wrote `Path` and omitted the `<'_>`.
|
||||
(Hidden, Path { angle_brackets: AngleBrackets::Missing }) => {
|
||||
(Implicit, Path { angle_brackets: AngleBrackets::Missing }) => {
|
||||
(self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>"))
|
||||
}
|
||||
|
||||
// The user wrote `&type` or `&mut type`.
|
||||
(Hidden, Reference) => (self.ident.span, format!("{new_lifetime} ")),
|
||||
(Implicit, Reference) => (self.ident.span, format!("{new_lifetime} ")),
|
||||
|
||||
(Hidden, source) => {
|
||||
unreachable!("can't suggest for a hidden lifetime of {source:?}")
|
||||
(Implicit, source) => {
|
||||
unreachable!("can't suggest for a implicit lifetime of {source:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ fn trait_object_roundtrips_impl(syntax: TraitObjectSyntax) {
|
|||
ident: Ident::new(sym::name, DUMMY_SP),
|
||||
kind: LifetimeKind::Static,
|
||||
source: LifetimeSource::Other,
|
||||
syntax: LifetimeSyntax::Hidden,
|
||||
syntax: LifetimeSyntax::Implicit,
|
||||
};
|
||||
let unambig = TyKind::TraitObject::<'_, ()>(&[], TaggedRef::new(<, syntax));
|
||||
let unambig_to_ambig = unsafe { std::mem::transmute::<_, TyKind<'_, AmbigArg>>(unambig) };
|
||||
|
|
|
|||
|
|
@ -253,11 +253,6 @@ lint_duplicate_macro_attribute =
|
|||
|
||||
lint_duplicate_matcher_binding = duplicate matcher binding
|
||||
|
||||
lint_elided_named_lifetime = elided lifetime has a name
|
||||
.label_elided = this elided lifetime gets resolved as `{$name}`
|
||||
.label_named = lifetime `{$name}` declared here
|
||||
.suggestion = consider specifying it explicitly
|
||||
|
||||
lint_enum_intrinsics_mem_discriminant =
|
||||
the return value of `mem::discriminant` is unspecified when called with a non-enum type
|
||||
.note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum
|
||||
|
|
@ -516,6 +511,28 @@ lint_metavariable_still_repeating = variable `{$name}` is still repeating at thi
|
|||
|
||||
lint_metavariable_wrong_operator = meta-variable repeats with different Kleene operator
|
||||
|
||||
lint_mismatched_lifetime_syntaxes =
|
||||
lifetime flowing from input to output with different syntax can be confusing
|
||||
.label_mismatched_lifetime_syntaxes_inputs =
|
||||
{$n_inputs ->
|
||||
[one] this lifetime flows
|
||||
*[other] these lifetimes flow
|
||||
} to the output
|
||||
.label_mismatched_lifetime_syntaxes_outputs =
|
||||
the {$n_outputs ->
|
||||
[one] lifetime gets
|
||||
*[other] lifetimes get
|
||||
} resolved as `{$lifetime_name}`
|
||||
|
||||
lint_mismatched_lifetime_syntaxes_suggestion_explicit =
|
||||
one option is to consistently use `{$lifetime_name}`
|
||||
|
||||
lint_mismatched_lifetime_syntaxes_suggestion_implicit =
|
||||
one option is to consistently remove the lifetime
|
||||
|
||||
lint_mismatched_lifetime_syntaxes_suggestion_mixed =
|
||||
one option is to remove the lifetime for references and use the anonymous lifetime for paths
|
||||
|
||||
lint_missing_fragment_specifier = missing fragment specifier
|
||||
|
||||
lint_missing_unsafe_on_extern = extern blocks should be unsafe
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ use rustc_errors::{
|
|||
use rustc_middle::middle::stability;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::{BuiltinLintDiag, ElidedLifetimeResolution};
|
||||
use rustc_span::{BytePos, kw};
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_span::BytePos;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::lints::{self, ElidedNamedLifetime};
|
||||
use crate::lints;
|
||||
|
||||
mod check_cfg;
|
||||
|
||||
|
|
@ -471,16 +471,5 @@ pub fn decorate_builtin_lint(
|
|||
BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by } => {
|
||||
lints::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.decorate_lint(diag)
|
||||
}
|
||||
BuiltinLintDiag::ElidedNamedLifetimes { elided: (span, kind), resolution } => {
|
||||
match resolution {
|
||||
ElidedLifetimeResolution::Static => {
|
||||
ElidedNamedLifetime { span, kind, name: kw::StaticLifetime, declaration: None }
|
||||
}
|
||||
ElidedLifetimeResolution::Param(name, declaration) => {
|
||||
ElidedNamedLifetime { span, kind, name, declaration: Some(declaration) }
|
||||
}
|
||||
}
|
||||
.decorate_lint(diag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ mod invalid_from_utf8;
|
|||
mod late;
|
||||
mod let_underscore;
|
||||
mod levels;
|
||||
mod lifetime_syntax;
|
||||
mod lints;
|
||||
mod macro_expr_fragment_specifier_2024_migration;
|
||||
mod map_unit_fn;
|
||||
|
|
@ -96,6 +97,7 @@ use impl_trait_overcaptures::ImplTraitOvercaptures;
|
|||
use internal::*;
|
||||
use invalid_from_utf8::*;
|
||||
use let_underscore::*;
|
||||
use lifetime_syntax::*;
|
||||
use macro_expr_fragment_specifier_2024_migration::*;
|
||||
use map_unit_fn::*;
|
||||
use multiple_supertrait_upcastable::*;
|
||||
|
|
@ -246,6 +248,7 @@ late_lint_methods!(
|
|||
StaticMutRefs: StaticMutRefs,
|
||||
UnqualifiedLocalImports: UnqualifiedLocalImports,
|
||||
CheckTransmutes: CheckTransmutes,
|
||||
LifetimeSyntax: LifetimeSyntax,
|
||||
]
|
||||
]
|
||||
);
|
||||
|
|
@ -353,6 +356,7 @@ fn register_builtins(store: &mut LintStore) {
|
|||
store.register_renamed("unused_tuple_struct_fields", "dead_code");
|
||||
store.register_renamed("static_mut_ref", "static_mut_refs");
|
||||
store.register_renamed("temporary_cstring_as_ptr", "dangling_pointers_from_temporaries");
|
||||
store.register_renamed("elided_named_lifetimes", "mismatched_lifetime_syntaxes");
|
||||
|
||||
// These were moved to tool lints, but rustc still sees them when compiling normally, before
|
||||
// tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use
|
||||
|
|
|
|||
503
compiler/rustc_lint/src/lifetime_syntax.rs
Normal file
503
compiler/rustc_lint/src/lifetime_syntax.rs
Normal file
|
|
@ -0,0 +1,503 @@
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{self as hir, LifetimeSource};
|
||||
use rustc_session::{declare_lint, declare_lint_pass};
|
||||
use rustc_span::Span;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::{LateContext, LateLintPass, LintContext, lints};
|
||||
|
||||
declare_lint! {
|
||||
/// The `mismatched_lifetime_syntaxes` lint detects when the same
|
||||
/// lifetime is referred to by different syntaxes between function
|
||||
/// arguments and return values.
|
||||
///
|
||||
/// The three kinds of syntaxes are:
|
||||
///
|
||||
/// 1. Named lifetimes. These are references (`&'a str`) or paths
|
||||
/// (`Person<'a>`) that use a lifetime with a name, such as
|
||||
/// `'static` or `'a`.
|
||||
///
|
||||
/// 2. Elided lifetimes. These are references with no explicit
|
||||
/// lifetime (`&str`), references using the anonymous lifetime
|
||||
/// (`&'_ str`), and paths using the anonymous lifetime
|
||||
/// (`Person<'_>`).
|
||||
///
|
||||
/// 3. Hidden lifetimes. These are paths that do not contain any
|
||||
/// visual indication that it contains a lifetime (`Person`).
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(mismatched_lifetime_syntaxes)]
|
||||
///
|
||||
/// pub fn mixing_named_with_elided(v: &'static u8) -> &u8 {
|
||||
/// v
|
||||
/// }
|
||||
///
|
||||
/// struct Person<'a> {
|
||||
/// name: &'a str,
|
||||
/// }
|
||||
///
|
||||
/// pub fn mixing_hidden_with_elided(v: Person) -> Person<'_> {
|
||||
/// v
|
||||
/// }
|
||||
///
|
||||
/// struct Foo;
|
||||
///
|
||||
/// impl Foo {
|
||||
/// // Lifetime elision results in the output lifetime becoming
|
||||
/// // `'static`, which is not what was intended.
|
||||
/// pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
|
||||
/// unsafe { &mut *(x as *mut _) }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Lifetime elision is useful because it frees you from having to
|
||||
/// give each lifetime its own name and show the relation of input
|
||||
/// and output lifetimes for common cases. However, a lifetime
|
||||
/// that uses inconsistent syntax between related arguments and
|
||||
/// return values is more confusing.
|
||||
///
|
||||
/// In certain `unsafe` code, lifetime elision combined with
|
||||
/// inconsistent lifetime syntax may result in unsound code.
|
||||
pub MISMATCHED_LIFETIME_SYNTAXES,
|
||||
Warn,
|
||||
"detects when a lifetime uses different syntax between arguments and return values"
|
||||
}
|
||||
|
||||
declare_lint_pass!(LifetimeSyntax => [MISMATCHED_LIFETIME_SYNTAXES]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for LifetimeSyntax {
|
||||
#[instrument(skip_all)]
|
||||
fn check_fn(
|
||||
&mut self,
|
||||
cx: &LateContext<'tcx>,
|
||||
_: hir::intravisit::FnKind<'tcx>,
|
||||
fd: &'tcx hir::FnDecl<'tcx>,
|
||||
_: &'tcx hir::Body<'tcx>,
|
||||
_: rustc_span::Span,
|
||||
_: rustc_span::def_id::LocalDefId,
|
||||
) {
|
||||
let mut input_map = Default::default();
|
||||
let mut output_map = Default::default();
|
||||
|
||||
for input in fd.inputs {
|
||||
LifetimeInfoCollector::collect(input, &mut input_map);
|
||||
}
|
||||
|
||||
if let hir::FnRetTy::Return(output) = fd.output {
|
||||
LifetimeInfoCollector::collect(output, &mut output_map);
|
||||
}
|
||||
|
||||
report_mismatches(cx, &input_map, &output_map);
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
fn report_mismatches<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
inputs: &LifetimeInfoMap<'tcx>,
|
||||
outputs: &LifetimeInfoMap<'tcx>,
|
||||
) {
|
||||
for (resolved_lifetime, output_info) in outputs {
|
||||
if let Some(input_info) = inputs.get(resolved_lifetime) {
|
||||
if !lifetimes_use_matched_syntax(input_info, output_info) {
|
||||
emit_mismatch_diagnostic(cx, input_info, output_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lifetimes_use_matched_syntax(input_info: &[Info<'_>], output_info: &[Info<'_>]) -> bool {
|
||||
// Categorize lifetimes into source/syntax buckets.
|
||||
let mut n_hidden = 0;
|
||||
let mut n_elided = 0;
|
||||
let mut n_named = 0;
|
||||
|
||||
for info in input_info.iter().chain(output_info) {
|
||||
use LifetimeSource::*;
|
||||
use hir::LifetimeSyntax::*;
|
||||
|
||||
let syntax_source = (info.lifetime.syntax, info.lifetime.source);
|
||||
|
||||
match syntax_source {
|
||||
// Ignore any other kind of lifetime.
|
||||
(_, Other) => continue,
|
||||
|
||||
// E.g. `&T`.
|
||||
(Implicit, Reference | OutlivesBound | PreciseCapturing) |
|
||||
// E.g. `&'_ T`.
|
||||
(ExplicitAnonymous, Reference | OutlivesBound | PreciseCapturing) |
|
||||
// E.g. `ContainsLifetime<'_>`.
|
||||
(ExplicitAnonymous, Path { .. }) => n_elided += 1,
|
||||
|
||||
// E.g. `ContainsLifetime`.
|
||||
(Implicit, Path { .. }) => n_hidden += 1,
|
||||
|
||||
// E.g. `&'a T`.
|
||||
(ExplicitBound, Reference | OutlivesBound | PreciseCapturing) |
|
||||
// E.g. `ContainsLifetime<'a>`.
|
||||
(ExplicitBound, Path { .. }) => n_named += 1,
|
||||
};
|
||||
}
|
||||
|
||||
let syntax_counts = (n_hidden, n_elided, n_named);
|
||||
tracing::debug!(?syntax_counts);
|
||||
|
||||
matches!(syntax_counts, (_, 0, 0) | (0, _, 0) | (0, 0, _))
|
||||
}
|
||||
|
||||
fn emit_mismatch_diagnostic<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
input_info: &[Info<'_>],
|
||||
output_info: &[Info<'_>],
|
||||
) {
|
||||
// There can only ever be zero or one bound lifetime
|
||||
// for a given lifetime resolution.
|
||||
let mut bound_lifetime = None;
|
||||
|
||||
// We offer the following kinds of suggestions (when appropriate
|
||||
// such that the suggestion wouldn't violate the lint):
|
||||
//
|
||||
// 1. Every lifetime becomes named, when there is already a
|
||||
// user-provided name.
|
||||
//
|
||||
// 2. A "mixed" signature, where references become implicit
|
||||
// and paths become explicitly anonymous.
|
||||
//
|
||||
// 3. Every lifetime becomes implicit.
|
||||
//
|
||||
// 4. Every lifetime becomes explicitly anonymous.
|
||||
//
|
||||
// Number 2 is arguably the most common pattern and the one we
|
||||
// should push strongest. Number 3 is likely the next most common,
|
||||
// followed by number 1. Coming in at a distant last would be
|
||||
// number 4.
|
||||
//
|
||||
// Beyond these, there are variants of acceptable signatures that
|
||||
// we won't suggest because they are very low-value. For example,
|
||||
// we will never suggest `fn(&T1, &'_ T2) -> &T3` even though that
|
||||
// would pass the lint.
|
||||
//
|
||||
// The following collections are the lifetime instances that we
|
||||
// suggest changing to a given alternate style.
|
||||
|
||||
// 1. Convert all to named.
|
||||
let mut suggest_change_to_explicit_bound = Vec::new();
|
||||
|
||||
// 2. Convert to mixed. We track each kind of change separately.
|
||||
let mut suggest_change_to_mixed_implicit = Vec::new();
|
||||
let mut suggest_change_to_mixed_explicit_anonymous = Vec::new();
|
||||
|
||||
// 3. Convert all to implicit.
|
||||
let mut suggest_change_to_implicit = Vec::new();
|
||||
|
||||
// 4. Convert all to explicit anonymous.
|
||||
let mut suggest_change_to_explicit_anonymous = Vec::new();
|
||||
|
||||
// Some styles prevent using implicit syntax at all.
|
||||
let mut allow_suggesting_implicit = true;
|
||||
|
||||
// It only makes sense to suggest mixed if we have both sources.
|
||||
let mut saw_a_reference = false;
|
||||
let mut saw_a_path = false;
|
||||
|
||||
for info in input_info.iter().chain(output_info) {
|
||||
use LifetimeSource::*;
|
||||
use hir::LifetimeSyntax::*;
|
||||
|
||||
let syntax_source = (info.lifetime.syntax, info.lifetime.source);
|
||||
|
||||
if let (_, Other) = syntax_source {
|
||||
// Ignore any other kind of lifetime.
|
||||
continue;
|
||||
}
|
||||
|
||||
if let (ExplicitBound, _) = syntax_source {
|
||||
bound_lifetime = Some(info);
|
||||
}
|
||||
|
||||
match syntax_source {
|
||||
// E.g. `&T`.
|
||||
(Implicit, Reference) => {
|
||||
suggest_change_to_explicit_anonymous.push(info);
|
||||
suggest_change_to_explicit_bound.push(info);
|
||||
}
|
||||
|
||||
// E.g. `&'_ T`.
|
||||
(ExplicitAnonymous, Reference) => {
|
||||
suggest_change_to_implicit.push(info);
|
||||
suggest_change_to_mixed_implicit.push(info);
|
||||
suggest_change_to_explicit_bound.push(info);
|
||||
}
|
||||
|
||||
// E.g. `ContainsLifetime`.
|
||||
(Implicit, Path { .. }) => {
|
||||
suggest_change_to_mixed_explicit_anonymous.push(info);
|
||||
suggest_change_to_explicit_anonymous.push(info);
|
||||
suggest_change_to_explicit_bound.push(info);
|
||||
}
|
||||
|
||||
// E.g. `ContainsLifetime<'_>`.
|
||||
(ExplicitAnonymous, Path { .. }) => {
|
||||
suggest_change_to_explicit_bound.push(info);
|
||||
}
|
||||
|
||||
// E.g. `&'a T`.
|
||||
(ExplicitBound, Reference) => {
|
||||
suggest_change_to_implicit.push(info);
|
||||
suggest_change_to_mixed_implicit.push(info);
|
||||
suggest_change_to_explicit_anonymous.push(info);
|
||||
}
|
||||
|
||||
// E.g. `ContainsLifetime<'a>`.
|
||||
(ExplicitBound, Path { .. }) => {
|
||||
suggest_change_to_mixed_explicit_anonymous.push(info);
|
||||
suggest_change_to_explicit_anonymous.push(info);
|
||||
}
|
||||
|
||||
(Implicit, OutlivesBound | PreciseCapturing) => {
|
||||
panic!("This syntax / source combination is not possible");
|
||||
}
|
||||
|
||||
// E.g. `+ '_`, `+ use<'_>`.
|
||||
(ExplicitAnonymous, OutlivesBound | PreciseCapturing) => {
|
||||
suggest_change_to_explicit_bound.push(info);
|
||||
}
|
||||
|
||||
// E.g. `+ 'a`, `+ use<'a>`.
|
||||
(ExplicitBound, OutlivesBound | PreciseCapturing) => {
|
||||
suggest_change_to_mixed_explicit_anonymous.push(info);
|
||||
suggest_change_to_explicit_anonymous.push(info);
|
||||
}
|
||||
|
||||
(_, Other) => {
|
||||
panic!("This syntax / source combination has already been skipped");
|
||||
}
|
||||
}
|
||||
|
||||
if matches!(syntax_source, (_, Path { .. } | OutlivesBound | PreciseCapturing)) {
|
||||
allow_suggesting_implicit = false;
|
||||
}
|
||||
|
||||
match syntax_source {
|
||||
(_, Reference) => saw_a_reference = true,
|
||||
(_, Path { .. }) => saw_a_path = true,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let make_implicit_suggestions =
|
||||
|infos: &[&Info<'_>]| infos.iter().map(|i| i.removing_span()).collect::<Vec<_>>();
|
||||
|
||||
let inputs = input_info.iter().map(|info| info.reporting_span()).collect();
|
||||
let outputs = output_info.iter().map(|info| info.reporting_span()).collect();
|
||||
|
||||
let explicit_bound_suggestion = bound_lifetime.map(|info| {
|
||||
build_mismatch_suggestion(info.lifetime_name(), &suggest_change_to_explicit_bound)
|
||||
});
|
||||
|
||||
let is_bound_static = bound_lifetime.is_some_and(|info| info.is_static());
|
||||
|
||||
tracing::debug!(?bound_lifetime, ?explicit_bound_suggestion, ?is_bound_static);
|
||||
|
||||
let should_suggest_mixed =
|
||||
// Do we have a mixed case?
|
||||
(saw_a_reference && saw_a_path) &&
|
||||
// Is there anything to change?
|
||||
(!suggest_change_to_mixed_implicit.is_empty() ||
|
||||
!suggest_change_to_mixed_explicit_anonymous.is_empty()) &&
|
||||
// If we have `'static`, we don't want to remove it.
|
||||
!is_bound_static;
|
||||
|
||||
let mixed_suggestion = should_suggest_mixed.then(|| {
|
||||
let implicit_suggestions = make_implicit_suggestions(&suggest_change_to_mixed_implicit);
|
||||
|
||||
let explicit_anonymous_suggestions = suggest_change_to_mixed_explicit_anonymous
|
||||
.iter()
|
||||
.map(|info| info.suggestion("'_"))
|
||||
.collect();
|
||||
|
||||
lints::MismatchedLifetimeSyntaxesSuggestion::Mixed {
|
||||
implicit_suggestions,
|
||||
explicit_anonymous_suggestions,
|
||||
tool_only: false,
|
||||
}
|
||||
});
|
||||
|
||||
tracing::debug!(
|
||||
?suggest_change_to_mixed_implicit,
|
||||
?suggest_change_to_mixed_explicit_anonymous,
|
||||
?mixed_suggestion,
|
||||
);
|
||||
|
||||
let should_suggest_implicit =
|
||||
// Is there anything to change?
|
||||
!suggest_change_to_implicit.is_empty() &&
|
||||
// We never want to hide the lifetime in a path (or similar).
|
||||
allow_suggesting_implicit &&
|
||||
// If we have `'static`, we don't want to remove it.
|
||||
!is_bound_static;
|
||||
|
||||
let implicit_suggestion = should_suggest_implicit.then(|| {
|
||||
let suggestions = make_implicit_suggestions(&suggest_change_to_implicit);
|
||||
|
||||
lints::MismatchedLifetimeSyntaxesSuggestion::Implicit { suggestions, tool_only: false }
|
||||
});
|
||||
|
||||
tracing::debug!(
|
||||
?should_suggest_implicit,
|
||||
?suggest_change_to_implicit,
|
||||
allow_suggesting_implicit,
|
||||
?implicit_suggestion,
|
||||
);
|
||||
|
||||
let should_suggest_explicit_anonymous =
|
||||
// Is there anything to change?
|
||||
!suggest_change_to_explicit_anonymous.is_empty() &&
|
||||
// If we have `'static`, we don't want to remove it.
|
||||
!is_bound_static;
|
||||
|
||||
let explicit_anonymous_suggestion = should_suggest_explicit_anonymous
|
||||
.then(|| build_mismatch_suggestion("'_", &suggest_change_to_explicit_anonymous));
|
||||
|
||||
tracing::debug!(
|
||||
?should_suggest_explicit_anonymous,
|
||||
?suggest_change_to_explicit_anonymous,
|
||||
?explicit_anonymous_suggestion,
|
||||
);
|
||||
|
||||
let lifetime_name = bound_lifetime.map(|info| info.lifetime_name()).unwrap_or("'_").to_owned();
|
||||
|
||||
// We can produce a number of suggestions which may overwhelm
|
||||
// the user. Instead, we order the suggestions based on Rust
|
||||
// idioms. The "best" choice is shown to the user and the
|
||||
// remaining choices are shown to tools only.
|
||||
let mut suggestions = Vec::new();
|
||||
suggestions.extend(explicit_bound_suggestion);
|
||||
suggestions.extend(mixed_suggestion);
|
||||
suggestions.extend(implicit_suggestion);
|
||||
suggestions.extend(explicit_anonymous_suggestion);
|
||||
|
||||
cx.emit_span_lint(
|
||||
MISMATCHED_LIFETIME_SYNTAXES,
|
||||
Vec::clone(&inputs),
|
||||
lints::MismatchedLifetimeSyntaxes { lifetime_name, inputs, outputs, suggestions },
|
||||
);
|
||||
}
|
||||
|
||||
fn build_mismatch_suggestion(
|
||||
lifetime_name: &str,
|
||||
infos: &[&Info<'_>],
|
||||
) -> lints::MismatchedLifetimeSyntaxesSuggestion {
|
||||
let lifetime_name = lifetime_name.to_owned();
|
||||
|
||||
let suggestions = infos.iter().map(|info| info.suggestion(&lifetime_name)).collect();
|
||||
|
||||
lints::MismatchedLifetimeSyntaxesSuggestion::Explicit {
|
||||
lifetime_name,
|
||||
suggestions,
|
||||
tool_only: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Info<'tcx> {
|
||||
type_span: Span,
|
||||
referenced_type_span: Option<Span>,
|
||||
lifetime: &'tcx hir::Lifetime,
|
||||
}
|
||||
|
||||
impl<'tcx> Info<'tcx> {
|
||||
fn lifetime_name(&self) -> &str {
|
||||
self.lifetime.ident.as_str()
|
||||
}
|
||||
|
||||
fn is_static(&self) -> bool {
|
||||
self.lifetime.is_static()
|
||||
}
|
||||
|
||||
/// When reporting a lifetime that is implicit, we expand the span
|
||||
/// to include the type. Otherwise we end up pointing at nothing,
|
||||
/// which is a bit confusing.
|
||||
fn reporting_span(&self) -> Span {
|
||||
if self.lifetime.is_implicit() { self.type_span } else { self.lifetime.ident.span }
|
||||
}
|
||||
|
||||
/// When removing an explicit lifetime from a reference,
|
||||
/// we want to remove the whitespace after the lifetime.
|
||||
///
|
||||
/// ```rust
|
||||
/// fn x(a: &'_ u8) {}
|
||||
/// ```
|
||||
///
|
||||
/// Should become:
|
||||
///
|
||||
/// ```rust
|
||||
/// fn x(a: &u8) {}
|
||||
/// ```
|
||||
// FIXME: Ideally, we'd also remove the lifetime declaration.
|
||||
fn removing_span(&self) -> Span {
|
||||
let mut span = self.suggestion("'dummy").0;
|
||||
|
||||
if let Some(referenced_type_span) = self.referenced_type_span {
|
||||
span = span.until(referenced_type_span);
|
||||
}
|
||||
|
||||
span
|
||||
}
|
||||
|
||||
fn suggestion(&self, lifetime_name: &str) -> (Span, String) {
|
||||
self.lifetime.suggestion(lifetime_name)
|
||||
}
|
||||
}
|
||||
|
||||
type LifetimeInfoMap<'tcx> = FxIndexMap<&'tcx hir::LifetimeKind, Vec<Info<'tcx>>>;
|
||||
|
||||
struct LifetimeInfoCollector<'a, 'tcx> {
|
||||
type_span: Span,
|
||||
referenced_type_span: Option<Span>,
|
||||
map: &'a mut LifetimeInfoMap<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> LifetimeInfoCollector<'a, 'tcx> {
|
||||
fn collect(ty: &'tcx hir::Ty<'tcx>, map: &'a mut LifetimeInfoMap<'tcx>) {
|
||||
let mut this = Self { type_span: ty.span, referenced_type_span: None, map };
|
||||
|
||||
intravisit::walk_unambig_ty(&mut this, ty);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for LifetimeInfoCollector<'a, 'tcx> {
|
||||
#[instrument(skip(self))]
|
||||
fn visit_lifetime(&mut self, lifetime: &'tcx hir::Lifetime) {
|
||||
let type_span = self.type_span;
|
||||
let referenced_type_span = self.referenced_type_span;
|
||||
|
||||
let info = Info { type_span, referenced_type_span, lifetime };
|
||||
|
||||
self.map.entry(&lifetime.kind).or_default().push(info);
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) -> Self::Result {
|
||||
let old_type_span = self.type_span;
|
||||
let old_referenced_type_span = self.referenced_type_span;
|
||||
|
||||
self.type_span = ty.span;
|
||||
if let hir::TyKind::Ref(_, ty) = ty.kind {
|
||||
self.referenced_type_span = Some(ty.ty.span);
|
||||
}
|
||||
|
||||
intravisit::walk_ty(self, ty);
|
||||
|
||||
self.type_span = old_type_span;
|
||||
self.referenced_type_span = old_referenced_type_span;
|
||||
}
|
||||
}
|
||||
|
|
@ -8,17 +8,17 @@ use rustc_errors::{
|
|||
Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag,
|
||||
EmissionGuarantee, LintDiagnostic, MultiSpan, Subdiagnostic, SuggestionStyle,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::VisitorExt;
|
||||
use rustc_hir::{self as hir, MissingLifetimeKind};
|
||||
use rustc_macros::{LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::inhabitedness::InhabitedPredicate;
|
||||
use rustc_middle::ty::{Clause, PolyExistentialTraitRef, Ty, TyCtxt};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::lint::AmbiguityErrorDiag;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, kw, sym};
|
||||
use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym};
|
||||
|
||||
use crate::builtin::{InitError, ShorthandAssocTyCollector, TypeAliasBounds};
|
||||
use crate::errors::{OverruledAttributeSub, RequestedLevel};
|
||||
|
|
@ -2752,58 +2752,6 @@ pub(crate) struct ElidedLifetimesInPaths {
|
|||
pub subdiag: ElidedLifetimeInPathSubdiag,
|
||||
}
|
||||
|
||||
pub(crate) struct ElidedNamedLifetime {
|
||||
pub span: Span,
|
||||
pub kind: MissingLifetimeKind,
|
||||
pub name: Symbol,
|
||||
pub declaration: Option<Span>,
|
||||
}
|
||||
|
||||
impl<G: EmissionGuarantee> LintDiagnostic<'_, G> for ElidedNamedLifetime {
|
||||
fn decorate_lint(self, diag: &mut rustc_errors::Diag<'_, G>) {
|
||||
let Self { span, kind, name, declaration } = self;
|
||||
diag.primary_message(fluent::lint_elided_named_lifetime);
|
||||
diag.arg("name", name);
|
||||
diag.span_label(span, fluent::lint_label_elided);
|
||||
if let Some(declaration) = declaration {
|
||||
diag.span_label(declaration, fluent::lint_label_named);
|
||||
}
|
||||
// FIXME(GrigorenkoPV): this `if` and `return` should be removed,
|
||||
// but currently this lint's suggestions can conflict with those of `clippy::needless_lifetimes`:
|
||||
// https://github.com/rust-lang/rust/pull/129840#issuecomment-2323349119
|
||||
// HACK: `'static` suggestions will never sonflict, emit only those for now.
|
||||
if name != kw::StaticLifetime {
|
||||
return;
|
||||
}
|
||||
match kind {
|
||||
MissingLifetimeKind::Underscore => diag.span_suggestion_verbose(
|
||||
span,
|
||||
fluent::lint_suggestion,
|
||||
format!("{name}"),
|
||||
Applicability::MachineApplicable,
|
||||
),
|
||||
MissingLifetimeKind::Ampersand => diag.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
fluent::lint_suggestion,
|
||||
format!("{name} "),
|
||||
Applicability::MachineApplicable,
|
||||
),
|
||||
MissingLifetimeKind::Comma => diag.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
fluent::lint_suggestion,
|
||||
format!("{name}, "),
|
||||
Applicability::MachineApplicable,
|
||||
),
|
||||
MissingLifetimeKind::Brackets => diag.span_suggestion_verbose(
|
||||
span.shrink_to_hi(),
|
||||
fluent::lint_suggestion,
|
||||
format!("<{name}>"),
|
||||
Applicability::MachineApplicable,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_invalid_crate_type_value)]
|
||||
pub(crate) struct UnknownCrateTypes {
|
||||
|
|
@ -3241,3 +3189,128 @@ pub(crate) struct ReservedMultihash {
|
|||
#[suggestion(code = " ", applicability = "machine-applicable")]
|
||||
pub suggestion: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct MismatchedLifetimeSyntaxes {
|
||||
pub lifetime_name: String,
|
||||
pub inputs: Vec<Span>,
|
||||
pub outputs: Vec<Span>,
|
||||
|
||||
pub suggestions: Vec<MismatchedLifetimeSyntaxesSuggestion>,
|
||||
}
|
||||
|
||||
impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for MismatchedLifetimeSyntaxes {
|
||||
fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) {
|
||||
diag.primary_message(fluent::lint_mismatched_lifetime_syntaxes);
|
||||
|
||||
diag.arg("lifetime_name", self.lifetime_name);
|
||||
|
||||
diag.arg("n_inputs", self.inputs.len());
|
||||
for input in self.inputs {
|
||||
let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_inputs);
|
||||
diag.span_label(input, a);
|
||||
}
|
||||
|
||||
diag.arg("n_outputs", self.outputs.len());
|
||||
for output in self.outputs {
|
||||
let a = diag.eagerly_translate(fluent::lint_label_mismatched_lifetime_syntaxes_outputs);
|
||||
diag.span_label(output, a);
|
||||
}
|
||||
|
||||
let mut suggestions = self.suggestions.into_iter();
|
||||
if let Some(s) = suggestions.next() {
|
||||
diag.subdiagnostic(s);
|
||||
|
||||
for mut s in suggestions {
|
||||
s.make_tool_only();
|
||||
diag.subdiagnostic(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum MismatchedLifetimeSyntaxesSuggestion {
|
||||
Implicit {
|
||||
suggestions: Vec<Span>,
|
||||
tool_only: bool,
|
||||
},
|
||||
|
||||
Mixed {
|
||||
implicit_suggestions: Vec<Span>,
|
||||
explicit_anonymous_suggestions: Vec<(Span, String)>,
|
||||
tool_only: bool,
|
||||
},
|
||||
|
||||
Explicit {
|
||||
lifetime_name: String,
|
||||
suggestions: Vec<(Span, String)>,
|
||||
tool_only: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl MismatchedLifetimeSyntaxesSuggestion {
|
||||
fn make_tool_only(&mut self) {
|
||||
use MismatchedLifetimeSyntaxesSuggestion::*;
|
||||
|
||||
let tool_only = match self {
|
||||
Implicit { tool_only, .. } | Mixed { tool_only, .. } | Explicit { tool_only, .. } => {
|
||||
tool_only
|
||||
}
|
||||
};
|
||||
|
||||
*tool_only = true;
|
||||
}
|
||||
}
|
||||
|
||||
impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion {
|
||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
use MismatchedLifetimeSyntaxesSuggestion::*;
|
||||
|
||||
let style = |tool_only| {
|
||||
if tool_only { SuggestionStyle::CompletelyHidden } else { SuggestionStyle::ShowAlways }
|
||||
};
|
||||
|
||||
match self {
|
||||
Implicit { suggestions, tool_only } => {
|
||||
let suggestions = suggestions.into_iter().map(|s| (s, String::new())).collect();
|
||||
diag.multipart_suggestion_with_style(
|
||||
fluent::lint_mismatched_lifetime_syntaxes_suggestion_implicit,
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
style(tool_only),
|
||||
);
|
||||
}
|
||||
|
||||
Mixed { implicit_suggestions, explicit_anonymous_suggestions, tool_only } => {
|
||||
let implicit_suggestions =
|
||||
implicit_suggestions.into_iter().map(|s| (s, String::new()));
|
||||
|
||||
let suggestions =
|
||||
implicit_suggestions.chain(explicit_anonymous_suggestions).collect();
|
||||
|
||||
diag.multipart_suggestion_with_style(
|
||||
fluent::lint_mismatched_lifetime_syntaxes_suggestion_mixed,
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
style(tool_only),
|
||||
);
|
||||
}
|
||||
|
||||
Explicit { lifetime_name, suggestions, tool_only } => {
|
||||
diag.arg("lifetime_name", lifetime_name);
|
||||
|
||||
let msg = diag.eagerly_translate(
|
||||
fluent::lint_mismatched_lifetime_syntaxes_suggestion_explicit,
|
||||
);
|
||||
|
||||
diag.multipart_suggestion_with_style(
|
||||
msg,
|
||||
suggestions,
|
||||
Applicability::MachineApplicable,
|
||||
style(tool_only),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ declare_lint_pass! {
|
|||
DUPLICATE_MACRO_ATTRIBUTES,
|
||||
ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
|
||||
ELIDED_LIFETIMES_IN_PATHS,
|
||||
ELIDED_NAMED_LIFETIMES,
|
||||
EXPLICIT_BUILTIN_CFGS_IN_FLAGS,
|
||||
EXPORTED_PRIVATE_DEPENDENCIES,
|
||||
FFI_UNWIND_CALLS,
|
||||
|
|
@ -1832,38 +1831,6 @@ declare_lint! {
|
|||
"hidden lifetime parameters in types are deprecated"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `elided_named_lifetimes` lint detects when an elided
|
||||
/// lifetime ends up being a named lifetime, such as `'static`
|
||||
/// or some lifetime parameter `'a`.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(elided_named_lifetimes)]
|
||||
/// struct Foo;
|
||||
/// impl Foo {
|
||||
/// pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
|
||||
/// unsafe { &mut *(x as *mut _) }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Lifetime elision is quite useful, because it frees you from having
|
||||
/// to give each lifetime its own name, but sometimes it can produce
|
||||
/// somewhat surprising resolutions. In safe code, it is mostly okay,
|
||||
/// because the borrow checker prevents any unsoundness, so the worst
|
||||
/// case scenario is you get a confusing error message in some other place.
|
||||
/// But with `unsafe` code, such unexpected resolutions may lead to unsound code.
|
||||
pub ELIDED_NAMED_LIFETIMES,
|
||||
Warn,
|
||||
"detects when an elided lifetime gets resolved to be `'static` or some named parameter"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `bare_trait_objects` lint suggests using `dyn Trait` for trait
|
||||
/// objects.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_data_structures::stable_hasher::{
|
|||
use rustc_error_messages::{DiagMessage, MultiSpan};
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_hir::def_id::DefPathHash;
|
||||
use rustc_hir::{HashStableContext, HirId, ItemLocalId, MissingLifetimeKind};
|
||||
use rustc_hir::{HashStableContext, HirId, ItemLocalId};
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
||||
pub use rustc_span::edition::Edition;
|
||||
use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol, sym};
|
||||
|
|
@ -610,12 +610,6 @@ pub enum DeprecatedSinceKind {
|
|||
InVersion(String),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ElidedLifetimeResolution {
|
||||
Static,
|
||||
Param(Symbol, Span),
|
||||
}
|
||||
|
||||
// This could be a closure, but then implementing derive trait
|
||||
// becomes hacky (and it gets allocated).
|
||||
#[derive(Debug)]
|
||||
|
|
@ -628,10 +622,6 @@ pub enum BuiltinLintDiag {
|
|||
},
|
||||
MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
|
||||
ElidedLifetimesInPaths(usize, Span, bool, Span),
|
||||
ElidedNamedLifetimes {
|
||||
elided: (Span, MissingLifetimeKind),
|
||||
resolution: ElidedLifetimeResolution,
|
||||
},
|
||||
UnknownCrateTypes {
|
||||
span: Span,
|
||||
candidate: Option<Symbol>,
|
||||
|
|
|
|||
|
|
@ -1729,7 +1729,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
if ident.name == kw::StaticLifetime {
|
||||
self.record_lifetime_res(
|
||||
lifetime.id,
|
||||
LifetimeRes::Static { suppress_elision_warning: false },
|
||||
LifetimeRes::Static,
|
||||
LifetimeElisionCandidate::Named,
|
||||
);
|
||||
return;
|
||||
|
|
@ -1877,8 +1877,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
if lifetimes_in_scope.is_empty() {
|
||||
self.record_lifetime_res(
|
||||
lifetime.id,
|
||||
// We are inside a const item, so do not warn.
|
||||
LifetimeRes::Static { suppress_elision_warning: true },
|
||||
LifetimeRes::Static,
|
||||
elision_candidate,
|
||||
);
|
||||
return;
|
||||
|
|
@ -2225,47 +2224,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
panic!("lifetime {id:?} resolved multiple times ({prev_res:?} before, {res:?} now)")
|
||||
}
|
||||
|
||||
match candidate {
|
||||
LifetimeElisionCandidate::Missing(missing @ MissingLifetime { .. }) => {
|
||||
debug_assert_eq!(id, missing.id);
|
||||
match res {
|
||||
LifetimeRes::Static { suppress_elision_warning } => {
|
||||
if !suppress_elision_warning {
|
||||
self.r.lint_buffer.buffer_lint(
|
||||
lint::builtin::ELIDED_NAMED_LIFETIMES,
|
||||
missing.id_for_lint,
|
||||
missing.span,
|
||||
BuiltinLintDiag::ElidedNamedLifetimes {
|
||||
elided: (missing.span, missing.kind),
|
||||
resolution: lint::ElidedLifetimeResolution::Static,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
LifetimeRes::Param { param, binder: _ } => {
|
||||
let tcx = self.r.tcx();
|
||||
self.r.lint_buffer.buffer_lint(
|
||||
lint::builtin::ELIDED_NAMED_LIFETIMES,
|
||||
missing.id_for_lint,
|
||||
missing.span,
|
||||
BuiltinLintDiag::ElidedNamedLifetimes {
|
||||
elided: (missing.span, missing.kind),
|
||||
resolution: lint::ElidedLifetimeResolution::Param(
|
||||
tcx.item_name(param.into()),
|
||||
tcx.source_span(param),
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
LifetimeRes::Fresh { .. }
|
||||
| LifetimeRes::Infer
|
||||
| LifetimeRes::Error
|
||||
| LifetimeRes::ElidedAnchor { .. } => {}
|
||||
}
|
||||
}
|
||||
LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => {}
|
||||
}
|
||||
|
||||
match res {
|
||||
LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static { .. } => {
|
||||
if let Some(ref mut candidates) = self.lifetime_elision_candidates {
|
||||
|
|
@ -2788,14 +2746,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
..
|
||||
}) => {
|
||||
self.with_static_rib(def_kind, |this| {
|
||||
this.with_lifetime_rib(
|
||||
LifetimeRibKind::Elided(LifetimeRes::Static {
|
||||
suppress_elision_warning: true,
|
||||
}),
|
||||
|this| {
|
||||
this.visit_ty(ty);
|
||||
},
|
||||
);
|
||||
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
|
||||
this.visit_ty(ty);
|
||||
});
|
||||
if let Some(expr) = expr {
|
||||
// We already forbid generic params because of the above item rib,
|
||||
// so it doesn't matter whether this is a trivial constant.
|
||||
|
|
@ -2832,9 +2785,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
|
|||
this.visit_generics(generics);
|
||||
|
||||
this.with_lifetime_rib(
|
||||
LifetimeRibKind::Elided(LifetimeRes::Static {
|
||||
suppress_elision_warning: true,
|
||||
}),
|
||||
LifetimeRibKind::Elided(LifetimeRes::Static),
|
||||
|this| this.visit_ty(ty),
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -3440,7 +3440,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
maybe_static = true;
|
||||
in_scope_lifetimes = vec![(
|
||||
Ident::with_dummy_span(kw::StaticLifetime),
|
||||
(DUMMY_NODE_ID, LifetimeRes::Static { suppress_elision_warning: false }),
|
||||
(DUMMY_NODE_ID, LifetimeRes::Static),
|
||||
)];
|
||||
}
|
||||
} else if elided_len == 0 {
|
||||
|
|
@ -3452,7 +3452,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
|||
maybe_static = true;
|
||||
in_scope_lifetimes = vec![(
|
||||
Ident::with_dummy_span(kw::StaticLifetime),
|
||||
(DUMMY_NODE_ID, LifetimeRes::Static { suppress_elision_warning: false }),
|
||||
(DUMMY_NODE_ID, LifetimeRes::Static),
|
||||
)];
|
||||
}
|
||||
} else if num_params == 1 {
|
||||
|
|
|
|||
|
|
@ -593,7 +593,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
|
|||
matches!(
|
||||
arg,
|
||||
hir::GenericArg::Lifetime(lifetime)
|
||||
if lifetime.is_syntactically_hidden()
|
||||
if lifetime.is_implicit()
|
||||
)
|
||||
}) {
|
||||
self.suggestions.push((
|
||||
|
|
|
|||
|
|
@ -77,11 +77,11 @@ fn main() {
|
|||
|
||||
struct NoIntoIter();
|
||||
impl NoIntoIter {
|
||||
fn iter(&self) -> slice::Iter<u8> {
|
||||
fn iter(&self) -> slice::Iter<'_, u8> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn iter_mut(&mut self) -> slice::IterMut<u8> {
|
||||
fn iter_mut(&mut self) -> slice::IterMut<'_, u8> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,11 +77,11 @@ fn main() {
|
|||
|
||||
struct NoIntoIter();
|
||||
impl NoIntoIter {
|
||||
fn iter(&self) -> slice::Iter<u8> {
|
||||
fn iter(&self) -> slice::Iter<'_, u8> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn iter_mut(&mut self) -> slice::IterMut<u8> {
|
||||
fn iter_mut(&mut self) -> slice::IterMut<'_, u8> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ fn main() {
|
|||
|
||||
struct Unrelated(&'static [u8]);
|
||||
impl Unrelated {
|
||||
fn next(&self) -> std::slice::Iter<u8> {
|
||||
fn next(&self) -> std::slice::Iter<'_, u8> {
|
||||
self.0.iter()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ impl S {
|
|||
|
||||
struct S2([u8]);
|
||||
impl S2 {
|
||||
fn iter(&self) -> core::slice::Iter<u8> {
|
||||
fn iter(&self) -> core::slice::Iter<'_, u8> {
|
||||
self.0.iter()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ struct Lt2<'a> {
|
|||
|
||||
impl<'a> Lt2<'a> {
|
||||
// The lifetime is different, but that’s irrelevant; see issue #734.
|
||||
pub fn new(s: &str) -> Lt2 {
|
||||
pub fn new(s: &str) -> Lt2<'_> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
clippy::unnecessary_wraps,
|
||||
dyn_drop,
|
||||
clippy::get_first,
|
||||
elided_named_lifetimes
|
||||
mismatched_lifetime_syntaxes,
|
||||
)]
|
||||
|
||||
extern crate proc_macros;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
clippy::unnecessary_wraps,
|
||||
dyn_drop,
|
||||
clippy::get_first,
|
||||
elided_named_lifetimes
|
||||
mismatched_lifetime_syntaxes,
|
||||
)]
|
||||
|
||||
extern crate proc_macros;
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ mod issue_9218 {
|
|||
|
||||
// Inferred to be `&'a str`, afaik.
|
||||
fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
|
||||
//~^ ERROR: elided lifetime has a name
|
||||
//~^ ERROR: lifetime flowing from input to output with different syntax
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,3 @@
|
|||
error: elided lifetime has a name
|
||||
--> tests/ui/ptr_arg.rs:314:56
|
||||
|
|
||||
LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
|
||||
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
|
||||
|
|
||||
= note: `-D elided-named-lifetimes` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]`
|
||||
|
||||
error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
|
||||
--> tests/ui/ptr_arg.rs:13:14
|
||||
|
|
||||
|
|
@ -240,5 +231,21 @@ error: writing `&String` instead of `&str` involves a new object where a slice w
|
|||
LL | fn good(v1: &String, v2: &String) {
|
||||
| ^^^^^^^ help: change this to: `&str`
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> tests/ui/ptr_arg.rs:314:36
|
||||
|
|
||||
LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str {
|
||||
| ^^ ^^ ---- the lifetime gets resolved as `'a`
|
||||
| | |
|
||||
| | these lifetimes flow to the output
|
||||
| these lifetimes flow to the output
|
||||
|
|
||||
= note: `-D mismatched-lifetime-syntaxes` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(mismatched_lifetime_syntaxes)]`
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &'a str {
|
||||
| ++
|
||||
|
||||
error: aborting due to 27 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ struct CounterWrapper<'a> {
|
|||
}
|
||||
|
||||
impl<'a> CounterWrapper<'a> {
|
||||
fn new(counter: &Counter) -> CounterWrapper {
|
||||
fn new(counter: &Counter) -> CounterWrapper<'_> {
|
||||
counter.i.fetch_add(1, Ordering::Relaxed);
|
||||
CounterWrapper { counter }
|
||||
}
|
||||
|
|
@ -204,7 +204,7 @@ impl<'a> Drop for CounterWrapper<'a> {
|
|||
}
|
||||
|
||||
impl Counter {
|
||||
fn temp_increment(&self) -> Vec<CounterWrapper> {
|
||||
fn temp_increment(&self) -> Vec<CounterWrapper<'_>> {
|
||||
vec![CounterWrapper::new(self), CounterWrapper::new(self)]
|
||||
}
|
||||
}
|
||||
|
|
@ -480,7 +480,7 @@ impl StateWithBoxedMutexGuard {
|
|||
fn new() -> StateWithBoxedMutexGuard {
|
||||
StateWithBoxedMutexGuard { u: Mutex::new(42) }
|
||||
}
|
||||
fn lock(&self) -> Box<MutexGuard<u64>> {
|
||||
fn lock(&self) -> Box<MutexGuard<'_, u64>> {
|
||||
Box::new(self.u.lock().unwrap())
|
||||
}
|
||||
}
|
||||
|
|
@ -507,7 +507,7 @@ impl StateStringWithBoxedMutexGuard {
|
|||
s: Mutex::new("A String".to_owned()),
|
||||
}
|
||||
}
|
||||
fn lock(&self) -> Box<MutexGuard<String>> {
|
||||
fn lock(&self) -> Box<MutexGuard<'_, String>> {
|
||||
Box::new(self.s.lock().unwrap())
|
||||
}
|
||||
}
|
||||
|
|
@ -686,11 +686,11 @@ struct Guard<'a, T>(MutexGuard<'a, T>);
|
|||
struct Ref<'a, T>(&'a T);
|
||||
|
||||
impl<'a, T> Guard<'a, T> {
|
||||
fn guard(&self) -> &MutexGuard<T> {
|
||||
fn guard(&self) -> &MutexGuard<'_, T> {
|
||||
&self.0
|
||||
}
|
||||
|
||||
fn guard_ref(&self) -> Ref<MutexGuard<T>> {
|
||||
fn guard_ref(&self) -> Ref<'_, MutexGuard<'_, T>> {
|
||||
Ref(&self.0)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ fn good_return_explicit_lt_ref<'a>(foo: &'a Foo) -> &'a u32 {
|
|||
&foo.0
|
||||
}
|
||||
|
||||
#[allow(mismatched_lifetime_syntaxes)]
|
||||
fn good_return_implicit_lt_struct(foo: &Foo) -> FooRef {
|
||||
FooRef { foo }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ fn good_return_explicit_lt_ref<'a>(foo: &'a Foo) -> &'a u32 {
|
|||
&foo.0
|
||||
}
|
||||
|
||||
#[allow(mismatched_lifetime_syntaxes)]
|
||||
fn good_return_implicit_lt_struct(foo: &Foo) -> FooRef {
|
||||
FooRef { foo }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:53:11
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:54:11
|
||||
|
|
||||
LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^ help: consider passing by value instead: `u32`
|
||||
|
|
@ -11,103 +11,103 @@ LL | #![deny(clippy::trivially_copy_pass_by_ref)]
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:53:20
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:54:20
|
||||
|
|
||||
LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^ help: consider passing by value instead: `Foo`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:53:29
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:54:29
|
||||
|
|
||||
LL | fn bad(x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^ help: consider passing by value instead: `Baz`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:63:12
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:64:12
|
||||
|
|
||||
LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^^ help: consider passing by value instead: `self`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:63:22
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:64:22
|
||||
|
|
||||
LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^ help: consider passing by value instead: `u32`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:63:31
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:64:31
|
||||
|
|
||||
LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^ help: consider passing by value instead: `Foo`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:63:40
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:64:40
|
||||
|
|
||||
LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^ help: consider passing by value instead: `Baz`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:69:16
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:70:16
|
||||
|
|
||||
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^ help: consider passing by value instead: `u32`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:69:25
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:70:25
|
||||
|
|
||||
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^ help: consider passing by value instead: `Foo`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:69:34
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:70:34
|
||||
|
|
||||
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^ help: consider passing by value instead: `Baz`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:74:35
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:75:35
|
||||
|
|
||||
LL | fn bad_issue7518(self, other: &Self) {}
|
||||
| ^^^^^ help: consider passing by value instead: `Self`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:87:16
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:88:16
|
||||
|
|
||||
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^ help: consider passing by value instead: `u32`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:87:25
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:88:25
|
||||
|
|
||||
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^ help: consider passing by value instead: `Foo`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:87:34
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:88:34
|
||||
|
|
||||
LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {}
|
||||
| ^^^^ help: consider passing by value instead: `Baz`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:94:33
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:95:33
|
||||
|
|
||||
LL | fn trait_method(&self, foo: &Foo);
|
||||
| ^^^^ help: consider passing by value instead: `Foo`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:132:21
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:133:21
|
||||
|
|
||||
LL | fn foo_never(x: &i32) {
|
||||
| ^^^^ help: consider passing by value instead: `i32`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:138:15
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:139:15
|
||||
|
|
||||
LL | fn foo(x: &i32) {
|
||||
| ^^^^ help: consider passing by value instead: `i32`
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:164:36
|
||||
--> tests/ui/trivially_copy_pass_by_ref.rs:165:36
|
||||
|
|
||||
LL | fn unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 {
|
||||
| ^^^^^^^ help: consider passing by value instead: `u32`
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ mod lifetimes {
|
|||
impl<'a> Foo<'a> {
|
||||
// Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) ->
|
||||
// Foo<'b>`
|
||||
fn foo(s: &str) -> Foo {
|
||||
fn foo(s: &str) -> Foo<'_> {
|
||||
Foo { foo_str: s }
|
||||
}
|
||||
// cannot replace with `Self`, because that's `Foo<'a>`
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ mod lifetimes {
|
|||
impl<'a> Foo<'a> {
|
||||
// Cannot use `Self` as return type, because the function is actually `fn foo<'b>(s: &'b str) ->
|
||||
// Foo<'b>`
|
||||
fn foo(s: &str) -> Foo {
|
||||
fn foo(s: &str) -> Foo<'_> {
|
||||
Foo { foo_str: s }
|
||||
}
|
||||
// cannot replace with `Self`, because that's `Foo<'a>`
|
||||
|
|
|
|||
|
|
@ -19,11 +19,11 @@ fn fat_ptr_via_local(a: &[u8]) -> &[u8] {
|
|||
x
|
||||
}
|
||||
|
||||
fn fat_ptr_from_struct(s: FatPtrContainer) -> &[u8] {
|
||||
fn fat_ptr_from_struct(s: FatPtrContainer<'_>) -> &[u8] {
|
||||
s.ptr
|
||||
}
|
||||
|
||||
fn fat_ptr_to_struct(a: &[u8]) -> FatPtrContainer {
|
||||
fn fat_ptr_to_struct(a: &[u8]) -> FatPtrContainer<'_> {
|
||||
FatPtrContainer { ptr: a }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ trait Iterator {
|
|||
}
|
||||
|
||||
trait IteratorExt: Iterator + Sized {
|
||||
fn by_ref(&mut self) -> ByRef<Self> {
|
||||
fn by_ref(&mut self) -> ByRef<'_, Self> {
|
||||
ByRef(self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@ trait SliceExt2 {
|
|||
impl<T> SliceExt2 for [T] {
|
||||
type Item = T;
|
||||
|
||||
fn split2<P>(&self, pred: P) -> Splits<T, P> where P: FnMut(&T) -> bool {
|
||||
fn split2<P>(&self, pred: P) -> Splits<'_, T, P> where P: FnMut(&T) -> bool {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn splitn2<P>(&self, n: u32, pred: P) -> SplitsN<Splits<T, P>> where P: FnMut(&T) -> bool {
|
||||
fn splitn2<P>(&self, n: u32, pred: P) -> SplitsN<Splits<'_, T, P>> where P: FnMut(&T) -> bool {
|
||||
SliceExt2::split2(self, pred);
|
||||
loop {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,32 +3,40 @@
|
|||
// Test that we normalize associated types that appear in bounds; if
|
||||
// we didn't, the call to `self.split2()` fails to type check.
|
||||
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
struct Splits<'a, T, P>(PhantomData<(&'a(),T,P)>);
|
||||
struct Splits<'a, T, P>(PhantomData<(&'a (), T, P)>);
|
||||
struct SplitsN<I>(PhantomData<I>);
|
||||
|
||||
trait SliceExt2 {
|
||||
type Item;
|
||||
|
||||
fn split2<'a, P>(&'a self, pred: P) -> Splits<'a, Self::Item, P>
|
||||
where P: FnMut(&Self::Item) -> bool;
|
||||
where
|
||||
P: FnMut(&Self::Item) -> bool;
|
||||
|
||||
fn splitn2<'a, P>(&'a self, n: usize, pred: P) -> SplitsN<Splits<'a, Self::Item, P>>
|
||||
where P: FnMut(&Self::Item) -> bool;
|
||||
where
|
||||
P: FnMut(&Self::Item) -> bool;
|
||||
}
|
||||
|
||||
impl<T> SliceExt2 for [T] {
|
||||
type Item = T;
|
||||
|
||||
fn split2<P>(&self, pred: P) -> Splits<T, P> where P: FnMut(&T) -> bool {
|
||||
fn split2<P>(&self, pred: P) -> Splits<'_, T, P>
|
||||
where
|
||||
P: FnMut(&T) -> bool,
|
||||
{
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn splitn2<P>(&self, n: usize, pred: P) -> SplitsN<Splits<T, P>> where P: FnMut(&T) -> bool {
|
||||
fn splitn2<P>(&self, n: usize, pred: P) -> SplitsN<Splits<'_, T, P>>
|
||||
where
|
||||
P: FnMut(&T) -> bool,
|
||||
{
|
||||
self.split2(pred);
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ trait Iterator {
|
|||
}
|
||||
|
||||
trait IteratorExt: Iterator + Sized {
|
||||
fn by_ref(&mut self) -> ByRef<Self> {
|
||||
fn by_ref(&mut self) -> ByRef<'_, Self> {
|
||||
ByRef(self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
tests/ui/associated-types/cache/elision.rs
vendored
2
tests/ui/associated-types/cache/elision.rs
vendored
|
|
@ -14,7 +14,7 @@ pub trait UnicodeStr {
|
|||
|
||||
impl UnicodeStr for str {
|
||||
#[inline]
|
||||
fn split_whitespace(&self) -> SplitWhitespace {
|
||||
fn split_whitespace(&self) -> SplitWhitespace<'_> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ where P: Pixel + 'static,
|
|||
loop { }
|
||||
}
|
||||
|
||||
pub fn pixels_mut(&mut self) -> PixelsMut<P> {
|
||||
pub fn pixels_mut(&mut self) -> PixelsMut<'_, P> {
|
||||
loop { }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ trait Foo {}
|
|||
impl Xyz {
|
||||
async fn do_sth<'a>(
|
||||
&'a self, foo: &dyn Foo
|
||||
) -> &dyn Foo //~ WARNING elided lifetime has a name
|
||||
) -> &dyn Foo
|
||||
{
|
||||
foo
|
||||
//~^ ERROR explicit lifetime required in the type of `foo` [E0621]
|
||||
|
|
|
|||
|
|
@ -1,14 +1,3 @@
|
|||
warning: elided lifetime has a name
|
||||
--> $DIR/issue-63388-1.rs:12:10
|
||||
|
|
||||
LL | async fn do_sth<'a>(
|
||||
| -- lifetime `'a` declared here
|
||||
LL | &'a self, foo: &dyn Foo
|
||||
LL | ) -> &dyn Foo
|
||||
| ^ this elided lifetime gets resolved as `'a`
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
|
||||
error[E0621]: explicit lifetime required in the type of `foo`
|
||||
--> $DIR/issue-63388-1.rs:14:9
|
||||
|
|
||||
|
|
@ -18,6 +7,6 @@ LL | &'a self, foo: &dyn Foo
|
|||
LL | foo
|
||||
| ^^^ lifetime `'a` required
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0621`.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ pub struct HelperStruct<'n> {
|
|||
}
|
||||
|
||||
impl DataStruct {
|
||||
pub fn f(&self) -> HelperStruct {
|
||||
pub fn f(&self) -> HelperStruct<'_> {
|
||||
let helpers = [vec![], vec![]];
|
||||
|
||||
HelperStruct { helpers: helpers.clone(), is_empty: helpers[0].is_empty() }
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ pub struct HelperStruct<'n> {
|
|||
}
|
||||
|
||||
impl DataStruct {
|
||||
pub fn f(&self) -> HelperStruct {
|
||||
pub fn f(&self) -> HelperStruct<'_> {
|
||||
let helpers = [vec![], vec![]];
|
||||
|
||||
HelperStruct { helpers, is_empty: helpers[0].is_empty() }
|
||||
|
|
|
|||
|
|
@ -1,10 +1,17 @@
|
|||
warning: elided lifetime has a name
|
||||
--> $DIR/issue-71348.rs:18:68
|
||||
warning: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/issue-71348.rs:18:40
|
||||
|
|
||||
LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
|
||||
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
|
||||
| ^^ -- ------------------------ the lifetimes get resolved as `'a`
|
||||
| | |
|
||||
| | the lifetimes get resolved as `'a`
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
= note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<'a, N>>::Target
|
||||
| +++
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,3 @@
|
|||
warning: elided lifetime has a name
|
||||
--> $DIR/issue-71348.rs:18:68
|
||||
|
|
||||
LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
|
||||
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
|
||||
error: `&'static str` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/issue-71348.rs:10:24
|
||||
|
|
||||
|
|
@ -38,5 +30,5 @@ help: add `#![feature(unsized_const_params)]` to the crate attributes to enable
|
|||
LL + #![feature(unsized_const_params)]
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ trait Get<'a, const N: &'static str> {
|
|||
impl Foo {
|
||||
fn ask<'a, const N: &'static str>(&'a self) -> &'a <Self as Get<N>>::Target
|
||||
//[min]~^ ERROR `&'static str` is forbidden as the type of a const generic parameter
|
||||
//~^^ WARNING elided lifetime has a name
|
||||
//[full]~^^ WARNING lifetime flowing from input to output with different syntax
|
||||
where
|
||||
Self: Get<'a, N>,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -589,7 +589,7 @@ impl Events {
|
|||
Ok(LogDrop(self, m))
|
||||
}
|
||||
/// Return an `Err` value that logs its drop.
|
||||
fn err(&self, m: u64) -> Result<LogDrop, LogDrop> {
|
||||
fn err(&self, m: u64) -> Result<LogDrop<'_>, LogDrop<'_>> {
|
||||
Err(LogDrop(self, m))
|
||||
}
|
||||
/// Log an event.
|
||||
|
|
|
|||
|
|
@ -589,7 +589,7 @@ impl Events {
|
|||
Ok(LogDrop(self, m))
|
||||
}
|
||||
/// Return an `Err` value that logs its drop.
|
||||
fn err(&self, m: u64) -> Result<LogDrop, LogDrop> {
|
||||
fn err(&self, m: u64) -> Result<LogDrop<'_>, LogDrop<'_>> {
|
||||
Err(LogDrop(self, m))
|
||||
}
|
||||
/// Log an event.
|
||||
|
|
|
|||
|
|
@ -23,11 +23,11 @@ impl Drop for LoudDrop<'_> {
|
|||
}
|
||||
|
||||
impl DropOrderCollector {
|
||||
fn option_loud_drop(&self, n: u32) -> Option<LoudDrop> {
|
||||
fn option_loud_drop(&self, n: u32) -> Option<LoudDrop<'_>> {
|
||||
Some(LoudDrop(self, n))
|
||||
}
|
||||
|
||||
fn loud_drop(&self, n: u32) -> LoudDrop {
|
||||
fn loud_drop(&self, n: u32) -> LoudDrop<'_> {
|
||||
LoudDrop(self, n)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ impl Drop for LoudDrop<'_> {
|
|||
}
|
||||
|
||||
impl DropOrderCollector {
|
||||
fn option_loud_drop(&self, n: u32) -> Option<LoudDrop> {
|
||||
fn option_loud_drop(&self, n: u32) -> Option<LoudDrop<'_>> {
|
||||
Some(LoudDrop(self, n))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ impl<'a> Drop for defer<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn defer(b: &Cell<bool>) -> defer {
|
||||
fn defer(b: &Cell<bool>) -> defer<'_> {
|
||||
defer {
|
||||
b: b
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ impl<'a> Drop for defer<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn defer(b: &Cell<bool>) -> defer {
|
||||
fn defer(b: &Cell<bool>) -> defer<'_> {
|
||||
defer {
|
||||
b: b
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ impl<'a> Drop for r<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn r(b: &Cell<isize>) -> r {
|
||||
fn r(b: &Cell<isize>) -> r<'_> {
|
||||
r {
|
||||
b: b
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@ impl Drop for LoudDrop<'_> {
|
|||
}
|
||||
|
||||
impl DropOrderCollector {
|
||||
fn option_loud_drop(&self, n: u32) -> Option<LoudDrop> {
|
||||
fn option_loud_drop(&self, n: u32) -> Option<LoudDrop<'_>> {
|
||||
Some(LoudDrop(self, n))
|
||||
}
|
||||
|
||||
fn loud_drop(&self, n: u32) -> LoudDrop {
|
||||
fn loud_drop(&self, n: u32) -> LoudDrop<'_> {
|
||||
LoudDrop(self, n)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//@ run-rustfix
|
||||
#![allow(dead_code, elided_named_lifetimes)]
|
||||
#![allow(dead_code, mismatched_lifetime_syntaxes)]
|
||||
#![deny(no_mangle_generic_items)]
|
||||
|
||||
pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//@ run-rustfix
|
||||
#![allow(dead_code, elided_named_lifetimes)]
|
||||
#![allow(dead_code, mismatched_lifetime_syntaxes)]
|
||||
#![deny(no_mangle_generic_items)]
|
||||
|
||||
#[export_name = "foo"]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//@ run-rustfix
|
||||
#![allow(dead_code, elided_named_lifetimes)]
|
||||
#![allow(dead_code, mismatched_lifetime_syntaxes)]
|
||||
#![deny(no_mangle_generic_items)]
|
||||
|
||||
pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//@ run-rustfix
|
||||
#![allow(dead_code, elided_named_lifetimes)]
|
||||
#![allow(dead_code, mismatched_lifetime_syntaxes)]
|
||||
#![deny(no_mangle_generic_items)]
|
||||
|
||||
#[no_mangle]
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ where
|
|||
|
||||
impl<T: 'static> Inject for RefMutFamily<T> {
|
||||
type I = Self;
|
||||
fn inject(_: &()) -> <Self::I as FamilyLt>::Out {
|
||||
fn inject(_: &()) -> <Self::I as FamilyLt<'_>>::Out {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) {
|
|||
|
||||
fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
|
||||
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
|
||||
//~| WARNING elided lifetime has a name
|
||||
|x| x
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/impl-fn-hrtb-bounds.rs:20:38
|
||||
--> $DIR/impl-fn-hrtb-bounds.rs:19:38
|
||||
|
|
||||
LL | fn d() -> impl Fn() -> (impl Debug + '_) {
|
||||
| ^^ expected named lifetime parameter
|
||||
|
|
@ -11,14 +11,6 @@ LL - fn d() -> impl Fn() -> (impl Debug + '_) {
|
|||
LL + fn d() -> impl Fn() -> (impl Debug + 'static) {
|
||||
|
|
||||
|
||||
warning: elided lifetime has a name
|
||||
--> $DIR/impl-fn-hrtb-bounds.rs:14:52
|
||||
|
|
||||
LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
|
||||
| -- lifetime `'a` declared here ^^ this elided lifetime gets resolved as `'a`
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
|
||||
error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
|
||||
--> $DIR/impl-fn-hrtb-bounds.rs:4:41
|
||||
|
|
||||
|
|
@ -55,7 +47,7 @@ note: lifetime declared here
|
|||
LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
|
||||
| ^^
|
||||
|
||||
error: aborting due to 4 previous errors; 1 warning emitted
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0106, E0657.
|
||||
For more information about an error, try `rustc --explain E0106`.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
|
||||
//~^ WARNING elided lifetime has a name
|
||||
|x| x
|
||||
//~^ ERROR expected generic lifetime parameter, found `'_`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,11 @@
|
|||
warning: elided lifetime has a name
|
||||
--> $DIR/impl-fn-predefined-lifetimes.rs:4:48
|
||||
|
|
||||
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
|
||||
| -- lifetime `'a` declared here ^^ this elided lifetime gets resolved as `'a`
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
|
||||
error[E0792]: expected generic lifetime parameter, found `'_`
|
||||
--> $DIR/impl-fn-predefined-lifetimes.rs:6:9
|
||||
--> $DIR/impl-fn-predefined-lifetimes.rs:5:9
|
||||
|
|
||||
LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
|
||||
| -- this generic parameter must be used with a generic lifetime parameter
|
||||
LL |
|
||||
LL | |x| x
|
||||
| ^
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0792`.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//@ check-pass
|
||||
|
||||
pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
|
||||
//~^ WARNING elided lifetime has a name
|
||||
//~^ WARNING lifetime flowing from input to output with different syntax
|
||||
v.into_iter()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
warning: elided lifetime has a name
|
||||
--> $DIR/rpit-assoc-pair-with-lifetime.rs:3:82
|
||||
warning: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/rpit-assoc-pair-with-lifetime.rs:3:31
|
||||
|
|
||||
LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
|
||||
| -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a`
|
||||
| ^^ this lifetime flows to the output ---- the lifetime gets resolved as `'a`
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
= note: `#[warn(mismatched_lifetime_syntaxes)]` on by default
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL | pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &'a u32)> {
|
||||
| ++
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ impl<'a> font<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn font(fontbuf: &Vec<u8> ) -> font {
|
||||
fn font(fontbuf: &Vec<u8> ) -> font<'_> {
|
||||
font {
|
||||
fontbuf: fontbuf
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//@ run-pass
|
||||
// Regression test for an obscure issue with the projection cache.
|
||||
|
||||
fn into_iter<I: Iterator>(a: &I) -> Groups<I> {
|
||||
fn into_iter<I: Iterator>(a: &I) -> Groups<'_, I> {
|
||||
Groups { _a: a }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ struct Outer<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Outer<'a> {
|
||||
fn new(inner: &dyn Inner) -> Outer {
|
||||
fn new(inner: &dyn Inner) -> Outer<'_> {
|
||||
Outer {
|
||||
inner: inner
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ impl Greeter1 for FixedGreeter<'_> {
|
|||
struct Greetings(pub Vec<String>);
|
||||
|
||||
impl Greetings {
|
||||
#[expect(mismatched_lifetime_syntaxes)]
|
||||
pub fn get(&self, i: usize) -> BoxedGreeter {
|
||||
(Box::new(FixedGreeter(&self.0[i])), Box::new(FixedGreeter(&self.0[i])))
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ impl Greeter1 for FixedGreeter<'_> {
|
|||
struct Greetings(pub Vec<String>);
|
||||
|
||||
impl Greetings {
|
||||
#[expect(mismatched_lifetime_syntaxes)]
|
||||
pub fn get(&self, i: usize) -> BoxedGreeter {
|
||||
(Box::new(FixedGreeter(&self.0[i])), Box::new(FixedGreeter(&self.0[i])))
|
||||
//~^ ERROR lifetime may not live long enough
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
error: lifetime may not live long enough
|
||||
--> $DIR/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs:32:9
|
||||
--> $DIR/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs:33:9
|
||||
|
|
||||
LL | pub fn get(&self, i: usize) -> BoxedGreeter {
|
||||
| - let's call the lifetime of this reference `'1`
|
||||
|
|
|
|||
|
|
@ -47,6 +47,5 @@ fn l<'a>(_: &'a str, _: &'a str) -> &str { "" }
|
|||
|
||||
// This is ok because both `'a` are for the same parameter.
|
||||
fn m<'a>(_: &'a Foo<'a>) -> &str { "" }
|
||||
//~^ WARNING elided lifetime has a name
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -105,16 +105,6 @@ help: consider using the `'a` lifetime
|
|||
LL | fn l<'a>(_: &'a str, _: &'a str) -> &'a str { "" }
|
||||
| ++
|
||||
|
||||
warning: elided lifetime has a name
|
||||
--> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:49:29
|
||||
|
|
||||
LL | fn m<'a>(_: &'a Foo<'a>) -> &str { "" }
|
||||
| -- ^ this elided lifetime gets resolved as `'a`
|
||||
| |
|
||||
| lifetime `'a` declared here
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
|
||||
error: aborting due to 7 previous errors; 1 warning emitted
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0106`.
|
||||
|
|
|
|||
|
|
@ -4,12 +4,8 @@ struct Foo {
|
|||
|
||||
impl Foo {
|
||||
fn foo<'a>(&'a self, x: &i32) -> &i32 {
|
||||
//~^ WARNING elided lifetime has a name
|
||||
|
||||
if true { &self.field } else { x } //~ ERROR explicit lifetime
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
|
|
|||
|
|
@ -1,22 +1,11 @@
|
|||
warning: elided lifetime has a name
|
||||
--> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:6:36
|
||||
|
|
||||
LL | fn foo<'a>(&'a self, x: &i32) -> &i32 {
|
||||
| -- ^ this elided lifetime gets resolved as `'a`
|
||||
| |
|
||||
| lifetime `'a` declared here
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
|
||||
error[E0621]: explicit lifetime required in the type of `x`
|
||||
--> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:9:36
|
||||
--> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:7:36
|
||||
|
|
||||
LL | fn foo<'a>(&'a self, x: &i32) -> &i32 {
|
||||
| ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
|
||||
...
|
||||
LL | if true { &self.field } else { x }
|
||||
| ^ lifetime `'a` required
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0621`.
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#![deny(elided_named_lifetimes)]
|
||||
#![deny(mismatched_lifetime_syntaxes)]
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
|
||||
//~^ ERROR elided lifetime has a name
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
unsafe { &mut *(x as *mut _) }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/example-from-issue48686.rs:6:21
|
||||
|
|
||||
LL | pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
|
||||
| ^^^^^^^ ------- the lifetime gets resolved as `'static`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/example-from-issue48686.rs:1:9
|
||||
|
|
||||
LL | #![deny(mismatched_lifetime_syntaxes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: one option is to consistently use `'static`
|
||||
|
|
||||
LL | pub fn get_mut(&'static self, x: &mut u8) -> &'static mut u8 {
|
||||
| +++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#![deny(mismatched_lifetime_syntaxes)]
|
||||
|
||||
fn ampersand<'a>(x: &'a u8) -> &u8 {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
x
|
||||
}
|
||||
|
||||
struct Brackets<'a>(&'a u8);
|
||||
|
||||
fn brackets<'a>(x: &'a u8) -> Brackets {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
Brackets(x)
|
||||
}
|
||||
|
||||
struct Comma<'a, T>(&'a T);
|
||||
|
||||
fn comma<'a>(x: &'a u8) -> Comma<u8> {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
Comma(x)
|
||||
}
|
||||
|
||||
fn underscore<'a>(x: &'a u8) -> &'_ u8 {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/missing-lifetime-kind.rs:3:22
|
||||
|
|
||||
LL | fn ampersand<'a>(x: &'a u8) -> &u8 {
|
||||
| ^^ --- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/missing-lifetime-kind.rs:1:9
|
||||
|
|
||||
LL | #![deny(mismatched_lifetime_syntaxes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL | fn ampersand<'a>(x: &'a u8) -> &'a u8 {
|
||||
| ++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/missing-lifetime-kind.rs:10:21
|
||||
|
|
||||
LL | fn brackets<'a>(x: &'a u8) -> Brackets {
|
||||
| ^^ -------- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL | fn brackets<'a>(x: &'a u8) -> Brackets<'a> {
|
||||
| ++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/missing-lifetime-kind.rs:17:18
|
||||
|
|
||||
LL | fn comma<'a>(x: &'a u8) -> Comma<u8> {
|
||||
| ^^ --------- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL | fn comma<'a>(x: &'a u8) -> Comma<'a, u8> {
|
||||
| +++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/missing-lifetime-kind.rs:22:23
|
||||
|
|
||||
LL | fn underscore<'a>(x: &'a u8) -> &'_ u8 {
|
||||
| ^^ -- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL - fn underscore<'a>(x: &'a u8) -> &'_ u8 {
|
||||
LL + fn underscore<'a>(x: &'a u8) -> &'a u8 {
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#![allow(mismatched_lifetime_syntaxes)]
|
||||
|
||||
//! Ensure that the lint level of `mismatched_lifetime_syntaxes` can
|
||||
//! be adjusted by attributes not applied at the crate-level.
|
||||
|
||||
#[warn(mismatched_lifetime_syntaxes)]
|
||||
mod foo {
|
||||
fn bar(x: &'static u8) -> &u8 {
|
||||
//~^ WARNING lifetime flowing from input to output with different syntax
|
||||
x
|
||||
}
|
||||
|
||||
#[deny(mismatched_lifetime_syntaxes)]
|
||||
fn baz(x: &'static u8) -> &u8 {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
x
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
warning: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/not-tied-to-crate.rs:8:16
|
||||
|
|
||||
LL | fn bar(x: &'static u8) -> &u8 {
|
||||
| ^^^^^^^ --- the lifetime gets resolved as `'static`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/not-tied-to-crate.rs:6:8
|
||||
|
|
||||
LL | #[warn(mismatched_lifetime_syntaxes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: one option is to consistently use `'static`
|
||||
|
|
||||
LL | fn bar(x: &'static u8) -> &'static u8 {
|
||||
| +++++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/not-tied-to-crate.rs:14:16
|
||||
|
|
||||
LL | fn baz(x: &'static u8) -> &u8 {
|
||||
| ^^^^^^^ --- the lifetime gets resolved as `'static`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/not-tied-to-crate.rs:13:12
|
||||
|
|
||||
LL | #[deny(mismatched_lifetime_syntaxes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: one option is to consistently use `'static`
|
||||
|
|
||||
LL | fn baz(x: &'static u8) -> &'static u8 {
|
||||
| +++++++
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#![deny(elided_named_lifetimes)]
|
||||
#![deny(mismatched_lifetime_syntaxes)]
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
|
|
@ -14,26 +14,26 @@ impl Trait for () {
|
|||
}
|
||||
|
||||
fn ampersand(x: &'static u8) -> &u8 {
|
||||
//~^ ERROR elided lifetime has a name
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
x
|
||||
}
|
||||
|
||||
struct Brackets<'a>(&'a u8);
|
||||
|
||||
fn brackets(x: &'static u8) -> Brackets {
|
||||
//~^ ERROR elided lifetime has a name
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
Brackets(x)
|
||||
}
|
||||
|
||||
struct Comma<'a, T>(&'a T);
|
||||
|
||||
fn comma(x: &'static u8) -> Comma<u8> {
|
||||
//~^ ERROR elided lifetime has a name
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
Comma(x)
|
||||
}
|
||||
|
||||
fn underscore(x: &'static u8) -> &'_ u8 {
|
||||
//~^ ERROR elided lifetime has a name
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
x
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/static.rs:16:18
|
||||
|
|
||||
LL | fn ampersand(x: &'static u8) -> &u8 {
|
||||
| ^^^^^^^ --- the lifetime gets resolved as `'static`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/static.rs:1:9
|
||||
|
|
||||
LL | #![deny(mismatched_lifetime_syntaxes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: one option is to consistently use `'static`
|
||||
|
|
||||
LL | fn ampersand(x: &'static u8) -> &'static u8 {
|
||||
| +++++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/static.rs:23:17
|
||||
|
|
||||
LL | fn brackets(x: &'static u8) -> Brackets {
|
||||
| ^^^^^^^ -------- the lifetime gets resolved as `'static`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'static`
|
||||
|
|
||||
LL | fn brackets(x: &'static u8) -> Brackets<'static> {
|
||||
| +++++++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/static.rs:30:14
|
||||
|
|
||||
LL | fn comma(x: &'static u8) -> Comma<u8> {
|
||||
| ^^^^^^^ --------- the lifetime gets resolved as `'static`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'static`
|
||||
|
|
||||
LL | fn comma(x: &'static u8) -> Comma<'static, u8> {
|
||||
| ++++++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/static.rs:35:19
|
||||
|
|
||||
LL | fn underscore(x: &'static u8) -> &'_ u8 {
|
||||
| ^^^^^^^ -- the lifetime gets resolved as `'static`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'static`
|
||||
|
|
||||
LL - fn underscore(x: &'static u8) -> &'_ u8 {
|
||||
LL + fn underscore(x: &'static u8) -> &'static u8 {
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
315
tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs
Normal file
315
tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
#![deny(mismatched_lifetime_syntaxes)]
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct ContainsLifetime<'a>(&'a u8);
|
||||
|
||||
struct S(u8);
|
||||
|
||||
fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
v
|
||||
}
|
||||
|
||||
fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
v
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
v
|
||||
}
|
||||
|
||||
fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
v
|
||||
}
|
||||
|
||||
fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
v
|
||||
}
|
||||
|
||||
fn explicit_bound_path_to_explicit_anonymous_path<'a>(
|
||||
v: ContainsLifetime<'a>,
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
) -> ContainsLifetime<'_> {
|
||||
v
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
ContainsLifetime(v)
|
||||
}
|
||||
|
||||
fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
ContainsLifetime(v)
|
||||
}
|
||||
|
||||
fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
ContainsLifetime(v)
|
||||
}
|
||||
|
||||
fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
ContainsLifetime(v)
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
v.0
|
||||
}
|
||||
|
||||
fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
v.0
|
||||
}
|
||||
|
||||
fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
v.0
|
||||
}
|
||||
|
||||
fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
v.0
|
||||
}
|
||||
|
||||
impl S {
|
||||
fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
&self.0
|
||||
}
|
||||
|
||||
fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
&self.0
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
ContainsLifetime(&self.0)
|
||||
}
|
||||
|
||||
fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
ContainsLifetime(&self.0)
|
||||
}
|
||||
|
||||
fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
ContainsLifetime(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
// If a function uses the `'static` lifetime, we should not suggest
|
||||
// replacing it with an explicitly anonymous or implicit
|
||||
// lifetime. Only suggest using `'static` everywhere.
|
||||
mod static_suggestions {
|
||||
#[derive(Copy, Clone)]
|
||||
struct ContainsLifetime<'a>(&'a u8);
|
||||
|
||||
struct S(u8);
|
||||
|
||||
fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
v
|
||||
}
|
||||
|
||||
fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
v
|
||||
}
|
||||
|
||||
fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
ContainsLifetime(v)
|
||||
}
|
||||
|
||||
fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
ContainsLifetime(v)
|
||||
}
|
||||
|
||||
impl S {
|
||||
fn static_ref_to_implicit_ref(&'static self) -> &u8 {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
&self.0
|
||||
}
|
||||
|
||||
fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
&self.0
|
||||
}
|
||||
|
||||
fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
ContainsLifetime(&self.0)
|
||||
}
|
||||
|
||||
fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
ContainsLifetime(&self.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `impl Trait` uses lifetimes in some additional ways.
|
||||
mod impl_trait {
|
||||
#[derive(Copy, Clone)]
|
||||
struct ContainsLifetime<'a>(&'a u8);
|
||||
|
||||
fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
move || _ = v
|
||||
}
|
||||
|
||||
fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
move || _ = v
|
||||
}
|
||||
|
||||
fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
move || _ = v
|
||||
}
|
||||
|
||||
fn explicit_bound_path_to_impl_trait_precise_capture<'a>(
|
||||
v: ContainsLifetime<'a>,
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
) -> impl FnOnce() + use<'_> {
|
||||
move || _ = v
|
||||
}
|
||||
}
|
||||
|
||||
/// `dyn Trait` uses lifetimes in some additional ways.
|
||||
mod dyn_trait {
|
||||
use std::iter;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct ContainsLifetime<'a>(&'a u8);
|
||||
|
||||
fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box<dyn Iterator<Item = &u8> + '_> {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
Box::new(iter::once(v))
|
||||
}
|
||||
|
||||
fn explicit_bound_path_to_dyn_trait_bound<'a>(
|
||||
v: ContainsLifetime<'a>,
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
) -> Box<dyn Iterator<Item = ContainsLifetime> + '_> {
|
||||
Box::new(iter::once(v))
|
||||
}
|
||||
}
|
||||
|
||||
/// These tests serve to exercise edge cases of the lint formatting
|
||||
mod diagnostic_output {
|
||||
fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) {
|
||||
//~^ ERROR lifetime flowing from input to output with different syntax
|
||||
(v, v)
|
||||
}
|
||||
}
|
||||
|
||||
/// These usages are expected to **not** trigger the lint
|
||||
mod acceptable_uses {
|
||||
#[derive(Copy, Clone)]
|
||||
struct ContainsLifetime<'a>(&'a u8);
|
||||
|
||||
struct S(u8);
|
||||
|
||||
fn implicit_ref_to_implicit_ref(v: &u8) -> &u8 {
|
||||
v
|
||||
}
|
||||
|
||||
fn explicit_anonymous_ref_to_explicit_anonymous_ref(v: &'_ u8) -> &'_ u8 {
|
||||
v
|
||||
}
|
||||
|
||||
fn explicit_bound_ref_to_explicit_bound_ref<'a>(v: &'a u8) -> &'a u8 {
|
||||
v
|
||||
}
|
||||
|
||||
fn implicit_path_to_implicit_path(v: ContainsLifetime) -> ContainsLifetime {
|
||||
v
|
||||
}
|
||||
|
||||
fn explicit_anonymous_path_to_explicit_anonymous_path(
|
||||
v: ContainsLifetime<'_>,
|
||||
) -> ContainsLifetime<'_> {
|
||||
v
|
||||
}
|
||||
|
||||
fn explicit_bound_path_to_explicit_bound_path<'a>(
|
||||
v: ContainsLifetime<'a>,
|
||||
) -> ContainsLifetime<'a> {
|
||||
v
|
||||
}
|
||||
|
||||
fn explicit_anonymous_ref_to_explicit_anonymous_path(v: &'_ u8) -> ContainsLifetime<'_> {
|
||||
ContainsLifetime(v)
|
||||
}
|
||||
|
||||
fn explicit_bound_ref_to_explicit_bound_path<'a>(v: &'a u8) -> ContainsLifetime<'a> {
|
||||
ContainsLifetime(v)
|
||||
}
|
||||
|
||||
fn explicit_anonymous_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &'_ u8 {
|
||||
v.0
|
||||
}
|
||||
|
||||
fn explicit_bound_path_to_explicit_bound_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 {
|
||||
v.0
|
||||
}
|
||||
|
||||
// These may be surprising, but ampersands count as enough of a
|
||||
// visual indicator that a reference exists that we treat
|
||||
// references with implicit lifetimes the same as if they were
|
||||
// explicitly anonymous.
|
||||
fn implicit_ref_to_explicit_anonymous_ref(v: &u8) -> &'_ u8 {
|
||||
v
|
||||
}
|
||||
|
||||
fn explicit_anonymous_ref_to_implicit_ref(v: &'_ u8) -> &u8 {
|
||||
v
|
||||
}
|
||||
|
||||
fn implicit_ref_to_explicit_anonymous_path(v: &u8) -> ContainsLifetime<'_> {
|
||||
ContainsLifetime(v)
|
||||
}
|
||||
|
||||
fn explicit_anonymous_path_to_implicit_ref(v: ContainsLifetime<'_>) -> &u8 {
|
||||
v.0
|
||||
}
|
||||
|
||||
impl S {
|
||||
fn method_implicit_ref_to_explicit_anonymous_ref(&self) -> &'_ u8 {
|
||||
&self.0
|
||||
}
|
||||
|
||||
fn method_explicit_anonymous_ref_to_implicit_ref(&'_ self) -> &u8 {
|
||||
&self.0
|
||||
}
|
||||
|
||||
fn method_implicit_ref_to_explicit_anonymous_path(&self) -> ContainsLifetime<'_> {
|
||||
ContainsLifetime(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
// `dyn Trait` has an "embedded" lifetime that we should **not**
|
||||
// lint about.
|
||||
fn dyn_trait_does_not_have_a_lifetime_generic(v: &u8) -> &dyn core::fmt::Debug {
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
473
tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr
Normal file
473
tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr
Normal file
|
|
@ -0,0 +1,473 @@
|
|||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:8:47
|
||||
|
|
||||
LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &u8 {
|
||||
| ^^ --- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:1:9
|
||||
|
|
||||
LL | #![deny(mismatched_lifetime_syntaxes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL | fn explicit_bound_ref_to_implicit_ref<'a>(v: &'a u8) -> &'a u8 {
|
||||
| ++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:13:57
|
||||
|
|
||||
LL | fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 {
|
||||
| ^^ -- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL - fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'_ u8 {
|
||||
LL + fn explicit_bound_ref_to_explicit_anonymous_ref<'a>(v: &'a u8) -> &'a u8 {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:20:48
|
||||
|
|
||||
LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime) -> ContainsLifetime<'_> {
|
||||
| ^^^^^^^^^^^^^^^^ -- the lifetime gets resolved as `'_`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'_`
|
||||
|
|
||||
LL | fn implicit_path_to_explicit_anonymous_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> {
|
||||
| ++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:25:65
|
||||
|
|
||||
LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime {
|
||||
| ^^ ---------------- the lifetime gets resolved as `'_`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'_`
|
||||
|
|
||||
LL | fn explicit_anonymous_path_to_implicit_path(v: ContainsLifetime<'_>) -> ContainsLifetime<'_> {
|
||||
| ++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:30:65
|
||||
|
|
||||
LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime {
|
||||
| ^^ ---------------- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL | fn explicit_bound_path_to_implicit_path<'a>(v: ContainsLifetime<'a>) -> ContainsLifetime<'a> {
|
||||
| ++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:36:25
|
||||
|
|
||||
LL | v: ContainsLifetime<'a>,
|
||||
| ^^ this lifetime flows to the output
|
||||
LL |
|
||||
LL | ) -> ContainsLifetime<'_> {
|
||||
| -- the lifetime gets resolved as `'a`
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL - ) -> ContainsLifetime<'_> {
|
||||
LL + ) -> ContainsLifetime<'a> {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:44:37
|
||||
|
|
||||
LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime {
|
||||
| ^^^ ---------------- the lifetime gets resolved as `'_`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
|
||||
|
|
||||
LL | fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> {
|
||||
| ++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:49:48
|
||||
|
|
||||
LL | fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime {
|
||||
| ^^ ---------------- the lifetime gets resolved as `'_`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
|
||||
|
|
||||
LL - fn explicit_anonymous_ref_to_implicit_path(v: &'_ u8) -> ContainsLifetime {
|
||||
LL + fn explicit_anonymous_ref_to_implicit_path(v: &u8) -> ContainsLifetime<'_> {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:54:48
|
||||
|
|
||||
LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime {
|
||||
| ^^ ---------------- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL | fn explicit_bound_ref_to_implicit_path<'a>(v: &'a u8) -> ContainsLifetime<'a> {
|
||||
| ++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:59:58
|
||||
|
|
||||
LL | fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> {
|
||||
| ^^ -- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL - fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'_> {
|
||||
LL + fn explicit_bound_ref_to_explicit_anonymous_path<'a>(v: &'a u8) -> ContainsLifetime<'a> {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:66:37
|
||||
|
|
||||
LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime) -> &u8 {
|
||||
| ^^^^^^^^^^^^^^^^ --- the lifetime gets resolved as `'_`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
|
||||
|
|
||||
LL | fn implicit_path_to_implicit_ref(v: ContainsLifetime<'_>) -> &u8 {
|
||||
| ++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:71:47
|
||||
|
|
||||
LL | fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 {
|
||||
| ^^^^^^^^^^^^^^^^ -- the lifetime gets resolved as `'_`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
|
||||
|
|
||||
LL - fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime) -> &'_ u8 {
|
||||
LL + fn implicit_path_to_explicit_anonymous_ref(v: ContainsLifetime<'_>) -> &u8 {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:76:64
|
||||
|
|
||||
LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &u8 {
|
||||
| ^^ --- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL | fn explicit_bound_path_to_implicit_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 {
|
||||
| ++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:81:74
|
||||
|
|
||||
LL | fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 {
|
||||
| ^^ -- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL - fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'_ u8 {
|
||||
LL + fn explicit_bound_path_to_explicit_anonymous_ref<'a>(v: ContainsLifetime<'a>) -> &'a u8 {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:87:55
|
||||
|
|
||||
LL | fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &u8 {
|
||||
| ^^ --- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL | fn method_explicit_bound_ref_to_implicit_ref<'a>(&'a self) -> &'a u8 {
|
||||
| ++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:92:65
|
||||
|
|
||||
LL | fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 {
|
||||
| ^^ -- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL - fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'_ u8 {
|
||||
LL + fn method_explicit_bound_ref_to_explicit_anonymous_ref<'a>(&'a self) -> &'a u8 {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:99:56
|
||||
|
|
||||
LL | fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime {
|
||||
| ^^ ---------------- the lifetime gets resolved as `'_`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to remove the lifetime for references and use the anonymous lifetime for paths
|
||||
|
|
||||
LL - fn method_explicit_anonymous_ref_to_implicit_path(&'_ self) -> ContainsLifetime {
|
||||
LL + fn method_explicit_anonymous_ref_to_implicit_path(&self) -> ContainsLifetime<'_> {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:104:56
|
||||
|
|
||||
LL | fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime {
|
||||
| ^^ ---------------- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL | fn method_explicit_bound_ref_to_implicit_path<'a>(&'a self) -> ContainsLifetime<'a> {
|
||||
| ++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:109:66
|
||||
|
|
||||
LL | fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> {
|
||||
| ^^ -- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL - fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'_> {
|
||||
LL + fn method_explicit_bound_ref_to_explicit_anonymous_path<'a>(&'a self) -> ContainsLifetime<'a> {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:124:39
|
||||
|
|
||||
LL | fn static_ref_to_implicit_ref(v: &'static u8) -> &u8 {
|
||||
| ^^^^^^^ --- the lifetime gets resolved as `'static`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'static`
|
||||
|
|
||||
LL | fn static_ref_to_implicit_ref(v: &'static u8) -> &'static u8 {
|
||||
| +++++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:129:49
|
||||
|
|
||||
LL | fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 {
|
||||
| ^^^^^^^ -- the lifetime gets resolved as `'static`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'static`
|
||||
|
|
||||
LL - fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'_ u8 {
|
||||
LL + fn static_ref_to_explicit_anonymous_ref(v: &'static u8) -> &'static u8 {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:134:40
|
||||
|
|
||||
LL | fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime {
|
||||
| ^^^^^^^ ---------------- the lifetime gets resolved as `'static`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'static`
|
||||
|
|
||||
LL | fn static_ref_to_implicit_path(v: &'static u8) -> ContainsLifetime<'static> {
|
||||
| +++++++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:139:50
|
||||
|
|
||||
LL | fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> {
|
||||
| ^^^^^^^ -- the lifetime gets resolved as `'static`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'static`
|
||||
|
|
||||
LL - fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'_> {
|
||||
LL + fn static_ref_to_explicit_anonymous_path(v: &'static u8) -> ContainsLifetime<'static> {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:145:40
|
||||
|
|
||||
LL | fn static_ref_to_implicit_ref(&'static self) -> &u8 {
|
||||
| ^^^^^^^ --- the lifetime gets resolved as `'static`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'static`
|
||||
|
|
||||
LL | fn static_ref_to_implicit_ref(&'static self) -> &'static u8 {
|
||||
| +++++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:150:50
|
||||
|
|
||||
LL | fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 {
|
||||
| ^^^^^^^ -- the lifetime gets resolved as `'static`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'static`
|
||||
|
|
||||
LL - fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'_ u8 {
|
||||
LL + fn static_ref_to_explicit_anonymous_ref(&'static self) -> &'static u8 {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:155:41
|
||||
|
|
||||
LL | fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime {
|
||||
| ^^^^^^^ ---------------- the lifetime gets resolved as `'static`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'static`
|
||||
|
|
||||
LL | fn static_ref_to_implicit_path(&'static self) -> ContainsLifetime<'static> {
|
||||
| +++++++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:160:51
|
||||
|
|
||||
LL | fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> {
|
||||
| ^^^^^^^ -- the lifetime gets resolved as `'static`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'static`
|
||||
|
|
||||
LL - fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'_> {
|
||||
LL + fn static_ref_to_explicit_anonymous_path(&'static self) -> ContainsLifetime<'static> {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:172:55
|
||||
|
|
||||
LL | fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ {
|
||||
| ^^ -- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL - fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + '_ {
|
||||
LL + fn explicit_bound_ref_to_impl_trait_bound<'a>(v: &'a u8) -> impl FnOnce() + 'a {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:177:65
|
||||
|
|
||||
LL | fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> {
|
||||
| ^^ -- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL - fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'_> {
|
||||
LL + fn explicit_bound_ref_to_impl_trait_precise_capture<'a>(v: &'a u8) -> impl FnOnce() + use<'a> {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:182:72
|
||||
|
|
||||
LL | fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ {
|
||||
| ^^ -- the lifetime gets resolved as `'a`
|
||||
| |
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL - fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + '_ {
|
||||
LL + fn explicit_bound_path_to_impl_trait_bound<'a>(v: ContainsLifetime<'a>) -> impl FnOnce() + 'a {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:188:29
|
||||
|
|
||||
LL | v: ContainsLifetime<'a>,
|
||||
| ^^ this lifetime flows to the output
|
||||
LL |
|
||||
LL | ) -> impl FnOnce() + use<'_> {
|
||||
| -- the lifetime gets resolved as `'a`
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL - ) -> impl FnOnce() + use<'_> {
|
||||
LL + ) -> impl FnOnce() + use<'a> {
|
||||
|
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:202:54
|
||||
|
|
||||
LL | fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box<dyn Iterator<Item = &u8> + '_> {
|
||||
| ^^ --- -- the lifetimes get resolved as `'a`
|
||||
| | |
|
||||
| | the lifetimes get resolved as `'a`
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL | fn explicit_bound_ref_to_dyn_trait_bound<'a>(v: &'a u8) -> Box<dyn Iterator<Item = &'a u8> + '_> {
|
||||
| ++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:208:29
|
||||
|
|
||||
LL | v: ContainsLifetime<'a>,
|
||||
| ^^ this lifetime flows to the output
|
||||
LL |
|
||||
LL | ) -> Box<dyn Iterator<Item = ContainsLifetime> + '_> {
|
||||
| ---------------- -- the lifetimes get resolved as `'a`
|
||||
| |
|
||||
| the lifetimes get resolved as `'a`
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL | ) -> Box<dyn Iterator<Item = ContainsLifetime<'a>> + '_> {
|
||||
| ++++
|
||||
|
||||
error: lifetime flowing from input to output with different syntax can be confusing
|
||||
--> $DIR/mismatched-lifetime-syntaxes.rs:217:33
|
||||
|
|
||||
LL | fn multiple_outputs<'a>(v: &'a u8) -> (&u8, &u8) {
|
||||
| ^^ --- --- the lifetimes get resolved as `'a`
|
||||
| | |
|
||||
| | the lifetimes get resolved as `'a`
|
||||
| this lifetime flows to the output
|
||||
|
|
||||
help: one option is to consistently use `'a`
|
||||
|
|
||||
LL | fn multiple_outputs<'a>(v: &'a u8) -> (&'a u8, &'a u8) {
|
||||
| ++ ++
|
||||
|
||||
error: aborting due to 34 previous errors
|
||||
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
error: elided lifetime has a name
|
||||
--> $DIR/example-from-issue48686.rs:6:50
|
||||
|
|
||||
LL | pub fn get_mut(&'static self, x: &mut u8) -> &mut u8 {
|
||||
| ^ this elided lifetime gets resolved as `'static`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/example-from-issue48686.rs:1:9
|
||||
|
|
||||
LL | #![deny(elided_named_lifetimes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: consider specifying it explicitly
|
||||
|
|
||||
LL | pub fn get_mut(&'static self, x: &mut u8) -> &'static mut u8 {
|
||||
| +++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
#![deny(elided_named_lifetimes)]
|
||||
|
||||
fn ampersand<'a>(x: &'a u8) -> &u8 {
|
||||
//~^ ERROR elided lifetime has a name
|
||||
x
|
||||
}
|
||||
|
||||
struct Brackets<'a>(&'a u8);
|
||||
|
||||
fn brackets<'a>(x: &'a u8) -> Brackets {
|
||||
//~^ ERROR elided lifetime has a name
|
||||
Brackets(x)
|
||||
}
|
||||
|
||||
struct Comma<'a, T>(&'a T);
|
||||
|
||||
fn comma<'a>(x: &'a u8) -> Comma<u8> {
|
||||
//~^ ERROR elided lifetime has a name
|
||||
Comma(x)
|
||||
}
|
||||
|
||||
fn underscore<'a>(x: &'a u8) -> &'_ u8 {
|
||||
//~^ ERROR elided lifetime has a name
|
||||
x
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
error: elided lifetime has a name
|
||||
--> $DIR/missing-lifetime-kind.rs:3:32
|
||||
|
|
||||
LL | fn ampersand<'a>(x: &'a u8) -> &u8 {
|
||||
| -- ^ this elided lifetime gets resolved as `'a`
|
||||
| |
|
||||
| lifetime `'a` declared here
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/missing-lifetime-kind.rs:1:9
|
||||
|
|
||||
LL | #![deny(elided_named_lifetimes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: elided lifetime has a name
|
||||
--> $DIR/missing-lifetime-kind.rs:10:31
|
||||
|
|
||||
LL | fn brackets<'a>(x: &'a u8) -> Brackets {
|
||||
| -- ^^^^^^^^ this elided lifetime gets resolved as `'a`
|
||||
| |
|
||||
| lifetime `'a` declared here
|
||||
|
||||
error: elided lifetime has a name
|
||||
--> $DIR/missing-lifetime-kind.rs:17:33
|
||||
|
|
||||
LL | fn comma<'a>(x: &'a u8) -> Comma<u8> {
|
||||
| -- ^ this elided lifetime gets resolved as `'a`
|
||||
| |
|
||||
| lifetime `'a` declared here
|
||||
|
||||
error: elided lifetime has a name
|
||||
--> $DIR/missing-lifetime-kind.rs:22:34
|
||||
|
|
||||
LL | fn underscore<'a>(x: &'a u8) -> &'_ u8 {
|
||||
| -- ^^ this elided lifetime gets resolved as `'a`
|
||||
| |
|
||||
| lifetime `'a` declared here
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#![allow(elided_named_lifetimes)]
|
||||
|
||||
#[warn(elided_named_lifetimes)]
|
||||
mod foo {
|
||||
fn bar(x: &'static u8) -> &u8 {
|
||||
//~^ WARNING elided lifetime has a name
|
||||
x
|
||||
}
|
||||
|
||||
#[deny(elided_named_lifetimes)]
|
||||
fn baz(x: &'static u8) -> &u8 {
|
||||
//~^ ERROR elided lifetime has a name
|
||||
x
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
warning: elided lifetime has a name
|
||||
--> $DIR/not-tied-to-crate.rs:5:31
|
||||
|
|
||||
LL | fn bar(x: &'static u8) -> &u8 {
|
||||
| ^ this elided lifetime gets resolved as `'static`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/not-tied-to-crate.rs:3:8
|
||||
|
|
||||
LL | #[warn(elided_named_lifetimes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: consider specifying it explicitly
|
||||
|
|
||||
LL | fn bar(x: &'static u8) -> &'static u8 {
|
||||
| +++++++
|
||||
|
||||
error: elided lifetime has a name
|
||||
--> $DIR/not-tied-to-crate.rs:11:31
|
||||
|
|
||||
LL | fn baz(x: &'static u8) -> &u8 {
|
||||
| ^ this elided lifetime gets resolved as `'static`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/not-tied-to-crate.rs:10:12
|
||||
|
|
||||
LL | #[deny(elided_named_lifetimes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: consider specifying it explicitly
|
||||
|
|
||||
LL | fn baz(x: &'static u8) -> &'static u8 {
|
||||
| +++++++
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
error: elided lifetime has a name
|
||||
--> $DIR/static.rs:16:33
|
||||
|
|
||||
LL | fn ampersand(x: &'static u8) -> &u8 {
|
||||
| ^ this elided lifetime gets resolved as `'static`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/static.rs:1:9
|
||||
|
|
||||
LL | #![deny(elided_named_lifetimes)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: consider specifying it explicitly
|
||||
|
|
||||
LL | fn ampersand(x: &'static u8) -> &'static u8 {
|
||||
| +++++++
|
||||
|
||||
error: elided lifetime has a name
|
||||
--> $DIR/static.rs:23:32
|
||||
|
|
||||
LL | fn brackets(x: &'static u8) -> Brackets {
|
||||
| ^^^^^^^^ this elided lifetime gets resolved as `'static`
|
||||
|
|
||||
help: consider specifying it explicitly
|
||||
|
|
||||
LL | fn brackets(x: &'static u8) -> Brackets<'static> {
|
||||
| +++++++++
|
||||
|
||||
error: elided lifetime has a name
|
||||
--> $DIR/static.rs:30:34
|
||||
|
|
||||
LL | fn comma(x: &'static u8) -> Comma<u8> {
|
||||
| ^ this elided lifetime gets resolved as `'static`
|
||||
|
|
||||
help: consider specifying it explicitly
|
||||
|
|
||||
LL | fn comma(x: &'static u8) -> Comma<'static, u8> {
|
||||
| ++++++++
|
||||
|
||||
error: elided lifetime has a name
|
||||
--> $DIR/static.rs:35:35
|
||||
|
|
||||
LL | fn underscore(x: &'static u8) -> &'_ u8 {
|
||||
| ^^ this elided lifetime gets resolved as `'static`
|
||||
|
|
||||
help: consider specifying it explicitly
|
||||
|
|
||||
LL - fn underscore(x: &'static u8) -> &'_ u8 {
|
||||
LL + fn underscore(x: &'static u8) -> &'static u8 {
|
||||
|
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
@ -5,7 +5,7 @@ use std::fmt::{self, Display};
|
|||
struct Mutex;
|
||||
|
||||
impl Mutex {
|
||||
fn lock(&self) -> MutexGuard {
|
||||
fn lock(&self) -> MutexGuard<'_> {
|
||||
MutexGuard(self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,11 +20,11 @@ fn fat_ptr_via_local(a: &[u8]) -> &[u8] {
|
|||
x
|
||||
}
|
||||
|
||||
fn fat_ptr_from_struct(s: FatPtrContainer) -> &[u8] {
|
||||
fn fat_ptr_from_struct(s: FatPtrContainer<'_>) -> &[u8] {
|
||||
s.ptr
|
||||
}
|
||||
|
||||
fn fat_ptr_to_struct(a: &[u8]) -> FatPtrContainer {
|
||||
fn fat_ptr_to_struct(a: &[u8]) -> FatPtrContainer<'_> {
|
||||
FatPtrContainer { ptr: a }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ struct Scratchpad<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Scratchpad<'a> {
|
||||
fn get<T: GenericVec<T>>(&self) -> Ref<[T]>
|
||||
fn get<T: GenericVec<T>>(&self) -> Ref<'_, [T]>
|
||||
where T: 'a
|
||||
{
|
||||
Ref::map(self.buffers.borrow(), |x| T::unwrap(x.as_ref()))
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ impl Drop for Mutex { fn drop(&mut self) { println!("Mutex::drop"); } }
|
|||
impl<'a> Drop for MutexGuard<'a> { fn drop(&mut self) { println!("MutexGuard::drop"); } }
|
||||
|
||||
impl Mutex {
|
||||
fn lock(&self) -> Result<MutexGuard, ()> { Ok(MutexGuard(self)) }
|
||||
fn lock(&self) -> Result<MutexGuard<'_>, ()> { Ok(MutexGuard(self)) }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
|||
|
|
@ -46,8 +46,6 @@ fn load1(ss: &dyn SomeTrait) -> &dyn SomeTrait {
|
|||
}
|
||||
|
||||
fn load2<'a>(ss: &'a dyn SomeTrait) -> &dyn SomeTrait {
|
||||
//~^ WARNING elided lifetime has a name
|
||||
|
||||
// Same as `load1` but with an explicit name thrown in for fun.
|
||||
|
||||
ss
|
||||
|
|
|
|||
|
|
@ -1,15 +1,5 @@
|
|||
warning: elided lifetime has a name
|
||||
--> $DIR/object-lifetime-default-elision.rs:48:40
|
||||
|
|
||||
LL | fn load2<'a>(ss: &'a dyn SomeTrait) -> &dyn SomeTrait {
|
||||
| -- ^ this elided lifetime gets resolved as `'a`
|
||||
| |
|
||||
| lifetime `'a` declared here
|
||||
|
|
||||
= note: `#[warn(elided_named_lifetimes)]` on by default
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/object-lifetime-default-elision.rs:73:5
|
||||
--> $DIR/object-lifetime-default-elision.rs:71:5
|
||||
|
|
||||
LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
|
||||
| -- -- lifetime `'b` defined here
|
||||
|
|
@ -21,5 +11,5 @@ LL | ss
|
|||
|
|
||||
= help: consider adding the following bound: `'a: 'b`
|
||||
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ impl<'a> Drop for r<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn r(i: &Cell<isize>) -> r {
|
||||
fn r(i: &Cell<isize>) -> r<'_> {
|
||||
r {
|
||||
i: i
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ enum roption<'a> {
|
|||
a, b(&'a usize)
|
||||
}
|
||||
|
||||
fn mk(cond: bool, ptr: &usize) -> roption {
|
||||
fn mk(cond: bool, ptr: &usize) -> roption<'_> {
|
||||
if cond {roption::a} else {roption::b(ptr)}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ impl<'a> Drop for r<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn r(i: &Cell<isize>) -> r {
|
||||
fn r(i: &Cell<isize>) -> r<'_> {
|
||||
r {
|
||||
i: i
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ impl<'a> shrinky_pointer<'a> {
|
|||
pub fn look_at(&self) -> isize { return self.i.get(); }
|
||||
}
|
||||
|
||||
fn shrinky_pointer(i: &Cell<isize>) -> shrinky_pointer {
|
||||
fn shrinky_pointer(i: &Cell<isize>) -> shrinky_pointer<'_> {
|
||||
shrinky_pointer {
|
||||
i: i
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
struct Pd;
|
||||
|
||||
impl Pd {
|
||||
fn it(&self) -> It {
|
||||
fn it(&self) -> It<'_> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ impl DropOrderCollector {
|
|||
println!("{n}");
|
||||
self.0.borrow_mut().push(n)
|
||||
}
|
||||
fn some_loud(&self, n: u32) -> Option<LoudDrop> {
|
||||
fn some_loud(&self, n: u32) -> Option<LoudDrop<'_>> {
|
||||
Some(LoudDrop(self, n))
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue