Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit fa696a3

Browse files
authoredApr 10, 2024
Rollup merge of #118391 - compiler-errors:lifetimes-eq, r=lcnr
Add `REDUNDANT_LIFETIMES` lint to detect lifetimes which are semantically redundant There already is a `UNUSED_LIFETIMES` lint which is fired when we detect where clause bounds like `where 'a: 'static`, however, it doesn't use the full power of lexical region resolution to detect failures. Right now `UNUSED_LIFETIMES` is an `Allow` lint, though presumably we could bump it to warn? I can (somewhat) easily implement a structured suggestion so this can be rustfix'd automatically, since we can just walk through the HIR body, replacing instances of the redundant lifetime. Fixes #118376 r? lcnr
2 parents b14d8b2 + da2b714 commit fa696a3

17 files changed

+332
-103
lines changed
 

‎compiler/rustc_errors/src/diagnostic_impls.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ impl<'a, T: Clone + IntoDiagArg> IntoDiagArg for &'a T {
4646
}
4747
}
4848

49+
#[macro_export]
4950
macro_rules! into_diag_arg_using_display {
5051
($( $ty:ty ),+ $(,)?) => {
5152
$(

‎compiler/rustc_hir_analysis/messages.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,9 @@ hir_analysis_pattern_type_wild_pat = "wildcard patterns are not permitted for pa
355355
hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
356356
.label = not allowed in type signatures
357357
358+
hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}`
359+
.note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}`
360+
358361
hir_analysis_requires_note = the `{$trait_name}` impl for `{$ty}` requires that `{$error_predicate}`
359362
360363
hir_analysis_return_type_notation_equality_bound =

‎compiler/rustc_hir_analysis/src/check/wfcheck.rs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ use rustc_ast as ast;
88
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
99
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
1010
use rustc_hir as hir;
11+
use rustc_hir::def::DefKind;
1112
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
1213
use rustc_hir::lang_items::LangItem;
1314
use rustc_hir::ItemKind;
1415
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
1516
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
17+
use rustc_macros::LintDiagnostic;
1618
use rustc_middle::query::Providers;
1719
use rustc_middle::ty::print::with_no_trimmed_paths;
1820
use rustc_middle::ty::trait_def::TraitSpecializationKind;
@@ -136,6 +138,8 @@ where
136138
infcx.implied_bounds_tys_compat(param_env, body_def_id, &assumed_wf_types, false);
137139
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
138140

141+
lint_redundant_lifetimes(tcx, body_def_id, &outlives_env);
142+
139143
let errors = infcx.resolve_regions(&outlives_env);
140144
if errors.is_empty() {
141145
return Ok(());
@@ -2010,6 +2014,137 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), Error
20102014
res
20112015
}
20122016

2017+
fn lint_redundant_lifetimes<'tcx>(
2018+
tcx: TyCtxt<'tcx>,
2019+
owner_id: LocalDefId,
2020+
outlives_env: &OutlivesEnvironment<'tcx>,
2021+
) {
2022+
let def_kind = tcx.def_kind(owner_id);
2023+
match def_kind {
2024+
DefKind::Struct
2025+
| DefKind::Union
2026+
| DefKind::Enum
2027+
| DefKind::Trait
2028+
| DefKind::TraitAlias
2029+
| DefKind::Fn
2030+
| DefKind::Const
2031+
| DefKind::Impl { of_trait: _ } => {
2032+
// Proceed
2033+
}
2034+
DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
2035+
let parent_def_id = tcx.local_parent(owner_id);
2036+
if matches!(tcx.def_kind(parent_def_id), DefKind::Impl { of_trait: true }) {
2037+
// Don't check for redundant lifetimes for associated items of trait
2038+
// implementations, since the signature is required to be compatible
2039+
// with the trait, even if the implementation implies some lifetimes
2040+
// are redundant.
2041+
return;
2042+
}
2043+
}
2044+
DefKind::Mod
2045+
| DefKind::Variant
2046+
| DefKind::TyAlias
2047+
| DefKind::ForeignTy
2048+
| DefKind::TyParam
2049+
| DefKind::ConstParam
2050+
| DefKind::Static { .. }
2051+
| DefKind::Ctor(_, _)
2052+
| DefKind::Macro(_)
2053+
| DefKind::ExternCrate
2054+
| DefKind::Use
2055+
| DefKind::ForeignMod
2056+
| DefKind::AnonConst
2057+
| DefKind::InlineConst
2058+
| DefKind::OpaqueTy
2059+
| DefKind::Field
2060+
| DefKind::LifetimeParam
2061+
| DefKind::GlobalAsm
2062+
| DefKind::Closure => return,
2063+
}
2064+
2065+
// The ordering of this lifetime map is a bit subtle.
2066+
//
2067+
// Specifically, we want to find a "candidate" lifetime that precedes a "victim" lifetime,
2068+
// where we can prove that `'candidate = 'victim`.
2069+
//
2070+
// `'static` must come first in this list because we can never replace `'static` with
2071+
// something else, but if we find some lifetime `'a` where `'a = 'static`, we want to
2072+
// suggest replacing `'a` with `'static`.
2073+
let mut lifetimes = vec![tcx.lifetimes.re_static];
2074+
lifetimes.extend(
2075+
ty::GenericArgs::identity_for_item(tcx, owner_id).iter().filter_map(|arg| arg.as_region()),
2076+
);
2077+
// If we are in a function, add its late-bound lifetimes too.
2078+
if matches!(def_kind, DefKind::Fn | DefKind::AssocFn) {
2079+
for var in tcx.fn_sig(owner_id).instantiate_identity().bound_vars() {
2080+
let ty::BoundVariableKind::Region(kind) = var else { continue };
2081+
lifetimes.push(ty::Region::new_late_param(tcx, owner_id.to_def_id(), kind));
2082+
}
2083+
}
2084+
lifetimes.retain(|candidate| candidate.has_name());
2085+
2086+
// Keep track of lifetimes which have already been replaced with other lifetimes.
2087+
// This makes sure that if `'a = 'b = 'c`, we don't say `'c` should be replaced by
2088+
// both `'a` and `'b`.
2089+
let mut shadowed = FxHashSet::default();
2090+
2091+
for (idx, &candidate) in lifetimes.iter().enumerate() {
2092+
// Don't suggest removing a lifetime twice. We only need to check this
2093+
// here and not up in the `victim` loop because equality is transitive,
2094+
// so if A = C and B = C, then A must = B, so it'll be shadowed too in
2095+
// A's victim loop.
2096+
if shadowed.contains(&candidate) {
2097+
continue;
2098+
}
2099+
2100+
for &victim in &lifetimes[(idx + 1)..] {
2101+
// We should only have late-bound lifetimes of the `BrNamed` variety,
2102+
// since we get these signatures straight from `hir_lowering`. And any
2103+
// other regions (ReError/ReStatic/etc.) shouldn't matter, since we
2104+
// can't really suggest to remove them.
2105+
let (ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
2106+
| ty::ReLateParam(ty::LateParamRegion {
2107+
bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
2108+
..
2109+
})) = victim.kind()
2110+
else {
2111+
continue;
2112+
};
2113+
2114+
// Do not rename lifetimes not local to this item since they'll overlap
2115+
// with the lint running on the parent. We still want to consider parent
2116+
// lifetimes which make child lifetimes redundant, otherwise we would
2117+
// have truncated the `identity_for_item` args above.
2118+
if tcx.parent(def_id) != owner_id.to_def_id() {
2119+
continue;
2120+
}
2121+
2122+
// If `candidate <: victim` and `victim <: candidate`, then they're equal.
2123+
if outlives_env.free_region_map().sub_free_regions(tcx, candidate, victim)
2124+
&& outlives_env.free_region_map().sub_free_regions(tcx, victim, candidate)
2125+
{
2126+
shadowed.insert(victim);
2127+
tcx.emit_node_span_lint(
2128+
rustc_lint_defs::builtin::REDUNDANT_LIFETIMES,
2129+
tcx.local_def_id_to_hir_id(def_id.expect_local()),
2130+
tcx.def_span(def_id),
2131+
RedundantLifetimeArgsLint { candidate, victim },
2132+
);
2133+
}
2134+
}
2135+
}
2136+
}
2137+
2138+
#[derive(LintDiagnostic)]
2139+
#[diag(hir_analysis_redundant_lifetime_args)]
2140+
#[note]
2141+
struct RedundantLifetimeArgsLint<'tcx> {
2142+
/// The lifetime we have found to be redundant.
2143+
victim: ty::Region<'tcx>,
2144+
// The lifetime we can replace the victim with.
2145+
candidate: ty::Region<'tcx>,
2146+
}
2147+
20132148
pub fn provide(providers: &mut Providers) {
20142149
*providers = Providers { check_mod_type_wf, check_well_formed, ..*providers };
20152150
}

