https://gcc.gnu.org/g:de23057dd6e82889d69c7cdeaee3073fa78a9078

commit r17-4346-gde23057dd6e82889d69c7cdeaee3073fa78a9078
Author: Philip Herron <[email protected]>
Date:   Tue Sep 8 12:26:51 2026 +0100

    gccrs: Fix handling where clauses into two passes
    
    Where constraints are annoying so we need to do it in two passes.
    
     1. Register bounds on the regular single segment TypePaths so like P: Deref
     2. Then register regular type bindings like I::Item or Item = U::Item
    
    As they can be order dependant as the initial predicate needs added to then
    param decls then onto whatever projections after.
    
    Fixes Rust-GCC/gccrs#4864
    
    gcc/rust/ChangeLog:
    
            * hir/tree/rust-hir-item.h: missing non const helper.
            * typecheck/rust-hir-type-check-base.h: new defer_bindings.
            * typecheck/rust-hir-type-check-implitem.cc 
(TypeCheckTopLevelExternItem::visit): new helper
            (TypeCheckImplItem::resolve_function_signature): Likewise.
            (TypeCheckImplItem::visit): Likewise.
            * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit):  
Likewise.
            (TypeCheckItem::resolve_function_signature):  Likewise.
            (TypeCheckItem::resolve_impl_block_substitutions):  Likewise.
            * typecheck/rust-hir-type-check-type.cc 
(ResolveWhereClauseItem::Resolve): new helper
            (ResolveWhereClauseItem::visit): support defer.
            * typecheck/rust-hir-type-check-type.h: update header.
            * typecheck/rust-hir-type-check.cc 
(TraitItemReference::get_type_from_fn): call new helper
            * typecheck/rust-tyty-bounds.cc: defer flag
    
    gcc/testsuite/ChangeLog:
    
            * rust/compile/issue-4864.rs: New test.
    
    Signed-off-by: Philip Herron <[email protected]>

Diff:
---
 gcc/rust/hir/tree/rust-hir-item.h                  |  2 +
 gcc/rust/typecheck/rust-hir-type-check-base.h      |  3 +-
 gcc/rust/typecheck/rust-hir-type-check-implitem.cc | 24 ++----
 gcc/rust/typecheck/rust-hir-type-check-item.cc     | 36 +++------
 gcc/rust/typecheck/rust-hir-type-check-type.cc     | 89 +++++++++++++++++++++-
 gcc/rust/typecheck/rust-hir-type-check-type.h      |  8 +-
 gcc/rust/typecheck/rust-hir-type-check.cc          | 10 +--
 gcc/rust/typecheck/rust-tyty-bounds.cc             | 13 +++-
 gcc/testsuite/rust/compile/issue-4864.rs           | 22 ++++++
 9 files changed, 150 insertions(+), 57 deletions(-)

diff --git a/gcc/rust/hir/tree/rust-hir-item.h 
b/gcc/rust/hir/tree/rust-hir-item.h
index a956e0b530f4..9a572bf92c65 100644
--- a/gcc/rust/hir/tree/rust-hir-item.h
+++ b/gcc/rust/hir/tree/rust-hir-item.h
@@ -2559,6 +2559,8 @@ public:
     return where_clause;
   }
 
+  WARN_UNUSED_RESULT WhereClause &get_where_clause () { return where_clause; }
+
   ExternalFunctionItem (
     Analysis::NodeMapping mappings, Identifier item_name,
     std::vector<std::unique_ptr<GenericParam>> generic_params,
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.h 
b/gcc/rust/typecheck/rust-hir-type-check-base.h
index 3a9df89a5826..61e545149cf4 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-base.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-base.h
@@ -53,7 +53,8 @@ protected:
     HIR::TypePath &path,
     tl::optional<std::reference_wrapper<HIR::Type>> associated_self,
     BoundPolarity polarity = BoundPolarity::RegularBound,
-    bool is_qualified_type = false, bool is_super_trait = false);
+    bool is_qualified_type = false, bool is_super_trait = false,
+    bool defer_bindings = false);
 
   bool check_for_unconstrained (
     const std::vector<TyTy::SubstitutionParamMapping> &params_to_constrain,
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc 
b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
index 9fb0d70a3401..8c65390f781c 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
@@ -80,14 +80,8 @@ TypeCheckTopLevelExternItem::visit 
(HIR::ExternalFunctionItem &function)
     }
 
   TyTy::RegionConstraints region_constraints;
