https://gcc.gnu.org/g:927d067721e91ad3d702f9b9efaf939afd319ef1

commit 927d067721e91ad3d702f9b9efaf939afd319ef1
Author: Philip Herron <herron.phi...@googlemail.com>
Date:   Wed Apr 30 14:37:49 2025 +0100

    gccrs: desugar APIT impl traits
    
    Argument position impl traits are simply syntatic sugar for generics. This
    adds a new desugar pass to do this. So for example:
    
        fn foo(a: impl Value, b: impl Value) -> i32
    
    Is desugared into:
    
        fn foo<T: Value, U: Value> (a: T, b: U) -> i32
    
    So it just works like any normal generic function. There are more complex 
cases such as:
    
        fn foo(_value: impl Bar<Baz = impl Foo>) -> i32
    
    Which has a generic argument binding which needs to be turned into a where 
constraint:
    
        fn foo<T, U>(_value: T) -> i32
            where
                T: Bar<Baz = U>,
                U: Foo,
    
    Fixes Rust-GCC#2015
    Fixes Rust-GCC#1487
    Fixes Rust-GCC#3454
    Fixes Rust-GCC#1482
    
    gcc/rust/ChangeLog:
    
            * Make-lang.in: new desugar file
            * ast/rust-ast.cc (ImplTraitTypeOneBound::as_string): its a 
unique_ptr now
            (FormatArgs::set_outer_attrs): reformat
            * ast/rust-path.h: remove has_generic_args assertion (can be empty 
because of desugar)
            * ast/rust-type.h (class ImplTraitTypeOneBound): add copy ctor and 
use unique_ptr
            * hir/rust-ast-lower-type.cc (ASTLoweringType::visit): update to 
use unique_ptr
            * parse/rust-parse-impl.h (Parser::parse_type): reuse the existing 
unique_ptr instead
            (Parser::parse_type_no_bounds): likewise
            (Parser::parse_pattern): likewise
            * resolve/rust-ast-resolve-type.cc (ResolveType::visit): its a 
unique_ptr now
            * rust-session-manager.cc (Session::compile_crate): call desugar
            * ast/rust-desugar-apit.cc: New file.
            * ast/rust-desugar-apit.h: New file.
    
    gcc/testsuite/ChangeLog:
    
            * rust/compile/issue-2015.rs: fully supported now
            * rust/compile/nr2/exclude: nr2 cant handle some of these
            * rust/compile/issue-1487.rs: New test.
            * rust/compile/issue-3454.rs: New test.
            * rust/execute/torture/impl_desugar-2.rs: New test.
            * rust/execute/torture/impl_desugar.rs: New test.
            * rust/execute/torture/impl_trait1.rs: New test.
            * rust/execute/torture/impl_trait2.rs: New test.
            * rust/execute/torture/impl_trait3.rs: New test.
            * rust/execute/torture/impl_trait4.rs: New test.
            * rust/execute/torture/issue-1482.rs: New test.
    
    Signed-off-by: Philip Herron <herron.phi...@googlemail.com>

Diff:
---
 gcc/rust/Make-lang.in                              |   1 +
 gcc/rust/ast/rust-ast.cc                           |   2 +-
 gcc/rust/ast/rust-desugar-apit.cc                  | 516 +++++++++++++++++++++
 gcc/rust/ast/rust-desugar-apit.h                   |  42 ++
 gcc/rust/ast/rust-path.h                           |   6 +-
 gcc/rust/ast/rust-type.h                           |  47 +-
 gcc/rust/hir/rust-ast-lower-type.cc                |   2 +-
 gcc/rust/parse/rust-parse-impl.h                   |  13 +-
 gcc/rust/resolve/rust-ast-resolve-type.cc          |   2 +-
 gcc/rust/rust-session-manager.cc                   |   2 +
 gcc/testsuite/rust/compile/issue-1487.rs           |  15 +
 gcc/testsuite/rust/compile/issue-2015.rs           |   3 +-
 gcc/testsuite/rust/compile/issue-3454.rs           |  20 +
 gcc/testsuite/rust/compile/nr2/exclude             |   3 +
 .../rust/execute/torture/impl_desugar-2.rs         |  32 ++
 gcc/testsuite/rust/execute/torture/impl_desugar.rs |  32 ++
 gcc/testsuite/rust/execute/torture/impl_trait1.rs  |  31 ++
 gcc/testsuite/rust/execute/torture/impl_trait2.rs  |  31 ++
 gcc/testsuite/rust/execute/torture/impl_trait3.rs  |  46 ++
 gcc/testsuite/rust/execute/torture/impl_trait4.rs  |  31 ++
 gcc/testsuite/rust/execute/torture/issue-1482.rs   |  23 +
 21 files changed, 866 insertions(+), 34 deletions(-)

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 5ae50d23f8f7..38235f188e64 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -242,6 +242,7 @@ GRS_OBJS = \
        rust/rust-collect-lang-items.o \
        rust/rust-desugar-for-loops.o \
        rust/rust-desugar-question-mark.o \
+       rust/rust-desugar-apit.o \
     $(END)
 # removed object files from here
 
diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc
index 494b21a1ba56..0f1a13282e08 100644
--- a/gcc/rust/ast/rust-ast.cc
+++ b/gcc/rust/ast/rust-ast.cc
@@ -2714,7 +2714,7 @@ ImplTraitTypeOneBound::as_string () const
 {
   std::string str ("ImplTraitTypeOneBound: \n TraitBound: ");
 
-  return str + trait_bound.as_string ();
+  return str + trait_bound->as_string ();
 }
 
 std::string
diff --git a/gcc/rust/ast/rust-desugar-apit.cc 
b/gcc/rust/ast/rust-desugar-apit.cc
new file mode 100644
index 000000000000..2f31bcfe7a32
--- /dev/null
+++ b/gcc/rust/ast/rust-desugar-apit.cc
@@ -0,0 +1,516 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-desugar-apit.h"
+#include "rust-ast.h"
+#include "rust-type.h"
+
+namespace Rust {
+namespace AST {
+
+class DesugarApitType : public DefaultASTVisitor
+{
+  using DefaultASTVisitor::visit;
+
+public:
+  static std::pair<AST::Type *, std::vector<std::unique_ptr<GenericParam>>>
+  Desugar (AST::Type &type)
+  {
+    DesugarApitType visitor (&type);
+    type.accept_vis (visitor);
+    rust_assert (visitor.translated != nullptr);
+    return std::make_pair (visitor.translated,
+                          std::move (visitor.implicit_generic_params));
+  }
+
+  // Generate a unique impl trait parameter name
+  static Identifier get_impl_name ()
+  {
+    static size_t counter = 0;
+    return Identifier ("Impl_" + std::to_string (counter++));
+  }
+
+  // these can hold other types
+  void visit (AST::TupleType &tuple) override
+  {
+    for (auto &elem : tuple.get_elems ())
+      {
+       auto &type = *elem.get ();
+       auto desugar = Desugar (type);
+       auto tt = desugar.first;
+
+       auto &implicit_generics = desugar.second;
+       if (implicit_generics.empty ())
+         continue;
+
+       if (tt != elem.get ())
+         elem = std::unique_ptr<Type> (tt);
+
+       for (auto &implicit_generic : implicit_generics)
+         implicit_generic_params.push_back (std::move (implicit_generic));
+      }
+  }
+
+  void visit (AST::ArrayType &type) override
+  {
+    auto &element_type = type.get_element_type ();
+    auto desugar = Desugar (*element_type);
+    auto tt = desugar.first;
+
+    auto &implicit_generics = desugar.second;
+    if (implicit_generics.empty ())
+      return;
+
+    if (tt != element_type.get ())
+      element_type = std::unique_ptr<AST::Type> (tt);
+
+    for (auto &implicit_generic : implicit_generics)
+      implicit_generic_params.push_back (std::move (implicit_generic));
+  }
+
+  void visit (AST::ReferenceType &type) override
+  {
+    // Get a reference to the current type for in-place modification
+    auto &referenced_type = type.get_type_referenced ();
+    auto desugar = Desugar (referenced_type);
+    auto tt = desugar.first;
+
+    auto &implicit_generics = desugar.second;
+    if (implicit_generics.empty ())
+      return;
+
+    // Update the reference type's contents rather than creating a new one
+    if (&referenced_type != tt)
+      {
+       std::unique_ptr<AST::TypeNoBounds> new_type_no_bounds (
+         static_cast<AST::TypeNoBounds *> (tt));
+       type.get_type_ptr () = std::move (new_type_no_bounds);
+      }
+
+    // Collect all the implicit generic parameters we found
+    for (auto &implicit_generic : implicit_generics)
+      implicit_generic_params.push_back (std::move (implicit_generic));
+  }
+
+  void visit (AST::RawPointerType &type) override
+  {
+    auto &pointed_type = type.get_type_pointed_to ();
+    auto desugar = Desugar (pointed_type);
+    auto tt = desugar.first;
+
+    auto &implicit_generics = desugar.second;
+    if (implicit_generics.empty ())
+      return;
+
+    // Update the pointer's inner type directly using the new accessor
+    if (&pointed_type != tt)
+      {
+       std::unique_ptr<AST::TypeNoBounds> new_type_no_bounds (
+         static_cast<AST::TypeNoBounds *> (tt));
+       type.get_type_ptr () = std::move (new_type_no_bounds);
+      }
+
+    // Collect all the implicit generic parameters we found
+    for (auto &implicit_generic : implicit_generics)
+      implicit_generic_params.push_back (std::move (implicit_generic));
+  }
+
+  void visit (AST::SliceType &type) override
+  {
+    auto &element_type = type.get_elem_type ();
+    auto desugar = Desugar (element_type);
+    auto tt = desugar.first;
+
+    auto &implicit_generics = desugar.second;
+    if (implicit_generics.empty ())
+      return;
+
+    if (&element_type != tt)
+      {
+       std::unique_ptr<AST::Type> new_elem_type (tt);
+       type.get_elem_type_ptr () = std::move (new_elem_type);
+      }
+
+    // Collect all the implicit generic parameters we found
+    for (auto &implicit_generic : implicit_generics)
+      implicit_generic_params.push_back (std::move (implicit_generic));
+  }
+
+  void visit (AST::ParenthesisedType &type) override
+  {
+    auto &inner_type_ptr = type.get_type_in_parens ();
+    auto desugar = Desugar (*inner_type_ptr);
+    auto tt = desugar.first;
+
+    auto &implicit_generics = desugar.second;
+    if (implicit_generics.empty ())
+      return;
+
+    if (inner_type_ptr.get () != tt)
+      {
+       std::unique_ptr<AST::Type> new_inner_type (tt);
+       inner_type_ptr = std::move (new_inner_type);
+      }
+
+    // Collect all the implicit generic parameters we found
+    for (auto &implicit_generic : implicit_generics)
+      implicit_generic_params.push_back (std::move (implicit_generic));
+  }
+
+  // this is where the desugar happens
+  void visit (AST::ImplTraitType &type) override
+  {
+    // Generate a unique name using the static method
+    auto ident = get_impl_name ();
+
+    // Create a type path for the new generic parameter
+    // Create a SimplePathSegment with the identifier string
+    auto simple_seg = SimplePathSegment (ident.as_string (), type.get_locus 
());
+    // Create a vector of SimplePathSegments for SimplePath constructor
+    std::vector<SimplePathSegment> simple_segs = {simple_seg};
+    // Create a SimplePath
+    auto simple_path = SimplePath (simple_segs, false, type.get_locus ());
+
+    // Convert to TypePath by creating path segments
+    std::vector<std::unique_ptr<TypePathSegment>> segments;
+    segments.push_back (std::unique_ptr<TypePathSegment> (new TypePathSegment (
+      PathIdentSegment (ident.as_string (), type.get_locus ()), false,
+      type.get_locus ())));
+
+    // Create TypePath from segments
+    auto type_path
+      = new TypePath (std::move (segments), type.get_locus (), false);
+
+    // Convert bounds from impl trait to generic parameter bounds
+    std::vector<std::unique_ptr<TypeParamBound>> bounds;
+    for (auto &bound : type.get_type_param_bounds ())
+      bounds.push_back (bound->clone_type_param_bound ());
+
+    // Create the new generic parameter
+    auto generic_param = std::unique_ptr<TypeParam> (
+      new TypeParam (ident, type.get_locus (), std::move (bounds)));
+
+    // Store the generic parameter to be added to the function signature
+    implicit_generic_params.push_back (std::move (generic_param));
+
+    // Replace impl trait with the new type parameter
+    translated = type_path;
+  }
+
+  void visit (AST::ImplTraitTypeOneBound &type) override
+  {
+    // Generate a unique name using the static method
+    auto ident = get_impl_name ();
+
+    // Create a type path for the new generic parameter
+    // Create a SimplePathSegment with the identifier string
+    auto simple_seg = SimplePathSegment (ident.as_string (), type.get_locus 
());
+    // Create a vector of SimplePathSegments for SimplePath constructor
+    std::vector<SimplePathSegment> simple_segs = {simple_seg};
+    // Create a SimplePath
+    auto simple_path = SimplePath (simple_segs, false, type.get_locus ());
+
+    // Convert to TypePath by creating path segments
+    std::vector<std::unique_ptr<TypePathSegment>> segments;
+    segments.push_back (std::unique_ptr<TypePathSegment> (new TypePathSegment (
+      PathIdentSegment (ident.as_string (), type.get_locus ()), false,
+      type.get_locus ())));
+
+    // Create TypePath from segments
+    auto type_path
+      = new TypePath (std::move (segments), type.get_locus (), false);
+
+    // Convert the bound to a generic parameter bound
+    std::vector<std::unique_ptr<TypeParamBound>> bounds;
+    bounds.push_back (std::move (type.get_trait_bound ()));
+
+    // Create the new generic parameter
+    auto generic_param = std::unique_ptr<TypeParam> (
+      new TypeParam (ident, type.get_locus (), std::move (bounds)));
+
+    // Store the generic parameter to be added to the function signature
+    implicit_generic_params.push_back (std::move (generic_param));
+
+    // Replace impl trait with the new type parameter
+    translated = type_path;
+  }
+
+private:
+  DesugarApitType (AST::Type *base)
+    : translated (base), implicit_generic_params ()
+  {}
+
+  AST::Type *translated;
+  std::vector<std::unique_ptr<GenericParam>> implicit_generic_params;
+};
+
+// ---------
+
+class ApitBoundProcessor
+{
+public:
+  ApitBoundProcessor (
+    WhereClause &where_clause,
+    std::vector<std::unique_ptr<GenericParam>> &generic_params)
+    : where_clause (where_clause), generic_params (generic_params)
+  {}
+
+  void go (std::vector<std::unique_ptr<GenericParam>> &implicit_generics)
+  {
+    // some desugars are more complex so imagine this case
+    //
+    // pub fn foo(_value: impl Bar<Baz = impl Foo>) -> i32 {
+    //   15
+    // }
+    //
+    // this needs to become:
+    //
+    // pub fn foo<T, U>(_value: T) -> i32
+    // where
+    //     T: Bar<Baz = U>,
+    //     U: Foo,
+    // {
+    //     15
+    // }
+    //
+    // so we need to walk all the implicit generics and the trait bounds paths
+    // for more generics
+
+    for (auto &implicit_generic : implicit_generics)
+      {
+       switch (implicit_generic->get_kind ())
+         {
+           case GenericParam::Kind::Type: {
+             TypeParam &p
+               = *static_cast<TypeParam *> (implicit_generic.get ());
+
+             process_type_param (p);
+             generic_params.push_back (std::move (implicit_generic));
+             for (auto &synth : synthetic_params)
+               generic_params.push_back (std::move (synth));
+             synthetic_params.clear ();
+           }
+           break;
+
+         default:
+           generic_params.push_back (std::move (implicit_generic));
+           break;
+         }
+      }
+  }
+
+private:
+  void process_type_param (TypeParam &p)
+  {
+    auto &bounds = p.get_type_param_bounds ();
+    std::vector<size_t> bounds_to_remove;
+    for (size_t i = 0; i < bounds.size (); i++)
+      {
+       auto &tb = bounds[i];
+       switch (tb->get_bound_type ())
+         {
+           case TypeParamBound::TypeParamBoundType::TRAIT: {
+             TraitBound &ttb = *static_cast<TraitBound *> (tb.get ());
+             TypePath &path = ttb.get_type_path ();
+             bool deusgared = process_type_path (p, ttb, path);
+             if (deusgared)
+               bounds_to_remove.push_back (i);
+           }
+
+         default:
+           break;
+         }
+      }
+    for (auto it = bounds_to_remove.rbegin (); it != bounds_to_remove.rend ();
+        ++it)
+      bounds.erase (bounds.begin () + *it);
+  }
+
+  bool process_type_path (TypeParam &p, TraitBound &parent, TypePath &path)
+  {
+    bool desugared = false;
+    for (auto &segment : path.get_segments ())
+      {
+       switch (segment->get_type ())
+         {
+           case TypePathSegment::SegmentType::GENERIC: {
+             TypePathSegmentGeneric &seg
+               = *static_cast<TypePathSegmentGeneric *> (segment.get ());
+             desugared |= process_generic_segment (p, parent, path, seg);
+           }
+
+         default:
+           break;
+         }
+      }
+    return desugared;
+  }
+
+  bool process_generic_segment (TypeParam &p, TraitBound &parent,
+                               TypePath &path, TypePathSegmentGeneric &seg)
+  {
+    // we need to look for any impl types as default arguments in any generics
+    // and remove this index from the generic arguments by using a where
+    // constraint instead
+
+    std::vector<std::unique_ptr<WhereClauseItem>> new_clauses;
+    GenericArgs &generic_args = seg.get_generic_args ();
+    std::vector<std::reference_wrapper<const GenericArgsBinding>>
+      bindings_desugared;
+    std::vector<GenericArgsBinding> &bindings
+      = generic_args.get_binding_args ();
+
+    for (auto &generic : bindings)
+      {
+       auto &t = generic.get_type ();
+       auto translated = DesugarApitType::Desugar (t);
+       auto tt = translated.first;
+
+       auto &implicit_generics = translated.second;
+       if (implicit_generics.empty ())
+         continue;
+
+       if (tt != &t)
+         {
+           bindings_desugared.push_back (generic);
+           generic.get_type_ptr () = std::unique_ptr<Type> (tt);
+         }
+
+       for (auto &implicit_generic : implicit_generics)
+         {
+           switch (implicit_generic->get_kind ())
+             {
+               case GenericParam::Kind::Type: {
+                 TypeParam &tp
+                   = *static_cast<TypeParam *> (implicit_generic.get ());
+
+                 std::vector<std::unique_ptr<TypeParamBound>>
+                   type_param_bounds;
+                 for (auto &b : tp.get_type_param_bounds ())
+                   type_param_bounds.push_back (std::move (b));
+                 tp.get_type_param_bounds ().clear ();
+
+                 // add synthetic parameter for this
+                 synthetic_params.push_back (std::move (implicit_generic));
+
+                 auto bound_type_path
+                   = get_type_for_identifier (tp.get_type_representation ());
+
+                 auto clause = new TypeBoundWhereClauseItem (
+                   {}, std::move (bound_type_path),
+                   std::move (type_param_bounds), tp.get_locus ());
+                 std::unique_ptr<WhereClauseItem> clause_item
+                   = std::unique_ptr<WhereClauseItem> (clause);
+                 new_clauses.push_back (std::move (clause_item));
+               }
+               break;
+
+             default:
+               synthetic_params.push_back (std::move (implicit_generic));
+               break;
+             }
+         }
+      }
+
+    std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds;
+    auto bound = std::unique_ptr<TypeParamBound> (new TraitBound (parent));
+    type_param_bounds.push_back (std::move (bound));
+    auto parent_type_path
+      = get_type_for_identifier (p.get_type_representation ());
+    auto clause
+      = new TypeBoundWhereClauseItem ({}, std::move (parent_type_path),
+                                     std::move (type_param_bounds),
+                                     parent.get_locus ());
+    std::unique_ptr<WhereClauseItem> clause_item
+      = std::unique_ptr<WhereClauseItem> (clause);
+    where_clause.get_items ().push_back (std::move (clause_item));
+
+    for (auto &where_item : new_clauses)
+      where_clause.get_items ().push_back (std::move (where_item));
+
+    return !bindings_desugared.empty ();
+  }
+
+  static std::unique_ptr<Type> get_type_for_identifier (const Identifier 
&ident)
+  {
+    auto simple_seg
+      = SimplePathSegment (ident.as_string (), ident.get_locus ());
+    std::vector<SimplePathSegment> simple_segs = {simple_seg};
+    auto simple_path = SimplePath (simple_segs, false, ident.get_locus ());
+    std::vector<std::unique_ptr<TypePathSegment>> segments;
+    segments.push_back (std::unique_ptr<TypePathSegment> (new TypePathSegment (
+      PathIdentSegment (ident.as_string (), ident.get_locus ()), false,
+      ident.get_locus ())));
+    auto type_path = new TypePath (std::move (segments), ident.get_locus ());
+    return std::unique_ptr<Type> (type_path);
+  }
+
+private:
+  WhereClause &where_clause;
+  std::vector<std::unique_ptr<GenericParam>> &generic_params;
+
+  // mutates
+  std::vector<std::unique_ptr<GenericParam>> synthetic_params;
+};
+
+// ---------
+
+DesugarApit::DesugarApit () {}
+
+void
+DesugarApit::go (AST::Crate &crate)
+{
+  DefaultASTVisitor::visit (crate);
+}
+
+void
+DesugarApit::visit (AST::Function &function)
+{
+  if (!function.has_function_params ())
+    return;
+
+  auto &fn_params = function.get_function_params ();
+  for (auto &param : fn_params)
+    {
+      if (param->is_variadic () || param->is_self ())
+       continue;
+
+      auto *p = param.get ();
+      auto &fp = *static_cast<AST::FunctionParam *> (p);
+      auto &type = fp.get_type ();
+
+      auto translated = DesugarApitType::Desugar (type);
+      auto tt = translated.first;
+
+      auto &implicit_generics = translated.second;
+      if (implicit_generics.empty ())
+       continue;
+
+      if (fp.get_type_ptr ().get () != tt)
+       {
+         fp.get_type_ptr () = std::unique_ptr<AST::Type> (tt);
+       }
+
+      ApitBoundProcessor processor (function.get_where_clause (),
+                                   function.get_generic_params ());
+      processor.go (implicit_generics);
+    }
+}
+
+} // namespace AST
+} // namespace Rust
diff --git a/gcc/rust/ast/rust-desugar-apit.h b/gcc/rust/ast/rust-desugar-apit.h
new file mode 100644
index 000000000000..07c25e2405cf
--- /dev/null
+++ b/gcc/rust/ast/rust-desugar-apit.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_DESUGAR_APIT_H
+#define RUST_DESUGAR_APIT_H
+
+#include "rust-ast-visitor.h"
+
+namespace Rust {
+namespace AST {
+
+class DesugarApit : public DefaultASTVisitor
+{
+  using DefaultASTVisitor::visit;
+
+public:
+  DesugarApit ();
+  void go (AST::Crate &);
+
+private:
+  void visit (AST::Function &) override;
+};
+
+} // namespace AST
+} // namespace Rust
+
+#endif // ! RUST_DESUGAR_APIT_H
diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h
index b6f8f5325855..31575105d98d 100644
--- a/gcc/rust/ast/rust-path.h
+++ b/gcc/rust/ast/rust-path.h
@@ -968,11 +968,7 @@ public:
   void accept_vis (ASTVisitor &vis) override;
 
   // TODO: is this better? Or is a "vis_pattern" better?
