https://gcc.gnu.org/g:0b522745670e83ee4b5af0782982743b3f715c30
commit r15-9090-g0b522745670e83ee4b5af0782982743b3f715c30 Author: Philip Herron <herron.phi...@googlemail.com> Date: Wed Mar 26 19:00:41 2025 +0000 gccrs: Add check for super traits being implemented by Self We need to recursively check the super traits of the predicate the Self type is trying to implement. Otherwise its cannot implement it. Fixes Rust-GCC#3553 gcc/rust/ChangeLog: * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::resolve_impl_block_substitutions): Track the polarity * typecheck/rust-tyty-bounds.cc (TypeBoundPredicate::validate_type_implements_this): new validator * typecheck/rust-tyty.h: new prototypes gcc/testsuite/ChangeLog: * rust/compile/issue-3553.rs: New test. Signed-off-by: Philip Herron <herron.phi...@googlemail.com> Diff: --- gcc/rust/typecheck/rust-hir-type-check-item.cc | 13 ++++-- gcc/rust/typecheck/rust-tyty-bounds.cc | 59 ++++++++++++++++++++++++++ gcc/rust/typecheck/rust-tyty.h | 8 ++++ gcc/testsuite/rust/compile/issue-3553.rs | 18 ++++++++ 4 files changed, 95 insertions(+), 3 deletions(-) diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc index a003848cce0e..977492143517 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-item.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc @@ -725,11 +725,11 @@ TypeCheckItem::resolve_impl_block_substitutions (HIR::ImplBlock &impl_block, // we don't error out here see: gcc/testsuite/rust/compile/traits2.rs // for example - specified_bound = get_predicate_from_bound (ref, impl_block.get_type ()); + specified_bound = get_predicate_from_bound (ref, impl_block.get_type (), + impl_block.get_polarity ()); } TyTy::BaseType *self = TypeCheckType::Resolve (impl_block.get_type ()); - if (self->is<TyTy::ErrorType> ()) { // we cannot check for unconstrained type arguments when the Self type is @@ -771,7 +771,14 @@ TypeCheckItem::validate_trait_impl_block ( // we don't error out here see: gcc/testsuite/rust/compile/traits2.rs // for example - specified_bound = get_predicate_from_bound (ref, impl_block.get_type ()); + specified_bound = get_predicate_from_bound (ref, impl_block.get_type (), + impl_block.get_polarity ()); + + // need to check that if this specified bound has super traits does this + // Self + // implement them? + specified_bound.validate_type_implements_super_traits ( + *self, impl_block.get_type (), impl_block.get_trait_ref ()); } bool is_trait_impl_block = !trait_reference->is_error (); diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index 65f24c0aa2ac..e028a0af80bb 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -828,6 +828,65 @@ TypeBoundPredicate::is_equal (const TypeBoundPredicate &other) const return true; } +bool +TypeBoundPredicate::validate_type_implements_super_traits ( + TyTy::BaseType &self, HIR::Type &impl_type, HIR::Type &trait) const +{ + if (get_polarity () != BoundPolarity::RegularBound) + return true; + + auto &ptref = *get (); + for (auto &super : super_traits) + { + if (super.get_polarity () != BoundPolarity::RegularBound) + continue; + + if (!super.validate_type_implements_this (self, impl_type, trait)) + { + auto &sptref = *super.get (); + + // emit error + std::string fixit1 + = "required by this bound in: " + ptref.get_name (); + std::string fixit2 = "the trait " + sptref.get_name () + + " is not implemented for " + + impl_type.as_string (); + + rich_location r (line_table, trait.get_locus ()); + r.add_fixit_insert_after (super.get_locus (), fixit1.c_str ()); + r.add_fixit_insert_after (trait.get_locus (), fixit2.c_str ()); + rust_error_at (r, ErrorCode::E0277, + "the trait bound %<%s: %s%> is not satisfied", + impl_type.as_string ().c_str (), + sptref.get_name ().c_str ()); + + return false; + } + + if (!super.validate_type_implements_super_traits (self, impl_type, trait)) + return false; + } + + return true; +} + +bool +TypeBoundPredicate::validate_type_implements_this (TyTy::BaseType &self, + HIR::Type &impl_type, + HIR::Type &trait) const +{ + const auto &ptref = *get (); + auto probed_bounds = Resolver::TypeBoundsProbe::Probe (&self); + for (auto &elem : probed_bounds) + { + auto &tref = *(elem.first); + if (ptref.is_equal (tref)) + return true; + } + + return false; +} + // trait item reference const Resolver::TraitItemReference * diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 0bfd29d98bb5..e814f07f445c 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -578,6 +578,14 @@ public: bool is_equal (const TypeBoundPredicate &other) const; + bool validate_type_implements_super_traits (TyTy::BaseType &self, + HIR::Type &impl_type, + HIR::Type &trait) const; + + bool validate_type_implements_this (TyTy::BaseType &self, + HIR::Type &impl_type, + HIR::Type &trait) const; + private: struct mark_is_error { diff --git a/gcc/testsuite/rust/compile/issue-3553.rs b/gcc/testsuite/rust/compile/issue-3553.rs new file mode 100644 index 000000000000..546f3c17bedd --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-3553.rs @@ -0,0 +1,18 @@ +trait Foo { + fn f(&self) -> isize; +} + +trait Bar: Foo { + fn g(&self) -> isize; +} + +struct A { + x: isize, +} + +impl Bar for A { + // { dg-error "the trait bound .A: Foo. is not satisfied .E0277." "" { target *-*-* } .-1 } + fn g(&self) -> isize { + self.f() + } +}