From 0b3370878b253244dd086c34a5c75c8ae69738ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 3 Jan 2025 00:55:03 +0000 Subject: [PATCH] Emit single error for `+ use<'_>` and don't suggest `use<'static>` ``` error[E0106]: missing lifetime specifier --> $DIR/bad-lifetimes.rs:1:39 | LL | fn no_elided_lt() -> impl Sized + use<'_> {} | ^^ expected named lifetime parameter | help: consider introducing a named lifetime parameter | LL | fn no_elided_lt<'a>() -> impl Sized + use<'a> {} | ++++ ~~ ``` Fix #134194. --- .../src/collect/resolve_bound_vars.rs | 13 +++++++---- compiler/rustc_resolve/src/late.rs | 22 ++++++++++++++++--- .../rustc_resolve/src/late/diagnostics.rs | 19 +++++++++++----- .../precise-capturing/bad-lifetimes.rs | 1 - .../precise-capturing/bad-lifetimes.stderr | 21 +++++------------- 5 files changed, 47 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index c03a1f6240fa3..8346ec4bde360 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -657,10 +657,15 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { LifetimeName::Param(def_id) => { self.resolve_lifetime_ref(def_id, lt); } - LifetimeName::Error => {} - LifetimeName::ImplicitObjectLifetimeDefault - | LifetimeName::Infer - | LifetimeName::Static => { + LifetimeName::Infer | LifetimeName::Error => { + // We don't check for explicit `'_` lifetimes because we'll already have an + // explicit error from late resolution explaining `use<'_>` is invalid. + self.tcx.dcx().span_delayed_bug( + lt.ident.span, + "found infer or error lifetime but no prior error", + ); + } + LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Static => { self.tcx.dcx().emit_err(errors::BadPreciseCapture { span: lt.ident.span, kind: "lifetime", diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 03aeb8720ca62..3204dfd64b1a6 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1132,6 +1132,18 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r fn visit_precise_capturing_arg(&mut self, arg: &'ast PreciseCapturingArg) { match arg { + PreciseCapturingArg::Lifetime(lt) if lt.ident.name == kw::UnderscoreLifetime => { + // We account for `+ use<'_>` explicitly to avoid providing an invalid suggestion + // for `+ use<'static>`. + let outer_failures = take(&mut self.diag_metadata.current_elision_failures); + visit::walk_precise_capturing_arg(self, arg); + let elision_failures = + replace(&mut self.diag_metadata.current_elision_failures, outer_failures); + if !elision_failures.is_empty() { + self.report_missing_lifetime_specifiers(elision_failures, None, true); + } + return; + } // Lower the lifetime regularly; we'll resolve the lifetime and check // it's a parameter later on in HIR lowering. PreciseCapturingArg::Lifetime(_) => {} @@ -1884,7 +1896,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } } self.record_lifetime_res(lifetime.id, LifetimeRes::Error, elision_candidate); - self.report_missing_lifetime_specifiers(vec![missing_lifetime], None); + self.report_missing_lifetime_specifiers(vec![missing_lifetime], None, false); } #[instrument(level = "debug", skip(self))] @@ -2104,7 +2116,11 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { LifetimeElisionCandidate::Ignore, ); } - self.report_missing_lifetime_specifiers(vec![missing_lifetime], None); + self.report_missing_lifetime_specifiers( + vec![missing_lifetime], + None, + false, + ); break; } LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstParamTy => {} @@ -2227,7 +2243,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { replace(&mut self.diag_metadata.current_elision_failures, outer_failures); if !elision_failures.is_empty() { let Err(failure_info) = elision_lifetime else { bug!() }; - self.report_missing_lifetime_specifiers(elision_failures, Some(failure_info)); + self.report_missing_lifetime_specifiers(elision_failures, Some(failure_info), false); } } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index a80b68d9773d4..e5293d3e58847 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3039,6 +3039,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { &mut self, lifetime_refs: Vec, function_param_lifetimes: Option<(Vec, Vec)>, + in_precise_capture: bool, ) -> ErrorGuaranteed { let num_lifetimes: usize = lifetime_refs.iter().map(|lt| lt.count).sum(); let spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect(); @@ -3050,14 +3051,22 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { "missing lifetime specifier{}", pluralize!(num_lifetimes) ); - self.add_missing_lifetime_specifiers_label( - &mut err, - lifetime_refs, - function_param_lifetimes, - ); + if in_precise_capture { + err.note( + "cannot capture elided lifetime with `use<'_>` when there is no lifetime in scope \ + to capture", + ); + } else { + self.add_missing_lifetime_specifiers_label( + &mut err, + lifetime_refs, + function_param_lifetimes, + ); + } err.emit() } + #[tracing::instrument(skip(self, err), level = "info")] fn add_missing_lifetime_specifiers_label( &mut self, err: &mut Diag<'_>, diff --git a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs index 161fe23c89995..8e30973cd3a18 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs +++ b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.rs @@ -1,6 +1,5 @@ fn no_elided_lt() -> impl Sized + use<'_> {} //~^ ERROR missing lifetime specifier -//~| ERROR expected lifetime parameter in `use<...>` precise captures list, found `'_` fn static_lt() -> impl Sized + use<'static> {} //~^ ERROR expected lifetime parameter in `use<...>` precise captures list, found `'static` diff --git a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr index c8dac3a69cd98..59173994a5af8 100644 --- a/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr +++ b/tests/ui/impl-trait/precise-capturing/bad-lifetimes.stderr @@ -2,36 +2,25 @@ error[E0106]: missing lifetime specifier --> $DIR/bad-lifetimes.rs:1:39 | LL | fn no_elided_lt() -> impl Sized + use<'_> {} - | ^^ expected named lifetime parameter - | - = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from -help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`, or if you will only have owned values - | -LL - fn no_elided_lt() -> impl Sized + use<'_> {} -LL + fn no_elided_lt() -> impl Sized + use<'static> {} + | ^^ | + = note: cannot capture elided lifetime with `use<'_>` when there is no lifetime in scope to capture error[E0261]: use of undeclared lifetime name `'missing` - --> $DIR/bad-lifetimes.rs:8:37 + --> $DIR/bad-lifetimes.rs:7:37 | LL | fn missing_lt() -> impl Sized + use<'missing> {} | - ^^^^^^^^ undeclared lifetime | | | help: consider introducing lifetime `'missing` here: `<'missing>` -error: expected lifetime parameter in `use<...>` precise captures list, found `'_` - --> $DIR/bad-lifetimes.rs:1:39 - | -LL | fn no_elided_lt() -> impl Sized + use<'_> {} - | ^^ - error: expected lifetime parameter in `use<...>` precise captures list, found `'static` - --> $DIR/bad-lifetimes.rs:5:36 + --> $DIR/bad-lifetimes.rs:4:36 | LL | fn static_lt() -> impl Sized + use<'static> {} | ^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0106, E0261. For more information about an error, try `rustc --explain E0106`.