From: Philip Herron <[email protected]>

The parser only recognized Foo<Bar = T> for the generic type bindings
syntax. This parses both flavours now into update generic args type.

Fixes Rust-GCC/gccrs#1726

gcc/rust/ChangeLog:

        * ast/rust-path.cc (GenericArgsBinding::as_string): new format
        * ast/rust-path.h (struct GenericArgsBinding): new kinds for bindings
        * hir/rust-ast-lower-base.cc (ASTLoweringBase::lower_binding): new
        * hir/tree/rust-hir-path.cc (GenericArgsBinding::GenericArgsBinding): 
likewise
        (GenericArgsBinding::operator=): likewise
        * hir/tree/rust-hir-path.h (class GenericArgsBinding): likewise
        * hir/tree/rust-hir.cc (GenericArgsBinding::to_string): likewise
        * parse/rust-parse-impl.hxx: peek for both types
        * typecheck/rust-type-util.cc (normalize_projection): track constrains
        * typecheck/rust-tyty-bounds.cc 
(TypeBoundPredicate::TypeBoundPredicate): new ctor
        (TypeBoundPredicate::operator=): likewise
        * typecheck/rust-tyty-subst.cc 
(SubstitutionArgumentMappings::get_constraint_args): new
        * typecheck/rust-tyty-subst.h: new
        * typecheck/rust-unify.cc (UnifyRules::expect_projection): fix loop

gcc/testsuite/ChangeLog:

        * rust/compile/associated-type-bound.rs: New test.
        * rust/compile/issue-1726-1.rs: New test.
        * rust/compile/issue-1726-2.rs: New test.

Signed-off-by: Philip Herron <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/f3d78219fefeb918ca3f11e56e77c3deff119cb8

The commit has been mentioned in the following issue(s):
 - Rust-GCC/gccrs#1726: https://github.com/Rust-GCC/gccrs/issues/1726

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4843

 gcc/rust/ast/rust-path.cc                     |  5 +-
 gcc/rust/ast/rust-path.h                      | 20 ++++++--
 gcc/rust/hir/rust-ast-lower-base.cc           | 13 ++++-
 gcc/rust/hir/tree/rust-hir-path.cc            |  8 +--
 gcc/rust/hir/tree/rust-hir-path.h             | 13 ++++-
 gcc/rust/hir/tree/rust-hir.cc                 |  4 +-
 gcc/rust/parse/rust-parse-impl.hxx            | 18 +++++--
 gcc/rust/typecheck/rust-type-util.cc          | 18 +++++++
 gcc/rust/typecheck/rust-tyty-bounds.cc        | 18 +++----
 gcc/rust/typecheck/rust-tyty-subst.cc         | 49 ++++++++++++------
 gcc/rust/typecheck/rust-tyty-subst.h          | 15 +++---
 gcc/rust/typecheck/rust-unify.cc              |  6 +++
 .../rust/compile/associated-type-bound.rs     | 50 +++++++++++++++++++
 gcc/testsuite/rust/compile/issue-1726-1.rs    | 17 +++++++
 gcc/testsuite/rust/compile/issue-1726-2.rs    | 42 ++++++++++++++++
 15 files changed, 248 insertions(+), 48 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/associated-type-bound.rs
 create mode 100644 gcc/testsuite/rust/compile/issue-1726-1.rs
 create mode 100644 gcc/testsuite/rust/compile/issue-1726-2.rs

diff --git a/gcc/rust/ast/rust-path.cc b/gcc/rust/ast/rust-path.cc
index 5260adc8a..e8b885cbc 100644
--- a/gcc/rust/ast/rust-path.cc
+++ b/gcc/rust/ast/rust-path.cc
@@ -108,8 +108,9 @@ GenericArg::disambiguate_to_type () const
 std::string
 GenericArgsBinding::as_string () const
 {
-  // TODO: rewrite to work with non-literalisable types
-  return identifier.as_string () + " = " + type->as_string ();
+  auto type_string = type->as_string ();
+  auto separator = kind == Kind::Constraint ? " : " : " = ";
+  return identifier.as_string () + separator + type_string;
 }
 
 std::string
diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h
index 3ce7ed7ef..ecb156e90 100644
--- a/gcc/rust/ast/rust-path.h
+++ b/gcc/rust/ast/rust-path.h
@@ -71,10 +71,18 @@ public:
 // A binding of an identifier to a type used in generic arguments in paths
 struct GenericArgsBinding
 {
+public:
+  enum class Kind
+  {
+    Equality,
+    Constraint
+  };
+
 private:
   Identifier identifier;
   std::unique_ptr<Type> type;
   location_t locus;
+  Kind kind;
 
 public:
   // Returns whether binding is in an error state.
@@ -90,7 +98,7 @@ public:
     if (type)
       new_type = type->reconstruct ();
 
-    return GenericArgsBinding (identifier, std::move (new_type), locus);
+    return GenericArgsBinding (identifier, std::move (new_type), locus, kind);
   }
 
   // Creates an error state generic args binding.
@@ -101,13 +109,15 @@ public:
 
   // Pointer type for type in constructor to enable polymorphism
   GenericArgsBinding (Identifier ident, std::unique_ptr<Type> type_ptr,
-                     location_t locus = UNDEF_LOCATION)
-    : identifier (std::move (ident)), type (std::move (type_ptr)), locus 
(locus)
+                     location_t locus = UNDEF_LOCATION,
+                     Kind kind = Kind::Equality)
+    : identifier (std::move (ident)), type (std::move (type_ptr)),
+      locus (locus), kind (kind)
   {}
 
   // Copy constructor has to deep copy the type as it is a unique pointer
   GenericArgsBinding (GenericArgsBinding const &other)
-    : identifier (other.identifier), locus (other.locus)
+    : identifier (other.identifier), locus (other.locus), kind (other.kind)
   {
     // guard to protect from null pointer dereference
     if (other.type != nullptr)
@@ -122,6 +132,7 @@ public:
   {
     identifier = other.identifier;
     locus = other.locus;
+    kind = other.kind;
 
     // guard to protect from null pointer dereference
     if (other.type != nullptr)
@@ -154,6 +165,7 @@ public:
   location_t get_locus () const { return locus; }
 
   Identifier get_identifier () const { return identifier; }
+  Kind get_kind () const { return kind; }
 };
 
 /* Class representing a const generic application */
diff --git a/gcc/rust/hir/rust-ast-lower-base.cc 
b/gcc/rust/hir/rust-ast-lower-base.cc
index a4ab5d5ed..33b1c2f51 100644
--- a/gcc/rust/hir/rust-ast-lower-base.cc
+++ b/gcc/rust/hir/rust-ast-lower-base.cc
@@ -651,10 +651,19 @@ ASTLoweringBase::lower_path_expr_seg 
(AST::PathExprSegment &s)
 HIR::GenericArgsBinding
 ASTLoweringBase::lower_binding (AST::GenericArgsBinding &binding)
 {
-  HIR::Type *lowered_type = ASTLoweringType::translate (binding.get_type ());
+  auto impl_trait_allowed
+    = binding.get_kind () == AST::GenericArgsBinding::Kind::Constraint
+       ? ASTLoweringType::ImplTrait::Allow
+       : ASTLoweringType::ImplTrait::Forbid;
+  HIR::Type *lowered_type
+    = ASTLoweringType::translate (binding.get_type (), false,
+                                 impl_trait_allowed);
+  auto kind = binding.get_kind () == AST::GenericArgsBinding::Kind::Constraint
+               ? HIR::GenericArgsBinding::Kind::Constraint
+               : HIR::GenericArgsBinding::Kind::Equality;
   return HIR::GenericArgsBinding (binding.get_identifier (),
                                  std::unique_ptr<HIR::Type> (lowered_type),
-                                 binding.get_locus ());
+                                 binding.get_locus (), kind);
 }
 
 HIR::GenericArgs
diff --git a/gcc/rust/hir/tree/rust-hir-path.cc 
b/gcc/rust/hir/tree/rust-hir-path.cc
index b887d0e07..1c1117f93 100644
--- a/gcc/rust/hir/tree/rust-hir-path.cc
+++ b/gcc/rust/hir/tree/rust-hir-path.cc
@@ -25,13 +25,14 @@ namespace HIR {
 
 GenericArgsBinding::GenericArgsBinding (Identifier ident,
                                        std::unique_ptr<Type> type_ptr,
-                                       location_t locus)
-  : identifier (std::move (ident)), type (std::move (type_ptr)), locus (locus)
+                                       location_t locus, Kind kind)
+  : identifier (std::move (ident)), type (std::move (type_ptr)), locus (locus),
+    kind (kind)
 {}
 
 GenericArgsBinding::GenericArgsBinding (GenericArgsBinding const &other)
   : identifier (other.identifier), type (other.type->clone_type ()),
-    locus (other.locus)
+    locus (other.locus), kind (other.kind)
 {}
 
 GenericArgsBinding &
