Skip to content

Commit 23b936f

Browse files
authored
Rollup merge of rust-lang#125258 - compiler-errors:static-if-no-lt, r=nnethercote
Resolve elided lifetimes in assoc const to static if no other lifetimes are in scope Implements the change to elided lifetime resolution in *associated consts* subject to FCP here: rust-lang#125190 (comment) Specifically, walk the enclosing lifetime ribs in an associated const, and if we find no other lifetimes, then resolve to `'static`. Also make it work for traits, but don't lint -- just give a hard error in that case.
2 parents 6b65c30 + 5f3357c commit 23b936f

21 files changed

+386
-210
lines changed

compiler/rustc_lint/messages.ftl

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ lint_associated_const_elided_lifetime = {$elided ->
1414
*[false] `'_` cannot be used here
1515
}
1616
.suggestion = use the `'static` lifetime
17+
.note = cannot automatically infer `'static` because of other lifetimes in scope
1718
1819
lint_async_fn_in_trait = use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified
1920
.note = you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future`

compiler/rustc_lint/src/context/diagnostics.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -319,11 +319,20 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
319319
BuiltinLintDiag::UnusedQualifications { removal_span } => {
320320
lints::UnusedQualifications { removal_span }.decorate_lint(diag);
321321
}
322-
BuiltinLintDiag::AssociatedConstElidedLifetime { elided, span: lt_span } => {
322+
BuiltinLintDiag::AssociatedConstElidedLifetime {
323+
elided,
324+
span: lt_span,
325+
lifetimes_in_scope,
326+
} => {
323327
let lt_span = if elided { lt_span.shrink_to_hi() } else { lt_span };
324328
let code = if elided { "'static " } else { "'static" };
325-
lints::AssociatedConstElidedLifetime { span: lt_span, code, elided }
326-
.decorate_lint(diag);
329+
lints::AssociatedConstElidedLifetime {
330+
span: lt_span,
331+
code,
332+
elided,
333+
lifetimes_in_scope,
334+
}
335+
.decorate_lint(diag);
327336
}
328337
BuiltinLintDiag::RedundantImportVisibility { max_vis, span: vis_span, import_vis } => {
329338
lints::RedundantImportVisibility { span: vis_span, help: (), max_vis, import_vis }

compiler/rustc_lint/src/lints.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2873,6 +2873,8 @@ pub struct AssociatedConstElidedLifetime {
28732873

28742874
pub code: &'static str,
28752875
pub elided: bool,
2876+
#[note]
2877+
pub lifetimes_in_scope: MultiSpan,
28762878
}
28772879

28782880
#[derive(LintDiagnostic)]

compiler/rustc_lint_defs/src/builtin.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -4593,16 +4593,18 @@ declare_lint! {
45934593

45944594
declare_lint! {
45954595
/// The `elided_lifetimes_in_associated_constant` lint detects elided lifetimes
4596-
/// that were erroneously allowed in associated constants.
4596+
/// in associated constants when there are other lifetimes in scope. This was
4597+
/// accidentally supported, and this lint was later relaxed to allow eliding
4598+
/// lifetimes to `'static` when there are no lifetimes in scope.
45974599
///
45984600
/// ### Example
45994601
///
46004602
/// ```rust,compile_fail
46014603
/// #![deny(elided_lifetimes_in_associated_constant)]
46024604
///
4603-
/// struct Foo;
4605+
/// struct Foo<'a>(&'a ());
46044606
///
4605-
/// impl Foo {
4607+
/// impl<'a> Foo<'a> {
46064608
/// const STR: &str = "hello, world";
46074609
/// }
46084610
/// ```

