From: Philip Herron Date: Wed, 26 Mar 2025 19:00:41 +0000 (+0000) Subject: gccrs: Add check for super traits being implemented by Self X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=31ee9259a71742a455ead61c8b6142dcfab28b0f;p=thirdparty%2Fgcc.git 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 --- diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc index 25da29b3178..f13e3a960d9 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 ()) { // 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 dc42941da23..853ed7ee3e8 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 a5840544de4..dc30d7dd068 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 00000000000..546f3c17bed --- /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() + } +}