‎compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use rustc_middle::hir::nested_filter;
2020
use rustc_middle::middle::resolve_bound_vars::*;
2121
use rustc_middle::query::Providers;
2222
use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor};
23-
use rustc_session::lint;
2423
use rustc_span::def_id::DefId;
2524
use rustc_span::symbol::{sym, Ident};
2625
use rustc_span::Span;
@@ -867,31 +866,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
867866
}) => {
868867
self.visit_lifetime(lifetime);
869868
walk_list!(self, visit_param_bound, bounds);
870-
871-
if lifetime.res != hir::LifetimeName::Static {
872-
for bound in bounds {
873-
let hir::GenericBound::Outlives(lt) = bound else {
874-
continue;
875-
};
876-
if lt.res != hir::LifetimeName::Static {
877-
continue;
878-
}
879-
self.insert_lifetime(lt, ResolvedArg::StaticLifetime);
880-
self.tcx.node_span_lint(
881-
lint::builtin::UNUSED_LIFETIMES,
882-
lifetime.hir_id,
883-
lifetime.ident.span,
884-
format!("unnecessary lifetime parameter `{}`", lifetime.ident),
885-
|lint| {
886-
let help = format!(
887-
"you can use the `'static` lifetime directly, in place of `{}`",
888-
lifetime.ident,
889-
);
890-
lint.help(help);
891-
},
892-
);
893-
}
894-
}
895869
}
896870
&hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
897871
self.visit_ty(lhs_ty);

