aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Herron <herron.philip@googlemail.com>2025-03-12 17:03:25 +0000
committerPhilip Herron <philip.herron@embecosm.com>2025-03-14 19:11:22 +0000
commit9d88bcce6da404acee0363d7d417b199aca011c5 (patch)
tree4bbfdc474170fe2e22c52d46d8b57158f8ba4a9a
parentaa88863a0f370235931f5d948ed5019fdc9254a9 (diff)
downloadgcc-9d88bcce6da404acee0363d7d417b199aca011c5.zip
gcc-9d88bcce6da404acee0363d7d417b199aca011c5.tar.gz
gcc-9d88bcce6da404acee0363d7d417b199aca011c5.tar.bz2
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.philip@googlemail.com>
-rw-r--r--gcc/rust/typecheck/rust-hir-trait-resolve.cc10
-rw-r--r--gcc/rust/typecheck/rust-hir-trait-resolve.h2
-rw-r--r--gcc/rust/typecheck/rust-type-util.cc7
-rw-r--r--gcc/rust/typecheck/rust-tyty-bounds.cc9
-rw-r--r--gcc/rust/typecheck/rust-tyty.cc3
-rw-r--r--gcc/testsuite/rust/execute/torture/issue-3126.rs52
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 ceb5b7a..0ed6fa0 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 93371a7..b938633 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 b797188..47bf679 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 0a04d7a..ffe3c1b 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 2086320..28c99a9 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 0000000..f505146
--- /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
+}