-  GenericArgs &get_generic_args ()
-  {
-    rust_assert (has_generic_args ());
-    return generic_args;
-  }
+  GenericArgs &get_generic_args () { return generic_args; }
 
   // Use covariance to override base class method
   TypePathSegmentGeneric *clone_type_path_segment_impl () const override
diff --git a/gcc/rust/ast/rust-type.h b/gcc/rust/ast/rust-type.h
index 48539a23cebe..c785b6e64964 100644
--- a/gcc/rust/ast/rust-type.h
+++ b/gcc/rust/ast/rust-type.h
@@ -73,6 +73,13 @@ public:
       type_path (std::move (type_path)), locus (locus)
   {}
 
+  TraitBound (TraitBound const &other)
+    : TypeParamBound (other.get_node_id ()), in_parens (other.in_parens),
+      opening_question_mark (other.opening_question_mark),
+      for_lifetimes (other.for_lifetimes), type_path (other.type_path),
+      locus (other.locus)
+  {}
+
   std::string as_string () const override;
 
   location_t get_locus () const override final { return locus; }
@@ -305,33 +312,31 @@ public:
 // Impl trait with a single bound? Poor reference material here.
 class ImplTraitTypeOneBound : public TypeNoBounds
 {
-  TraitBound trait_bound;
+  std::unique_ptr<TypeParamBound> trait_bound;
   location_t locus;
 
-protected:
-  /* Use covariance to implement clone function as returning this object rather
-   * than base */
-  ImplTraitTypeOneBound *clone_type_no_bounds_impl () const override
-  {
-    return new ImplTraitTypeOneBound (*this);
-  }
-
 public:
-  ImplTraitTypeOneBound (TraitBound trait_bound, location_t locus)
+  ImplTraitTypeOneBound (std::unique_ptr<TypeParamBound> trait_bound,
+                        location_t locus)
     : trait_bound (std::move (trait_bound)), locus (locus)
   {}
 
+  ImplTraitTypeOneBound (ImplTraitTypeOneBound const &other)
+    : trait_bound (other.trait_bound->clone_type_param_bound ()),
+      locus (other.locus)
+  {}
+
   std::string as_string () const override;
 
   location_t get_locus () const override final { return locus; }
 
   void accept_vis (ASTVisitor &vis) override;
 
-  // TODO: would a "vis_type" be better?
-  TraitBound &get_trait_bound ()
+  std::unique_ptr<TypeParamBound> &get_trait_bound () { return trait_bound; }
+
+  TypeNoBounds *clone_type_no_bounds_impl () const override
   {
-    // TODO: check to ensure invariants are met?
-    return trait_bound;
+    return new ImplTraitTypeOneBound (*this);
   }
 };
 
