Skip to content

Commit e9897c3

Browse files
Rollup merge of rust-lang#115011 - compiler-errors:warn-on-elided-assoc-ct-lt, r=cjgillot
Warn on elided lifetimes in associated constants (`ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT`) Elided lifetimes in associated constants (in impls) erroneously resolve to fresh lifetime parameters on the impl since rust-lang#97313. This is not correct behavior (see rust-lang#38831). I originally opened rust-lang#114716 to fix this, but given the time that has passed, the crater results seem pretty bad: rust-lang#114716 (comment) This PR alternatively implements a lint against this behavior, and I'm hoping to bump this to deny in a few versions.
2 parents 6c7678d + b1c609e commit e9897c3

File tree

10 files changed

+180
-27
lines changed

10 files changed

+180
-27
lines changed

compiler/rustc_lint/src/context.rs

+8
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,14 @@ pub trait LintContext: Sized {
966966
Applicability::MachineApplicable
967967
);
968968
}
969+
BuiltinLintDiagnostics::AssociatedConstElidedLifetime { elided, span } => {
970+
db.span_suggestion_verbose(
971+
if elided { span.shrink_to_hi() } else { span },
972+
"use the `'static` lifetime",
973+
if elided { "'static " } else { "'static" },
974+
Applicability::MachineApplicable
975+
);
976+
}
969977
}
970978
// Rewrap `db`, and pass control to the user.
971979
decorate(db)

compiler/rustc_lint_defs/src/builtin.rs

+42
Original file line numberDiff line numberDiff line change
@@ -3376,6 +3376,7 @@ declare_lint_pass! {
33763376
DEPRECATED_IN_FUTURE,
33773377
DEPRECATED_WHERE_CLAUSE_LOCATION,
33783378
DUPLICATE_MACRO_ATTRIBUTES,
3379+
ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
33793380
ELIDED_LIFETIMES_IN_PATHS,
33803381
EXPORTED_PRIVATE_DEPENDENCIES,
33813382
FFI_UNWIND_CALLS,
@@ -4527,3 +4528,44 @@ declare_lint! {
45274528
reference: "issue #114095 <https://github.com/rust-lang/rust/issues/114095>",
45284529
};
45294530
}
4531+
4532+
declare_lint! {
4533+
/// The `elided_lifetimes_in_associated_constant` lint detects elided lifetimes
4534+
/// that were erroneously allowed in associated constants.
4535+
///
4536+
/// ### Example
4537+
///
4538+
/// ```rust,compile_fail
4539+
/// #![deny(elided_lifetimes_in_associated_constant)]
4540+
///
4541+
/// struct Foo;
4542+
///
4543+
/// impl Foo {
4544+
/// const STR: &str = "hello, world";
4545+
/// }
4546+
/// ```
4547+
///
4548+
/// {{produces}}
4549+
///
4550+
/// ### Explanation
4551+
///
4552+
/// Previous version of Rust
4553+
///
4554+
/// Implicit static-in-const behavior was decided [against] for associated
4555+
/// constants because of ambiguity. This, however, regressed and the compiler
4556+
/// erroneously treats elided lifetimes in associated constants as lifetime
4557+
/// parameters on the impl.
4558+
///
4559+
/// This is a [future-incompatible] lint to transition this to a
4560+
/// hard error in the future.
4561+
///
4562+
/// [against]: https://github.com/rust-lang/rust/issues/38831
4563+
/// [future-incompatible]: ../index.md#future-incompatible-lints
4564+
pub ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
4565+
Warn,
4566+
"elided lifetimes cannot be used in associated constants in impls",
4567+
@future_incompatible = FutureIncompatibleInfo {
4568+
reason: FutureIncompatibilityReason::FutureReleaseError,
4569+
reference: "issue #115010 <https://github.com/rust-lang/rust/issues/115010>",
4570+
};
4571+
}

compiler/rustc_lint_defs/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,10 @@ pub enum BuiltinLintDiagnostics {
572572
/// The span of the unnecessarily-qualified path to remove.
573573
removal_span: Span,
574574
},
575+
AssociatedConstElidedLifetime {
576+
elided: bool,
577+
span: Span,
578+
},
575579
}
576580

577581
/// Lints that are buffered up early on in the `Session` before the

