[committed,039/103] gccrs: Add check for recursive trait cycles

Message ID 20230221120230.596966-40-arthur.cohen@embecosm.com
State Unresolved
Headers
Series [committed,001/103] gccrs: Fix missing dead code analysis ICE on local enum definition |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Arthur Cohen Feb. 21, 2023, 12:01 p.m. UTC
  From: Philip Herron <philip.herron@embecosm.com>

gcc/rust/ChangeLog:

	* typecheck/rust-hir-trait-resolve.cc (TraitResolver::resolve_trait): Check if a
	trait query is currently in progress.
	* typecheck/rust-hir-type-check.h (class TraitQueryGuard): Add helpers around
	checking for trait queries and inserting them.

gcc/testsuite/ChangeLog:

	* rust/compile/issue-1589.rs: New test.
---
 gcc/rust/typecheck/rust-hir-trait-resolve.cc | 12 +++++++-
 gcc/rust/typecheck/rust-hir-type-check.h     | 29 ++++++++++++++++++++
 gcc/testsuite/rust/compile/issue-1589.rs     |  5 ++++
 3 files changed, 45 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/rust/compile/issue-1589.rs
  

Patch

diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
index 1b0bcaac79d..2ec9b2ef83e 100644
--- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc
+++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
@@ -141,6 +141,14 @@  TraitResolver::resolve_trait (HIR::Trait *trait_reference)
       return tref;
     }
 
+  DefId trait_id = trait_reference->get_mappings ().get_defid ();
+  if (context->trait_query_in_progress (trait_id))
+    {
+      rust_error_at (trait_reference->get_locus (), "trait cycle detected");
+      return &TraitReference::error_node ();
+    }
+
+  TraitQueryGuard guard (trait_id);
   TyTy::BaseType *self = nullptr;
   std::vector<TyTy::SubstitutionParamMapping> substitutions;
   for (auto &generic_param : trait_reference->get_generic_params ())
@@ -201,8 +209,10 @@  TraitResolver::resolve_trait (HIR::Trait *trait_reference)
 	      HIR::TraitBound *b
 		= static_cast<HIR::TraitBound *> (bound.get ());
 
-	      // FIXME this might be recursive we need a check for that
 	      auto predicate = get_predicate_from_bound (b->get_path ());
+	      if (predicate.is_error ())
+		return &TraitReference::error_node ();
+
 	      specified_bounds.push_back (predicate);
 	      super_traits.push_back (predicate.get ());
 	    }
diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h
index a1dd8052246..2b47c6738b5 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.h
+++ b/gcc/rust/typecheck/rust-hir-type-check.h
@@ -381,6 +381,19 @@  public:
     return querys_in_progress.find (id) != querys_in_progress.end ();
   }
 
+  void insert_trait_query (DefId id) { trait_queries_in_progress.insert (id); }
+
+  void trait_query_completed (DefId id)
+  {
+    trait_queries_in_progress.erase (id);
+  }
+
+  bool trait_query_in_progress (DefId id) const
+  {
+    return trait_queries_in_progress.find (id)
+	   != trait_queries_in_progress.end ();
+  }
+
 private:
   TypeCheckContext ();
 
@@ -418,6 +431,7 @@  private:
 
   // query context lookups
   std::set<HirId> querys_in_progress;
+  std::set<DefId> trait_queries_in_progress;
 };
 
 class TypeResolution
@@ -426,6 +440,21 @@  public:
   static void Resolve (HIR::Crate &crate);
 };
 
+class TraitQueryGuard
+{
+public:
+  TraitQueryGuard (DefId id) : id (id), ctx (*TypeCheckContext::get ())
+  {
+    ctx.insert_trait_query (id);
+  }
+
+  ~TraitQueryGuard () { ctx.trait_query_completed (id); }
+
+private:
+  DefId id;
+  TypeCheckContext &ctx;
+};
+
 } // namespace Resolver
 } // namespace Rust
 
diff --git a/gcc/testsuite/rust/compile/issue-1589.rs b/gcc/testsuite/rust/compile/issue-1589.rs
new file mode 100644
index 00000000000..79a5866e4af
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-1589.rs
@@ -0,0 +1,5 @@ 
+pub trait A: B {}
+// { dg-error "trait cycle detected" "" { target *-*-* } .-1 }
+
+pub trait B: A {}
+// { dg-error "trait cycle detected" "" { target *-*-* } .-1 }