@@ -529,6 +534,9 @@ public:
     return *type;
   }
 
+  // Getter for direct access to the type unique_ptr
+  std::unique_ptr<TypeNoBounds> &get_type_ptr () { return type; }
+
 protected:
   /* Use covariance to implement clone function as returning this object rather
    * than base */
@@ -604,6 +612,9 @@ public:
 
   TypeNoBounds &get_base_type () { return *type; }
 
+  // Getter for direct access to the type unique_ptr
+  std::unique_ptr<TypeNoBounds> &get_type_ptr () { return type; }
+
 protected:
   /* Use covariance to implement clone function as returning this object rather
    * than base */
@@ -666,6 +677,11 @@ public:
     return *size;
   }
 
+  std::unique_ptr<Type> &get_element_type () { return elem_type; }
+
+  // Additional getter for direct access to the size expr unique_ptr
+  std::unique_ptr<Expr> &get_size_ptr () { return size; }
+
 protected:
   /* Use covariance to implement clone function as returning this object rather
    * than base */
@@ -719,6 +735,9 @@ public:
     return *elem_type;
   }
 
+  // Getter for direct access to the elem_type unique_ptr
+  std::unique_ptr<Type> &get_elem_type_ptr () { return elem_type; }
+
 protected:
   /* Use covariance to implement clone function as returning this object rather
    * than base */