-  if (function.has_where_clause ())
-    {
-      for (auto &where_clause_item : function.get_where_clause ().get_items ())
-       {
-         ResolveWhereClauseItem::Resolve (*where_clause_item,
-                                          region_constraints);
-       }
-    }
+  ResolveWhereClauseItem::Resolve (function.get_where_clause (),
+                                  region_constraints);
 
   TyTy::BaseType *ret_type = nullptr;
   if (!function.has_return_type ())
@@ -254,11 +248,8 @@ TypeCheckImplItem::resolve_function_signature 
(HIR::Function &function)
                            function.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
-  for (auto &where_clause_item : function.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item.get (),
-                                      region_constraints);
-    }
+  ResolveWhereClauseItem::Resolve (function.get_where_clause (),
+                                  region_constraints);
 
   TyTy::BaseType *ret_type = nullptr;
   if (!function.has_function_return_type ())
@@ -510,11 +501,8 @@ TypeCheckImplItem::visit (HIR::TypeAlias &alias)
   context->insert_type (alias.get_mappings (), actual_type);
   result = actual_type;
   TyTy::RegionConstraints region_constraints;
-  for (auto &where_clause_item : alias.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item.get (),
-                                      region_constraints);
-    }
+  ResolveWhereClauseItem::Resolve (alias.get_where_clause (),
+                                  region_constraints);
 }
 
 TypeCheckImplItemWithTrait::TypeCheckImplItemWithTrait (
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc 
b/gcc/rust/typecheck/rust-hir-type-check-item.cc
index 2f2005b71bf7..4d02e3b5c52d 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc
@@ -310,10 +310,8 @@ TypeCheckItem::visit (HIR::TypeAlias &alias)
   context->insert_type (alias.get_mappings (), actual_type);
 
   TyTy::RegionConstraints region_constraints;
-  for (auto &where_clause_item : alias.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints);
-    }
+  ResolveWhereClauseItem::Resolve (alias.get_where_clause (),
+                                  region_constraints);
   infered = actual_type;
 }
 
@@ -329,10 +327,8 @@ TypeCheckItem::visit (HIR::TupleStruct &struct_decl)
                            struct_decl.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
-  for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints);
-    }
+  ResolveWhereClauseItem::Resolve (struct_decl.get_where_clause (),
+                                  region_constraints);
 
   // Process #[repr(X)] attribute, if any
   const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
@@ -410,10 +406,8 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl)
                            struct_decl.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
-  for (auto &where_clause_item : struct_decl.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints);
-    }
+  ResolveWhereClauseItem::Resolve (struct_decl.get_where_clause (),
+                                  region_constraints);
 
   // Process #[repr(X)] attribute, if any
   const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
@@ -577,10 +571,8 @@ TypeCheckItem::visit (HIR::Union &union_decl)
                            union_decl.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
-  for (auto &where_clause_item : union_decl.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints);
-    }
+  ResolveWhereClauseItem::Resolve (union_decl.get_where_clause (),
+                                  region_constraints);
 
   std::vector<TyTy::StructFieldType *> fields;
   for (auto &variant : union_decl.get_variants ())
@@ -833,10 +825,8 @@ TypeCheckItem::resolve_function_signature (HIR::Function 
&function)
                            function.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
-  for (auto &where_clause_item : function.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints);
-    }
+  ResolveWhereClauseItem::Resolve (function.get_where_clause (),
+                                  region_constraints);
 
   TyTy::BaseType *ret_type = nullptr;
   if (!function.has_function_return_type ())
@@ -1053,10 +1043,8 @@ TypeCheckItem::resolve_impl_block_substitutions 
(HIR::ImplBlock &impl_block,
                            impl_block.get_generic_params (), substitutions);
 
   TyTy::RegionConstraints region_constraints;
-  for (auto &where_clause_item : impl_block.get_where_clause ().get_items ())
-    {
-      ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints);
-    }
+  ResolveWhereClauseItem::Resolve (impl_block.get_where_clause (),
+                                  region_constraints);
 
   auto specified_bound = TyTy::TypeBoundPredicate::error ();
   TraitReference *trait_reference = &TraitReference::error_node ();
diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc 
b/gcc/rust/typecheck/rust-hir-type-check-type.cc
index 84baab6ffa76..5fe75cf487b8 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-type.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc
@@ -1023,6 +1023,64 @@ ResolveWhereClauseItem::Resolve (HIR::WhereClauseItem 
&item,
     }
 }
 