compiler/rustc_resolve/src/late.rs

+55-24
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,10 @@ enum LifetimeRibKind {
311311
/// error on default object bounds (e.g., `Box<dyn Foo>`).
312312
AnonymousReportError,
313313

314+
/// Resolves elided lifetimes to `'static`, but gives a warning that this behavior
315+
/// is a bug and will be reverted soon.
316+
AnonymousWarnToStatic(NodeId),
317+
314318
/// Signal we cannot find which should be the anonymous lifetime.
315319
ElisionFailure,
316320

@@ -1148,6 +1152,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
11481152
}
11491153
LifetimeRibKind::AnonymousCreateParameter { .. }
11501154
| LifetimeRibKind::AnonymousReportError
1155+
| LifetimeRibKind::AnonymousWarnToStatic(_)
11511156
| LifetimeRibKind::Elided(_)
11521157
| LifetimeRibKind::ElisionFailure
11531158
| LifetimeRibKind::ConcreteAnonConst(_)
@@ -1515,6 +1520,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
15151520
// lifetime would be illegal.
15161521
LifetimeRibKind::Item
15171522
| LifetimeRibKind::AnonymousReportError
1523+
| LifetimeRibKind::AnonymousWarnToStatic(_)
15181524
| LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many),
15191525
// An anonymous lifetime is legal here, and bound to the right
15201526
// place, go ahead.
@@ -1576,7 +1582,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
15761582
| LifetimeRibKind::Elided(_)
15771583
| LifetimeRibKind::Generics { .. }
15781584
| LifetimeRibKind::ElisionFailure
1579-
| LifetimeRibKind::AnonymousReportError => {}
1585+
| LifetimeRibKind::AnonymousReportError
1586+
| LifetimeRibKind::AnonymousWarnToStatic(_) => {}
15801587
}
15811588
}
15821589