diff --git a/gcc/rust/hir/rust-ast-lower-type.cc 
b/gcc/rust/hir/rust-ast-lower-type.cc
index d871583253c7..6a5b7dba866c 100644
--- a/gcc/rust/hir/rust-ast-lower-type.cc
+++ b/gcc/rust/hir/rust-ast-lower-type.cc
@@ -519,7 +519,7 @@ ASTLoweringType::visit (AST::ImplTraitTypeOneBound &type)
 
   std::vector<std::unique_ptr<HIR::TypeParamBound>> bounds;
 
-  auto b = ASTLoweringTypeBounds::translate (type.get_trait_bound ());
+  auto b = ASTLoweringTypeBounds::translate (*type.get_trait_bound ().get ());
   bounds.push_back (std::unique_ptr<HIR::TypeParamBound> (b));
 
   auto crate_num = mappings.get_current_crate ();
diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h
index e47b9e015e2e..e165998e2cb9 100644
--- a/gcc/rust/parse/rust-parse-impl.h
+++ b/gcc/rust/parse/rust-parse-impl.h
@@ -9117,14 +9117,8 @@ Parser<ManagedTokenSource>::parse_type (bool save_errors)
          t = lexer.peek_token ();
          if (t->get_id () != PLUS)
            {
-             // convert trait bound to value object
-             AST::TraitBound value_bound (*initial_bound);
-
-             // DEBUG: removed as unique ptr, so should auto-delete
-             // delete initial_bound;
-
              return std::unique_ptr<AST::ImplTraitTypeOneBound> (
-               new AST::ImplTraitTypeOneBound (std::move (value_bound),
+               new AST::ImplTraitTypeOneBound (std::move (initial_bound),
                                                locus));
            }
 
@@ -9955,11 +9949,8 @@ Parser<ManagedTokenSource>::parse_type_no_bounds ()
              return nullptr;
            }
 