compiler/rustc_lint_defs/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,7 @@ pub enum BuiltinLintDiag {
696696
AssociatedConstElidedLifetime {
697697
elided: bool,
698698
span: Span,
699+
lifetimes_in_scope: MultiSpan,
699700
},
700701
RedundantImportVisibility {
701702
span: Span,

compiler/rustc_resolve/src/late.rs

+89-53
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,10 @@ enum LifetimeRibKind {
310310
/// error on default object bounds (e.g., `Box<dyn Foo>`).
311311
AnonymousReportError,
312312

313-
/// Resolves elided lifetimes to `'static`, but gives a warning that this behavior
314-
/// is a bug and will be reverted soon.
315-
AnonymousWarn(NodeId),
313+
/// Resolves elided lifetimes to `'static` if there are no other lifetimes in scope,
314+
/// otherwise give a warning that the previous behavior of introducing a new early-bound
315+
/// lifetime is a bug and will be removed (if `emit_lint` is enabled).
316+
StaticIfNoLifetimeInScope { lint_id: NodeId, emit_lint: bool },
316317

317318
/// Signal we cannot find which should be the anonymous lifetime.
318319
ElisionFailure,
@@ -1212,7 +1213,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
12121213
}
12131214
LifetimeRibKind::AnonymousCreateParameter { .. }
12141215
| LifetimeRibKind::AnonymousReportError
1215-
| LifetimeRibKind::AnonymousWarn(_)
1216+
| LifetimeRibKind::StaticIfNoLifetimeInScope { .. }
12161217
| LifetimeRibKind::Elided(_)
12171218
| LifetimeRibKind::ElisionFailure
12181219
| LifetimeRibKind::ConcreteAnonConst(_)
@@ -1580,7 +1581,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
15801581
// lifetime would be illegal.
15811582
LifetimeRibKind::Item
15821583
| LifetimeRibKind::AnonymousReportError
1583-
| LifetimeRibKind::AnonymousWarn(_)
1584+
| LifetimeRibKind::StaticIfNoLifetimeInScope { .. }
15841585
| LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many),
15851586
// An anonymous lifetime is legal here, and bound to the right
15861587
// place, go ahead.
@@ -1643,7 +1644,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
16431644
| LifetimeRibKind::Generics { .. }
16441645
| LifetimeRibKind::ElisionFailure
16451646
| LifetimeRibKind::AnonymousReportError
1646-
| LifetimeRibKind::AnonymousWarn(_) => {}
1647+
| LifetimeRibKind::StaticIfNoLifetimeInScope { .. } => {}
16471648
}
16481649
}
16491650