‎compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ declare_lint_pass! {
7979
PROC_MACRO_BACK_COMPAT,
8080
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
8181
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
82+
REDUNDANT_LIFETIMES,
8283
REFINING_IMPL_TRAIT_INTERNAL,
8384
REFINING_IMPL_TRAIT_REACHABLE,
8485
RENAMED_AND_REMOVED_LINTS,
@@ -1707,6 +1708,33 @@ declare_lint! {
17071708
"detects lifetime parameters that are never used"
17081709
}
17091710

1711+
declare_lint! {
1712+
/// The `redundant_lifetimes` lint detects lifetime parameters that are
1713+
/// redundant because they are equal to another named lifetime.
1714+
///
1715+
/// ### Example
1716+
///
1717+
/// ```rust,compile_fail
1718+
/// #[deny(redundant_lifetimes)]
1719+
///
1720+
/// // `'a = 'static`, so all usages of `'a` can be replaced with `'static`
1721+
/// pub fn bar<'a: 'static>() {}
1722+
///
1723+
/// // `'a = 'b`, so all usages of `'b` can be replaced with `'a`
1724+
/// pub fn bar<'a: 'b, 'b: 'a>() {}
1725+
/// ```
1726+
///
1727+
/// {{produces}}
1728+
///
1729+
/// ### Explanation
1730+
///
1731+
/// Unused lifetime parameters may signal a mistake or unfinished code.
1732+
/// Consider removing the parameter.
1733+
pub REDUNDANT_LIFETIMES,
1734+
Allow,
1735+
"detects lifetime parameters that are redundant because they are equal to some other named lifetime"
1736+
}
1737+
17101738
declare_lint! {
17111739
/// The `tyvar_behind_raw_pointer` lint detects raw pointer to an
17121740
/// inference variable.

‎compiler/rustc_middle/src/ty/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,7 @@ pub struct GlobalCtxt<'tcx> {
757757
impl<'tcx> GlobalCtxt<'tcx> {
758758
/// Installs `self` in a `TyCtxt` and `ImplicitCtxt` for the duration of
759759
/// `f`.
760-
pub fn enter<'a: 'tcx, F, R>(&'a self, f: F) -> R
760+
pub fn enter<F, R>(&'tcx self, f: F) -> R
761761
where
762762
F: FnOnce(TyCtxt<'tcx>) -> R,
763763
{

‎compiler/rustc_middle/src/ty/diagnostics.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,23 @@ use std::fmt::Write;
55
use std::ops::ControlFlow;
66

77
use crate::ty::{
8-
AliasTy, Const, ConstKind, FallibleTypeFolder, InferConst, InferTy, Opaque, PolyTraitPredicate,
9-
Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
10-
TypeVisitor,
8+
self, AliasTy, Const, ConstKind, FallibleTypeFolder, InferConst, InferTy, Opaque,
9+
PolyTraitPredicate, Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
10+
TypeSuperVisitable, TypeVisitable, TypeVisitor,
1111
};
1212

1313
use rustc_data_structures::fx::FxHashMap;
14-
use rustc_errors::{Applicability, Diag, DiagArgValue, IntoDiagArg};
14+
use rustc_errors::{into_diag_arg_using_display, Applicability, Diag, DiagArgValue, IntoDiagArg};
1515
use rustc_hir as hir;
1616
use rustc_hir::def::DefKind;
1717
use rustc_hir::def_id::DefId;
1818
use rustc_hir::{PredicateOrigin, WherePredicate};
1919
use rustc_span::{BytePos, Span};
2020
use rustc_type_ir::TyKind::*;
2121

22-
impl<'tcx> IntoDiagArg for Ty<'tcx> {
23-
fn into_diag_arg(self) -> DiagArgValue {
24-
self.to_string().into_diag_arg()
25-
}
22+
into_diag_arg_using_display! {
23+
Ty<'_>,
24+
ty::Region<'_>,
2625
}
2726

2827
impl<'tcx> Ty<'tcx> {

‎tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
#![warn(unused_lifetimes)]
1+
#![warn(unused_lifetimes, redundant_lifetimes)]
22

33
pub trait X {
4-
type Y<'a: 'static>;
5-
//~^ WARNING unnecessary lifetime parameter
4+
type Y<'a: 'static>; //~ WARN unnecessary lifetime parameter `'a`
65
}
76

87
impl X for () {
Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,5 @@
1-
warning: unnecessary lifetime parameter `'a`
2-
--> $DIR/unsatisfied-item-lifetime-bound.rs:4:12
3-
|
4-
LL | type Y<'a: 'static>;
5-
| ^^
6-
|
7-
= help: you can use the `'static` lifetime directly, in place of `'a`
8-
note: the lint level is defined here
9-
--> $DIR/unsatisfied-item-lifetime-bound.rs:1:9
10-
|
11-
LL | #![warn(unused_lifetimes)]
12-
| ^^^^^^^^^^^^^^^^
13-
141
error[E0478]: lifetime bound not satisfied
15-
--> $DIR/unsatisfied-item-lifetime-bound.rs:9:18
2+
--> $DIR/unsatisfied-item-lifetime-bound.rs:8:18
163
|
174
LL | type Y<'a: 'static>;
185
| ------------------- definition of `Y` from trait
@@ -21,7 +8,7 @@ LL | type Y<'a> = &'a ();
218
| ^^^^^^
229
|
2310
note: lifetime parameter instantiated with the lifetime `'a` as defined here
24-
--> $DIR/unsatisfied-item-lifetime-bound.rs:9:12
11+
--> $DIR/unsatisfied-item-lifetime-bound.rs:8:12
2512
|
2613
LL | type Y<'a> = &'a ();
2714
| ^^
@@ -32,44 +19,57 @@ LL | type Y<'a> = &'a () where 'a: 'static;
3219
| +++++++++++++++++
3320

3421
error[E0478]: lifetime bound not satisfied
35-
--> $DIR/unsatisfied-item-lifetime-bound.rs:14:8
22+
--> $DIR/unsatisfied-item-lifetime-bound.rs:13:8
3623
|
3724
LL | f: <T as X>::Y<'a>,
3825
| ^^^^^^^^^^^^^^^
3926
|
4027
note: lifetime parameter instantiated with the lifetime `'a` as defined here
41-
--> $DIR/unsatisfied-item-lifetime-bound.rs:13:10
28+
--> $DIR/unsatisfied-item-lifetime-bound.rs:12:10
4229
|
4330
LL | struct B<'a, T: for<'r> X<Y<'r> = &'r ()>> {
4431
| ^^
4532
= note: but lifetime parameter must outlive the static lifetime
4633

4734
error[E0478]: lifetime bound not satisfied
48-
--> $DIR/unsatisfied-item-lifetime-bound.rs:19:8
35+
--> $DIR/unsatisfied-item-lifetime-bound.rs:18:8
4936
|
5037
LL | f: <T as X>::Y<'a>,
5138
| ^^^^^^^^^^^^^^^
5239
|
5340
note: lifetime parameter instantiated with the lifetime `'a` as defined here
54-
--> $DIR/unsatisfied-item-lifetime-bound.rs:18:10
41+
--> $DIR/unsatisfied-item-lifetime-bound.rs:17:10
5542
|
5643
LL | struct C<'a, T: X> {
5744
| ^^
5845
= note: but lifetime parameter must outlive the static lifetime
5946

6047
error[E0478]: lifetime bound not satisfied
61-
--> $DIR/unsatisfied-item-lifetime-bound.rs:24:8
48+
--> $DIR/unsatisfied-item-lifetime-bound.rs:23:8
6249
|
6350
LL | f: <() as X>::Y<'a>,
6451
| ^^^^^^^^^^^^^^^^
6552
|
6653
note: lifetime parameter instantiated with the lifetime `'a` as defined here
67-
--> $DIR/unsatisfied-item-lifetime-bound.rs:23:10
54+
--> $DIR/unsatisfied-item-lifetime-bound.rs:22:10
6855
|
6956
LL | struct D<'a> {
7057
| ^^
7158
= note: but lifetime parameter must outlive the static lifetime
7259

60+
warning: unnecessary lifetime parameter `'a`
61+
--> $DIR/unsatisfied-item-lifetime-bound.rs:4:12
62+
|
63+
LL | type Y<'a: 'static>;
64+
| ^^
65+
|
66+
= note: you can use the `'static` lifetime directly, in place of `'a`
67+
note: the lint level is defined here
68+
--> $DIR/unsatisfied-item-lifetime-bound.rs:1:27
69+
|
70+
LL | #![warn(unused_lifetimes, redundant_lifetimes)]
71+
| ^^^^^^^^^^^^^^^^^^^
72+
7373
error: aborting due to 4 previous errors; 1 warning emitted
7474

7575
For more information about this error, try `rustc --explain E0478`.

‎tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
//
99
// 'a : 'b
1010

11-
#![warn(unused_lifetimes)]
11+
#![warn(redundant_lifetimes)]
1212

13-
fn test<'a,'b>(x: &'a i32) -> &'b i32
14-
where 'a: 'static //~ WARN unnecessary lifetime parameter `'a`
13+
fn test<'a,'b>(x: &'a i32) -> &'b i32 //~ WARN unnecessary lifetime parameter `'a`
14+
where 'a: 'static
1515
{
1616
x
1717
}
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
warning: unnecessary lifetime parameter `'a`
2-
--> $DIR/regions-free-region-outlives-static-outlives-free-region.rs:14:11
2+
--> $DIR/regions-free-region-outlives-static-outlives-free-region.rs:13:9
33
|
4-
LL | where 'a: 'static
5-
| ^^
4+
LL | fn test<'a,'b>(x: &'a i32) -> &'b i32
5+
| ^^
66
|
7-
= help: you can use the `'static` lifetime directly, in place of `'a`
7+
= note: you can use the `'static` lifetime directly, in place of `'a`
88
note: the lint level is defined here
99
--> $DIR/regions-free-region-outlives-static-outlives-free-region.rs:11:9
1010
|
11-
LL | #![warn(unused_lifetimes)]
12-
| ^^^^^^^^^^^^^^^^
11+
LL | #![warn(redundant_lifetimes)]
12+
| ^^^^^^^^^^^^^^^^^^^
1313

1414
warning: 1 warning emitted
1515

‎tests/ui/regions/regions-static-bound-rpass.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
//@ run-pass
22

3-
#![warn(unused_lifetimes)]
3+
#![warn(redundant_lifetimes)]
44

55
fn invariant_id<'a,'b>(t: &'b mut &'static ()) -> &'b mut &'a ()
6-
where 'a: 'static { t }
76
//~^ WARN unnecessary lifetime parameter `'a`
7+
where 'a: 'static { t }
88

99
fn static_id<'a>(t: &'a ()) -> &'static ()
10-
where 'a: 'static { t }
1110
//~^ WARN unnecessary lifetime parameter `'a`
11+
where 'a: 'static { t }
1212

1313
fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static ()
14+
//~^ WARN unnecessary lifetime parameter `'a`
15+
//~| WARN unnecessary lifetime parameter `'b`
1416
where 'a: 'b, 'b: 'static { t }
15-
//~^ WARN unnecessary lifetime parameter `'b`
1617

1718
fn ref_id<'a>(t: &'a ()) -> &'a () where 'static: 'a { t }
1819

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,39 @@
11
warning: unnecessary lifetime parameter `'a`
2-
--> $DIR/regions-static-bound-rpass.rs:6:11
2+
--> $DIR/regions-static-bound-rpass.rs:5:17
33
|
4-
LL | where 'a: 'static { t }
5-
| ^^
4+
LL | fn invariant_id<'a,'b>(t: &'b mut &'static ()) -> &'b mut &'a ()
5+
| ^^
66
|
7-
= help: you can use the `'static` lifetime directly, in place of `'a`
7+
= note: you can use the `'static` lifetime directly, in place of `'a`
88
note: the lint level is defined here
99
--> $DIR/regions-static-bound-rpass.rs:3:9
1010
|
11-
LL | #![warn(unused_lifetimes)]
12-
| ^^^^^^^^^^^^^^^^
11+
LL | #![warn(redundant_lifetimes)]
12+
| ^^^^^^^^^^^^^^^^^^^
1313

1414
warning: unnecessary lifetime parameter `'a`
15-
--> $DIR/regions-static-bound-rpass.rs:10:11
15+
--> $DIR/regions-static-bound-rpass.rs:9:14
1616
|
17-
LL | where 'a: 'static { t }
18-
| ^^
17+
LL | fn static_id<'a>(t: &'a ()) -> &'static ()
18+
| ^^
1919
|
20-
= help: you can use the `'static` lifetime directly, in place of `'a`
20+
= note: you can use the `'static` lifetime directly, in place of `'a`
21+
22+
warning: unnecessary lifetime parameter `'a`
23+
--> $DIR/regions-static-bound-rpass.rs:13:23
24+
|
25+
LL | fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static ()
26+
| ^^
27+
|
28+
= note: you can use the `'static` lifetime directly, in place of `'a`
2129

2230
warning: unnecessary lifetime parameter `'b`
23-
--> $DIR/regions-static-bound-rpass.rs:14:19
31+
--> $DIR/regions-static-bound-rpass.rs:13:26
2432
|
25-
LL | where 'a: 'b, 'b: 'static { t }
26-
| ^^
33+
LL | fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static ()
34+
| ^^
2735
|
28-
= help: you can use the `'static` lifetime directly, in place of `'b`
36+
= note: you can use the `'static` lifetime directly, in place of `'b`
2937

30-
warning: 3 warnings emitted
38+
warning: 4 warnings emitted
3139

‎tests/ui/regions/regions-static-bound.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
#![warn(unused_lifetimes)]
1+
#![warn(unused_lifetimes, redundant_lifetimes)]
22

33
fn static_id<'a,'b>(t: &'a ()) -> &'static () where 'a: 'static { t }
4-
//~^ WARN lifetime parameter `'b` never used
5-
//~| WARN unnecessary lifetime parameter `'a`
4+
//~^ WARN unnecessary lifetime parameter `'a`
5+
//~| WARN lifetime parameter `'b` never used
66

77
fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static ()
8+
//~^ WARN unnecessary lifetime parameter `'a`
9+
//~| WARN unnecessary lifetime parameter `'b`
810
where 'a: 'b, 'b: 'static { t }
9-
//~^ WARN unnecessary lifetime parameter `'b`
1011

1112
fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
1213
t

‎tests/ui/regions/regions-static-bound.stderr

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,35 +9,48 @@ LL | fn static_id<'a,'b>(t: &'a ()) -> &'static () where 'a: 'static { t }
99
note: the lint level is defined here
1010
--> $DIR/regions-static-bound.rs:1:9
1111
|
12-
LL | #![warn(unused_lifetimes)]
12+
LL | #![warn(unused_lifetimes, redundant_lifetimes)]
1313
| ^^^^^^^^^^^^^^^^
1414

1515
warning: unnecessary lifetime parameter `'a`
16-
--> $DIR/regions-static-bound.rs:3:53
16+
--> $DIR/regions-static-bound.rs:3:14
1717
|
1818
LL | fn static_id<'a,'b>(t: &'a ()) -> &'static () where 'a: 'static { t }
19-
| ^^
19+
| ^^
2020
|
21-
= help: you can use the `'static` lifetime directly, in place of `'a`
21+
= note: you can use the `'static` lifetime directly, in place of `'a`
22+
note: the lint level is defined here
23+
--> $DIR/regions-static-bound.rs:1:27
24+
|
25+
LL | #![warn(unused_lifetimes, redundant_lifetimes)]
26+
| ^^^^^^^^^^^^^^^^^^^
27+
28+
warning: unnecessary lifetime parameter `'a`
29+
--> $DIR/regions-static-bound.rs:7:23
30+
|
31+
LL | fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static ()
32+
| ^^
33+
|
34+
= note: you can use the `'static` lifetime directly, in place of `'a`
2235

2336
warning: unnecessary lifetime parameter `'b`
24-
--> $DIR/regions-static-bound.rs:8:19
37+
--> $DIR/regions-static-bound.rs:7:26
2538
|
26-
LL | where 'a: 'b, 'b: 'static { t }
27-
| ^^
39+
LL | fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static ()
40+
| ^^
2841
|
29-
= help: you can use the `'static` lifetime directly, in place of `'b`
42+
= note: you can use the `'static` lifetime directly, in place of `'b`
3043

3144
error: lifetime may not live long enough
32-
--> $DIR/regions-static-bound.rs:12:5
45+
--> $DIR/regions-static-bound.rs:13:5
3346
|
3447
LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
3548
| -- lifetime `'a` defined here
3649
LL | t
3750
| ^ returning this value requires that `'a` must outlive `'static`
3851

3952
error[E0521]: borrowed data escapes outside of function
40-
--> $DIR/regions-static-bound.rs:17:5
53+
--> $DIR/regions-static-bound.rs:18:5
4154
|
4255
LL | fn error(u: &(), v: &()) {
4356
| - - let's call the lifetime of this reference `'1`
@@ -50,7 +63,7 @@ LL | static_id(&u);
5063
| argument requires that `'1` must outlive `'static`
5164

5265
error[E0521]: borrowed data escapes outside of function
53-
--> $DIR/regions-static-bound.rs:19:5
66+
--> $DIR/regions-static-bound.rs:20:5
5467
|
5568
LL | fn error(u: &(), v: &()) {
5669
| - - let's call the lifetime of this reference `'2`
@@ -63,6 +76,6 @@ LL | static_id_indirect(&v);
6376
| `v` escapes the function body here
6477
| argument requires that `'2` must outlive `'static`
6578

66-
error: aborting due to 3 previous errors; 3 warnings emitted
79+
error: aborting due to 3 previous errors; 4 warnings emitted
6780

6881
For more information about this error, try `rustc --explain E0521`.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![deny(redundant_lifetimes)]
2+
3+
fn a<'a, 'b>(x: &'a &'b &'a ()) {} //~ ERROR unnecessary lifetime parameter `'b`
4+
5+
fn b<'a: 'b, 'b: 'a>() {} //~ ERROR unnecessary lifetime parameter `'b`
6+
7+
struct Foo<T: 'static>(T);
8+
fn c<'a>(_: Foo<&'a ()>) {} //~ ERROR unnecessary lifetime parameter `'a`
9+
10+
struct Bar<'a>(&'a ());
11+
impl<'a> Bar<'a> {
12+
fn d<'b: 'a>(&'b self) {} //~ ERROR unnecessary lifetime parameter `'b`
13+
}
14+
15+
fn ok(x: &'static &()) {}
16+
17+
trait Tr<'a> {}
18+
impl<'a: 'static> Tr<'a> for () {} //~ ERROR unnecessary lifetime parameter `'a`
19+
20+
fn main() {}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error: unnecessary lifetime parameter `'b`
2+
--> $DIR/transitively-redundant-lifetimes.rs:3:10
3+
|
4+
LL | fn a<'a, 'b>(x: &'a &'b &'a ()) {}
5+
| ^^
6+
|
7+
= note: you can use the `'a` lifetime directly, in place of `'b`
8+
note: the lint level is defined here
9+
--> $DIR/transitively-redundant-lifetimes.rs:1:9
10+
|
11+
LL | #![deny(redundant_lifetimes)]
12+
| ^^^^^^^^^^^^^^^^^^^
13+
14+
error: unnecessary lifetime parameter `'b`
15+
--> $DIR/transitively-redundant-lifetimes.rs:5:14
16+
|
17+
LL | fn b<'a: 'b, 'b: 'a>() {}
18+
| ^^
19+
|
20+
= note: you can use the `'a` lifetime directly, in place of `'b`
21+
22+
error: unnecessary lifetime parameter `'a`
23+
--> $DIR/transitively-redundant-lifetimes.rs:8:6
24+
|
25+
LL | fn c<'a>(_: Foo<&'a ()>) {}
26+
| ^^
27+
|
28+
= note: you can use the `'static` lifetime directly, in place of `'a`
29+
30+
error: unnecessary lifetime parameter `'a`
31+
--> $DIR/transitively-redundant-lifetimes.rs:18:6
32+
|
33+
LL | impl<'a: 'static> Tr<'a> for () {}
34+
| ^^
35+
|
36+
= note: you can use the `'static` lifetime directly, in place of `'a`
37+
38+
error: unnecessary lifetime parameter `'b`
39+
--> $DIR/transitively-redundant-lifetimes.rs:12:10
40+
|
41+
LL | fn d<'b: 'a>(&'b self) {}
42+
| ^^
43+
|
44+
= note: you can use the `'a` lifetime directly, in place of `'b`
45+
46+
error: aborting due to 5 previous errors
47+

0 commit comments

Comments
 (0)
Please sign in to comment.