@@ -40,6 +41,7 @@ GenericArgsBinding::operator= (GenericArgsBinding const 
&other)
   identifier = other.identifier;
   type = other.type->clone_type ();
   locus = other.locus;
+  kind = other.kind;
   return *this;
 }
 
diff --git a/gcc/rust/hir/tree/rust-hir-path.h 
b/gcc/rust/hir/tree/rust-hir-path.h
index c6b3cbfab..b9de6b90b 100644
--- a/gcc/rust/hir/tree/rust-hir-path.h
+++ b/gcc/rust/hir/tree/rust-hir-path.h
@@ -63,10 +63,19 @@ public:
 // A binding of an identifier to a type used in generic arguments in paths
 class GenericArgsBinding
 {
+public:
+  enum class Kind
+  {
+    Equality,
+    Constraint
+  };
+
+private:
   Identifier identifier;
   std::unique_ptr<Type> type;
 
   location_t locus;
+  Kind kind;
 
 public:
   // Returns whether binding is in an error state.
@@ -84,7 +93,8 @@ public:
 
   // Pointer type for type in constructor to enable polymorphism
   GenericArgsBinding (Identifier ident, std::unique_ptr<Type> type_ptr,
-                     location_t locus = UNDEF_LOCATION);
+                     location_t locus = UNDEF_LOCATION,
+                     Kind kind = Kind::Equality);
 
   // Copy constructor has to deep copy the type as it is a unique pointer
   GenericArgsBinding (GenericArgsBinding const &other);
@@ -116,6 +126,7 @@ public:
   }
 
   location_t get_locus () const { return locus; }
+  Kind get_kind () const { return kind; }
 };
 
 class ConstGenericArg
diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc
index 7d611ed5c..00db9fc64 100644
--- a/gcc/rust/hir/tree/rust-hir.cc
+++ b/gcc/rust/hir/tree/rust-hir.cc
@@ -2387,7 +2387,9 @@ GenericArgs::to_string () const
 std::string
 GenericArgsBinding::to_string () const
 {
-  return identifier.as_string () + " = " + type->to_string ();
+  auto type_string = type->to_string ();
+  auto separator = kind == Kind::Constraint ? " : " : " = ";
+  return identifier.as_string () + separator + type_string;
 }
 
 std::string
diff --git a/gcc/rust/parse/rust-parse-impl.hxx 
b/gcc/rust/parse/rust-parse-impl.hxx
index b5f417685..652f128c6 100644
--- a/gcc/rust/parse/rust-parse-impl.hxx
+++ b/gcc/rust/parse/rust-parse-impl.hxx
@@ -5247,7 +5247,8 @@ Parser<ManagedTokenSource>::parse_path_generic_args ()
 
       // ensure not binding being parsed as type accidently
       if (t->get_id () == IDENTIFIER
-         && lexer.peek_token (1)->get_id () == EQUAL)
+         && (lexer.peek_token (1)->get_id () == EQUAL
+             || lexer.peek_token (1)->get_id () == COLON))
        break;
 
       auto arg = parse_generic_arg ();
@@ -5324,12 +5325,21 @@ Parser<ManagedTokenSource>::parse_generic_args_binding 
()
   lexer.skip_token ();
   Identifier ident{ident_tok};
 
-  if (!skip_token (EQUAL))
+  if (lexer.peek_token ()->get_id () == COLON)
     {
-      // skip after somewhere?
-      return AST::GenericArgsBinding::create_error ();
+      lexer.skip_token ();
+      auto bounds_locus = lexer.peek_token ()->get_locus ();
+      auto bounds = parse_type_param_bounds ();
+      auto type = std::unique_ptr<AST::Type> (
+       new AST::ImplTraitType (std::move (bounds), bounds_locus));
+      return AST::GenericArgsBinding (
+       std::move (ident), std::move (type), ident_tok->get_locus (),
+       AST::GenericArgsBinding::Kind::Constraint);
     }
 
+  if (!skip_token (EQUAL))
+    return AST::GenericArgsBinding::create_error ();
+
   // parse type (required)
   std::unique_ptr<AST::Type> type = parse_type ();
   if (type == nullptr)
