Change:
The lint is triggered by the following code (from , cc : In the environment , the type surprisingly requires for well-formedness (see ), but this constraint is not used in implied bounds, so I believe it can't be exploited for unsoundness. The lint was upgraded to deny-by-default in the current beta (1.68.0-beta.5 2023-02-15 ). So this counts as regression? cc label C-bug T-types T-compiler regression-from-stable-to-beta
:facepalm: I think this is due to us preferring param-env candidates for .
So the issue here is that requires . We try to prove that in the hybrid param-env of the impl's WC + trait method's WC, being after substituting . Due to some frustrating precedence rules around candidate assembly in the trait solver, we try to match against the param-env candidate and get . We also assemble a built-in sized bound, but always prefer the param-env candidate over that. That requires us to prove , which is not known to be true in the hybrid param-env, triggering the lint.
I wonder if we could get away with not checking , but just the implied lifetime bounds or something :thinking:
WG-prioritization assigning priority (). label -I-prioritize +P-medium
Been thinking about this a little bit. One thought I had was to check that the impl method is WF given only the trait method, but I think that would break this example: I wonder if we could get away with not checking WF(return-type), but just the implied lifetime bounds or something This is annoying difficult, because it's not straightforward to get "just the implied lifetime bounds" of a type. I'm playing around with using and filtering outlives bounds, but that can generate more predicates (which, I thought we had somewhere a function that recurses though those). We'll see if this works...

Discussion:
use super::potentially_plural_count; use crate::errors::LifetimesOrBoundsMismatchOnTrait; use hir::def_id::{DefId, LocalDefId}; <del> use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; </del> <ins> use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; </ins> use rustc_errors::{ pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed, MultiSpan, };

infer::HigherRankedType, tcx.fn_sig(impl_m.def_id).instantiate_identity(), ); <del> let unnormalized_impl_fty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(unnormalized_impl_sig)); </del> let norm_cause = ObligationCause::misc(impl_m_span, impl_m_def_id); let impl_sig = ocx.normalize(&norm_cause, param_env, unnormalized_impl_sig);

} if check_implied_wf == CheckImpliedWfMode::Check && !(impl_sig, trait_sig).references_error() { <del> // We need to check that the impl's args are well-formed given // the hybrid param-env (impl + trait method where-clauses). ocx.register_obligation(traits::Obligation::new( infcx.tcx, ObligationCause::dummy(), param_env, ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( unnormalized_impl_fty.into(), ))), )); </del> <ins> // See #108544. Annoying, we can end up in cases where, because of winnowing, // we pick param env candidates over a more general impl, leading to more // stricter lifetime requirements than we would otherwise need. This can // trigger the lint. Instead, let's only consider type outlives and // region outlives obligations. // // FIXME(-Ztrait-solver=next): Try removing this hack again once // the new solver is stable. let mut wf_args: smallvec::SmallVec<[_; 4]> = unnormalized_impl_sig.inputs_and_output.iter().map(|ty| ty.into()).collect(); // Annoyingly, asking for the WF predicates of an array (with an unevaluated const (only?)) // will give back the well-formed predicate of the same array. let mut wf_args_seen: FxHashSet<_> = wf_args.iter().copied().collect(); while let Some(arg) = wf_args.pop() { let Some(obligations) = rustc_trait_selection::traits::wf::obligations( infcx, param_env, impl_m_def_id, 0, arg, impl_m_span, ) else { continue; }; for obligation in obligations { match obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause( ty::ClauseKind::RegionOutlives(..) | ty::ClauseKind::TypeOutlives(..), ) => ocx.register_obligation(obligation), ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { if wf_args_seen.insert(arg) { wf_args.push(arg) } } _ => {} } } } </ins> } // Check that all obligations are satisfied by the implementation's

<ins> // check-pass // See issue #109356. We don't want a false positive to the `implied_bounds_entailment` lint. use std::borrow::Cow; pub trait Trait { fn method(self) -> Option<Cow<'static, str>> where Self: Sized; } impl<'a> Trait for Cow<'a, str> { // If we're not careful here, we'll check `WF(return-type)` using the trait // and impl where clauses, requiring that `Cow<'a, str>: Sized`. This is // obviously true, but if we pick the `Self: Sized` clause from the trait // over the "inherent impl", we will require `'a == 'static`, which triggers // the `implied_bounds_entailment` lint. fn method(self) -> Option<Cow<'static, str>> { None } } fn main() {} </ins>

<ins> // check-pass pub trait Trait<'a, 'b> { fn method(self, _: &'static &'static ()) where 'a: 'b; } impl<'a> Trait<'a, 'static> for () { // On first glance, this seems like we have the extra implied bound that // `'a: 'static`, but we know this from the trait method where clause. fn method(self, _: &'static &'a ()) {} } fn main() {} </ins>