+void
+ResolveWhereClauseItem::Resolve (HIR::WhereClause &clause,
+                                TyTy::RegionConstraints &region_constraints)
+{
+  ResolveWhereClauseItem resolver (region_constraints);
+
+  class PlainTypePath : public HIR::HIRTypeVisitor
+  {
+  public:
+    bool matches = false;
+
+    void visit (HIR::TypePathSegmentFunction &segment) override {}
+    void visit (HIR::QualifiedPathInType &path) override {}
+    void visit (HIR::TraitBound &bound) override {}
+    void visit (HIR::ImplTraitType &type) override {}
+    void visit (HIR::TraitObjectType &type) override {}
+    void visit (HIR::ParenthesisedType &type) override {}
+    void visit (HIR::TupleType &type) override {}
+    void visit (HIR::NeverType &type) override {}
+    void visit (HIR::RawPointerType &type) override {}
+    void visit (HIR::ReferenceType &type) override {}
+    void visit (HIR::ArrayType &type) override {}
+    void visit (HIR::SliceType &type) override {}
+    void visit (HIR::InferredType &type) override {}
+    void visit (HIR::BareFunctionType &type) override {}
+
+    void visit (HIR::TypePath &path) override
+    {
+      bool is_single = path.get_segments ().size () == 1;
+      bool final_seg_is_reg
+       = path.get_final_segment ().get_type () == HIR::TypePathSegment::REG;
+
+      matches = is_single && final_seg_is_reg;
+    }
+  };
+
+  resolver.defer_bindings = true;
+  for (auto &item : clause.get_items ())
+    if (item->get_item_type () == HIR::WhereClauseItem::TYPE_BOUND)
+      {
+       auto &bound = static_cast<HIR::TypeBoundWhereClauseItem &> (*item);
+       PlainTypePath plain;
+       bound.get_bound_type ().accept_vis (plain);
+       if (plain.matches)
+         resolver.visit (bound);
+      }
+
+  resolver.defer_bindings = false;
+  resolver.complete_bindings = true;
+  for (auto &item : clause.get_items ())
+    {
+      if (item->get_item_type () == HIR::WhereClauseItem::TYPE_BOUND)
+       resolver.visit (static_cast<HIR::TypeBoundWhereClauseItem &> (*item));
+      else
+       Resolve (*item, region_constraints);
+    }
+}
+
 void
 ResolveWhereClauseItem::visit (HIR::LifetimeWhereClauseItem &item)
 {
@@ -1060,6 +1118,9 @@ ResolveWhereClauseItem::visit 
(HIR::TypeBoundWhereClauseItem &item)
     = TypeCheckType::Resolve (binding_type_path,
                              TypeCheckType::ResolutionMode::CANONICAL);
 
+  if (defer_bindings && binding->get_kind () != TyTy::TypeKind::PARAM)
+    return;
+
   // FIXME double check there might be a trait cycle here see TypeParam 
handling
 
   std::vector<TyTy::TypeBoundPredicate> specified_bounds;
@@ -1072,13 +1133,17 @@ ResolveWhereClauseItem::visit 
(HIR::TypeBoundWhereClauseItem &item)
            auto *b = static_cast<HIR::TraitBound *> (bound.get ());
 
            TyTy::TypeBoundPredicate predicate
-             = get_predicate_from_bound (b->get_path (), binding_type_path);
+             = get_predicate_from_bound (b->get_path (), binding_type_path,
+                                         BoundPolarity::RegularBound, false,
+                                         false, defer_bindings);
            if (!predicate.is_error ())
              specified_bounds.push_back (std::move (predicate));
          }
          break;
        case HIR::TypeParamBound::BoundType::LIFETIME:
          {
+           if (defer_bindings)
+             break;
            if (auto param = binding->try_as<TyTy::ParamType> ())
              {
                auto *b = static_cast<HIR::Lifetime *> (bound.get ());
@@ -1098,7 +1163,27 @@ ResolveWhereClauseItem::visit 
(HIR::TypeBoundWhereClauseItem &item)
          break;
        }
     }
-  binding->inherit_bounds (specified_bounds);
+
+  for (const auto &predicate : specified_bounds)
+    {
+      bool replaced = false;
+      if (complete_bindings)
+       {
+         for (auto &bound : binding->get_specified_bounds ())
+           {
+             if (bound.get_id () == predicate.get_id ()
+                 && bound.get_locus () == predicate.get_locus ())
+               {
+                 bound = predicate;
+                 replaced = true;
+                 break;
+               }
+           }
+       }
+
+      if (!replaced)
+       binding->inherit_bound (predicate);
+    }
 }
 
 } // namespace Resolver
diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h 
b/gcc/rust/typecheck/rust-hir-type-check-type.h
index 9cc0fdbc3e97..ee1d0c97d971 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-type.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-type.h
@@ -132,7 +132,7 @@ class ResolveWhereClauseItem : public TypeCheckBase
   TyTy::RegionConstraints &region_constraints;
 
 public:
