https://gcc.gnu.org/g:9d88bcce6da404acee0363d7d417b199aca011c5
commit 9d88bcce6da404acee0363d7d417b199aca011c5 Author: Philip Herron <herron.phi...@googlemail.com> Date: Wed Mar 12 17:03:25 2025 +0000 gccrs: check for recursion trait cycle with bounds checks We need to be careful when doing bounds check as to not create a recusive trait resolution. This patch checks for that case and fixes a bad type is equal check on ADT Types which was caught with a regression here. Fixes Rust-GCC#3126 gcc/rust/ChangeLog: * typecheck/rust-hir-trait-resolve.cc (TraitResolver::ResolveHirItem): new helper * typecheck/rust-hir-trait-resolve.h: add helper prototype * typecheck/rust-type-util.cc (query_type): add debug * typecheck/rust-tyty-bounds.cc (TypeBoundsProbe::scan): check for recursion * typecheck/rust-tyty.cc (VariantDef::is_equal): fix is equal check gcc/testsuite/ChangeLog: * rust/execute/torture/issue-3126.rs: New test. Signed-off-by: Philip Herron <herron.phi...@googlemail.com> Diff: --- gcc/rust/typecheck/rust-hir-trait-resolve.cc | 10 +++++ gcc/rust/typecheck/rust-hir-trait-resolve.h | 2 + gcc/rust/typecheck/rust-type-util.cc | 7 +++- gcc/rust/typecheck/rust-tyty-bounds.cc | 9 ++++ gcc/rust/typecheck/rust-tyty.cc | 3 -- gcc/testsuite/rust/execute/torture/issue-3126.rs | 52 ++++++++++++++++++++++++ 6 files changed, 78 insertions(+), 5 deletions(-) diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc index ceb5b7a91b22..0ed6fa0859e4 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc @@ -107,6 +107,16 @@ TraitResolver::Lookup (HIR::TypePath &path) return resolver.lookup_path (path); } +HIR::Trait * +TraitResolver::ResolveHirItem (const HIR::TypePath &path) +{ + TraitResolver resolver; + + HIR::Trait *lookup = nullptr; + bool ok = resolver.resolve_path_to_trait (path, &lookup); + return ok ? lookup : nullptr; +} + TraitResolver::TraitResolver () : TypeCheckBase () {} bool diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.h b/gcc/rust/typecheck/rust-hir-trait-resolve.h index 93371a7be253..b938633d1f9d 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.h +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.h @@ -58,6 +58,8 @@ public: static TraitReference *Lookup (HIR::TypePath &path); + static HIR::Trait *ResolveHirItem (const HIR::TypePath &path); + private: TraitResolver (); diff --git a/gcc/rust/typecheck/rust-type-util.cc b/gcc/rust/typecheck/rust-type-util.cc index b797188bca7f..47bf67943640 100644 --- a/gcc/rust/typecheck/rust-type-util.cc +++ b/gcc/rust/typecheck/rust-type-util.cc @@ -87,8 +87,11 @@ query_type (HirId reference, TyTy::BaseType **result) // is it an impl_type? if (auto impl_block_by_type = mappings.lookup_impl_block_type (reference)) { - *result - = TypeCheckItem::ResolveImplBlockSelf (*impl_block_by_type.value ()); + // found an impl item + HIR::ImplBlock *impl = impl_block_by_type.value (); + rust_debug_loc (impl->get_locus (), "resolved impl block type {%u} to", + reference); + *result = TypeCheckItem::ResolveImplBlockSelf (*impl); context->query_completed (reference); return true; } diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index 0a04d7ab079c..ffe3c1b4ba35 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -20,6 +20,7 @@ #include "rust-hir-type-bounds.h" #include "rust-hir-trait-resolve.h" #include "rust-substitution-mapper.h" +#include "rust-hir-trait-resolve.h" #include "rust-type-util.h" namespace Rust { @@ -71,6 +72,14 @@ TypeBoundsProbe::scan () if (!impl->has_trait_ref ()) return true; + // can be recursive trait resolution + HIR::Trait *t = TraitResolver::ResolveHirItem (impl->get_trait_ref ()); + if (t == nullptr) + return true; + DefId trait_id = t->get_mappings ().get_defid (); + if (context->trait_query_in_progress (trait_id)) + return true; + HirId impl_ty_id = impl->get_type ().get_mappings ().get_hirid (); TyTy::BaseType *impl_type = nullptr; if (!query_type (impl_ty_id, &impl_type)) diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 208632012728..28c99a986ad6 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -1566,9 +1566,6 @@ VariantDef::is_equal (const VariantDef &other) const if (identifier.compare (other.identifier) != 0) return false; - if (discriminant != other.discriminant) - return false; - if (fields.size () != other.fields.size ()) return false; diff --git a/gcc/testsuite/rust/execute/torture/issue-3126.rs b/gcc/testsuite/rust/execute/torture/issue-3126.rs new file mode 100644 index 000000000000..f5051467f027 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-3126.rs @@ -0,0 +1,52 @@ +/* { dg-output "child\r*\n" }*/ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "sized"] +pub trait Sized {} + +struct Foo { + my_int: u32, + // { dg-warning "field is never read: .my_int." "" { target *-*-* } .-1 } +} + +trait Parent<T> { + fn parent(&self) -> T; +} + +trait Child: Parent<u32> { + fn child(&self); +} + +impl Parent<u32> for Foo { + fn parent(&self) -> u32 { + unsafe { + let parent = "parent %i\n\0"; + let msg = parent as *const str; + printf(msg as *const i8, self.my_int); + return self.my_int; + } + } +} + +impl Child for Foo { + fn child(&self) { + let _ = self; + unsafe { + let child = "child\n\0"; + let msg = child as *const str; + printf(msg as *const i8); + } + } +} + +pub fn main() -> i32 { + let a = Foo { my_int: 0xf00dfeed }; + let b: &dyn Child = &a; + + // b.parent(); + b.child(); + + 0 +}