about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJake Goulding <jake.goulding@gmail.com>2025-06-06 14:18:32 -0400
committerJake Goulding <jake.goulding@gmail.com>2025-06-06 16:27:16 -0400
commit9c6320abb4bbe51f876e5e918a600e9a5c9dd11b (patch)
tree5536d0146f5ea8219eeeb6663675f923af03912a
parentd00435f223dc3a88d8c5f472b10ba948b7959cc6 (diff)
downloadrust-9c6320abb4bbe51f876e5e918a600e9a5c9dd11b.tar.gz
rust-9c6320abb4bbe51f876e5e918a600e9a5c9dd11b.zip
Apply `mismatched-lifetime-syntaxes` to trait and extern functions
-rw-r--r--compiler/rustc_lint/src/lifetime_syntax.rs40
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs2
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs39
-rw-r--r--tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr67
-rw-r--r--tests/ui/traits/associated_type_bound/hrtb-associated.rs2
5 files changed, 140 insertions, 10 deletions
diff --git a/compiler/rustc_lint/src/lifetime_syntax.rs b/compiler/rustc_lint/src/lifetime_syntax.rs
index 31b038e6a46..95b7b69bd5a 100644
--- a/compiler/rustc_lint/src/lifetime_syntax.rs
+++ b/compiler/rustc_lint/src/lifetime_syntax.rs
@@ -84,19 +84,45 @@ impl<'tcx> LateLintPass<'tcx> for LifetimeSyntax {
         _: rustc_span::Span,
         _: rustc_span::def_id::LocalDefId,
     ) {
-        let mut input_map = Default::default();
-        let mut output_map = Default::default();
+        check_fn_like(cx, fd);
+    }
 
-        for input in fd.inputs {
-            LifetimeInfoCollector::collect(input, &mut input_map);
+    #[instrument(skip_all)]
+    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, ti: &'tcx hir::TraitItem<'tcx>) {
+        match ti.kind {
+            hir::TraitItemKind::Const(..) => {}
+            hir::TraitItemKind::Fn(fn_sig, _trait_fn) => check_fn_like(cx, fn_sig.decl),
+            hir::TraitItemKind::Type(..) => {}
         }
+    }
 
-        if let hir::FnRetTy::Return(output) = fd.output {
-            LifetimeInfoCollector::collect(output, &mut output_map);
+    #[instrument(skip_all)]
+    fn check_foreign_item(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        fi: &'tcx rustc_hir::ForeignItem<'tcx>,
+    ) {
+        match fi.kind {
+            hir::ForeignItemKind::Fn(fn_sig, _idents, _generics) => check_fn_like(cx, fn_sig.decl),
+            hir::ForeignItemKind::Static(..) => {}
+            hir::ForeignItemKind::Type => {}
         }
+    }
+}
+
+fn check_fn_like<'tcx>(cx: &LateContext<'tcx>, fd: &'tcx hir::FnDecl<'tcx>) {
+    let mut input_map = Default::default();
+    let mut output_map = Default::default();
 
-        report_mismatches(cx, &input_map, &output_map);
+    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)]
diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs
index e00a31e26aa..cca60852efd 100644
--- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs
+++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs
@@ -20,7 +20,7 @@ where
     Self: Sized,
 {
     type I: for<'a> FamilyLt<'a>;
-    fn inject(_: &()) -> <Self::I as FamilyLt>::Out;
+    fn inject(_: &()) -> <Self::I as FamilyLt<'_>>::Out;
 }
 
 impl<T: 'static> Inject for RefMutFamily<T> {
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs
index 6d8487b99c6..b98423afb17 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.rs
@@ -220,6 +220,45 @@ mod diagnostic_output {
     }
 }
 
+/// Trait functions are represented differently in the HIR. Make sure
+/// we visit them.
+mod trait_functions {
+    #[derive(Copy, Clone)]
+    struct ContainsLifetime<'a>(&'a u8);
+
+    trait TheTrait {
+        fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime;
+        //~^ ERROR lifetime flowing from input to output with different syntax
+
+        fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime;
+        //~^ ERROR lifetime flowing from input to output with different syntax
+    }
+
+    impl TheTrait for &u8 {
+        fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime {
+            //~^ ERROR lifetime flowing from input to output with different syntax
+            ContainsLifetime(v)
+        }
+
+        fn method_implicit_ref_to_implicit_path(&self) -> ContainsLifetime {
+            //~^ ERROR lifetime flowing from input to output with different syntax
+            ContainsLifetime(self)
+        }
+    }
+}
+
+/// Extern functions are represented differently in the HIR. Make sure
+/// we visit them.
+mod foreign_functions {
+    #[derive(Copy, Clone)]
+    struct ContainsLifetime<'a>(&'a u8);
+
+    extern "Rust" {
+        fn implicit_ref_to_implicit_path(v: &u8) -> ContainsLifetime;
+        //~^ ERROR lifetime flowing from input to output with different syntax
+    }
+}
+
 /// These usages are expected to **not** trigger the lint
 mod acceptable_uses {
     #[derive(Copy, Clone)]
diff --git a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr
index 0ec16a266b6..108b3f14169 100644
--- a/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr
+++ b/tests/ui/lifetimes/mismatched-lifetime-syntaxes.stderr
@@ -469,5 +469,70 @@ 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
+error: lifetime flowing from input to output with different syntax can be confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:230:45
+   |
+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:233:49
+   |
+LL |         fn method_implicit_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_implicit_ref_to_implicit_path(&self) -> ContainsLifetime<'_>;
+   |                                                                           ++++
+
+error: lifetime flowing from input to output with different syntax can be confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:238:45
+   |
+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:243:49
+   |
+LL |         fn method_implicit_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_implicit_ref_to_implicit_path(&self) -> ContainsLifetime<'_> {
+   |                                                                           ++++
+
+error: lifetime flowing from input to output with different syntax can be confusing
+  --> $DIR/mismatched-lifetime-syntaxes.rs:257:45
+   |
+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: aborting due to 39 previous errors
 
diff --git a/tests/ui/traits/associated_type_bound/hrtb-associated.rs b/tests/ui/traits/associated_type_bound/hrtb-associated.rs
index 59e5a09c0cb..bf9f59c05e3 100644
--- a/tests/ui/traits/associated_type_bound/hrtb-associated.rs
+++ b/tests/ui/traits/associated_type_bound/hrtb-associated.rs
@@ -10,7 +10,7 @@ pub trait Provides<'a> {
 pub trait Selector: for<'a> Provides<'a> {
     type Namespace: PartialEq + for<'a> PartialEq<<Self as Provides<'a>>::Item>;
 
-    fn get_namespace(&self) -> <Self as Provides>::Item;
+    fn get_namespace(&self) -> <Self as Provides<'_>>::Item;
 }
 
 pub struct MySelector;