-  static void Resolve (HIR::WhereClauseItem &item,
+  static void Resolve (HIR::WhereClause &clause,
                       TyTy::RegionConstraints &region_constraints);
 
 protected:
@@ -140,6 +140,12 @@ protected:
   void visit (HIR::TypeBoundWhereClauseItem &item);
 
 private:
+  static void Resolve (HIR::WhereClauseItem &item,
+                      TyTy::RegionConstraints &region_constraints);
+
+  bool defer_bindings = false;
+  bool complete_bindings = false;
+
   ResolveWhereClauseItem (TyTy::RegionConstraints &region_constraints)
     : region_constraints (region_constraints)
   {}
diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc 
b/gcc/rust/typecheck/rust-hir-type-check.cc
index d111207b7294..d4c21d09ca84 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check.cc
@@ -169,7 +169,6 @@ TraitItemReference::get_type_from_fn (/*const*/ 
HIR::TraitItemFunc &fn) const
   std::vector<TyTy::SubstitutionParamMapping> substitutions
     = inherited_substitutions;
 
-  TyTy::RegionConstraints region_constraints;
   HIR::TraitFunctionDecl &function = fn.get_decl ();
   if (function.has_generics ())
     {
@@ -180,12 +179,9 @@ TraitItemReference::get_type_from_fn (/*const*/ 
HIR::TraitItemFunc &fn) const
                                           ABI::RUST);
     }
 
-  if (function.has_where_clause ())
-    {
-      for (auto &where_clause_item : function.get_where_clause ().get_items ())
-       ResolveWhereClauseItem::Resolve (*where_clause_item,
-                                        region_constraints);
-    }
+  TyTy::RegionConstraints region_constraints;
+  ResolveWhereClauseItem::Resolve (function.get_where_clause (),
+                                  region_constraints);
 
   TyTy::BaseType *ret_type = nullptr;
   if (!function.has_return_type ())
diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc 
b/gcc/rust/typecheck/rust-tyty-bounds.cc
index 0240a635ca71..bb2c5ed14f15 100644
--- a/gcc/rust/typecheck/rust-tyty-bounds.cc
+++ b/gcc/rust/typecheck/rust-tyty-bounds.cc
@@ -261,7 +261,8 @@ TyTy::TypeBoundPredicate
 TypeCheckBase::get_predicate_from_bound (
   HIR::TypePath &type_path,
   tl::optional<std::reference_wrapper<HIR::Type>> associated_self,
-  BoundPolarity polarity, bool is_qualified_type_path, bool is_super_trait)
+  BoundPolarity polarity, bool is_qualified_type_path, bool is_super_trait,
+  bool defer_bindings)
 {
   TyTy::TypeBoundPredicate lookup = TyTy::TypeBoundPredicate::error ();
   bool already_resolved
@@ -340,7 +341,7 @@ TypeCheckBase::get_predicate_from_bound (
 
        std::vector<HIR::GenericArgsBinding> bindings;
 
-       if (fn.has_return_type ())
+       if (fn.has_return_type () && !defer_bindings)
          {
            TypeCheckType::Resolve (fn.get_return_type ());
 
@@ -377,6 +378,9 @@ TypeCheckBase::get_predicate_from_bound (
                               args.get_locus ());
     }
 
+  if (defer_bindings)
+    args.get_binding_args ().clear ();
+
   // we try to apply generic arguments when they are non empty and or when the
   // predicate requires them so that we get the relevant Foo expects x number
   // arguments but got zero see test case rust/compile/traits12.rs
@@ -387,8 +391,9 @@ TypeCheckBase::get_predicate_from_bound (
                                         is_super_trait);
     }
 
-  context->insert_resolved_predicate (type_path.get_mappings ().get_hirid (),
-                                     predicate);
+  if (!defer_bindings)
+    context->insert_resolved_predicate (type_path.get_mappings ().get_hirid (),
+                                       predicate);
 
   return predicate;
 }
diff --git a/gcc/testsuite/rust/compile/issue-4864.rs 
b/gcc/testsuite/rust/compile/issue-4864.rs
new file mode 100644
index 000000000000..c05000a3cadd
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-4864.rs
@@ -0,0 +1,22 @@
+#![feature(no_core, lang_items)]
+#![no_core]
+#[lang = "sized"]
+pub trait Sized {}
+trait Iterator {
+    type Item;
+}
+trait IntoIterator {
+    type Item;
+    type IntoIter: Iterator<Item = Self::Item>;
+}
+pub struct Flatten<I, U> {
+    pub inner: I,
+    pub extra: U,
+}
+impl<I, U> Iterator for Flatten<I, U>
+where
+    I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>,
+    U: Iterator,
+{
+    type Item = U::Item;
+}

Reply via email to