@@ -1616,6 +1623,25 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
16161623
self.record_lifetime_res(lifetime.id, res, elision_candidate);
16171624
return;
16181625
}
1626+
LifetimeRibKind::AnonymousWarnToStatic(node_id) => {
1627+
self.record_lifetime_res(lifetime.id, LifetimeRes::Static, elision_candidate);
1628+
let msg = if elided {
1629+
"`&` without an explicit lifetime name cannot be used here"
1630+
} else {
1631+
"`'_` cannot be used here"
1632+
};
1633+
self.r.lint_buffer.buffer_lint_with_diagnostic(
1634+
lint::builtin::ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
1635+
node_id,
1636+
lifetime.ident.span,
1637+
msg,
1638+
lint::BuiltinLintDiagnostics::AssociatedConstElidedLifetime {
1639+
elided,
1640+
span: lifetime.ident.span,
1641+
},
1642+
);
1643+
return;
1644+
}
16191645
LifetimeRibKind::AnonymousReportError => {
16201646
let (msg, note) = if elided {
16211647
(
@@ -1811,7 +1837,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
18111837
//
18121838
// impl Foo for std::cell::Ref<u32> // note lack of '_
18131839
// async fn foo(_: std::cell::Ref<u32>) { ... }
1814-
LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } => {
1840+
LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. }
1841+
| LifetimeRibKind::AnonymousWarnToStatic(_) => {
18151842
let sess = self.r.tcx.sess;
18161843
let mut err = rustc_errors::struct_span_err!(
18171844
sess,
@@ -2898,7 +2925,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
28982925
match &item.kind {
28992926
AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
29002927
debug!("resolve_implementation AssocItemKind::Const");
2901-
29022928
self.with_generic_param_rib(
29032929
&generics.params,
29042930
RibKind::AssocItem,
@@ -2908,28 +2934,33 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
29082934
kind: LifetimeBinderKind::ConstItem,
29092935
},
29102936
|this| {
2911-
// If this is a trait impl, ensure the const
2912-
// exists in trait
2913-
this.check_trait_item(
2914-
item.id,
2915-
item.ident,
2916-
&item.kind,
2917-
ValueNS,
2918-
item.span,
2919-
seen_trait_items,
2920-
|i, s, c| ConstNotMemberOfTrait(i, s, c),
2921-
);
2937+
this.with_lifetime_rib(
2938+
LifetimeRibKind::AnonymousWarnToStatic(item.id),
2939+
|this| {
2940+
// If this is a trait impl, ensure the const
2941+
// exists in trait
2942+
this.check_trait_item(
2943+
item.id,
2944+
item.ident,
2945+
&item.kind,
2946+
ValueNS,
2947+
item.span,
2948+
seen_trait_items,
2949+
|i, s, c| ConstNotMemberOfTrait(i, s, c),
2950+
);
29222951

2923-
this.visit_generics(generics);
2924-
this.visit_ty(ty);
2925-
if let Some(expr) = expr {
2926-
// We allow arbitrary const expressions inside of associated consts,
2927-
// even if they are potentially not const evaluatable.
2928-
//
2929-
// Type parameters can already be used and as associated consts are
2930-
// not used as part of the type system, this is far less surprising.
2931-
this.resolve_const_body(expr, None);
2932-
}
2952+
this.visit_generics(generics);
2953+
this.visit_ty(ty);
2954+
if let Some(expr) = expr {
2955+
// We allow arbitrary const expressions inside of associated consts,
2956+
// even if they are potentially not const evaluatable.
2957+
//
2958+
// Type parameters can already be used and as associated consts are
2959+
// not used as part of the type system, this is far less surprising.
2960+
this.resolve_const_body(expr, None);
2961+
}
2962+
},
2963+
);
29332964
},
29342965
);
29352966
}

src/bootstrap/tool.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,7 @@ pub struct RustAnalyzer {
601601
}
602602

603603
impl RustAnalyzer {
604-
pub const ALLOW_FEATURES: &str =
604+
pub const ALLOW_FEATURES: &'static str =
605605
"proc_macro_internals,proc_macro_diagnostic,proc_macro_span,proc_macro_span_shrink";
606606
}
607607

src/tools/rust-analyzer/crates/test-utils/src/fixture.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ impl FixtureWithProjectMeta {
313313
}
314314

315315
impl MiniCore {
316-
const RAW_SOURCE: &str = include_str!("./minicore.rs");
316+
const RAW_SOURCE: &'static str = include_str!("./minicore.rs");
317317

318318
fn has_flag(&self, flag: &str) -> bool {
319319
self.activated_flags.iter().any(|it| it == flag)

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

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ 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!
810
}
911

1012
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
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+
115
error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants
216
--> $DIR/infer-placeholder-in-non-suggestable-pos.rs:6:26
317
|
418
LL | const ASSOC: &dyn Fn(_) = 1i32;
519
| ^ not allowed in type signatures
620

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

923
For more information about this error, try `rustc --explain E0121`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![deny(elided_lifetimes_in_associated_constant)]
2+
3+
use std::marker::PhantomData;
4+
5+
struct Foo<'a> {
6+
x: PhantomData<&'a ()>,
7+
}
8+
9+
impl<'a> Foo<'a> {
10+
const FOO: Foo<'_> = Foo { x: PhantomData::<&()> };
11+
//~^ ERROR `'_` cannot be used here
12+
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
13+
14+
const BAR: &() = &();
15+
//~^ ERROR `&` without an explicit lifetime name cannot be used here
16+
//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
17+
}
18+
19+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error: `'_` cannot be used here
2+
--> $DIR/assoc-const-elided-lifetime.rs:10:20
3+
|
4+
LL | const FOO: Foo<'_> = Foo { x: PhantomData::<&()> };
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: the lint level is defined here
10+
--> $DIR/assoc-const-elided-lifetime.rs:1:9
11+
|
12+
LL | #![deny(elided_lifetimes_in_associated_constant)]
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
help: use the `'static` lifetime
15+
|
16+
LL | const FOO: Foo<'static> = Foo { x: PhantomData::<&()> };
17+
| ~~~~~~~
18+
19+
error: `&` without an explicit lifetime name cannot be used here
20+
--> $DIR/assoc-const-elided-lifetime.rs:14:16
21+
|
22+
LL | const BAR: &() = &();
23+
| ^
24+
|
25+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
26+
= note: for more information, see issue #115010 <https://github.com/rust-lang/rust/issues/115010>
27+
help: use the `'static` lifetime
28+
|
29+
LL | const BAR: &'static () = &();
30+
| +++++++
31+
32+
error: aborting due to 2 previous errors
33+

0 commit comments

Comments
 (0)