-         // convert trait bound to value object
-         AST::TraitBound value_bound (*initial_bound);
-
          return std::unique_ptr<AST::ImplTraitTypeOneBound> (
-           new AST::ImplTraitTypeOneBound (std::move (value_bound), locus));
+           new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus));
        }
     case DYN:
       case QUESTION_MARK: {
diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc 
b/gcc/rust/resolve/rust-ast-resolve-type.cc
index 8df6b952ca06..d68c86fc8fd9 100644
--- a/gcc/rust/resolve/rust-ast-resolve-type.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-type.cc
@@ -140,7 +140,7 @@ ResolveType::visit (AST::ImplTraitType &type)
 void
 ResolveType::visit (AST::ImplTraitTypeOneBound &type)
 {
-  ResolveTypeBound::go (type.get_trait_bound ());
+  ResolveTypeBound::go (*type.get_trait_bound ().get ());
 }
 
 // resolve relative type-paths
diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc
index 5563d103ff5e..bb91ab2b979f 100644
--- a/gcc/rust/rust-session-manager.cc
+++ b/gcc/rust/rust-session-manager.cc
@@ -20,6 +20,7 @@
 #include "rust-collect-lang-items.h"
 #include "rust-desugar-for-loops.h"
 #include "rust-desugar-question-mark.h"
+#include "rust-desugar-apit.h"
 #include "rust-diagnostics.h"
 #include "rust-hir-pattern-analysis.h"
 #include "rust-immutable-name-resolution-context.h"
@@ -619,6 +620,7 @@ Session::compile_crate (const char *filename)
 
   AST::DesugarForLoops ().go (parsed_crate);
   AST::DesugarQuestionMark ().go (parsed_crate);
+  AST::DesugarApit ().go (parsed_crate);
 
   rust_debug ("\033[0;31mSUCCESSFULLY FINISHED EXPANSION \033[0m");
   if (options.dump_option_enabled (CompileOptions::EXPANSION_DUMP))
diff --git a/gcc/testsuite/rust/compile/issue-1487.rs 
b/gcc/testsuite/rust/compile/issue-1487.rs
new file mode 100644
index 000000000000..4a4d759ef2e9
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-1487.rs
@@ -0,0 +1,15 @@
+// { dg-options "-w" }
+#[lang = "sized"]
+trait Sized {}
+
+trait Printable {
+    fn print(&self);
+}
+
+struct Foo;
+
+impl Printable for Foo {
+    fn print(&self) {}
+}
+
+fn take_printable(_: impl Printable) {}
diff --git a/gcc/testsuite/rust/compile/issue-2015.rs 
b/gcc/testsuite/rust/compile/issue-2015.rs
index 7789ecda3763..7e0365163e5a 100644
--- a/gcc/testsuite/rust/compile/issue-2015.rs
+++ b/gcc/testsuite/rust/compile/issue-2015.rs
@@ -1,4 +1,5 @@
-// { dg-additional-options "-frust-compile-until=lowering" }
+#[lang = "sized"]
+trait Sized {}
 
 macro_rules! impl_foo {
        () => { impl Foo }
diff --git a/gcc/testsuite/rust/compile/issue-3454.rs 
b/gcc/testsuite/rust/compile/issue-3454.rs
new file mode 100644
index 000000000000..2a3c0c714606
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3454.rs
@@ -0,0 +1,20 @@
+#[lang = "sized"]
+pub trait Sized {}
+
+macro_rules! impl_foo {
+       () => { impl Foo }
+}
+
+pub trait Foo {}
+
+pub trait Bar {
+    type Baz;
+}
+
+pub fn foo(_value: impl Bar<Baz = impl_foo!()>) -> i32 {
+    15
+}
+
+pub fn bar(_value: impl Bar<Baz = impl Foo>) -> i32 {
+    16
+}
diff --git a/gcc/testsuite/rust/compile/nr2/exclude 
b/gcc/testsuite/rust/compile/nr2/exclude
index c020e36fba4a..d3bdb1cce0df 100644
--- a/gcc/testsuite/rust/compile/nr2/exclude
+++ b/gcc/testsuite/rust/compile/nr2/exclude
@@ -14,4 +14,7 @@ issue-3663.rs
 issue-3671.rs
 issue-3652.rs
 issue-3649.rs
+issue-1487.rs
+issue-2015.rs
+issue-3454.rs
 # please don't delete the trailing newline
diff --git a/gcc/testsuite/rust/execute/torture/impl_desugar-2.rs 
b/gcc/testsuite/rust/execute/torture/impl_desugar-2.rs
new file mode 100644
index 000000000000..c73ea34c6dab
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/impl_desugar-2.rs
@@ -0,0 +1,32 @@
+#[lang = "sized"]
+trait Sized {}
+
+macro_rules! impl_foo {
+       () => { impl Foo }
+}
+
+pub trait Foo {}
+
+pub trait Bar {
+    type Baz;
+}
+
+struct MyBaz; // { dg-warning "struct is never constructed" }
+impl Foo for MyBaz {}
+
+struct MyBar;
+
+impl Bar for MyBar {
+    type Baz = MyBaz;
+}
+
+pub fn foo(_value: impl Bar<Baz = impl_foo!()>) -> i32 {
+    15
+}
+
+fn main() -> i32 {
+    let bar = MyBar;
+    let result: i32 = foo(bar);
+
+    result - 15
+}
diff --git a/gcc/testsuite/rust/execute/torture/impl_desugar.rs 
b/gcc/testsuite/rust/execute/torture/impl_desugar.rs
new file mode 100644
index 000000000000..22d39519f305
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/impl_desugar.rs
@@ -0,0 +1,32 @@
+#[lang = "sized"]
+trait Sized {}
+
+pub trait Foo {}
+
+pub trait Bar {
+    type Baz;
+}
+
+struct MyBaz; // { dg-warning "struct is never constructed" }
+impl Foo for MyBaz {}
+
+struct MyBar;
+
+impl Bar for MyBar {
+    type Baz = MyBaz;
+}
+
+pub fn foo<T, U>(_value: T) -> i32
+where
+    T: Bar<Baz = U>,
+    U: Foo,
+{
+    15
+}
+
+fn main() -> i32 {
+    let bar = MyBar;
+    let result: i32 = foo::<MyBar, MyBaz>(bar);
+
+    result - 15
+}
diff --git a/gcc/testsuite/rust/execute/torture/impl_trait1.rs 
b/gcc/testsuite/rust/execute/torture/impl_trait1.rs
new file mode 100644
index 000000000000..33a5c8cf1dbb
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/impl_trait1.rs
@@ -0,0 +1,31 @@
+#[lang = "sized"]
+trait Sized {}
+
+pub trait Value {
+    fn get(&self) -> i32;
+}
+
+struct Foo(i32);
+struct Bar(i32);
+
+impl Value for Foo {
+    fn get(&self) -> i32 {
+        self.0
+    }
+}
+impl Value for Bar {
+    fn get(&self) -> i32 {
+        self.0
+    }
+}
+
+pub fn foo(a: impl Value, b: impl Value) -> i32 {
+    a.get() + b.get()
+}
+
+fn main() -> i32 {
+    let a = Foo(1);
+    let b = Bar(2);
+
+    foo(a, b) - 3
+}
diff --git a/gcc/testsuite/rust/execute/torture/impl_trait2.rs 
b/gcc/testsuite/rust/execute/torture/impl_trait2.rs
new file mode 100644
index 000000000000..29f393d679d2
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/impl_trait2.rs
@@ -0,0 +1,31 @@
+#[lang = "sized"]
+trait Sized {}
+
+pub trait Value {
+    fn get(&self) -> i32;
+}
+
+struct Foo(i32);
+struct Bar(i32);
+
+impl Value for Foo {
+    fn get(&self) -> i32 {
+        self.0
+    }
+}
+impl Value for Bar {
+    fn get(&self) -> i32 {
+        self.0
+    }
+}
+
+pub fn foo(a: &impl Value, b: &impl Value) -> i32 {
+    a.get() + b.get()
+}
+
+fn main() -> i32 {
+    let a = Foo(1);
+    let b = Bar(2);
+
+    foo(&a, &b) - 3
+}
diff --git a/gcc/testsuite/rust/execute/torture/impl_trait3.rs 
b/gcc/testsuite/rust/execute/torture/impl_trait3.rs
new file mode 100644
index 000000000000..97e2972aeb22
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/impl_trait3.rs
@@ -0,0 +1,46 @@
+/* { dg-output "Hello from Message\r*\n" } */
+#[lang = "sized"]
+pub trait Sized {}
+
+extern "C" {
+    fn printf(s: *const i8, ...);
+}
+
+trait Speak {
+    fn speak(&self) -> &'static str;
+}
+
+trait Printer {
+    fn print(&self, input: impl Speak);
+}
+
+struct Console;
+
+impl Printer for Console {
+    fn print(&self, input: impl Speak) {
+        // { dg-warning "unused name .self." "" { target *-*-* } .-1 }
+        unsafe {
+            let a = input.speak();
+            let b = a as *const str;
+            let c = b as *const i8;
+
+            printf(c);
+        }
+    }
+}
+
+struct Message(&'static str);
+
+impl Speak for Message {
+    fn speak(&self) -> &'static str {
+        self.0
+    }
+}
+
+fn main() -> i32 {
+    let c = Console;
+    let msg = Message("Hello from Message\n");
+    c.print(msg);
+
+    0
+}
diff --git a/gcc/testsuite/rust/execute/torture/impl_trait4.rs 
b/gcc/testsuite/rust/execute/torture/impl_trait4.rs
new file mode 100644
index 000000000000..67d00957e3d6
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/impl_trait4.rs
@@ -0,0 +1,31 @@
+#[lang = "sized"]
+trait Sized {}
+
+trait Foo {
+    fn id(&self) -> i32;
+}
+
+struct A(i32);
+struct B(i32);
+
+impl Foo for A {
+    fn id(&self) -> i32 {
+        self.0
+    }
+}
+
+impl Foo for B {
+    fn id(&self) -> i32 {
+        self.0
+    }
+}
+
+fn takes_tuple(pair: (impl Foo, impl Foo)) -> i32 {
+    pair.0.id() + pair.1.id()
+}
+
+fn main() -> i32 {
+    let a = A(1);
+    let b = B(2);
+    takes_tuple((a, b)) - 3
+}
diff --git a/gcc/testsuite/rust/execute/torture/issue-1482.rs 
b/gcc/testsuite/rust/execute/torture/issue-1482.rs
new file mode 100644
index 000000000000..ed8dc8146103
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/issue-1482.rs
@@ -0,0 +1,23 @@
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "fn_once"]
+pub trait FnOnce<Args> {
+    #[lang = "fn_once_output"]
+    type Output;
+
+    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+fn takes_fn(a: i32, f: impl FnOnce(i32) -> i32) -> i32 {
+    f(a)
+}
+
+pub fn main() -> i32 {
+    let capture = 2;
+    let a = |i: i32| {
+        let b = i + capture;
+        b
+    };
+    takes_fn(1, a) - 3
+}

Reply via email to