diff --git a/Cargo.lock b/Cargo.lock index 3110f32ade968..28a4e8eea098d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3580,6 +3580,7 @@ dependencies = [ "either", "itertools 0.12.1", "polonius-engine", + "rustc_ast", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml index bafc62c7318b4..a53267502f901 100644 --- a/compiler/rustc_borrowck/Cargo.toml +++ b/compiler/rustc_borrowck/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" either = "1.5.0" itertools = "0.12" polonius-engine = "0.13.0" +rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index c06bf94a6fd5f..74ea8ec20f6b1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1,5 +1,6 @@ //! Error reporting machinery for lifetime errors. +use rustc_ast::TraitObjectSyntax::Dyn; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; @@ -16,14 +17,13 @@ use rustc_infer::infer::{ HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor, }, error_reporting::unexpected_hidden_region_diagnostic, - NllRegionVariableOrigin, RelateParamBound, + BoundRegionConversionTime, NllRegionVariableOrigin, RelateParamBound, }; +use rustc_infer::traits::util::{elaborate_predicates_of, filter_predicates}; use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::{ConstraintCategory, ReturnConstraint}; -use rustc_middle::ty::GenericArgs; -use rustc_middle::ty::TypeVisitor; -use rustc_middle::ty::{self, RegionVid, Ty}; -use rustc_middle::ty::{Region, TyCtxt}; +use rustc_middle::traits::ObligationCauseCode; +use rustc_middle::ty::{self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeVisitor}; use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; @@ -499,19 +499,25 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } }; + if let ConstraintCategory::CallArgument(Some(ty)) = category { + self.explain_impl_static_obligation(&mut diag, ty, cause.span, outlived_fr); + } else if let ObligationCauseCode::MethodCallConstraint(ty, call_span) = cause.code() { + self.explain_impl_static_obligation(&mut diag, *ty, *call_span, outlived_fr); + } + match variance_info { ty::VarianceDiagInfo::None => {} ty::VarianceDiagInfo::Invariant { ty, param_index } => { let (desc, note) = match ty.kind() { ty::RawPtr(ty_mut) => { - assert_eq!(ty_mut.mutbl, rustc_hir::Mutability::Mut); + assert_eq!(ty_mut.mutbl, hir::Mutability::Mut); ( format!("a mutable pointer to `{}`", ty_mut.ty), "mutable pointers are invariant over their type parameter".to_string(), ) } ty::Ref(_, inner_ty, mutbl) => { - assert_eq!(*mutbl, rustc_hir::Mutability::Mut); + assert_eq!(*mutbl, hir::Mutability::Mut); ( format!("a mutable reference to `{inner_ty}`"), "mutable references are invariant over their type parameter" @@ -527,10 +533,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let adt_desc = adt.descr(); let desc = format!( - "the type `{ty}`, which makes the generic argument `{generic_arg}` invariant" + "the type `{ty}`, which makes the generic argument `{generic_arg}` \ + invariant" ); let note = format!( - "the {adt_desc} `{base_ty}` is invariant over the parameter `{base_generic_arg}`" + "the {adt_desc} `{base_ty}` is invariant over the parameter \ + `{base_generic_arg}`" ); (desc, note) } @@ -548,14 +556,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; diag.note(format!("requirement occurs because of {desc}",)); diag.note(note); - diag.help("see for more information about variance"); + diag.help( + "see for more \ + information about variance", + ); } } for extra in extra_info { match extra { ExtraConstraintInfo::PlaceholderFromPredicate(span) => { - diag.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime"); + diag.span_note( + span, + "due to current limitations in the borrow checker, this implies a \ + `'static` lifetime", + ); } } } @@ -563,6 +578,222 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.buffer_error(diag); } + /// Report a specialized error when a `'static` obligation comes from an `impl dyn Trait` + /// + /// ```text + /// error: lifetime may not live long enough + /// --> $DIR/static-impl-obligation.rs:8:27 + /// | + /// LL | fn bar<'a>(x: &'a &'a u32) { + /// | -- lifetime `'a` defined here + /// LL | let y: &dyn Foo = x; + /// | ^ cast requires that `'a` must outlive `'static` + /// LL | y.hello(); + /// | --------- calling this method introduces a `'static` lifetime requirement + /// | + /// note: the `impl` on `(dyn a::Foo + 'static)` has a `'static` lifetime requirement + /// --> $DIR/static-impl-obligation.rs:4:10 + /// | + /// LL | impl dyn Foo { + /// | ^^^^^^^ + /// help: relax the implicit `'static` bound on the impl + /// | + /// LL | impl dyn Foo + '_ { + /// | ++++ + /// ``` + /// ```text + /// error: lifetime may not live long enough + /// --> $DIR/static-impl-obligation.rs:173:27 + /// | + /// LL | fn bar<'a>(x: &'a &'a u32) { + /// | -- lifetime `'a` defined here + /// LL | let y: &dyn Foo = x; + /// | ^ cast requires that `'a` must outlive `'static` + /// LL | y.hello(); + /// | --------- calling this method introduces a `'static` lifetime requirement + /// | + /// note: the `impl` on `(dyn p::Foo + 'static)` has `'static` lifetime requirements + /// --> $DIR/static-impl-obligation.rs:169:20 + /// | + /// LL | impl dyn Foo + 'static where Self: 'static { + /// | ^^^^^^^ ^^^^^^^ + /// LL | fn hello(&self) where Self: 'static {} + /// | ^^^^^^^ + /// ``` + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] + fn explain_impl_static_obligation( + &self, + diag: &mut Diag<'_>, + ty: Ty<'tcx>, + call_span: Span, + outlived_fr: RegionVid, + ) { + let tcx = self.infcx.tcx; + let ty::FnDef(def_id, args) = ty.kind() else { + return; + }; + let Ok(Some(instance)) = ty::Instance::resolve( + tcx, + self.param_env, + *def_id, + self.infcx.resolve_vars_if_possible(args), + ) else { + return; + }; + debug!(?instance); + let def_id = instance.def_id(); + let mut parent = tcx.parent(def_id); + debug!(?def_id, ?parent); + let trait_preds: Vec<_> = match tcx.def_kind(parent) { + hir::def::DefKind::Impl { .. } => tcx + .trait_id_of_impl(parent) + .map_or(vec![], |id| elaborate_predicates_of(tcx, id).collect()), + hir::def::DefKind::Trait => { + let Some(ty) = args.get(0).and_then(|arg| arg.as_type()) else { + return; + }; + let mut impls = vec![]; + tcx.for_each_relevant_impl(parent, ty, |id| { + impls.push(id); + }); + if let [def_id] = impls[..] { + // The method we have is on the trait, but for `parent` we want to analyze the + // relevant impl instead. + let preds = elaborate_predicates_of(tcx, parent); + parent = def_id; + preds.collect() + } else { + return; + } + } + _ => return, + }; + debug!(?def_id, ?parent); + let ty = tcx.type_of(parent).instantiate_identity(); + debug!(?ty); + if self.to_error_region(outlived_fr) != Some(tcx.lifetimes.re_static) { + return; + } + + // Look for `'static` bounds in the generics of the method and the `impl`. + // ``` + // impl dyn Trait where Self: 'static { + // fn foo(&self) where Self: 'static {} + // } + // ``` + let mut predicates: Vec = elaborate_predicates_of(tcx, def_id) + .chain(elaborate_predicates_of(tcx, parent)) + .chain(trait_preds) + .filter_map(filter_predicates(tcx.lifetimes.re_static, |pred_ty| { + self.infcx.can_eq(self.param_env, ty, pred_ty) + || matches!( + pred_ty.kind(), + ty::Param(name) if name.name == kw::SelfUpper) + })) + .collect(); + debug!(?predicates); + + // Look at the receiver for `&'static self`, which introduces a `'static` obligation. + // ``` + // impl dyn Trait { + // fn foo(&'static self) {} + // } + // ``` + if let ty::Ref(region, _, _) = self + .infcx + .instantiate_binder_with_fresh_vars( + call_span, + BoundRegionConversionTime::FnCall, + tcx.fn_sig(def_id).instantiate_identity().inputs().map_bound(|inputs| inputs[0]), + ) + .kind() + && *region == tcx.lifetimes.re_static + && let Some(assoc) = tcx.opt_associated_item(def_id) + && assoc.fn_has_self_parameter + { + // We have a `&'static self` receiver. + if let Some(def_id) = def_id.as_local() + && let owner = tcx.expect_hir_owner_node(def_id) + && let Some(decl) = owner.fn_decl() + && let Some(ty) = decl.inputs.get(0) + { + // Point at the `&'static self` receiver. + predicates.push(ty.span); + } else { + // The method is not defined on the local crate, point at the signature + // instead of just the receiver as an approximation. + predicates.push(tcx.def_span(def_id)) + } + } + + let mut new_primary_span = false; + // When we have the HIR `Node` at hand, see if we can identify an + // implicit `'static` bound in an `impl dyn Trait {}` and if that's + // the only restriction, suggest relaxing it. + if let Some(hir::Node::Item(hir::Item { + kind: + hir::ItemKind::Impl(hir::Impl { + self_ty: hir::Ty { kind: hir::TyKind::TraitObject(_, lt, _), span, .. }, + .. + }), + .. + })) = tcx.hir().get_if_local(parent) + { + let suggestion = match lt.res { + hir::LifetimeName::ImplicitObjectLifetimeDefault if predicates.is_empty() => { + // `impl dyn Trait {}` + Some(( + span.shrink_to_hi(), + "consider relaxing the implicit `'static` requirement on the impl", + " + '_", + )) + } + hir::LifetimeName::Static if predicates.is_empty() => { + // `impl dyn Trait + 'static {}` + Some((lt.ident.span, "consider relaxing this `'static` requirement", "'_")) + } + _ => None, + }; + if let Some((span, msg, sugg)) = suggestion { + // We only emit the suggestion to write `impl dyn Trait + '_ {}` if that's the only + // thing needed. + diag.span_suggestion_verbose(span, msg, sugg, Applicability::MachineApplicable); + new_primary_span = true; + } else if let hir::LifetimeName::ImplicitObjectLifetimeDefault + | hir::LifetimeName::Static = lt.res + { + // Otherwise, we add the right span for the note pointing at all the places where + // a `'static` requirement is introduced when invoking the method on this `impl`. + predicates.push(lt.ident.span); + } + } else if let ty::Dynamic(_, region, ty::Dyn) = ty.kind() + && *region == tcx.lifetimes.re_static + { + // The `self_ty` has a `'static` bound on a `dyn Trait`, either implicit or explicit, + // but we don't have access to the HIR to identify which one nor to provide a targetted + // enough `Span`, so instead we fall back to pointing at the `impl` header instead. + predicates.push(tcx.def_span(parent)); + } + if !predicates.is_empty() { + new_primary_span = true; + let a_static_lt = if predicates.len() == 1 { + "a `'static` lifetime requirement" + } else { + "`'static` lifetime requirements" + }; + let span: MultiSpan = predicates.into(); + diag.span_note(span, format!("the `impl` on `{ty}` has {a_static_lt}")); + } + if new_primary_span && diag.span.primary_span() != Some(call_span) { + diag.replace_span_with(call_span, false); + diag.span_label( + call_span, + "calling this method introduces a `'static` lifetime requirement", + ); + } + } + /// Report a specialized error when `FnMut` closures return a reference to a captured variable. /// This function expects `fr` to be local and `outlived_fr` to not be local. /// @@ -810,7 +1041,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.add_static_impl_trait_suggestion(&mut diag, *fr, fr_name, *outlived_fr); self.suggest_adding_lifetime_params(&mut diag, *fr, *outlived_fr); self.suggest_move_on_borrowing_closure(&mut diag); - diag } @@ -927,37 +1157,32 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let tcx = self.infcx.tcx; - let instance = if let ConstraintCategory::CallArgument(Some(func_ty)) = category { - let (fn_did, args) = match func_ty.kind() { - ty::FnDef(fn_did, args) => (fn_did, args), - _ => return, - }; - debug!(?fn_did, ?args); + let ConstraintCategory::CallArgument(Some(func_ty)) = category else { + return; + }; + let ty::FnDef(fn_did, args) = func_ty.kind() else { + return; + }; + debug!(?fn_did, ?args); - // Only suggest this on function calls, not closures - let ty = tcx.type_of(fn_did).instantiate_identity(); - debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind()); - if let ty::Closure(_, _) = ty.kind() { - return; - } + // Only suggest this on function calls, not closures + let ty = tcx.type_of(fn_did).instantiate_identity(); + debug!("ty: {:?}, ty.kind: {:?}", ty, ty.kind()); + if let ty::Closure(_, _) = ty.kind() { + return; + } - if let Ok(Some(instance)) = ty::Instance::resolve( - tcx, - self.param_env, - *fn_did, - self.infcx.resolve_vars_if_possible(args), - ) { - instance - } else { - return; - } - } else { + let Ok(Some(instance)) = ty::Instance::resolve( + tcx, + self.param_env, + *fn_did, + self.infcx.resolve_vars_if_possible(args), + ) else { return; }; - let param = match find_param_with_region(tcx, f, o) { - Some(param) => param, - None => return, + let Some(param) = find_param_with_region(tcx, f, o) else { + return; }; debug!(?param); @@ -1001,12 +1226,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { "calling this method introduces the `impl`'s `'static` requirement", ); err.subdiagnostic(self.dcx(), RequireStaticErr::UsedImpl { multi_span }); - err.span_suggestion_verbose( - span.shrink_to_hi(), - "consider relaxing the implicit `'static` requirement", - " + '_", - Applicability::MaybeIncorrect, - ); + if let hir::TyKind::TraitObject(traits, lt, Dyn) = self_ty.kind + && lt.res == hir::LifetimeName::ImplicitObjectLifetimeDefault + && traits.iter().any(|t| t.span == *span) + { + // We already handle the case where `self_ty` has an implicit `'static` + // requirement specifically in `explain_impl_static_obligation`. + } else { + err.span_suggestion_verbose( + span.shrink_to_hi(), + "consider relaxing the implicit `'static` requirement", + " + '_", + Applicability::MaybeIncorrect, + ); + } suggested = true; } } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index c3800a1f1f21b..c44f92f6cb534 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -2051,11 +2051,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { CRATE_DEF_ID.to_def_id(), predicate_span, )) + } else if let ConstraintCategory::CallArgument(Some(fn_def)) = constraint.category { + Some(ObligationCauseCode::MethodCallConstraint(fn_def, constraint.span)) } else { None } }) - .unwrap_or_else(|| ObligationCauseCode::MiscObligation); + .unwrap_or(ObligationCauseCode::MiscObligation); // Classify each of the constraints along the path. let mut categorized_path: Vec> = path diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 331b3b97c3496..80e4ead7ae0e0 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -53,6 +53,7 @@ use crate::errors::{self, ObligationCauseFailureCode, TypeErrorAdditionalDiags}; use crate::infer; use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; use crate::infer::ExpectedFound; +use crate::traits::util::{elaborate_predicates_of, filter_predicates}; use crate::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, PredicateObligation, @@ -61,7 +62,7 @@ use crate::traits::{ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diag, DiagCtxt, DiagStyledString, - ErrorGuaranteed, IntoDiagArg, + ErrorGuaranteed, IntoDiagArg, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -458,11 +459,62 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // the error. If all of these fails, we fall back to a rather // general bit of code that displays the error information RegionResolutionError::ConcreteFailure(origin, sub, sup) => { - if sub.is_placeholder() || sup.is_placeholder() { - self.report_placeholder_failure(origin, sub, sup).emit() + let extra_info = self.find_trait_object_relate_failure_reason( + generic_param_scope, + &origin, + sub, + sup, + ); + let mut err = if sub.is_placeholder() || sup.is_placeholder() { + self.report_placeholder_failure(origin, sub, sup) } else { - self.report_concrete_failure(origin, sub, sup).emit() + self.report_concrete_failure(origin, sub, sup) + }; + if let Some((primary_spans, relevant_bindings)) = extra_info { + if primary_spans.has_primary_spans() { + // We shorten the span from the whole field type to only the traits + // and lifetime bound that failed. + err.span(primary_spans); + } + if relevant_bindings.has_primary_spans() { + // Point at all the trait obligations for the lifetime that + // couldn't be met. + err.span_note( + relevant_bindings, + format!("`{sub}` requirement introduced here"), + ); + } } + if let hir::def::DefKind::Impl { .. } = + self.tcx.def_kind(generic_param_scope) + && let Some(def_id) = + self.tcx.trait_id_of_impl(generic_param_scope.into()) + { + // Collect all the `Span`s corresponding to the predicates introducing + // the `sub` lifetime that couldn't be met (sometimes `'static`) on + // both the `trait` and the `impl`. + let spans: Vec = elaborate_predicates_of(self.tcx, def_id) + .chain(elaborate_predicates_of( + self.tcx, + generic_param_scope.into(), + )) + .filter_map(filter_predicates(self.tcx.lifetimes.re_static, |_| { + true + })) + .collect(); + + if !spans.is_empty() { + let spans_len = spans.len(); + err.span_note( + MultiSpan::from(spans), + format!( + "`{sub}` requirement{} introduced here", + pluralize!(spans_len), + ), + ); + } + } + err.emit() } RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => self @@ -2634,6 +2686,128 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if sub_region.is_error() | sup_region.is_error() { err.delay_as_bug() } else { err.emit() } } + /// If a field on a struct has a trait object with lifetime requirement that can't be satisfied + /// by one of the traits in the trait object, shorten the span from the whole field type to only + /// the relevant traits and the lifetime. We also collect the spans for the places where the + /// traits' obligations were introduced. + fn find_trait_object_relate_failure_reason( + &self, + generic_param_scope: LocalDefId, + origin: &SubregionOrigin<'tcx>, + sub: ty::Region<'tcx>, + sup: ty::Region<'tcx>, + ) -> Option<(MultiSpan, MultiSpan)> { + let infer::RelateRegionParamBound(span) = origin else { + return None; + }; + let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Struct(item, _), .. })) = + self.tcx.hir().get_if_local(generic_param_scope.into()) + else { + return None; + }; + /// Collect all `hir::Ty<'_>` `Span`s for trait objects with the sup lifetime. + pub struct HirTraitObjectVisitor<'tcx> { + pub expected_region: ty::Region<'tcx>, + pub found_region: ty::Region<'tcx>, + pub primary_spans: Vec, + pub secondary_spans: Vec, + pub pred_spans: Vec, + pub tcx: TyCtxt<'tcx>, + } + impl<'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'tcx> { + fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) { + if match (lt.res, self.expected_region.kind()) { + ( + hir::LifetimeName::ImplicitObjectLifetimeDefault + | hir::LifetimeName::Static, + ty::RegionKind::ReStatic, + ) => true, + (hir::LifetimeName::Param(a), ty::RegionKind::ReEarlyParam(b)) => { + a.to_def_id() == b.def_id + } + _ => false, + } { + // We want to keep a span to the lifetime bound on the trait object. + self.primary_spans.push(lt.ident.span); + } + } + fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { + match t.kind { + // Find all the trait objects that have the lifetime that was found. + hir::TyKind::TraitObject(poly_trait_refs, lt, _) + if match (lt.res, self.expected_region.kind()) { + ( + hir::LifetimeName::ImplicitObjectLifetimeDefault + | hir::LifetimeName::Static, + ty::RegionKind::ReStatic, + ) => true, + (hir::LifetimeName::Param(a), ty::RegionKind::ReEarlyParam(b)) => { + a.to_def_id() == b.def_id + } + _ => false, + } => + { + for ptr in poly_trait_refs { + if let Some(def_id) = ptr.trait_ref.trait_def_id() { + // Find the bounds on the trait with the lifetime that couldn't be met. + let bindings: Vec = elaborate_predicates_of(self.tcx, def_id) + .filter_map(filter_predicates(self.found_region, |_| true)) + .collect(); + if !bindings.is_empty() { + self.secondary_spans.push(ptr.span); + self.pred_spans.extend(bindings); + } + } + } + } + // Detect when an associated item is given a lifetime restriction that the + // definition of that associated item couldn't meet. + hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { + self.pred_spans.extend( + elaborate_predicates_of(self.tcx, path.res.def_id()) + .filter_map(filter_predicates(self.found_region, |_| true)) + .collect::>(), + ); + } + _ => {} + } + hir::intravisit::walk_ty(self, t); + } + } + let mut visitor = HirTraitObjectVisitor { + expected_region: sup, + found_region: sub, + primary_spans: vec![], + secondary_spans: vec![], + pred_spans: vec![], + tcx: self.tcx, + }; + for field in item.fields() { + if field.ty.span == *span { + // `span` points at the type of a field, we only want to look for trait objects in + // the field that failed. + visitor.visit_ty(field.ty); + } + } + + visitor.primary_spans.sort(); + let mut primary_span: MultiSpan = visitor.primary_spans.clone().into(); + if let Some(last) = visitor.primary_spans.iter().rev().next() { + primary_span.push_span_label( + *last, + format!( + "lifetime bound{s} not satisfied", + s = pluralize!(visitor.primary_spans.len()) + ), + ); + } + + for span in visitor.secondary_spans { + primary_span.push_span_label(span, format!("this requires `{sub}`")); + } + Some((primary_span, visitor.pred_spans.into())) + } + /// Determine whether an error associated with the given span and definition /// should be treated as being caused by the implicit `From` conversion /// within `?` desugaring. diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index e9df0505cbbdc..2ed96f2f7db4f 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -4,6 +4,7 @@ use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::traits::{self, Obligation, PredicateObligation}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; +use rustc_span::def_id::DefId; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -235,6 +236,37 @@ pub fn elaborate<'tcx, O: Elaboratable<'tcx>>( elaborator } +pub fn elaborate_predicates_of<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> Elaborator<'tcx, (ty::Predicate<'tcx>, Span)> { + elaborate( + tcx, + tcx.predicates_of(def_id).predicates.iter().map(|(p, sp)| (p.as_predicate(), *sp)), + ) +} + +pub fn filter_predicates<'tcx>( + region: ty::Region<'tcx>, + check_ty: impl Fn(Ty<'tcx>) -> bool, +) -> impl Fn((ty::Predicate<'tcx>, Span)) -> Option { + move |(pred, span)| { + let ty::PredicateKind::Clause(clause) = pred.kind().skip_binder() else { + return None; + }; + match clause { + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(pred_ty, r)) + if r == region && check_ty(pred_ty) => + { + Some(span) + } + ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(_, r)) if r == region => { + Some(span) + } + _ => None, + } + } +} impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { fn extend_deduped(&mut self, obligations: impl IntoIterator) { // Only keep those bounds that we haven't already seen. diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index a04bd636622ea..227dd666d583b 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -451,6 +451,9 @@ pub enum ObligationCauseCode<'tcx> { /// Obligations emitted during the normalization of a weak type alias. TypeAlias(InternedObligationCauseCode<'tcx>, Span, DefId), + + /// During borrowck we've found a method call that could have introduced a lifetime requirement. + MethodCallConstraint(Ty<'tcx>, Span), } /// Whether a value can be extracted into a const. diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index d19c2bd1f60ea..c25d37f502575 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2726,6 +2726,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::MethodReceiver | ObligationCauseCode::ReturnNoExpression | ObligationCauseCode::UnifyReceiver(..) + | ObligationCauseCode::MethodCallConstraint(..) | ObligationCauseCode::MiscObligation | ObligationCauseCode::WellFormed(..) | ObligationCauseCode::MatchImpl(..) diff --git a/src/tools/clippy/tests/ui/crashes/ice-6256.fixed b/src/tools/clippy/tests/ui/crashes/ice-6256.fixed new file mode 100644 index 0000000000000..84fb95c955728 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-6256.fixed @@ -0,0 +1,15 @@ +// originally from rustc ./tests/ui/regions/issue-78262.rs +// ICE: to get the signature of a closure, use args.as_closure().sig() not fn_sig() +#![allow(clippy::upper_case_acronyms)] + +trait TT {} + +impl dyn TT + '_ { + fn func(&self) {} +} + +#[rustfmt::skip] +fn main() { + let f = |x: &dyn TT| x.func(); + //~^ ERROR: borrowed data escapes outside of closure +} diff --git a/src/tools/clippy/tests/ui/crashes/ice-6256.stderr b/src/tools/clippy/tests/ui/crashes/ice-6256.stderr index 922772a6147bc..48d5bc2bbd54a 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6256.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6256.stderr @@ -8,6 +8,11 @@ LL | let f = |x: &dyn TT| x.func(); | | | argument requires that `'1` must outlive `'static` | | let's call the lifetime of this reference `'1` | `x` is a reference that is only valid in the closure body + | +help: consider relaxing the implicit `'static` requirement on the impl + | +LL | impl dyn TT + '_ { + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0478.stderr b/tests/ui/error-codes/E0478.stderr index 6ecde0e14e5e3..e6b03df16b109 100644 --- a/tests/ui/error-codes/E0478.stderr +++ b/tests/ui/error-codes/E0478.stderr @@ -1,8 +1,8 @@ error[E0478]: lifetime bound not satisfied - --> $DIR/E0478.rs:4:12 + --> $DIR/E0478.rs:4:37 | LL | child: Box + 'SnowWhite>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ lifetime bound not satisfied | note: lifetime parameter instantiated with the lifetime `'SnowWhite` as defined here --> $DIR/E0478.rs:3:22 diff --git a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr index 8d21b9172c87a..70b94176d6576 100644 --- a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr +++ b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr @@ -32,10 +32,10 @@ LL | type Y<'a> = &'a () where 'a: 'static; | +++++++++++++++++ error[E0478]: lifetime bound not satisfied - --> $DIR/unsatisfied-item-lifetime-bound.rs:14:8 + --> $DIR/unsatisfied-item-lifetime-bound.rs:14:20 | LL | f: ::Y<'a>, - | ^^^^^^^^^^^^^^^ + | ^^ lifetime bound not satisfied | note: lifetime parameter instantiated with the lifetime `'a` as defined here --> $DIR/unsatisfied-item-lifetime-bound.rs:13:10 @@ -43,12 +43,17 @@ note: lifetime parameter instantiated with the lifetime `'a` as defined here LL | struct B<'a, T: for<'r> X = &'r ()>> { | ^^ = note: but lifetime parameter must outlive the static lifetime +note: `'static` requirement introduced here + --> $DIR/unsatisfied-item-lifetime-bound.rs:4:16 + | +LL | type Y<'a: 'static>; + | ^^^^^^^ error[E0478]: lifetime bound not satisfied - --> $DIR/unsatisfied-item-lifetime-bound.rs:19:8 + --> $DIR/unsatisfied-item-lifetime-bound.rs:19:20 | LL | f: ::Y<'a>, - | ^^^^^^^^^^^^^^^ + | ^^ lifetime bound not satisfied | note: lifetime parameter instantiated with the lifetime `'a` as defined here --> $DIR/unsatisfied-item-lifetime-bound.rs:18:10 @@ -56,12 +61,17 @@ note: lifetime parameter instantiated with the lifetime `'a` as defined here LL | struct C<'a, T: X> { | ^^ = note: but lifetime parameter must outlive the static lifetime +note: `'static` requirement introduced here + --> $DIR/unsatisfied-item-lifetime-bound.rs:4:16 + | +LL | type Y<'a: 'static>; + | ^^^^^^^ error[E0478]: lifetime bound not satisfied - --> $DIR/unsatisfied-item-lifetime-bound.rs:24:8 + --> $DIR/unsatisfied-item-lifetime-bound.rs:24:21 | LL | f: <() as X>::Y<'a>, - | ^^^^^^^^^^^^^^^^ + | ^^ lifetime bound not satisfied | note: lifetime parameter instantiated with the lifetime `'a` as defined here --> $DIR/unsatisfied-item-lifetime-bound.rs:23:10 @@ -69,6 +79,11 @@ note: lifetime parameter instantiated with the lifetime `'a` as defined here LL | struct D<'a> { | ^^ = note: but lifetime parameter must outlive the static lifetime +note: `'static` requirement introduced here + --> $DIR/unsatisfied-item-lifetime-bound.rs:4:16 + | +LL | type Y<'a: 'static>; + | ^^^^^^^ error: aborting due to 4 previous errors; 1 warning emitted diff --git a/tests/ui/lifetimes/dyn-trait-static-obligation.rs b/tests/ui/lifetimes/dyn-trait-static-obligation.rs new file mode 100644 index 0000000000000..1c129c1728203 --- /dev/null +++ b/tests/ui/lifetimes/dyn-trait-static-obligation.rs @@ -0,0 +1,47 @@ +use std::cell::*; + +#[derive(Default)] +struct Test { + pub foo: u32, +} + +trait FooSetter { + fn set_foo(&mut self, value: u32); +} + +impl FooSetter for Test { + fn set_foo(&mut self, value: u32) { + self.foo = value; + } +} + +trait BaseSetter{ + fn set(&mut self, value: u32); +} +impl BaseSetter for dyn FooSetter { + fn set(&mut self, value: u32){ + self.set_foo(value); + } +} + +struct TestHolder<'a> { + pub holder: Option>, +} + +impl <'a>TestHolder<'a>{ + pub fn test_foo(&self){ + self.holder.as_ref().unwrap().borrow_mut().set(20); + //~^ ERROR borrowed data escapes outside of method + } +} + +fn main() { + let mut test = Test::default(); + test.foo = 10; + { + let holder = TestHolder { holder: Some(RefCell::from(&mut test))}; + + holder.test_foo(); + } + test.foo = 30; +} diff --git a/tests/ui/lifetimes/dyn-trait-static-obligation.stderr b/tests/ui/lifetimes/dyn-trait-static-obligation.stderr new file mode 100644 index 0000000000000..bc22e6ef2e9a3 --- /dev/null +++ b/tests/ui/lifetimes/dyn-trait-static-obligation.stderr @@ -0,0 +1,24 @@ +error[E0521]: borrowed data escapes outside of method + --> $DIR/dyn-trait-static-obligation.rs:33:8 + | +LL | impl <'a>TestHolder<'a>{ + | -- lifetime `'a` defined here +LL | pub fn test_foo(&self){ + | ----- `self` is a reference that is only valid in the method body +LL | self.holder.as_ref().unwrap().borrow_mut().set(20); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `self` escapes the method body here + | argument requires that `'a` must outlive `'static` + | + = note: requirement occurs because of a mutable reference to `dyn FooSetter` + = note: mutable references are invariant over their type parameter + = help: see for more information about variance +help: consider relaxing the implicit `'static` requirement on the impl + | +LL | impl BaseSetter for dyn FooSetter + '_ { + | ++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/lifetimes/point-at-lifetime-obligation-from-trait-in-trait-object.rs b/tests/ui/lifetimes/point-at-lifetime-obligation-from-trait-in-trait-object.rs new file mode 100644 index 0000000000000..47f1abd38a1c5 --- /dev/null +++ b/tests/ui/lifetimes/point-at-lifetime-obligation-from-trait-in-trait-object.rs @@ -0,0 +1,6 @@ +use std::any::Any; + +struct Something<'a> { + broken: Box //~ ERROR lifetime bound not satisfied +} +fn main() {} diff --git a/tests/ui/lifetimes/point-at-lifetime-obligation-from-trait-in-trait-object.stderr b/tests/ui/lifetimes/point-at-lifetime-obligation-from-trait-in-trait-object.stderr new file mode 100644 index 0000000000000..f2b4feffd5d5a --- /dev/null +++ b/tests/ui/lifetimes/point-at-lifetime-obligation-from-trait-in-trait-object.stderr @@ -0,0 +1,20 @@ +error[E0478]: lifetime bound not satisfied + --> $DIR/point-at-lifetime-obligation-from-trait-in-trait-object.rs:4:27 + | +LL | broken: Box + | --- ^^ lifetime bound not satisfied + | | + | this requires `'static` + | +note: lifetime parameter instantiated with the lifetime `'a` as defined here + --> $DIR/point-at-lifetime-obligation-from-trait-in-trait-object.rs:3:18 + | +LL | struct Something<'a> { + | ^^ + = note: but lifetime parameter must outlive the static lifetime +note: `'static` requirement introduced here + --> $SRC_DIR/core/src/any.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0478`. diff --git a/tests/ui/lifetimes/static-impl-obligation.rs b/tests/ui/lifetimes/static-impl-obligation.rs new file mode 100644 index 0000000000000..a1cd60d66d184 --- /dev/null +++ b/tests/ui/lifetimes/static-impl-obligation.rs @@ -0,0 +1,291 @@ +mod a { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo { //~ HELP consider relaxing the implicit `'static` requirement + fn hello(&self) {} + } + fn bar<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod b { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo { + fn hello(&'static self) {} + } + fn bar<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod c { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo { + fn hello(&'static self) where Self: 'static {} + } + fn bar<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod d { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo { + fn hello(&self) where Self: 'static {} + } + fn bar<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod e { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo + 'static { //~ HELP consider relaxing this `'static` requirement + fn hello(&self) {} + } + fn bar<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod f { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo + 'static { + fn hello(&'static self) {} + } + fn bar<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod g { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo + 'static { + fn hello(&'static self) where Self: 'static {} + } + fn bar<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod h { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo + 'static { + fn hello(&self) where Self: 'static {} + } + fn bar<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod i { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo where Self: 'static { + fn hello(&self) {} + } + fn bar<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod j { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo where Self: 'static { + fn hello(&'static self) {} + } + fn bar<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod k { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo where Self: 'static { + fn hello(&'static self) where Self: 'static {} + } + fn bar<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod l { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo where Self: 'static { + fn hello(&self) where Self: 'static {} + } + fn bar<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod m { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo + 'static where Self: 'static { + fn hello(&self) {} + } + fn bar<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod n { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo + 'static where Self: 'static { + fn hello(&'static self) {} + } + fn bar<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod o { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo + 'static where Self: 'static { + fn hello(&'static self) where Self: 'static {} + } + fn bar<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod p { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo + 'static where Self: 'static { + fn hello(&self) where Self: 'static {} + } + fn bar<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod q { + struct Foo {} + impl Foo { + fn hello(&'static self) {} + } + fn bar<'a>(x: &'a &'a Foo) { + x.hello(); //~ ERROR borrowed data escapes outside of function + } +} +mod r { + struct Foo {} + impl Foo { + fn hello(&'static self) where Self: 'static {} + } + fn bar<'a>(x: &'a &'a Foo) { + x.hello(); //~ ERROR borrowed data escapes outside of function + } +} +mod s { + trait Foo {} + impl<'a> Foo for &'a u32 {} + + trait Trait { fn hello(&self) {} } + + impl Trait for dyn Foo { //~ HELP consider relaxing the implicit `'static` requirement on the impl + fn hello(&self) {} + + } + fn convert<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod t { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + trait MyTrait where Self: 'static { + fn use_self(&self) -> &() where Self: 'static { panic!() } + } + trait Irrelevant { + fn use_self(&self) -> &() { panic!() } + } + + impl MyTrait for dyn ObjectTrait + '_ {} //~ ERROR lifetime bound not satisfied + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + val.use_self() //~ ERROR borrowed data escapes + } +} +mod u { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + trait MyTrait { + fn use_self(&self) -> &() where Self: 'static { panic!() } + } + trait Irrelevant { + fn use_self(&self) -> &() { panic!() } + } + + impl MyTrait for dyn ObjectTrait + '_ {} + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + val.use_self() //~ ERROR borrowed data escapes + } +} +mod v { + trait OtherTrait<'a> {} + impl<'a> OtherTrait<'a> for &'a () {} + + trait ObjectTrait {} + trait MyTrait where Self: 'static { + fn use_self(&'static self) -> &() { panic!() } + } + trait Irrelevant { + fn use_self(&self) -> &() { panic!() } + } + + impl MyTrait for dyn ObjectTrait {} + + fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + val.use_self() //~ ERROR borrowed data escapes + } +} +mod w { + trait Foo {} + impl<'a> Foo for &'a u32 {} + + trait Trait where Self: 'static { fn hello(&self) {} } + + impl Trait for dyn Foo + '_ { //~ERROR lifetime bound not satisfied + fn hello(&self) {} + + } + fn convert<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; + y.hello(); //~ ERROR lifetime may not live long enough + } +} +mod x { + trait Foo {} + impl<'a> Foo for &'a u32 {} + impl dyn Foo + '_ where Self: '_ { //~ ERROR `'_` cannot be used here + fn hello(&self) {} + + } + fn convert<'a>(x: &'a &'a u32) { + let y: &dyn Foo = x; //~ ERROR lifetime may not live long enough + y.hello(); + } +} +fn main() {} diff --git a/tests/ui/lifetimes/static-impl-obligation.stderr b/tests/ui/lifetimes/static-impl-obligation.stderr new file mode 100644 index 0000000000000..150662931b26c --- /dev/null +++ b/tests/ui/lifetimes/static-impl-obligation.stderr @@ -0,0 +1,473 @@ +error[E0637]: `'_` cannot be used here + --> $DIR/static-impl-obligation.rs:282:35 + | +LL | impl dyn Foo + '_ where Self: '_ { + | ^^ `'_` is a reserved lifetime name + +error[E0478]: lifetime bound not satisfied + --> $DIR/static-impl-obligation.rs:222:10 + | +LL | impl MyTrait for dyn ObjectTrait + '_ {} + | ^^^^^^^ + | +note: lifetime parameter instantiated with the anonymous lifetime as defined here + --> $DIR/static-impl-obligation.rs:222:40 + | +LL | impl MyTrait for dyn ObjectTrait + '_ {} + | ^^ + = note: but lifetime parameter must outlive the static lifetime +note: `'static` requirement introduced here + --> $DIR/static-impl-obligation.rs:215:31 + | +LL | trait MyTrait where Self: 'static { + | ^^^^^^^ + +error[E0521]: borrowed data escapes outside of function + --> $DIR/static-impl-obligation.rs:225:9 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | -- --- `val` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here +LL | val.use_self() + | ^^^^^^^^^^^^^^ + | | + | `val` escapes the function body here + | argument requires that `'a` must outlive `'static` + | +note: the `impl` on `dyn t::ObjectTrait` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:215:31 + | +LL | trait MyTrait where Self: 'static { + | ^^^^^^^ +LL | fn use_self(&self) -> &() where Self: 'static { panic!() } + | ^^^^^^^ + +error[E0521]: borrowed data escapes outside of function + --> $DIR/static-impl-obligation.rs:243:9 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | -- --- `val` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here +LL | val.use_self() + | ^^^^^^^^^^^^^^ + | | + | `val` escapes the function body here + | argument requires that `'a` must outlive `'static` + | +note: the `impl` on `dyn u::ObjectTrait` has a `'static` lifetime requirement + --> $DIR/static-impl-obligation.rs:234:47 + | +LL | fn use_self(&self) -> &() where Self: 'static { panic!() } + | ^^^^^^^ + +error[E0521]: borrowed data escapes outside of function + --> $DIR/static-impl-obligation.rs:261:9 + | +LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { + | -- --- `val` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here +LL | val.use_self() + | ^^^^^^^^^^^^^^ + | | + | `val` escapes the function body here + | argument requires that `'a` must outlive `'static` + | +note: the used `impl` has a `'static` requirement + --> $DIR/static-impl-obligation.rs:258:26 + | +LL | fn use_self(&'static self) -> &() { panic!() } + | -------- calling this method introduces the `impl`'s `'static` requirement +... +LL | impl MyTrait for dyn ObjectTrait {} + | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement +note: the `impl` on `(dyn v::ObjectTrait + 'static)` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:251:31 + | +LL | trait MyTrait where Self: 'static { + | ^^^^^^^ +LL | fn use_self(&'static self) -> &() { panic!() } + | ^^^^^^^^^^^^^ +... +LL | impl MyTrait for dyn ObjectTrait {} + | ^^^^^^^^^^^^^^^ + +error[E0478]: lifetime bound not satisfied + --> $DIR/static-impl-obligation.rs:270:10 + | +LL | impl Trait for dyn Foo + '_ { + | ^^^^^ + | +note: lifetime parameter instantiated with the anonymous lifetime as defined here + --> $DIR/static-impl-obligation.rs:270:30 + | +LL | impl Trait for dyn Foo + '_ { + | ^^ + = note: but lifetime parameter must outlive the static lifetime +note: `'static` requirement introduced here + --> $DIR/static-impl-obligation.rs:268:29 + | +LL | trait Trait where Self: 'static { fn hello(&self) {} } + | ^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:9:9 + | +LL | fn bar<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +help: consider relaxing the implicit `'static` requirement on the impl + | +LL | impl dyn Foo + '_ { + | ++++ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:20:9 + | +LL | fn bar<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +note: the `impl` on `(dyn b::Foo + 'static)` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:15:10 + | +LL | impl dyn Foo { + | ^^^^^^^ +LL | fn hello(&'static self) {} + | ^^^^^^^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:31:9 + | +LL | fn bar<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +note: the `impl` on `(dyn c::Foo + 'static)` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:26:10 + | +LL | impl dyn Foo { + | ^^^^^^^ +LL | fn hello(&'static self) where Self: 'static {} + | ^^^^^^^^^^^^^ ^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:42:9 + | +LL | fn bar<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +note: the `impl` on `(dyn d::Foo + 'static)` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:37:10 + | +LL | impl dyn Foo { + | ^^^^^^^ +LL | fn hello(&self) where Self: 'static {} + | ^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:53:9 + | +LL | fn bar<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +help: consider relaxing this `'static` requirement + | +LL | impl dyn Foo + '_ { + | ~~ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:64:9 + | +LL | fn bar<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +note: the `impl` on `(dyn f::Foo + 'static)` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:59:20 + | +LL | impl dyn Foo + 'static { + | ^^^^^^^ +LL | fn hello(&'static self) {} + | ^^^^^^^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:75:9 + | +LL | fn bar<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +note: the `impl` on `(dyn g::Foo + 'static)` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:70:20 + | +LL | impl dyn Foo + 'static { + | ^^^^^^^ +LL | fn hello(&'static self) where Self: 'static {} + | ^^^^^^^^^^^^^ ^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:86:9 + | +LL | fn bar<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +note: the `impl` on `(dyn h::Foo + 'static)` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:81:20 + | +LL | impl dyn Foo + 'static { + | ^^^^^^^ +LL | fn hello(&self) where Self: 'static {} + | ^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:97:9 + | +LL | fn bar<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +note: the `impl` on `(dyn i::Foo + 'static)` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:92:10 + | +LL | impl dyn Foo where Self: 'static { + | ^^^^^^^ ^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:108:9 + | +LL | fn bar<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +note: the `impl` on `(dyn j::Foo + 'static)` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:103:10 + | +LL | impl dyn Foo where Self: 'static { + | ^^^^^^^ ^^^^^^^ +LL | fn hello(&'static self) {} + | ^^^^^^^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:119:9 + | +LL | fn bar<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +note: the `impl` on `(dyn k::Foo + 'static)` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:114:10 + | +LL | impl dyn Foo where Self: 'static { + | ^^^^^^^ ^^^^^^^ +LL | fn hello(&'static self) where Self: 'static {} + | ^^^^^^^^^^^^^ ^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:130:9 + | +LL | fn bar<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +note: the `impl` on `(dyn l::Foo + 'static)` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:125:10 + | +LL | impl dyn Foo where Self: 'static { + | ^^^^^^^ ^^^^^^^ +LL | fn hello(&self) where Self: 'static {} + | ^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:141:9 + | +LL | fn bar<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +note: the `impl` on `(dyn m::Foo + 'static)` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:136:20 + | +LL | impl dyn Foo + 'static where Self: 'static { + | ^^^^^^^ ^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:152:9 + | +LL | fn bar<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +note: the `impl` on `(dyn n::Foo + 'static)` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:147:20 + | +LL | impl dyn Foo + 'static where Self: 'static { + | ^^^^^^^ ^^^^^^^ +LL | fn hello(&'static self) {} + | ^^^^^^^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:163:9 + | +LL | fn bar<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +note: the `impl` on `(dyn o::Foo + 'static)` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:158:20 + | +LL | impl dyn Foo + 'static where Self: 'static { + | ^^^^^^^ ^^^^^^^ +LL | fn hello(&'static self) where Self: 'static {} + | ^^^^^^^^^^^^^ ^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:174:9 + | +LL | fn bar<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +note: the `impl` on `(dyn p::Foo + 'static)` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:169:20 + | +LL | impl dyn Foo + 'static where Self: 'static { + | ^^^^^^^ ^^^^^^^ +LL | fn hello(&self) where Self: 'static {} + | ^^^^^^^ + +error[E0521]: borrowed data escapes outside of function + --> $DIR/static-impl-obligation.rs:183:9 + | +LL | fn bar<'a>(x: &'a &'a Foo) { + | -- - `x` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here +LL | x.hello(); + | ^^^^^^^^^ + | | + | `x` escapes the function body here + | argument requires that `'a` must outlive `'static` + | +note: the `impl` on `q::Foo` has a `'static` lifetime requirement + --> $DIR/static-impl-obligation.rs:180:18 + | +LL | fn hello(&'static self) {} + | ^^^^^^^^^^^^^ + +error[E0521]: borrowed data escapes outside of function + --> $DIR/static-impl-obligation.rs:192:9 + | +LL | fn bar<'a>(x: &'a &'a Foo) { + | -- - `x` is a reference that is only valid in the function body + | | + | lifetime `'a` defined here +LL | x.hello(); + | ^^^^^^^^^ + | | + | `x` escapes the function body here + | argument requires that `'a` must outlive `'static` + | +note: the `impl` on `r::Foo` has `'static` lifetime requirements + --> $DIR/static-impl-obligation.rs:189:18 + | +LL | fn hello(&'static self) where Self: 'static {} + | ^^^^^^^^^^^^^ ^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:207:9 + | +LL | fn convert<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +help: consider relaxing the implicit `'static` requirement on the impl + | +LL | impl Trait for dyn Foo + '_ { + | ++++ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:276:9 + | +LL | fn convert<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | - cast requires that `'a` must outlive `'static` +LL | y.hello(); + | ^^^^^^^^^ calling this method introduces a `'static` lifetime requirement + | +note: the `impl` on `dyn w::Foo` has a `'static` lifetime requirement + --> $DIR/static-impl-obligation.rs:268:29 + | +LL | trait Trait where Self: 'static { fn hello(&self) {} } + | ^^^^^^^ + +error: lifetime may not live long enough + --> $DIR/static-impl-obligation.rs:287:27 + | +LL | fn convert<'a>(x: &'a &'a u32) { + | -- lifetime `'a` defined here +LL | let y: &dyn Foo = x; + | ^ cast requires that `'a` must outlive `'static` + +error: aborting due to 27 previous errors + +Some errors have detailed explanations: E0478, E0521, E0637. +For more information about an error, try `rustc --explain E0478`. diff --git a/tests/ui/regions/issue-78262.base.stderr b/tests/ui/regions/issue-78262.base.stderr index 113c84c656287..f267c5280beee 100644 --- a/tests/ui/regions/issue-78262.base.stderr +++ b/tests/ui/regions/issue-78262.base.stderr @@ -8,6 +8,11 @@ LL | let f = |x: &dyn TT| x.func(); | | | argument requires that `'1` must outlive `'static` | | let's call the lifetime of this reference `'1` | `x` is a reference that is only valid in the closure body + | +help: consider relaxing the implicit `'static` requirement on the impl + | +LL | impl dyn TT + '_ { + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/regions/issue-78262.polonius.stderr b/tests/ui/regions/issue-78262.polonius.stderr index 113c84c656287..f267c5280beee 100644 --- a/tests/ui/regions/issue-78262.polonius.stderr +++ b/tests/ui/regions/issue-78262.polonius.stderr @@ -8,6 +8,11 @@ LL | let f = |x: &dyn TT| x.func(); | | | argument requires that `'1` must outlive `'static` | | let's call the lifetime of this reference `'1` | `x` is a reference that is only valid in the closure body + | +help: consider relaxing the implicit `'static` requirement on the impl + | +LL | impl dyn TT + '_ { + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/regions/region-bounds-on-objects-and-type-parameters.stderr b/tests/ui/regions/region-bounds-on-objects-and-type-parameters.stderr index b15d2affeea37..c1d5c4d908bac 100644 --- a/tests/ui/regions/region-bounds-on-objects-and-type-parameters.stderr +++ b/tests/ui/regions/region-bounds-on-objects-and-type-parameters.stderr @@ -5,10 +5,10 @@ LL | z: Box+'b+'c>, | ^^ error[E0478]: lifetime bound not satisfied - --> $DIR/region-bounds-on-objects-and-type-parameters.rs:21:8 + --> $DIR/region-bounds-on-objects-and-type-parameters.rs:21:23 | LL | z: Box+'b+'c>, - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^ lifetime bound not satisfied | note: lifetime parameter instantiated with the lifetime `'b` as defined here --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:15 diff --git a/tests/ui/regions/regions-wf-trait-object.stderr b/tests/ui/regions/regions-wf-trait-object.stderr index 2099615082083..df08b67048f6c 100644 --- a/tests/ui/regions/regions-wf-trait-object.stderr +++ b/tests/ui/regions/regions-wf-trait-object.stderr @@ -1,8 +1,8 @@ error[E0478]: lifetime bound not satisfied - --> $DIR/regions-wf-trait-object.rs:7:8 + --> $DIR/regions-wf-trait-object.rs:7:29 | LL | x: Box+'b> - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ lifetime bound not satisfied | note: lifetime parameter instantiated with the lifetime `'b` as defined here --> $DIR/regions-wf-trait-object.rs:6:15 diff --git a/tests/ui/static/static-lifetime.stderr b/tests/ui/static/static-lifetime.stderr index 8c9434ce3cb0b..c6c775dc79582 100644 --- a/tests/ui/static/static-lifetime.stderr +++ b/tests/ui/static/static-lifetime.stderr @@ -10,6 +10,11 @@ note: lifetime parameter instantiated with the lifetime `'a` as defined here LL | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} | ^^ = note: but lifetime parameter must outlive the static lifetime +note: `'static` requirement introduced here + --> $DIR/static-lifetime.rs:1:30 + | +LL | pub trait Arbitrary: Sized + 'static {} + | ^^^^^^^ 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 6effaf61099ec..ebc5807e0415b 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 @@ -18,7 +18,7 @@ LL | impl MyTrait for dyn ObjectTrait { | ^^^^^^^^^^^^^^ this has an implicit `'static` lifetime requirement LL | fn use_self(&self) -> &() { panic!() } | -------- calling this method introduces the `impl`'s `'static` requirement -help: consider relaxing the implicit `'static` requirement +help: consider relaxing the implicit `'static` requirement on the impl | LL | impl MyTrait for dyn ObjectTrait + '_ { | ++++ @@ -43,7 +43,7 @@ LL | impl dyn ObjectTrait { | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement LL | fn use_self(&self) -> &() { panic!() } | -------- calling this method introduces the `impl`'s `'static` requirement -help: consider relaxing the implicit `'static` requirement +help: consider relaxing the implicit `'static` requirement on the impl | LL | impl dyn ObjectTrait + '_ { | ++++ @@ -69,7 +69,7 @@ LL | fn use_self(&self) -> &() { panic!() } ... LL | impl MyTrait for dyn ObjectTrait {} | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement -help: consider relaxing the implicit `'static` requirement +help: consider relaxing the implicit `'static` requirement on the impl | LL | impl MyTrait for dyn ObjectTrait + '_ {} | ++++ @@ -95,7 +95,7 @@ LL | fn use_self(&self) -> &() { panic!() } ... LL | impl MyTrait for dyn ObjectTrait {} | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement -help: consider relaxing the implicit `'static` requirement +help: consider relaxing the implicit `'static` requirement on the impl | LL | impl MyTrait for dyn ObjectTrait + '_ {} | ++++ @@ -120,7 +120,7 @@ LL | impl MyTrait for dyn ObjectTrait { | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement LL | fn use_self(&self) -> &() { panic!() } | -------- calling this method introduces the `impl`'s `'static` requirement -help: consider relaxing the implicit `'static` requirement +help: consider relaxing the implicit `'static` requirement on the impl | LL | impl MyTrait for dyn ObjectTrait + '_ { | ++++