diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs index e68df228c6b51..594d76b8b393f 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs @@ -257,7 +257,12 @@ fn compare_predicate_entailment<'tcx>( // Compute placeholder form of impl and trait method tys. let tcx = infcx.tcx; - let mut wf_tys = FxIndexSet::default(); + // Add implied bounds from the impl header. + let mut wf_tys = ocx.assumed_wf_types( + param_env, + impl_m_span, + tcx.local_parent(impl_m.def_id.expect_local()), + ); let impl_sig = infcx.replace_bound_vars_with_fresh_vars( impl_m_span, diff --git a/src/test/ui/implied-bounds/compare-impl-method-projections.rs b/src/test/ui/implied-bounds/compare-impl-method-projections.rs new file mode 100644 index 0000000000000..f6c022adb9690 --- /dev/null +++ b/src/test/ui/implied-bounds/compare-impl-method-projections.rs @@ -0,0 +1,47 @@ +// Same as ./compare-impl-method.rs but we shouldn't use implied bounds from projections in impl +// header. See `mod exploit` for why. +// check-fail + +trait Project { + type Ty; +} +impl Project for T { + type Ty = (); +} + +trait Trait { + fn get(); +} + +impl<'a, 'b> Trait for <&'a &'b () as Project>::Ty { + fn get() + where + 'b: 'a, + //~^ ERROR impl has stricter requirements than trait + { + } +} + +mod exploit { + trait Trait { + fn extend(self) -> &'static str; + } + + impl<'a> Trait<<&'static &'a u8 as super::Project>::Ty> for &'a str { + fn extend(self) -> &'static str + where + 'a: 'static, + //~^ ERROR impl has stricter requirements than trait + //~| WARN unnecessary lifetime + { + self + } + } + + fn main() { + let val = <&str as Trait<()>>::extend(&String::from("blah blah blah")); + println!("{}", val); + } +} + +fn main() {} diff --git a/src/test/ui/implied-bounds/compare-impl-method-projections.stderr b/src/test/ui/implied-bounds/compare-impl-method-projections.stderr new file mode 100644 index 0000000000000..8d514a9773331 --- /dev/null +++ b/src/test/ui/implied-bounds/compare-impl-method-projections.stderr @@ -0,0 +1,29 @@ +warning: unnecessary lifetime parameter `'a` + --> $DIR/compare-impl-method-projections.rs:33:13 + | +LL | 'a: 'static, + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'a` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/compare-impl-method-projections.rs:19:13 + | +LL | fn get(); + | --------- definition of `get` from trait +... +LL | 'b: 'a, + | ^^ impl has extra requirement `'b: 'a` + +error[E0276]: impl has stricter requirements than trait + --> $DIR/compare-impl-method-projections.rs:33:17 + | +LL | fn extend(self) -> &'static str; + | -------------------------------- definition of `extend` from trait +... +LL | 'a: 'static, + | ^^^^^^^ impl has extra requirement `'a: 'static` + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0276`. diff --git a/src/test/ui/implied-bounds/compare-impl-method.rs b/src/test/ui/implied-bounds/compare-impl-method.rs new file mode 100644 index 0000000000000..65a86f74df7a2 --- /dev/null +++ b/src/test/ui/implied-bounds/compare-impl-method.rs @@ -0,0 +1,19 @@ +// Check implied bounds are used when comparing trait and impl methods. +// issue: #105495 +// check-pass + +trait Trait { + fn get(); +} + +// An implied bound 'b: 'a +impl<'a, 'b> Trait for &'a &'b u8 { + fn get() where 'b: 'a, {} +} + +// An explicit bound 'b: 'a +impl<'a, 'b> Trait for (&'a u8, &'b u8) where 'b: 'a, { + fn get() where 'b: 'a, {} +} + +fn main() {}