And finally add tests
This commit is contained in:
parent
1529c661e4
commit
052de1da4f
@ -9,31 +9,89 @@ use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
|
||||
use rustc_middle::ty::{
|
||||
self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||
};
|
||||
use rustc_session::lint::FutureIncompatibilityReason;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{BytePos, Span};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::{declare_lint, declare_lint_pass};
|
||||
use rustc_span::{sym, BytePos, Span};
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::{LateContext, LateLintPass};
|
||||
|
||||
// TODO: feature gate these too
|
||||
|
||||
declare_lint! {
|
||||
/// UwU
|
||||
/// The `impl_trait_overcaptures` lint warns against cases where lifetime
|
||||
/// capture behavior will differ in edition 2024.
|
||||
///
|
||||
/// In the 2024 edition, `impl Trait`s will capture all lifetimes in scope,
|
||||
/// rather than just the lifetimes that are mentioned in the bounds of the type.
|
||||
/// Often these sets are equal, but if not, it means that the `impl Trait` may
|
||||
/// cause erroneous borrow-checker errors.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// # #![feature(precise_capturing)]
|
||||
/// # #![allow(incomplete_features)]
|
||||
/// # #![deny(impl_trait_overcaptures)]
|
||||
/// # use std::fmt::Display;
|
||||
/// let mut x = vec![];
|
||||
/// x.push(1);
|
||||
///
|
||||
/// fn test(x: &Vec<i32>) -> impl Display {
|
||||
/// x[0]
|
||||
/// }
|
||||
///
|
||||
/// let element = test(&x);
|
||||
/// x.push(2);
|
||||
/// println!("{element}");
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// In edition < 2024, the returned `impl Display` doesn't capture the
|
||||
/// lifetime from the `&Vec<i32>`, so the vector can be mutably borrowed
|
||||
/// while the `impl Display` is live.
|
||||
///
|
||||
/// To fix this, we can explicitly state that the `impl Display` doesn't
|
||||
/// capture any lifetimes, using `impl use<> Display`.
|
||||
pub IMPL_TRAIT_OVERCAPTURES,
|
||||
Allow,
|
||||
"will capture more lifetimes than possibly intended in edition 2024",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
|
||||
reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
|
||||
};
|
||||
"`impl Trait` will capture more lifetimes than possibly intended in edition 2024",
|
||||
@feature_gate = sym::precise_capturing;
|
||||
//@future_incompatible = FutureIncompatibleInfo {
|
||||
// reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
|
||||
// reference: "<FIXME>",
|
||||
//};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// UwU
|
||||
/// The `impl_trait_redundant_captures` lint warns against cases where use of the
|
||||
/// precise capturing `use<...>` syntax is not needed.
|
||||
///
|
||||
/// In the 2024 edition, `impl Trait`s will capture all lifetimes in scope.
|
||||
/// If precise-capturing `use<...>` syntax is used, and the set of parameters
|
||||
/// that are captures are *equal* to the set of parameters in scope, then
|
||||
/// the syntax is redundant, and can be removed.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// # #![feature(precise_capturing, lifetime_capture_rules_2024)]
|
||||
/// # #![allow(incomplete_features)]
|
||||
/// # #![deny(impl_trait_redundant_captures)]
|
||||
/// fn test<'a>(x: &'a i32) -> impl use<'a> Sized { x }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// To fix this, remove the `use<'a>`, since the lifetime is already captured
|
||||
/// since it is in scope.
|
||||
pub IMPL_TRAIT_REDUNDANT_CAPTURES,
|
||||
Warn,
|
||||
"uwu 2"
|
||||
"redundant precise-capturing `use<...>` syntax on an `impl Trait`",
|
||||
@feature_gate = sym::precise_capturing;
|
||||
}
|
||||
|
||||
declare_lint_pass!(
|
||||
@ -106,7 +164,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
|
||||
for arg in t.bound_vars() {
|
||||
let arg: ty::BoundVariableKind = arg;
|
||||
match arg {
|
||||
ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(def_id, ..)) => {
|
||||
ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(def_id, ..))
|
||||
| ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, _)) => {
|
||||
added.push(def_id);
|
||||
let unique = self.in_scope_parameters.insert(def_id);
|
||||
assert!(unique);
|
||||
@ -265,7 +324,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
|
||||
}
|
||||
_ => {
|
||||
self.tcx.dcx().span_delayed_bug(
|
||||
self.tcx().hir().span(arg.hir_id()),
|
||||
self.tcx.hir().span(arg.hir_id()),
|
||||
"no valid for captured arg",
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
//@ run-rustfix
|
||||
|
||||
#![feature(precise_capturing)]
|
||||
#![allow(unused, incomplete_features)]
|
||||
#![deny(impl_trait_overcaptures)]
|
||||
|
||||
fn named<'a>(x: &'a i32) -> impl use<> Sized { *x }
|
||||
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||
|
||||
fn implicit(x: &i32) -> impl use<> Sized { *x }
|
||||
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||
|
||||
struct W;
|
||||
impl W {
|
||||
fn hello(&self, x: &i32) -> impl use<'_> Sized + '_ { self }
|
||||
//~^ ERROR `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
|
||||
}
|
||||
|
||||
trait Higher<'a> {
|
||||
type Output;
|
||||
}
|
||||
impl Higher<'_> for () {
|
||||
type Output = ();
|
||||
}
|
||||
|
||||
fn hrtb() -> impl for<'a> Higher<'a, Output = impl use<> Sized> {}
|
||||
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||
|
||||
fn main() {}
|
29
tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs
Normal file
29
tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs
Normal file
@ -0,0 +1,29 @@
|
||||
//@ run-rustfix
|
||||
|
||||
#![feature(precise_capturing)]
|
||||
#![allow(unused, incomplete_features)]
|
||||
#![deny(impl_trait_overcaptures)]
|
||||
|
||||
fn named<'a>(x: &'a i32) -> impl Sized { *x }
|
||||
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||
|
||||
fn implicit(x: &i32) -> impl Sized { *x }
|
||||
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||
|
||||
struct W;
|
||||
impl W {
|
||||
fn hello(&self, x: &i32) -> impl Sized + '_ { self }
|
||||
//~^ ERROR `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
|
||||
}
|
||||
|
||||
trait Higher<'a> {
|
||||
type Output;
|
||||
}
|
||||
impl Higher<'_> for () {
|
||||
type Output = ();
|
||||
}
|
||||
|
||||
fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
|
||||
//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,75 @@
|
||||
error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||
--> $DIR/overcaptures-2024.rs:7:29
|
||||
|
|
||||
LL | fn named<'a>(x: &'a i32) -> impl Sized { *x }
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
|
||||
--> $DIR/overcaptures-2024.rs:7:10
|
||||
|
|
||||
LL | fn named<'a>(x: &'a i32) -> impl Sized { *x }
|
||||
| ^^
|
||||
= note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
|
||||
note: the lint level is defined here
|
||||
--> $DIR/overcaptures-2024.rs:5:9
|
||||
|
|
||||
LL | #![deny(impl_trait_overcaptures)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||
|
|
||||
LL | fn named<'a>(x: &'a i32) -> impl use<> Sized { *x }
|
||||
| +++++
|
||||
|
||||
error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||
--> $DIR/overcaptures-2024.rs:10:25
|
||||
|
|
||||
LL | fn implicit(x: &i32) -> impl Sized { *x }
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
|
||||
--> $DIR/overcaptures-2024.rs:10:16
|
||||
|
|
||||
LL | fn implicit(x: &i32) -> impl Sized { *x }
|
||||
| ^
|
||||
= note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
|
||||
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||
|
|
||||
LL | fn implicit(x: &i32) -> impl use<> Sized { *x }
|
||||
| +++++
|
||||
|
||||
error: `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
|
||||
--> $DIR/overcaptures-2024.rs:15:33
|
||||
|
|
||||
LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self }
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
|
||||
--> $DIR/overcaptures-2024.rs:15:24
|
||||
|
|
||||
LL | fn hello(&self, x: &i32) -> impl Sized + '_ { self }
|
||||
| ^
|
||||
= note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
|
||||
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||
|
|
||||
LL | fn hello(&self, x: &i32) -> impl use<'_> Sized + '_ { self }
|
||||
| +++++++
|
||||
|
||||
error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
|
||||
--> $DIR/overcaptures-2024.rs:26:47
|
||||
|
|
||||
LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
note: specifically, this lifetime is in scope but not mentioned in the type's bounds
|
||||
--> $DIR/overcaptures-2024.rs:26:23
|
||||
|
|
||||
LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
|
||||
| ^^
|
||||
= note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
|
||||
help: use the precise capturing `use<...>` syntax to make the captures explicit
|
||||
|
|
||||
LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl use<> Sized> {}
|
||||
| +++++
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
Loading…
x
Reference in New Issue
Block a user