@@ -1677,16 +1678,36 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
16771678
self.record_lifetime_res(lifetime.id, res, elision_candidate);
16781679
return;
16791680
}
1680-
LifetimeRibKind::AnonymousWarn(node_id) => {
1681-
self.r.lint_buffer.buffer_lint(
1682-
lint::builtin::ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
1683-
node_id,
1684-
lifetime.ident.span,
1685-
lint::BuiltinLintDiag::AssociatedConstElidedLifetime {
1686-
elided,
1687-
span: lifetime.ident.span,
1688-
},
1689-
);
1681+
LifetimeRibKind::StaticIfNoLifetimeInScope { lint_id: node_id, emit_lint } => {
1682+
let mut lifetimes_in_scope = vec![];
1683+
for rib in &self.lifetime_ribs[..i] {
1684+
lifetimes_in_scope.extend(rib.bindings.iter().map(|(ident, _)| ident.span));
1685+
// Consider any anonymous lifetimes, too
1686+
if let LifetimeRibKind::AnonymousCreateParameter { binder, .. } = rib.kind
1687+
&& let Some(extra) = self.r.extra_lifetime_params_map.get(&binder)
1688+
{
1689+
lifetimes_in_scope.extend(extra.iter().map(|(ident, _, _)| ident.span));
1690+
}
1691+
}
1692+
if lifetimes_in_scope.is_empty() {
1693+
self.record_lifetime_res(
1694+
lifetime.id,
1695+
LifetimeRes::Static,
1696+
elision_candidate,
1697+
);
1698+
return;
1699+
} else if emit_lint {
1700+
self.r.lint_buffer.buffer_lint(
1701+
lint::builtin::ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
1702+
node_id,
1703+
lifetime.ident.span,
1704+
lint::BuiltinLintDiag::AssociatedConstElidedLifetime {
1705+
elided,
1706+
span: lifetime.ident.span,
1707+
lifetimes_in_scope: lifetimes_in_scope.into(),
1708+
},
1709+
);
1710+
}
16901711
}
16911712
LifetimeRibKind::AnonymousReportError => {
16921713
if elided {
@@ -1904,7 +1925,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
19041925
// impl Foo for std::cell::Ref<u32> // note lack of '_
19051926
// async fn foo(_: std::cell::Ref<u32>) { ... }
19061927
LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. }
1907-
| LifetimeRibKind::AnonymousWarn(_) => {
1928+
| LifetimeRibKind::StaticIfNoLifetimeInScope { .. } => {
19081929
let sess = self.r.tcx.sess;
19091930
let subdiag = rustc_errors::elided_lifetime_in_path_suggestion(
19101931
sess.source_map(),
@@ -2838,19 +2859,27 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
28382859
kind: LifetimeBinderKind::ConstItem,
28392860
},
28402861
|this| {
2841-
this.visit_generics(generics);
2842-
this.visit_ty(ty);
2843-
2844-
// Only impose the restrictions of `ConstRibKind` for an
2845-
// actual constant expression in a provided default.
2846-
if let Some(expr) = expr {
2847-
// We allow arbitrary const expressions inside of associated consts,
2848-
// even if they are potentially not const evaluatable.
2849-
//
2850-
// Type parameters can already be used and as associated consts are
2851-
// not used as part of the type system, this is far less surprising.
2852-
this.resolve_const_body(expr, None);
2853-
}
2862+
this.with_lifetime_rib(
2863+
LifetimeRibKind::StaticIfNoLifetimeInScope {
2864+
lint_id: item.id,
2865+
emit_lint: false,
2866+
},
2867+
|this| {
2868+
this.visit_generics(generics);
2869+
this.visit_ty(ty);
2870+
2871+
// Only impose the restrictions of `ConstRibKind` for an
2872+
// actual constant expression in a provided default.
2873+
if let Some(expr) = expr {
2874+
// We allow arbitrary const expressions inside of associated consts,
2875+
// even if they are potentially not const evaluatable.
2876+
//
2877+
// Type parameters can already be used and as associated consts are
2878+
// not used as part of the type system, this is far less surprising.
2879+
this.resolve_const_body(expr, None);
2880+
}
2881+
},
2882+
)
28542883
},
28552884
);
28562885
}
@@ -3030,30 +3059,37 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
30303059
kind: LifetimeBinderKind::ConstItem,
30313060
},
30323061
|this| {
3033-
this.with_lifetime_rib(LifetimeRibKind::AnonymousWarn(item.id), |this| {
3034-
// If this is a trait impl, ensure the const
3035-
// exists in trait
3036-
this.check_trait_item(
3037-
item.id,
3038-
item.ident,
3039-
&item.kind,
3040-
ValueNS,
3041-
item.span,
3042-
seen_trait_items,
3043-
|i, s, c| ConstNotMemberOfTrait(i, s, c),
3044-
);
3062+
this.with_lifetime_rib(
3063+
LifetimeRibKind::StaticIfNoLifetimeInScope {
3064+
lint_id: item.id,
3065+
// In impls, it's not a hard error yet due to backcompat.
3066+
emit_lint: true,
3067+
},
3068+
|this| {
3069+
// If this is a trait impl, ensure the const
3070+
// exists in trait
3071+
this.check_trait_item(
3072+
item.id,
3073+
item.ident,
3074+
&item.kind,
3075+
ValueNS,
3076+
item.span,
3077+
seen_trait_items,
3078+
|i, s, c| ConstNotMemberOfTrait(i, s, c),
3079+
);
30453080

3046-
this.visit_generics(generics);
3047-
this.visit_ty(ty);
3048-
if let Some(expr) = expr {
3049-
// We allow arbitrary const expressions inside of associated consts,
3050-
// even if they are potentially not const evaluatable.
3051-
//
3052-
// Type parameters can already be used and as associated consts are
3053-
// not used as part of the type system, this is far less surprising.
3054-
this.resolve_const_body(expr, None);
3055-
}
3056-
});
3081+
this.visit_generics(generics);
3082+
this.visit_ty(ty);
3083+
if let Some(expr) = expr {
3084+
// We allow arbitrary const expressions inside of associated consts,
3085+
// even if they are potentially not const evaluatable.
3086+
//
3087+
// Type parameters can already be used and as associated consts are
3088+
// not used as part of the type system, this is far less surprising.
3089+
this.resolve_const_body(expr, None);
3090+
}
3091+
},
3092+
);
30573093
},
30583094
);
30593095
}
+3-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1+
//@ check-pass
2+
13
struct S;
24

