aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Herron <herron.philip@googlemail.com>2025-04-30 14:37:49 +0100
committerPhilip Herron <philip.herron@embecosm.com>2025-05-07 15:07:22 +0000
commit927d067721e91ad3d702f9b9efaf939afd319ef1 (patch)
treef8d3afae5dc6176f72e1bd8702b39812012f4296
parentef44f649655dcbba63b925c06e923ed1aefd6678 (diff)
downloadgcc-927d067721e91ad3d702f9b9efaf939afd319ef1.zip
gcc-927d067721e91ad3d702f9b9efaf939afd319ef1.tar.gz
gcc-927d067721e91ad3d702f9b9efaf939afd319ef1.tar.bz2
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.philip@googlemail.com>
-rw-r--r--gcc/rust/Make-lang.in1
-rw-r--r--gcc/rust/ast/rust-ast.cc2
-rw-r--r--gcc/rust/ast/rust-desugar-apit.cc516
-rw-r--r--gcc/rust/ast/rust-desugar-apit.h42
-rw-r--r--gcc/rust/ast/rust-path.h6
-rw-r--r--gcc/rust/ast/rust-type.h47
-rw-r--r--gcc/rust/hir/rust-ast-lower-type.cc2
-rw-r--r--gcc/rust/parse/rust-parse-impl.h13
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.cc2
-rw-r--r--gcc/rust/rust-session-manager.cc2
-rw-r--r--gcc/testsuite/rust/compile/issue-1487.rs15
-rw-r--r--gcc/testsuite/rust/compile/issue-2015.rs3
-rw-r--r--gcc/testsuite/rust/compile/issue-3454.rs20
-rw-r--r--gcc/testsuite/rust/compile/nr2/exclude3
-rw-r--r--gcc/testsuite/rust/execute/torture/impl_desugar-2.rs32
-rw-r--r--gcc/testsuite/rust/execute/torture/impl_desugar.rs32
-rw-r--r--gcc/testsuite/rust/execute/torture/impl_trait1.rs31
-rw-r--r--gcc/testsuite/rust/execute/torture/impl_trait2.rs31
-rw-r--r--gcc/testsuite/rust/execute/torture/impl_trait3.rs46
-rw-r--r--gcc/testsuite/rust/execute/torture/impl_trait4.rs31
-rw-r--r--gcc/testsuite/rust/execute/torture/issue-1482.rs23
21 files changed, 866 insertions, 34 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 5ae50d2..38235f1 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 494b21a..0f1a132 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 0000000..2f31bcf
--- /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 0000000..07c25e2
--- /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 b6f8f53..3157510 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 48539a2..c785b6e 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 d871583..6a5b7db 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 e47b9e0..e165998 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 8df6b95..d68c86f 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 5563d10..bb91ab2 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 0000000..4a4d759
--- /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 7789ecd..7e03651 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 0000000..2a3c0c7
--- /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 c020e36..d3bdb1c 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 0000000..c73ea34
--- /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 0000000..22d3951
--- /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 0000000..33a5c8c
--- /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 0000000..29f393d
--- /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 0000000..97e2972
--- /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 0000000..67d0095
--- /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 0000000..ed8dc81
--- /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
+}