diff --git a/gcc/rust/typecheck/rust-type-util.cc 
b/gcc/rust/typecheck/rust-type-util.cc
index 21559cb2a..005defb50 100644
--- a/gcc/rust/typecheck/rust-type-util.cc
+++ b/gcc/rust/typecheck/rust-type-util.cc
@@ -679,6 +679,24 @@ normalize_projection (TyTy::ProjectionType *proj, 
location_t locus,
              auto it = binding.find (assoc_name);
              if (it != binding.end ())
                return it->second;
+
+             const auto &constraints
+               = bound.get_substitution_arguments ().get_constraint_args ();
+             auto constraint = constraints.find (assoc_name);
+             if (constraint != constraints.end ())
+               {
+                 TyTy::BaseType *constrained = proj->clone ();
+                 constrained->inherit_bounds (*constraint->second);
+
+                 // Keep the constrained projection distinct from the canonical
+                 // associated-type declaration.
+                 auto &mappings = Analysis::Mappings::get ();
+                 HirId fresh = mappings.get_next_hir_id ();
+                 constrained->set_ref (fresh);
+                 constrained->set_ty_ref (fresh);
+                 ctx->insert_implicit_type (fresh, constrained);
+                 return constrained;
+               }
            }
        }
 
diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc 
b/gcc/rust/typecheck/rust-tyty-bounds.cc
index fca42d61a..5a1e02fe8 100644
--- a/gcc/rust/typecheck/rust-tyty-bounds.cc
+++ b/gcc/rust/typecheck/rust-tyty-bounds.cc
@@ -469,11 +469,10 @@ TypeBoundPredicate::TypeBoundPredicate (const 
TypeBoundPredicate &other)
       copied_arg_mappings.push_back (std::move (c));
     }
 
-  used_arguments
-    = SubstitutionArgumentMappings (copied_arg_mappings,
-                                   other.used_arguments.get_binding_args (),
-                                   other.used_arguments.get_regions (),
-                                   other.used_arguments.get_locus ());
+  used_arguments = SubstitutionArgumentMappings (
+    copied_arg_mappings, other.used_arguments.get_binding_args (),
+    other.used_arguments.get_regions (), other.used_arguments.get_locus (),
+    nullptr, false, false, other.used_arguments.get_constraint_args ());
 }
 
 TypeBoundPredicate &
@@ -511,11 +510,10 @@ TypeBoundPredicate::operator= (const TypeBoundPredicate 
&other)
       copied_arg_mappings.emplace_back (&substitutions.at (i++), argument);
     }
 
-  used_arguments
-    = SubstitutionArgumentMappings (copied_arg_mappings,
-                                   other.used_arguments.get_binding_args (),
-                                   other.used_arguments.get_regions (),
-                                   other.used_arguments.get_locus ());
+  used_arguments = SubstitutionArgumentMappings (
+    copied_arg_mappings, other.used_arguments.get_binding_args (),
+    other.used_arguments.get_regions (), other.used_arguments.get_locus (),
+    nullptr, false, false, other.used_arguments.get_constraint_args ());
   super_traits = other.super_traits;
 
   return *this;
diff --git a/gcc/rust/typecheck/rust-tyty-subst.cc 
b/gcc/rust/typecheck/rust-tyty-subst.cc
index 46e22288c..bed285eee 100644
--- a/gcc/rust/typecheck/rust-tyty-subst.cc
+++ b/gcc/rust/typecheck/rust-tyty-subst.cc
@@ -336,16 +336,18 @@ 
SubstitutionArgumentMappings::SubstitutionArgumentMappings (
   std::vector<SubstitutionArg> mappings,
   std::map<std::string, BaseType *> binding_args, RegionParamList regions,
   location_t locus, ParamSubstCb param_subst_cb, bool trait_item_flag,
-  bool error_flag)
+  bool error_flag, std::map<std::string, BaseType *> constraint_args)
   : mappings (std::move (mappings)), binding_args (binding_args),
-    regions (regions), locus (locus), param_subst_cb (param_subst_cb),
-    trait_item_flag (trait_item_flag), error_flag (error_flag)
+    constraint_args (constraint_args), regions (regions), locus (locus),
+    param_subst_cb (param_subst_cb), trait_item_flag (trait_item_flag),
+    error_flag (error_flag)
 {}
 
 SubstitutionArgumentMappings::SubstitutionArgumentMappings (
   const SubstitutionArgumentMappings &other)
   : mappings (other.mappings), binding_args (other.binding_args),
-    regions (other.regions), locus (other.locus), param_subst_cb (nullptr),
+    constraint_args (other.constraint_args), regions (other.regions),
+    locus (other.locus), param_subst_cb (nullptr),
     trait_item_flag (other.trait_item_flag), error_flag (other.error_flag)
 {}
 