35
impl S {
46
const C: &&str = &"";
5-
//~^ WARN `&` without an explicit lifetime name cannot be used here
6-
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
7-
//~| WARN `&` without an explicit lifetime name cannot be used here
8-
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
9-
//~| ERROR in type `&&str`, reference has a longer lifetime than the data it references
7+
// Now resolves to `&'static &'static str`.
108
}
119

1210
fn main() {}

tests/ui/associated-consts/double-elided.stderr

-47
This file was deleted.

tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.rs

-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ trait Trait {
55
impl Trait for () {
66
const ASSOC: &dyn Fn(_) = 1i32;
77
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated constants
8-
//~| WARN `&` without an explicit lifetime name cannot be used here
9-
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
108
}
119

1210
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,9 @@
1-
warning: `&` without an explicit lifetime name cannot be used here
2-
--> $DIR/infer-placeholder-in-non-suggestable-pos.rs:6:18
3-
|
4-
LL | const ASSOC: &dyn Fn(_) = 1i32;
5-
| ^
6-
|
7-
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
8-
= note: for more information, see issue #115010 <https://github.com/rust-lang/rust/issues/115010>
9-
= note: `#[warn(elided_lifetimes_in_associated_constant)]` on by default
10-
help: use the `'static` lifetime
11-
|
12-
LL | const ASSOC: &'static dyn Fn(_) = 1i32;
13-
| +++++++
14-
151
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
162
--> $DIR/infer-placeholder-in-non-suggestable-pos.rs:6:26
173
|
184
LL | const ASSOC: &dyn Fn(_) = 1i32;
195
| ^ not allowed in type signatures
206

21-
error: aborting due to 1 previous error; 1 warning emitted
7+
error: aborting due to 1 previous error
228

239
For more information about this error, try `rustc --explain E0121`.

tests/ui/consts/assoc-const-elided-lifetime.stderr

+12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ LL | const FOO: Foo<'_> = Foo { x: PhantomData::<&()> };
66
|
77
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
88
= note: for more information, see issue #115010 <https://github.com/rust-lang/rust/issues/115010>
9+
note: cannot automatically infer `'static` because of other lifetimes in scope
10+
--> $DIR/assoc-const-elided-lifetime.rs:9:6
11+
|
12+
LL | impl<'a> Foo<'a> {
13+
| ^^
914
note: the lint level is defined here
1015
--> $DIR/assoc-const-elided-lifetime.rs:1:9
1116
|
@@ -24,6 +29,13 @@ LL | const BAR: &() = &();
2429
|
2530
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
2631
= note: for more information, see issue #115010 <https://github.com/rust-lang/rust/issues/115010>
32+
note: cannot automatically infer `'static` because of other lifetimes in scope
33+
--> $DIR/assoc-const-elided-lifetime.rs:9:6
34+
|
35+
LL | impl<'a> Foo<'a> {
36+
| ^^
37+
LL | const FOO: Foo<'_> = Foo { x: PhantomData::<&()> };
38+
| ^^
2739
help: use the `'static` lifetime
2840
|
2941
LL | const BAR: &'static () = &();

0 commit comments

Comments
 (0)