Skip to content

Commit 9d88bcc

Browse files
committed
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 #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 <[email protected]>
1 parent aa88863 commit 9d88bcc

File tree

6 files changed

+78
-5
lines changed

6 files changed

+78
-5
lines changed

gcc/rust/typecheck/rust-hir-trait-resolve.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ TraitResolver::Lookup (HIR::TypePath &path)
107107
return resolver.lookup_path (path);
108108
}
109109

110+
HIR::Trait *
111+
TraitResolver::ResolveHirItem (const HIR::TypePath &path)
112+
{
113+
TraitResolver resolver;
114+
115+
HIR::Trait *lookup = nullptr;
116+
bool ok = resolver.resolve_path_to_trait (path, &lookup);
117+
return ok ? lookup : nullptr;
118+
}
119+
110120
TraitResolver::TraitResolver () : TypeCheckBase () {}
111121

112122
bool

gcc/rust/typecheck/rust-hir-trait-resolve.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ class TraitResolver : public TypeCheckBase
5858

5959
static TraitReference *Lookup (HIR::TypePath &path);
6060

61+
static HIR::Trait *ResolveHirItem (const HIR::TypePath &path);
62+
6163
private:
6264
TraitResolver ();
6365

gcc/rust/typecheck/rust-type-util.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,11 @@ query_type (HirId reference, TyTy::BaseType **result)
8787
// is it an impl_type?
8888
if (auto impl_block_by_type = mappings.lookup_impl_block_type (reference))
8989
{
90-
*result
91-
= TypeCheckItem::ResolveImplBlockSelf (*impl_block_by_type.value ());
90+
// found an impl item
91+
HIR::ImplBlock *impl = impl_block_by_type.value ();
92+
rust_debug_loc (impl->get_locus (), "resolved impl block type {%u} to",
93+
reference);
94+
*result = TypeCheckItem::ResolveImplBlockSelf (*impl);
9295
context->query_completed (reference);
9396
return true;
9497
}

gcc/rust/typecheck/rust-tyty-bounds.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "rust-hir-type-bounds.h"
2121
#include "rust-hir-trait-resolve.h"
2222
#include "rust-substitution-mapper.h"
23+
#include "rust-hir-trait-resolve.h"
2324
#include "rust-type-util.h"
2425

2526
namespace Rust {
@@ -71,6 +72,14 @@ TypeBoundsProbe::scan ()
7172
if (!impl->has_trait_ref ())
7273
return true;
7374

75+
// can be recursive trait resolution
76+
HIR::Trait *t = TraitResolver::ResolveHirItem (impl->get_trait_ref ());
77+
if (t == nullptr)
78+
return true;
79+
DefId trait_id = t->get_mappings ().get_defid ();
80+
if (context->trait_query_in_progress (trait_id))
81+
return true;
82+
7483
HirId impl_ty_id = impl->get_type ().get_mappings ().get_hirid ();
7584
TyTy::BaseType *impl_type = nullptr;
7685
if (!query_type (impl_ty_id, &impl_type))

gcc/rust/typecheck/rust-tyty.cc

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1566,9 +1566,6 @@ VariantDef::is_equal (const VariantDef &other) const
15661566
if (identifier.compare (other.identifier) != 0)
15671567
return false;
15681568

1569-
if (discriminant != other.discriminant)
1570-
return false;
1571-
15721569
if (fields.size () != other.fields.size ())
15731570
return false;
15741571

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/* { dg-output "child\r*\n" }*/
2+
extern "C" {
3+
fn printf(s: *const i8, ...);
4+
}
5+
6+
#[lang = "sized"]
7+
pub trait Sized {}
8+
9+
struct Foo {
10+
my_int: u32,
11+
// { dg-warning "field is never read: .my_int." "" { target *-*-* } .-1 }
12+
}
13+
14+
trait Parent<T> {
15+
fn parent(&self) -> T;
16+
}
17+
18+
trait Child: Parent<u32> {
19+
fn child(&self);
20+
}
21+
22+
impl Parent<u32> for Foo {
23+
fn parent(&self) -> u32 {
24+
unsafe {
25+
let parent = "parent %i\n\0";
26+
let msg = parent as *const str;
27+
printf(msg as *const i8, self.my_int);
28+
return self.my_int;
29+
}
30+
}
31+
}
32+
33+
impl Child for Foo {
34+
fn child(&self) {
35+
let _ = self;
36+
unsafe {
37+
let child = "child\n\0";
38+
let msg = child as *const str;
39+
printf(msg as *const i8);
40+
}
41+
}
42+
}
43+
44+
pub fn main() -> i32 {
45+
let a = Foo { my_int: 0xf00dfeed };
46+
let b: &dyn Child = &a;
47+
48+
// b.parent();
49+
b.child();
50+
51+
0
52+
}

0 commit comments

Comments
 (0)