@@ -355,6 +357,7 @@ SubstitutionArgumentMappings::operator= (
 {
   mappings = other.mappings;
   binding_args = other.binding_args;
+  constraint_args = other.constraint_args;
   regions = other.regions;
   locus = other.locus;
   param_subst_cb = nullptr;
@@ -476,6 +479,12 @@ SubstitutionArgumentMappings::get_binding_args () const
   return binding_args;
 }
 
+const std::map<std::string, BaseType *> &
+SubstitutionArgumentMappings::get_constraint_args () const
+{
+  return constraint_args;
+}
+
 std::string
 SubstitutionArgumentMappings::as_string () const
 {
@@ -685,6 +694,7 @@ SubstitutionRef::get_mappings_from_generic_args (
   HIR::GenericArgs &args, const std::vector<Region> &regions)
 {
   std::map<std::string, BaseType *> binding_arguments;
+  std::map<std::string, BaseType *> constraint_arguments;
   if (args.get_binding_args ().size () > 0)
     {
       if (supports_associated_bindings ())
@@ -721,8 +731,13 @@ SubstitutionRef::get_mappings_from_generic_args (
                  return SubstitutionArgumentMappings::error ();
                }
 
-             binding_arguments[binding.get_identifier ().as_string ()]
-               = resolved;
+             if (binding.get_kind ()
+                 == HIR::GenericArgsBinding::Kind::Constraint)
+               constraint_arguments[binding.get_identifier ().as_string ()]
+                 = resolved;
+             else
+               binding_arguments[binding.get_identifier ().as_string ()]
+                 = resolved;
            }
        }
       else
@@ -945,10 +960,15 @@ SubstitutionRef::get_mappings_from_generic_args (
        }
     }
 
-  return {mappings, binding_arguments,
+  return {mappings,
+         binding_arguments,
          RegionParamList::from_subst (used_arguments.get_regions ().size (),
                                       regions),
-         args.get_locus ()};
+         args.get_locus (),
+         nullptr,
+         false,
+         false,
+         constraint_arguments};
 }
 
 BaseType *
@@ -1036,12 +1056,10 @@ SubstitutionRef::adjust_mappings_for_this (
   if (resolved_mappings.empty ())
     return SubstitutionArgumentMappings::error ();
 
-  return SubstitutionArgumentMappings (resolved_mappings,
-                                      mappings.get_binding_args (),
-                                      mappings.get_regions (),
-                                      mappings.get_locus (),
-                                      mappings.get_subst_cb (),
-                                      mappings.trait_item_mode ());
+  return SubstitutionArgumentMappings (
+    resolved_mappings, mappings.get_binding_args (), mappings.get_regions (),
+    mappings.get_locus (), mappings.get_subst_cb (),
+    mappings.trait_item_mode (), false, mappings.get_constraint_args ());
 }
 
 bool
@@ -1101,7 +1119,8 @@ SubstitutionRef::solve_mappings_from_receiver_for_self (
   return SubstitutionArgumentMappings (resolved_mappings,
                                       mappings.get_binding_args (),
                                       mappings.get_regions (),
-                                      mappings.get_locus ());
+                                      mappings.get_locus (), nullptr, false,
+                                      false, mappings.get_constraint_args ());
 }
 
 bool
