diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 9bb60d47ac849..01341c4c0f7f5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -17,7 +17,7 @@ use rustc_middle::mir::{AnnotationSource, ConstraintCategory, ReturnConstraint}; use rustc_middle::ty::{ self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitor, fold_regions, }; -use rustc_span::{Ident, Span, Symbol, bug, kw}; +use rustc_span::{Ident, Pos, Span, Symbol, bug, kw}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::infer::nice_region_error::{ self, HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor, find_anon_type, @@ -672,6 +672,7 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { if let ConstraintCategory::CallArgument(Some(ty)) = category { self.explain_impl_static_obligation(&mut diag, ty, outlived_fr); } + self.suggest_explicit_static_object_lifetime(&mut diag, &errci); match variance_info { ty::VarianceDiagInfo::None => {} @@ -1254,6 +1255,222 @@ impl<'diag, 'tcx> MirBorrowckCtxt<'_, 'diag, 'tcx> { } } + fn suggest_explicit_static_object_lifetime( + &self, + diag: &mut Diag<'_>, + errci: &ErrorConstraintInfo<'tcx>, + ) { + let tcx = self.infcx.tcx; + let (Some(region), Some(outlived_region)) = ( + self.regioncx.to_error_region(errci.fr), + self.regioncx.to_error_region(errci.outlived_fr), + ) else { + return; + }; + if !outlived_region.is_static() { + return; + } + let ConstraintCategory::CallArgument(Some(fn_ty)) = errci.category else { return }; + let ty::FnDef(def_id, args) = *fn_ty.kind() else { return }; + let Some(args) = args.no_bound_vars() else { return }; + if tcx.is_closure_like(def_id) { + return; + } + // CallArgument erases lifetime arguments. Bounds can still require the reference to + // outlive another region, even if the instantiated signature contains no `&'static`. + let clauses = tcx.clauses_of(def_id); + if clauses.instantiate_identity(tcx).into_iter().chain(clauses.instantiate(tcx, args)).any( + |(clause, _)| match clause.skip_norm_wip().kind().skip_binder() { + ty::ClauseKind::RegionOutlives(ty::OutlivesClause(longer, shorter)) => { + longer != shorter && !longer.is_static() + } + ty::ClauseKind::TypeOutlives(ty::OutlivesClause(ty, lifetime)) + if lifetime.is_static() => + { + ty.walk().any(|arg| { + matches!(arg.as_type().map(Ty::kind), + Some(ty::Ref(region, ..)) if !region.is_static()) + }) + } + _ => false, + }, + ) { + return; + } + let Some(call) = self.find_expr(errci.span) else { return }; + let call_args: Vec<_> = match call.kind { + hir::ExprKind::Call(_, args) => args.iter().collect(), + hir::ExprKind::MethodCall(_, receiver, args, _) => { + std::iter::once(receiver).chain(args).collect() + } + _ => return, + }; + let Some(body) = tcx.hir_maybe_body_owned_by(self.mir_def_id()) else { return }; + let Some(hir_sig) = tcx.hir_fn_sig_by_hir_id(self.mir_hir_id()) else { return }; + let decl = hir_sig.decl; + let callee_sig = tcx.fn_sig(def_id).instantiate(tcx, args).skip_norm_wip().skip_binder(); + // Typeck results have erased regions. The liberated signature retains the object lifetime. + let caller_sig = tcx.liberate_late_bound_regions( + self.mir_def_id().to_def_id(), + tcx.fn_sig(self.mir_def_id()).instantiate_identity().skip_norm_wip(), + ); + let needs_static_reference = |mut ty: Ty<'tcx>| { + while let ty::Ref(lifetime, inner, _) = *ty.kind() { + if lifetime.is_static() { + return true; + } + ty = inner; + } + false + }; + let mut seen_params = FxIndexSet::default(); + for (arg, expected) in std::iter::zip(call_args.iter().copied(), callee_sig.inputs()) { + if needs_static_reference(*expected) { + continue; + } + let ty::Dynamic(expected_predicates, expected_region) = *expected.peel_refs().kind() + else { + continue; + }; + if !expected_region.is_static() { + continue; + } + + // Follow the actual argument back to its parameter, rather than editing another + // parameter that happens to use the same lifetime or trait. + let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = arg.kind else { + continue; + }; + let hir::def::Res::Local(binding) = path.res else { continue }; + let Some(index) = body.params.iter().position(|param| param.pat.hir_id == binding) + else { + continue; + }; + let ty::Dynamic(predicates, object_region) = + *caller_sig.inputs()[index].peel_refs().kind() + else { + continue; + }; + if object_region != region { + continue; + } + // Callee lifetimes may be bound or erased here. Preserve explicit `'static` and + // repeated lifetime arguments: changing the object bound cannot fix those mismatches. + let comparable_predicates = |predicates| { + let mut regions = FxIndexSet::default(); + fold_regions(tcx, predicates, |region, _| { + if region.is_static() { + region + } else { + let (index, _) = regions.insert_full(region); + ty::Region::new_late_param( + tcx, + self.mir_def_id().to_def_id(), + ty::LateParamRegionKind::Anon(index as u32), + ) + } + }) + }; + let source_predicates = comparable_predicates(predicates); + let target_predicates = comparable_predicates(expected_predicates); + if source_predicates.principal().map(|p| tcx.anonymize_bound_vars(p)) + != target_predicates.principal().map(|p| tcx.anonymize_bound_vars(p)) + || !source_predicates + .projection_bounds() + .map(|p| tcx.anonymize_bound_vars(p)) + .eq(target_predicates.projection_bounds().map(|p| tcx.anonymize_bound_vars(p))) + { + continue; + } + // The same parameter may also be passed where the reference itself must be static. + if !seen_params.insert(index) + || std::iter::zip(&call_args, callee_sig.inputs()).any(|(other, expected)| { + needs_static_reference(*expected) + && matches!(other.kind, + hir::ExprKind::Path(hir::QPath::Resolved(None, path)) + if path.res == hir::def::Res::Local(binding)) + }) + { + continue; + } + let param_ty = decl.inputs[index]; + let object_ty = param_ty.peel_refs(); + let hir::TyKind::TraitObject(_, lifetime) = object_ty.kind else { continue }; + if lifetime.kind != hir::LifetimeKind::ImplicitObjectLifetimeDefault + || !object_ty.span.can_be_used_for_suggestions() + { + continue; + } + let lifetime_explanation = + if rustc_trait_selection::traits::wf::object_region_bounds(tcx, predicates) + .is_empty() + { + "this trait object's lifetime defaults to the reference's lifetime" + } else { + "this trait object's lifetime is inferred from its trait's lifetime bounds" + }; + + struct ElidedOutputLifetime<'tcx> { + tcx: TyCtxt<'tcx>, + object_lifetime: &'tcx hir::Lifetime, + found: bool, + } + impl<'tcx> Visitor<'tcx> for ElidedOutputLifetime<'tcx> { + fn visit_lifetime(&mut self, lifetime: &'tcx hir::Lifetime) { + let resolved = self.tcx.named_bound_var(lifetime.hir_id); + self.found |= lifetime.syntax != hir::LifetimeSyntax::ExplicitBound + && resolved.is_some() + && resolved == self.tcx.named_bound_var(self.object_lifetime.hir_id); + } + } + let mut output_lifetime = + ElidedOutputLifetime { tcx, object_lifetime: lifetime.pointer(), found: false }; + if let hir::FnRetTy::Return(output) = decl.output { + output_lifetime.visit_ty_unambig(output); + } + if output_lifetime.found { + // Adding another input lifetime would make output lifetime elision ambiguous. + diag.span_note(object_ty.span, lifetime_explanation); + continue; + } + + let source_map = tcx.sess.source_map(); + let Ok(mut snippet) = source_map.span_to_snippet(object_ty.span) else { continue }; + if let hir::TyKind::TraitObject(bounds, _) = object_ty.kind + && let Some(bound) = bounds.last() + && let Some(segment) = bound.trait_ref.path.segments.last() + && let Some(output) = segment.args().paren_sugar_output() + && let output = output.peel_refs() + && let hir::TyKind::TraitObject(..) = output.kind + { + if !object_ty.span.contains(output.span) { + continue; + } + // Otherwise `+ 'static` would bind to the callable's output trait object. + let start = (output.span.lo() - object_ty.span.lo()).to_usize(); + let end = (output.span.hi() - object_ty.span.lo()).to_usize(); + snippet.insert(end, ')'); + snippet.insert(start, '('); + } + let prefix = source_map + .span_to_snippet(param_ty.span.with_hi(object_ty.span.lo())) + .unwrap_or_default(); + let replacement = if prefix.trim_end().ends_with('(') { + format!("{snippet} + 'static") + } else { + format!("({snippet} + 'static)") + }; + diag.span_suggestion( + object_ty.span, + format!( + "{lifetime_explanation}; consider adding an explicit `'static` bound to the trait object" + ), + replacement, + Applicability::MaybeIncorrect, + ); + } + } + fn maybe_suggest_constrain_dyn_trait_impl( &self, diag: &mut Diag<'_>, diff --git a/tests/ui/object-lifetime/implicit-object-lifetime-no-suggestion.rs b/tests/ui/object-lifetime/implicit-object-lifetime-no-suggestion.rs new file mode 100644 index 0000000000000..055438a925724 --- /dev/null +++ b/tests/ui/object-lifetime/implicit-object-lifetime-no-suggestion.rs @@ -0,0 +1,121 @@ +#![allow(dead_code, mismatched_lifetime_syntaxes)] + +use std::error::Error; + +fn explicit_bound<'a, T: Error + 'static>(err: &(dyn Error + 'a)) -> bool { + err.is::() //~ ERROR borrowed data escapes outside of function +} + +fn explicit_placeholder(err: &(dyn Error + '_)) -> bool { + err.is::() //~ ERROR borrowed data escapes outside of function +} + +fn return_static(err: &dyn Error) -> &'static dyn Error { + err //~ ERROR lifetime may not live long enough +} + +fn return_other<'a, 'b>(err: &'a dyn Error) -> &'b dyn Error { + err //~ ERROR lifetime may not live long enough +} + +fn takes_static_reference(_: &'static dyn Error) {} + +fn static_reference_argument(err: &dyn Error) { + takes_static_reference(err); //~ ERROR borrowed data escapes outside of function +} + +fn takes_static_object_and_reference(_: &'static (dyn Error + 'static)) {} + +fn static_reference_and_object(err: &dyn Error) { + takes_static_object_and_reference(err); //~ ERROR borrowed data escapes outside of function +} + +fn takes_object_and_static_reference(_: &(dyn Error + 'static), _: &'static dyn Error) {} + +fn repeated_static_reference(err: &dyn Error) { + takes_object_and_static_reference(err, err); //~ ERROR borrowed data escapes outside of function +} + +fn takes_object_and_reference<'a>(_: &(dyn Error + 'a), _: &'static u32) {} + +fn unrelated_parameter<'a>(err: &'a dyn Error, other: &'a u32) { + takes_object_and_reference(err, other); //~ ERROR borrowed data escapes outside of function +} + +fn takes_generic_static(_: &T) {} + +fn generic_bound(err: &dyn Error) { + takes_generic_static(err); //~ ERROR borrowed data escapes outside of function +} + +trait Trait { + fn needs_static(&self) where Self: 'static {} +} + +fn where_self(err: &dyn Trait) { + err.needs_static(); //~ ERROR borrowed data escapes outside of function +} + +fn elided_output(err: &dyn Error) -> Option<&T> { + err.downcast_ref::() //~ ERROR borrowed data escapes outside of function +} + +fn named_input_elided_output<'a, T: Error + 'static>(err: &'a dyn Error) -> Option<&T> { + err.downcast_ref::() //~ ERROR borrowed data escapes outside of function +} + +fn placeholder_output(err: &dyn Error) -> Option<&'_ T> { + err.downcast_ref::() //~ ERROR borrowed data escapes outside of function +} + +fn takes_predicate_reference<'a: 'static>(_: &'a (dyn Error + 'static)) {} + +fn predicate_reference(err: &dyn Error) { + takes_predicate_reference(err); //~ ERROR borrowed data escapes outside of function +} + +fn takes_transitive_reference<'a: 'b, 'b: 'static>(_: &'a (dyn Error + 'static)) {} + +fn transitive_reference(err: &dyn Error) { + takes_transitive_reference(err); //~ ERROR borrowed data escapes outside of function +} + +fn takes_reference_type<'a>(_: &'a (dyn Error + 'static)) +where + &'a (dyn Error + 'static): 'static, +{ +} + +fn reference_type_bound(err: &dyn Error) { + takes_reference_type(err); //~ ERROR borrowed data escapes outside of function +} + +trait LifetimeArgument<'a> {} + +fn takes_static_argument(_: &(dyn LifetimeArgument<'static> + 'static)) {} + +fn mismatched_argument<'a>(arg: &'a dyn LifetimeArgument<'a>) { + takes_static_argument(arg); //~ ERROR borrowed data escapes outside of function +} + +trait AssociatedType { + type Item; +} + +fn takes_static_associated_type(_: &(dyn AssociatedType + 'static)) {} + +fn mismatched_associated_type<'a>(arg: &'a dyn AssociatedType) { + takes_static_associated_type(arg); //~ ERROR borrowed data escapes outside of function +} + +trait RepeatedLifetime<'a, 'b> {} + +fn takes_repeated_lifetime<'c>(_: &(dyn RepeatedLifetime<'c, 'c> + 'static)) {} + +fn mismatched_repeated_lifetime<'a, 'b>(arg: &'a dyn RepeatedLifetime<'a, 'b>) { + //~^ ERROR one or more lifetime errors were found in this item + takes_repeated_lifetime(arg); //~ ERROR borrowed data escapes outside of function + //~^ ERROR borrowed data escapes outside of function +} + +fn main() {} diff --git a/tests/ui/object-lifetime/implicit-object-lifetime-no-suggestion.stderr b/tests/ui/object-lifetime/implicit-object-lifetime-no-suggestion.stderr new file mode 100644 index 0000000000000..fdd9c09959f58 --- /dev/null +++ b/tests/ui/object-lifetime/implicit-object-lifetime-no-suggestion.stderr @@ -0,0 +1,362 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:6:5 + | +LL | fn explicit_bound<'a, T: Error + 'static>(err: &(dyn Error + 'a)) -> bool { + | -- --- `err` is only valid in the function body + | | + | lifetime `'a` defined here +LL | err.is::() + | ^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'a` must outlive `'static` + | +note: `'static` lifetime requirement from `<(dyn std::error::Error + 'static)>::is` introduced here + --> $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here + ::: $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:10:5 + | +LL | fn explicit_placeholder(err: &(dyn Error + '_)) -> bool { + | --- -- lifetime `'1` introduced here + | | + | `err` is only valid in the function body + | has type `&(dyn std::error::Error + '1)` +LL | err.is::() + | ^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +note: `'static` lifetime requirement from `<(dyn std::error::Error + 'static)>::is` introduced here + --> $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here + ::: $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here + +error: lifetime may not live long enough + --> $DIR/implicit-object-lifetime-no-suggestion.rs:14:5 + | +LL | fn return_static(err: &dyn Error) -> &'static dyn Error { + | - let's call the lifetime of this reference `'1` +LL | err + | ^^^ returning this value requires that `'1` must outlive `'static` + | +help: to declare that the trait object captures data from argument `err`, you can add an explicit `'_` lifetime bound + | +LL | fn return_static(err: &dyn Error) -> &'static dyn Error + '_ { + | ++++ + +error: lifetime may not live long enough + --> $DIR/implicit-object-lifetime-no-suggestion.rs:18:5 + | +LL | fn return_other<'a, 'b>(err: &'a dyn Error) -> &'b dyn Error { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | err + | ^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:24:5 + | +LL | fn static_reference_argument(err: &dyn Error) { + | --- - let's call the lifetime of this reference `'1` + | | + | `err` is only valid in the function body +LL | takes_static_reference(err); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'1` must outlive `'static` + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:30:5 + | +LL | fn static_reference_and_object(err: &dyn Error) { + | --- - let's call the lifetime of this reference `'1` + | | + | `err` is only valid in the function body +LL | takes_static_object_and_reference(err); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'1` must outlive `'static` + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:36:5 + | +LL | fn repeated_static_reference(err: &dyn Error) { + | --- - let's call the lifetime of this reference `'1` + | | + | `err` is only valid in the function body +LL | takes_object_and_static_reference(err, err); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'1` must outlive `'static` + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:42:5 + | +LL | fn unrelated_parameter<'a>(err: &'a dyn Error, other: &'a u32) { + | -- --- `err` is only valid in the function body + | | + | lifetime `'a` defined here +LL | takes_object_and_reference(err, other); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'a` must outlive `'static` + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:48:5 + | +LL | fn generic_bound(err: &dyn Error) { + | --- - let's call the lifetime of this reference `'1` + | | + | `err` is only valid in the function body +LL | takes_generic_static(err); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +note: `'static` lifetime requirement from `takes_generic_static` introduced here + --> $DIR/implicit-object-lifetime-no-suggestion.rs:45:37 + | +LL | fn takes_generic_static(_: &T) {} + | ^^^^^^^ lifetime requirement introduced here + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:56:5 + | +LL | fn where_self(err: &dyn Trait) { + | --- - let's call the lifetime of this reference `'1` + | | + | `err` is only valid in the function body +LL | err.needs_static(); + | ^^^^^^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +note: `'static` lifetime requirement from `Trait::needs_static` introduced here + --> $DIR/implicit-object-lifetime-no-suggestion.rs:52:40 + | +LL | trait Trait { +LL | fn needs_static(&self) where Self: 'static {} + | ^^^^^^^ lifetime requirement introduced here + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:60:5 + | +LL | fn elided_output(err: &dyn Error) -> Option<&T> { + | --- - let's call the lifetime of this reference `'1` + | | + | `err` is only valid in the function body +LL | err.downcast_ref::() + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +note: `'static` lifetime requirement from `<(dyn std::error::Error + 'static)>::downcast_ref` introduced here + --> $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here + ::: $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here +note: this trait object's lifetime defaults to the reference's lifetime + --> $DIR/implicit-object-lifetime-no-suggestion.rs:59:44 + | +LL | fn elided_output(err: &dyn Error) -> Option<&T> { + | ^^^^^^^^^ + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:64:5 + | +LL | fn named_input_elided_output<'a, T: Error + 'static>(err: &'a dyn Error) -> Option<&T> { + | -- --- `err` is only valid in the function body + | | + | lifetime `'a` defined here +LL | err.downcast_ref::() + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'a` must outlive `'static` + | +note: `'static` lifetime requirement from `<(dyn std::error::Error + 'static)>::downcast_ref` introduced here + --> $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here + ::: $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here +note: this trait object's lifetime defaults to the reference's lifetime + --> $DIR/implicit-object-lifetime-no-suggestion.rs:63:63 + | +LL | fn named_input_elided_output<'a, T: Error + 'static>(err: &'a dyn Error) -> Option<&T> { + | ^^^^^^^^^ + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:68:5 + | +LL | fn placeholder_output(err: &dyn Error) -> Option<&'_ T> { + | --- - let's call the lifetime of this reference `'1` + | | + | `err` is only valid in the function body +LL | err.downcast_ref::() + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +note: `'static` lifetime requirement from `<(dyn std::error::Error + 'static)>::downcast_ref` introduced here + --> $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here + ::: $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here +note: this trait object's lifetime defaults to the reference's lifetime + --> $DIR/implicit-object-lifetime-no-suggestion.rs:67:49 + | +LL | fn placeholder_output(err: &dyn Error) -> Option<&'_ T> { + | ^^^^^^^^^ + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:74:5 + | +LL | fn predicate_reference(err: &dyn Error) { + | --- - let's call the lifetime of this reference `'1` + | | + | `err` is only valid in the function body +LL | takes_predicate_reference(err); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +note: `'static` lifetime requirement from `takes_predicate_reference` introduced here + --> $DIR/implicit-object-lifetime-no-suggestion.rs:71:34 + | +LL | fn takes_predicate_reference<'a: 'static>(_: &'a (dyn Error + 'static)) {} + | ^^^^^^^ lifetime requirement introduced here + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:80:5 + | +LL | fn transitive_reference(err: &dyn Error) { + | --- - let's call the lifetime of this reference `'1` + | | + | `err` is only valid in the function body +LL | takes_transitive_reference(err); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +note: `'static` lifetime requirement from `takes_transitive_reference` introduced here + --> $DIR/implicit-object-lifetime-no-suggestion.rs:77:43 + | +LL | fn takes_transitive_reference<'a: 'b, 'b: 'static>(_: &'a (dyn Error + 'static)) {} + | ^^^^^^^ lifetime requirement introduced here + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:90:5 + | +LL | fn reference_type_bound(err: &dyn Error) { + | --- - let's call the lifetime of this reference `'1` + | | + | `err` is only valid in the function body +LL | takes_reference_type(err); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +note: `'static` lifetime requirement from `takes_reference_type` introduced here + --> $DIR/implicit-object-lifetime-no-suggestion.rs:85:32 + | +LL | fn takes_reference_type<'a>(_: &'a (dyn Error + 'static)) +LL | where +LL | &'a (dyn Error + 'static): 'static, + | ^^^^^^^ lifetime requirement introduced here + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:98:5 + | +LL | fn mismatched_argument<'a>(arg: &'a dyn LifetimeArgument<'a>) { + | -- --- `arg` is only valid in the function body + | | + | lifetime `'a` defined here +LL | takes_static_argument(arg); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `arg` escapes the function body here + | argument requires that `'a` must outlive `'static` + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:108:5 + | +LL | fn mismatched_associated_type<'a>(arg: &'a dyn AssociatedType) { + | -- --- `arg` is only valid in the function body + | | + | lifetime `'a` defined here +LL | takes_static_associated_type(arg); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `arg` escapes the function body here + | argument requires that `'a` must outlive `'static` + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:117:5 + | +LL | fn mismatched_repeated_lifetime<'a, 'b>(arg: &'a dyn RepeatedLifetime<'a, 'b>) { + | -- --- `arg` is only valid in the function body + | | + | lifetime `'a` defined here +LL | +LL | takes_repeated_lifetime(arg); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `arg` escapes the function body here + | argument requires that `'a` must outlive `'static` + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-no-suggestion.rs:117:5 + | +LL | fn mismatched_repeated_lifetime<'a, 'b>(arg: &'a dyn RepeatedLifetime<'a, 'b>) { + | -- --- `arg` is only valid in the function body + | | + | lifetime `'b` defined here +LL | +LL | takes_repeated_lifetime(arg); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `arg` escapes the function body here + | argument requires that `'b` must outlive `'static` + +error: one or more lifetime errors were found in this item + --> $DIR/implicit-object-lifetime-no-suggestion.rs:115:4 + | +LL | fn mismatched_repeated_lifetime<'a, 'b>(arg: &'a dyn RepeatedLifetime<'a, 'b>) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: replace `'a` with `'static` + = help: replace `'b` with `'static` + +error: aborting due to 21 previous errors + +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/object-lifetime/implicit-object-lifetime-static-suggestion.fixed b/tests/ui/object-lifetime/implicit-object-lifetime-static-suggestion.fixed new file mode 100644 index 0000000000000..ffd8e2ff1a8d2 --- /dev/null +++ b/tests/ui/object-lifetime/implicit-object-lifetime-static-suggestion.fixed @@ -0,0 +1,122 @@ +//@ run-rustfix + +#![allow(dead_code)] + +use std::error::Error; + +fn is_caused_by(err: &(dyn Error + 'static)) -> bool { + err.is::() //~ ERROR borrowed data escapes outside of function + || err.source().is_some_and(|cause| is_caused_by::(cause)) +} + +fn named<'a, T: Error + 'static>(err: &'a (dyn Error + 'static)) -> bool { + err.is::() //~ ERROR borrowed data escapes outside of function +} + +fn early_bound<'a: 'a, T: Error + 'static>(err: &'a (dyn Error + 'static)) -> bool { + err.is::() //~ ERROR borrowed data escapes outside of function +} + +fn mutable<'a, T: Error + 'static>(err: &'a mut (dyn Error + 'static)) -> Option<&'a mut T> { + err.downcast_mut::() //~ ERROR borrowed data escapes outside of function +} + +fn parenthesized(err: &(dyn Error + 'static)) -> bool { + err.is::() //~ ERROR borrowed data escapes outside of function +} + +fn other_bounds(err: &(dyn Error + Send + Sync + 'static)) -> bool { + err.is::() //~ ERROR borrowed data escapes outside of function +} + +fn takes_static_object(_: &(dyn Error + 'static)) {} + +fn function_call(err: &(dyn Error + 'static)) { + takes_static_object(err); //~ ERROR borrowed data escapes outside of function +} + +fn takes_two_static_objects(_: &(dyn Error + 'static), _: &(dyn Error + 'static)) {} + +fn repeated_argument(err: &(dyn Error + 'static)) { + takes_two_static_objects(err, err); //~ ERROR borrowed data escapes outside of function +} + +fn shared_region<'a, T: Error + 'static>(_: &'a u32, err: &'a (dyn Error + 'static)) -> bool { + err.is::() //~ ERROR lifetime may not live long enough +} + +fn same_trait<'a, T: Error + 'static>(_: &'a dyn Error, err: &'a (dyn Error + 'static)) -> bool { + err.is::() //~ ERROR lifetime may not live long enough +} + +fn takes_static_callable(_: &(dyn Fn() -> &'static (dyn std::fmt::Debug) + 'static)) {} + +fn callable(value: &(dyn Fn() -> &'static (dyn std::fmt::Debug) + 'static)) { + takes_static_callable(value); //~ ERROR borrowed data escapes outside of function +} + +trait DerivedLifetime<'a>: 'a {} + +fn takes_derived_lifetime<'a>(_: &(dyn DerivedLifetime<'a> + 'static)) {} + +fn derived_lifetime<'a, 'b>(arg: &'b (dyn DerivedLifetime<'a> + 'static)) { + takes_derived_lifetime(arg); //~ ERROR borrowed data escapes outside of function +} + +trait LifetimeArgument<'a> {} + +fn takes_lifetime_argument<'a>(_: &(dyn LifetimeArgument<'a> + 'static)) {} + +fn matching_lifetime_argument<'a>(arg: &'a (dyn LifetimeArgument<'a> + 'static)) { + takes_lifetime_argument(arg); //~ ERROR borrowed data escapes outside of function +} + +trait IndependentLifetimes<'a, 'b> {} + +fn takes_independent_lifetimes<'c, 'd>(_: &(dyn IndependentLifetimes<'c, 'd> + 'static)) {} + +fn matching_independent_lifetimes<'a, 'b>(arg: &'a (dyn IndependentLifetimes<'a, 'b> + 'static)) { + takes_independent_lifetimes(arg); //~ ERROR borrowed data escapes outside of function +} + +trait AssociatedType { + type Item; +} + +fn takes_associated_type<'a>(_: &(dyn AssociatedType + 'static)) {} + +fn matching_associated_type<'a>(arg: &'a (dyn AssociatedType + 'static)) { + takes_associated_type(arg); //~ ERROR borrowed data escapes outside of function +} + +fn drop_auto_trait(arg: &(dyn Error + Send + 'static)) { + takes_static_object(arg); //~ ERROR borrowed data escapes outside of function +} + +fn takes_higher_ranked(_: &(dyn Fn(&str) + 'static)) {} + +fn higher_ranked(arg: &(dyn Fn(&str) + 'static)) { + takes_higher_ranked(arg); //~ ERROR borrowed data escapes outside of function +} + +trait Typed {} + +fn takes_typed(_: &(dyn Typed + 'static)) {} + +fn typed(arg: &(dyn Typed + 'static)) { + takes_typed(arg); //~ ERROR borrowed data escapes outside of function +} + +fn main() { + let mut err = std::fmt::Error; + is_caused_by::(&err); + named::(&err); + early_bound::(&err); + mutable::(&mut err); + parenthesized::(&err); + other_bounds::(&err); + function_call(&err); + repeated_argument(&err); + shared_region::(&0, &err); + same_trait::(&err, &err); +} diff --git a/tests/ui/object-lifetime/implicit-object-lifetime-static-suggestion.rs b/tests/ui/object-lifetime/implicit-object-lifetime-static-suggestion.rs new file mode 100644 index 0000000000000..75dc3762111c2 --- /dev/null +++ b/tests/ui/object-lifetime/implicit-object-lifetime-static-suggestion.rs @@ -0,0 +1,122 @@ +//@ run-rustfix + +#![allow(dead_code)] + +use std::error::Error; + +fn is_caused_by(err: &dyn Error) -> bool { + err.is::() //~ ERROR borrowed data escapes outside of function + || err.source().is_some_and(|cause| is_caused_by::(cause)) +} + +fn named<'a, T: Error + 'static>(err: &'a dyn Error) -> bool { + err.is::() //~ ERROR borrowed data escapes outside of function +} + +fn early_bound<'a: 'a, T: Error + 'static>(err: &'a dyn Error) -> bool { + err.is::() //~ ERROR borrowed data escapes outside of function +} + +fn mutable<'a, T: Error + 'static>(err: &'a mut dyn Error) -> Option<&'a mut T> { + err.downcast_mut::() //~ ERROR borrowed data escapes outside of function +} + +fn parenthesized(err: &(dyn Error)) -> bool { + err.is::() //~ ERROR borrowed data escapes outside of function +} + +fn other_bounds(err: &(dyn Error + Send + Sync)) -> bool { + err.is::() //~ ERROR borrowed data escapes outside of function +} + +fn takes_static_object(_: &(dyn Error + 'static)) {} + +fn function_call(err: &dyn Error) { + takes_static_object(err); //~ ERROR borrowed data escapes outside of function +} + +fn takes_two_static_objects(_: &(dyn Error + 'static), _: &(dyn Error + 'static)) {} + +fn repeated_argument(err: &dyn Error) { + takes_two_static_objects(err, err); //~ ERROR borrowed data escapes outside of function +} + +fn shared_region<'a, T: Error + 'static>(_: &'a u32, err: &'a dyn Error) -> bool { + err.is::() //~ ERROR lifetime may not live long enough +} + +fn same_trait<'a, T: Error + 'static>(_: &'a dyn Error, err: &'a dyn Error) -> bool { + err.is::() //~ ERROR lifetime may not live long enough +} + +fn takes_static_callable(_: &(dyn Fn() -> &'static (dyn std::fmt::Debug) + 'static)) {} + +fn callable(value: &dyn Fn() -> &'static dyn std::fmt::Debug) { + takes_static_callable(value); //~ ERROR borrowed data escapes outside of function +} + +trait DerivedLifetime<'a>: 'a {} + +fn takes_derived_lifetime<'a>(_: &(dyn DerivedLifetime<'a> + 'static)) {} + +fn derived_lifetime<'a, 'b>(arg: &'b dyn DerivedLifetime<'a>) { + takes_derived_lifetime(arg); //~ ERROR borrowed data escapes outside of function +} + +trait LifetimeArgument<'a> {} + +fn takes_lifetime_argument<'a>(_: &(dyn LifetimeArgument<'a> + 'static)) {} + +fn matching_lifetime_argument<'a>(arg: &'a dyn LifetimeArgument<'a>) { + takes_lifetime_argument(arg); //~ ERROR borrowed data escapes outside of function +} + +trait IndependentLifetimes<'a, 'b> {} + +fn takes_independent_lifetimes<'c, 'd>(_: &(dyn IndependentLifetimes<'c, 'd> + 'static)) {} + +fn matching_independent_lifetimes<'a, 'b>(arg: &'a dyn IndependentLifetimes<'a, 'b>) { + takes_independent_lifetimes(arg); //~ ERROR borrowed data escapes outside of function +} + +trait AssociatedType { + type Item; +} + +fn takes_associated_type<'a>(_: &(dyn AssociatedType + 'static)) {} + +fn matching_associated_type<'a>(arg: &'a dyn AssociatedType) { + takes_associated_type(arg); //~ ERROR borrowed data escapes outside of function +} + +fn drop_auto_trait(arg: &(dyn Error + Send)) { + takes_static_object(arg); //~ ERROR borrowed data escapes outside of function +} + +fn takes_higher_ranked(_: &(dyn Fn(&str) + 'static)) {} + +fn higher_ranked(arg: &dyn Fn(&str)) { + takes_higher_ranked(arg); //~ ERROR borrowed data escapes outside of function +} + +trait Typed {} + +fn takes_typed(_: &(dyn Typed + 'static)) {} + +fn typed(arg: &dyn Typed) { + takes_typed(arg); //~ ERROR borrowed data escapes outside of function +} + +fn main() { + let mut err = std::fmt::Error; + is_caused_by::(&err); + named::(&err); + early_bound::(&err); + mutable::(&mut err); + parenthesized::(&err); + other_bounds::(&err); + function_call(&err); + repeated_argument(&err); + shared_region::(&0, &err); + same_trait::(&err, &err); +} diff --git a/tests/ui/object-lifetime/implicit-object-lifetime-static-suggestion.stderr b/tests/ui/object-lifetime/implicit-object-lifetime-static-suggestion.stderr new file mode 100644 index 0000000000000..a44f292732859 --- /dev/null +++ b/tests/ui/object-lifetime/implicit-object-lifetime-static-suggestion.stderr @@ -0,0 +1,392 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-static-suggestion.rs:8:5 + | +LL | fn is_caused_by(err: &dyn Error) -> bool { + | --- - let's call the lifetime of this reference `'1` + | | + | `err` is only valid in the function body +LL | err.is::() + | ^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +note: `'static` lifetime requirement from `<(dyn std::error::Error + 'static)>::is` introduced here + --> $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here + ::: $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL - fn is_caused_by(err: &dyn Error) -> bool { +LL + fn is_caused_by(err: &(dyn Error + 'static)) -> bool { + | + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-static-suggestion.rs:13:5 + | +LL | fn named<'a, T: Error + 'static>(err: &'a dyn Error) -> bool { + | -- --- `err` is only valid in the function body + | | + | lifetime `'a` defined here +LL | err.is::() + | ^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'a` must outlive `'static` + | +note: `'static` lifetime requirement from `<(dyn std::error::Error + 'static)>::is` introduced here + --> $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here + ::: $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL - fn named<'a, T: Error + 'static>(err: &'a dyn Error) -> bool { +LL + fn named<'a, T: Error + 'static>(err: &'a (dyn Error + 'static)) -> bool { + | + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-static-suggestion.rs:17:5 + | +LL | fn early_bound<'a: 'a, T: Error + 'static>(err: &'a dyn Error) -> bool { + | -- --- `err` is only valid in the function body + | | + | lifetime `'a` defined here +LL | err.is::() + | ^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'a` must outlive `'static` + | +note: `'static` lifetime requirement from `<(dyn std::error::Error + 'static)>::is` introduced here + --> $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here + ::: $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL - fn early_bound<'a: 'a, T: Error + 'static>(err: &'a dyn Error) -> bool { +LL + fn early_bound<'a: 'a, T: Error + 'static>(err: &'a (dyn Error + 'static)) -> bool { + | + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-static-suggestion.rs:21:5 + | +LL | fn mutable<'a, T: Error + 'static>(err: &'a mut dyn Error) -> Option<&'a mut T> { + | -- --- `err` is only valid in the function body + | | + | lifetime `'a` defined here +LL | err.downcast_mut::() + | ^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'a` must outlive `'static` + | +note: `'static` lifetime requirement from `<(dyn std::error::Error + 'static)>::downcast_mut` introduced here + --> $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here + ::: $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here + = note: requirement occurs because of a mutable reference to `(dyn std::error::Error + 'static)` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL - fn mutable<'a, T: Error + 'static>(err: &'a mut dyn Error) -> Option<&'a mut T> { +LL + fn mutable<'a, T: Error + 'static>(err: &'a mut (dyn Error + 'static)) -> Option<&'a mut T> { + | + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-static-suggestion.rs:25:5 + | +LL | fn parenthesized(err: &(dyn Error)) -> bool { + | --- - let's call the lifetime of this reference `'1` + | | + | `err` is only valid in the function body +LL | err.is::() + | ^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +note: `'static` lifetime requirement from `<(dyn std::error::Error + 'static)>::is` introduced here + --> $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here + ::: $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL | fn parenthesized(err: &(dyn Error + 'static)) -> bool { + | +++++++++ + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-static-suggestion.rs:29:5 + | +LL | fn other_bounds(err: &(dyn Error + Send + Sync)) -> bool { + | --- - let's call the lifetime of this reference `'1` + | | + | `err` is only valid in the function body +LL | err.is::() + | ^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +note: `'static` lifetime requirement from `<(dyn std::error::Error + Send + Sync + 'static)>::is` introduced here + --> $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here + ::: $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL | fn other_bounds(err: &(dyn Error + Send + Sync + 'static)) -> bool { + | +++++++++ + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-static-suggestion.rs:35:5 + | +LL | fn function_call(err: &dyn Error) { + | --- - let's call the lifetime of this reference `'1` + | | + | `err` is only valid in the function body +LL | takes_static_object(err); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL - fn function_call(err: &dyn Error) { +LL + fn function_call(err: &(dyn Error + 'static)) { + | + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-static-suggestion.rs:41:5 + | +LL | fn repeated_argument(err: &dyn Error) { + | --- - let's call the lifetime of this reference `'1` + | | + | `err` is only valid in the function body +LL | takes_two_static_objects(err, err); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `err` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL - fn repeated_argument(err: &dyn Error) { +LL + fn repeated_argument(err: &(dyn Error + 'static)) { + | + +error: lifetime may not live long enough + --> $DIR/implicit-object-lifetime-static-suggestion.rs:45:5 + | +LL | fn shared_region<'a, T: Error + 'static>(_: &'a u32, err: &'a dyn Error) -> bool { + | -- lifetime `'a` defined here +LL | err.is::() + | ^^^^^^^^^^^^^ argument requires that `'a` must outlive `'static` + | +note: `'static` lifetime requirement from `<(dyn std::error::Error + 'static)>::is` introduced here + --> $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here + ::: $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL - fn shared_region<'a, T: Error + 'static>(_: &'a u32, err: &'a dyn Error) -> bool { +LL + fn shared_region<'a, T: Error + 'static>(_: &'a u32, err: &'a (dyn Error + 'static)) -> bool { + | + +error: lifetime may not live long enough + --> $DIR/implicit-object-lifetime-static-suggestion.rs:49:5 + | +LL | fn same_trait<'a, T: Error + 'static>(_: &'a dyn Error, err: &'a dyn Error) -> bool { + | -- lifetime `'a` defined here +LL | err.is::() + | ^^^^^^^^^^^^^ argument requires that `'a` must outlive `'static` + | +note: `'static` lifetime requirement from `<(dyn std::error::Error + 'static)>::is` introduced here + --> $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here + ::: $SRC_DIR/core/src/error.rs:LL:COL + | + = note: lifetime requirement introduced here +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL - fn same_trait<'a, T: Error + 'static>(_: &'a dyn Error, err: &'a dyn Error) -> bool { +LL + fn same_trait<'a, T: Error + 'static>(_: &'a dyn Error, err: &'a (dyn Error + 'static)) -> bool { + | + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-static-suggestion.rs:55:5 + | +LL | fn callable(value: &dyn Fn() -> &'static dyn std::fmt::Debug) { + | ----- - let's call the lifetime of this reference `'1` + | | + | `value` declared here, outside of the function body + | `value` is only valid in the function body +LL | takes_static_callable(value); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `value` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL - fn callable(value: &dyn Fn() -> &'static dyn std::fmt::Debug) { +LL + fn callable(value: &(dyn Fn() -> &'static (dyn std::fmt::Debug) + 'static)) { + | + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-static-suggestion.rs:63:5 + | +LL | fn derived_lifetime<'a, 'b>(arg: &'b dyn DerivedLifetime<'a>) { + | -- --- `arg` is only valid in the function body + | | + | lifetime `'b` defined here +LL | takes_derived_lifetime(arg); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `arg` escapes the function body here + | argument requires that `'b` must outlive `'static` + | +help: this trait object's lifetime is inferred from its trait's lifetime bounds; consider adding an explicit `'static` bound to the trait object + | +LL - fn derived_lifetime<'a, 'b>(arg: &'b dyn DerivedLifetime<'a>) { +LL + fn derived_lifetime<'a, 'b>(arg: &'b (dyn DerivedLifetime<'a> + 'static)) { + | + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-static-suggestion.rs:71:5 + | +LL | fn matching_lifetime_argument<'a>(arg: &'a dyn LifetimeArgument<'a>) { + | -- --- `arg` is only valid in the function body + | | + | lifetime `'a` defined here +LL | takes_lifetime_argument(arg); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `arg` escapes the function body here + | argument requires that `'a` must outlive `'static` + | +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL - fn matching_lifetime_argument<'a>(arg: &'a dyn LifetimeArgument<'a>) { +LL + fn matching_lifetime_argument<'a>(arg: &'a (dyn LifetimeArgument<'a> + 'static)) { + | + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-static-suggestion.rs:79:5 + | +LL | fn matching_independent_lifetimes<'a, 'b>(arg: &'a dyn IndependentLifetimes<'a, 'b>) { + | -- --- `arg` is only valid in the function body + | | + | lifetime `'a` defined here +LL | takes_independent_lifetimes(arg); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `arg` escapes the function body here + | argument requires that `'a` must outlive `'static` + | +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL - fn matching_independent_lifetimes<'a, 'b>(arg: &'a dyn IndependentLifetimes<'a, 'b>) { +LL + fn matching_independent_lifetimes<'a, 'b>(arg: &'a (dyn IndependentLifetimes<'a, 'b> + 'static)) { + | + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-static-suggestion.rs:89:5 + | +LL | fn matching_associated_type<'a>(arg: &'a dyn AssociatedType) { + | -- --- `arg` is only valid in the function body + | | + | lifetime `'a` defined here +LL | takes_associated_type(arg); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `arg` escapes the function body here + | argument requires that `'a` must outlive `'static` + | +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL - fn matching_associated_type<'a>(arg: &'a dyn AssociatedType) { +LL + fn matching_associated_type<'a>(arg: &'a (dyn AssociatedType + 'static)) { + | + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-static-suggestion.rs:93:5 + | +LL | fn drop_auto_trait(arg: &(dyn Error + Send)) { + | --- - let's call the lifetime of this reference `'1` + | | + | `arg` is only valid in the function body +LL | takes_static_object(arg); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `arg` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL | fn drop_auto_trait(arg: &(dyn Error + Send + 'static)) { + | +++++++++ + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-static-suggestion.rs:99:5 + | +LL | fn higher_ranked(arg: &dyn Fn(&str)) { + | --- - let's call the lifetime of this reference `'1` + | | + | `arg` is only valid in the function body +LL | takes_higher_ranked(arg); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `arg` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL - fn higher_ranked(arg: &dyn Fn(&str)) { +LL + fn higher_ranked(arg: &(dyn Fn(&str) + 'static)) { + | + +error[E0521]: borrowed data escapes outside of function + --> $DIR/implicit-object-lifetime-static-suggestion.rs:107:5 + | +LL | fn typed(arg: &dyn Typed) { + | --- - let's call the lifetime of this reference `'1` + | | + | `arg` is only valid in the function body +LL | takes_typed(arg); + | ^^^^^^^^^^^^^^^^ + | | + | `arg` escapes the function body here + | argument requires that `'1` must outlive `'static` + | +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL - fn typed(arg: &dyn Typed) { +LL + fn typed(arg: &(dyn Typed + 'static)) { + | + +error: aborting due to 18 previous errors + +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/regions/regions-static-bound-on-type-param.stderr b/tests/ui/regions/regions-static-bound-on-type-param.stderr index 64496cb703bee..f39b4f0c50126 100644 --- a/tests/ui/regions/regions-static-bound-on-type-param.stderr +++ b/tests/ui/regions/regions-static-bound-on-type-param.stderr @@ -18,6 +18,11 @@ note: `'static` lifetime requirement from `<(dyn std::error::Error + 'static)>:: ::: $SRC_DIR/core/src/error.rs:LL:COL | = note: lifetime requirement introduced here +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL - fn err_is(err: &dyn Error) -> bool { +LL + fn err_is(err: &(dyn Error + 'static)) -> bool { + | error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr index 9793b7fb8dc7a..c17cb32aaf11b 100644 --- a/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr +++ b/tests/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr @@ -61,6 +61,11 @@ help: consider relaxing the implicit `'static` requirement | LL | impl dyn ObjectTrait + '_ { | ++++ +help: this trait object's lifetime defaults to the reference's lifetime; consider adding an explicit `'static` bound to the trait object + | +LL - fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { +LL + fn use_it<'a>(val: &'a (dyn ObjectTrait + 'static)) -> impl OtherTrait<'a> + 'a { + | error[E0521]: borrowed data escapes outside of function --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:92:9