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 ¶m : 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 +}