diff --git a/gcc/rust/typecheck/rust-tyty-subst.h 
b/gcc/rust/typecheck/rust-tyty-subst.h
index 8a71f8907..947488afb 100644
--- a/gcc/rust/typecheck/rust-tyty-subst.h
+++ b/gcc/rust/typecheck/rust-tyty-subst.h
@@ -175,12 +175,12 @@ typedef std::function<void (const ParamType &, const 
SubstitutionArg &)>
 class SubstitutionArgumentMappings
 {
 public:
-  SubstitutionArgumentMappings (std::vector<SubstitutionArg> mappings,
-                               std::map<std::string, BaseType *> binding_args,
-                               RegionParamList regions, location_t locus,
-                               ParamSubstCb param_subst_cb = nullptr,
-                               bool trait_item_flag = false,
-                               bool error_flag = false);
+  SubstitutionArgumentMappings (
+    std::vector<SubstitutionArg> mappings,
+    std::map<std::string, BaseType *> binding_args, RegionParamList regions,
+    location_t locus, ParamSubstCb param_subst_cb = nullptr,
+    bool trait_item_flag = false, bool error_flag = false,
+    std::map<std::string, BaseType *> constraint_args = {});
 
   SubstitutionArgumentMappings (const SubstitutionArgumentMappings &other);
   SubstitutionArgumentMappings &
@@ -233,6 +233,8 @@ public:
 
   const std::map<std::string, BaseType *> &get_binding_args () const;
 
+  const std::map<std::string, BaseType *> &get_constraint_args () const;
+
   const RegionParamList &get_regions () const;
   RegionParamList &get_mut_regions ();
 
@@ -247,6 +249,7 @@ public:
 private:
   std::vector<SubstitutionArg> mappings;
   std::map<std::string, BaseType *> binding_args;
+  std::map<std::string, BaseType *> constraint_args;
   RegionParamList regions;
   location_t locus;
   ParamSubstCb param_subst_cb;
diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc
index 32aebff52..e6a863a5b 100644
--- a/gcc/rust/typecheck/rust-unify.cc
+++ b/gcc/rust/typecheck/rust-unify.cc
@@ -1989,6 +1989,12 @@ UnifyRules::expect_projection (TyTy::ProjectionType 
*ltype,
       {
        if (ltype->is_trait_position ())
          {
+           // A trait-position projection whose Self is still generic cannot be
+           // normalized against a concrete impl candidate.
+           auto dself = ltype->get_self ()->destructure ();
+           if (dself->is<TyTy::ParamType> ())
+             return ltype;
+
            TyTy::BaseType *ln
              = normalize_projection (ltype, locus, false, false);
            if (ln != nullptr && ln != ltype)
diff --git a/gcc/testsuite/rust/compile/associated-type-bound.rs 
b/gcc/testsuite/rust/compile/associated-type-bound.rs
new file mode 100644
index 000000000..43cc57533
--- /dev/null
+++ b/gcc/testsuite/rust/compile/associated-type-bound.rs
@@ -0,0 +1,50 @@
+#![feature(lang_items, no_core)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+pub trait Iterator {
+    type Item;
+}
+
+pub trait IntoIterator {
+    type IntoIter;
+}
+
+pub struct FlattenCompat<I, U>(I, U);
+
+pub struct Flatten<I: Iterator<Item: IntoIterator>> {
+    pub inner: FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>,
+}
+
+pub trait Foo {
+    type Bar;
+
+    fn foo(&self);
+}
+
+pub trait Copy {}
+
+pub trait Container<T> {
+    type Item;
+}
+
+pub fn c<F: Foo<Bar: Foo>>(value: &F::Bar)
+where
+    F::Bar: Copy,
+{
+    value.foo();
+}
+
+pub fn nested<F: Foo<Bar: Foo>>() {
+    let _: *const <F::Bar as Foo>::Bar;
+}
+
+pub fn multiple_bounds<F: Foo<Bar: Foo + Copy>>() {
+    let _: *const <F::Bar as Foo>::Bar;
+}
+
+pub fn positional_and_bound<T, C: Container<T, Item: Foo>>() {
+    let _: *const <C::Item as Foo>::Bar;
+}
diff --git a/gcc/testsuite/rust/compile/issue-1726-1.rs 
b/gcc/testsuite/rust/compile/issue-1726-1.rs
new file mode 100644
index 000000000..0e78fff3c
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-1726-1.rs
@@ -0,0 +1,17 @@
+#![feature(lang_items, no_core)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+pub trait Foo {
+    type Bar;
+}
+
+pub trait Copy {}
+
+pub fn c<F: Foo<Bar: Foo>>()
+where
+    F::Bar: Copy,
+{
+}
diff --git a/gcc/testsuite/rust/compile/issue-1726-2.rs 
b/gcc/testsuite/rust/compile/issue-1726-2.rs
new file mode 100644
index 000000000..4808b5709
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-1726-2.rs
@@ -0,0 +1,42 @@
+#![feature(lang_items, no_core)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+pub trait Foo {
+    type Bar;
+
+    fn foo(&self);
+}
+
+pub trait Copy {}
+
+pub fn c<F: Foo<Bar: Foo>>(value: &F::Bar)
+where
+    F::Bar: Copy,
+{
+    value.foo();
+}
+
+pub struct Outer;
+pub struct Inner;
+
+impl Foo for Outer {
+    type Bar = Inner;
+
+    fn foo(&self) {}
+}
+
+impl Foo for Inner {
+    type Bar = Inner;
+
+    fn foo(&self) {}
+}
+
+impl Copy for Inner {}
+
+pub fn main() {
+    let inner = Inner;
+    c::<Outer>(&inner);
+}

base-commit: 2c764560d7c41f9aef6d69eb25777622d583eea1
-- 
2.55.0

Reply via email to