https://gcc.gnu.org/g:50507b79c724fff0ce53e61b93bb34b97cecb07a
commit r17-4323-g50507b79c724fff0ce53e61b93bb34b97cecb07a Author: Philip Herron <[email protected]> Date: Thu Sep 3 19:59:49 2026 +0100 gccrs: Fix parser handling for Foo<Bar: SomeTrait> The parser only recognized Foo<Bar = T> for the generic type bindings syntax. This parses both flavours now into update generic args type. Fixes Rust-GCC/gccrs#1726 gcc/rust/ChangeLog: * ast/rust-path.cc (GenericArgsBinding::as_string): new format * ast/rust-path.h (struct GenericArgsBinding): new kinds for bindings * hir/rust-ast-lower-base.cc (ASTLoweringBase::lower_binding): new * hir/tree/rust-hir-path.cc (GenericArgsBinding::GenericArgsBinding): likewise (GenericArgsBinding::operator=): likewise * hir/tree/rust-hir-path.h (class GenericArgsBinding): likewise * hir/tree/rust-hir.cc (GenericArgsBinding::to_string): likewise * parse/rust-parse-impl.hxx: peek for both types * typecheck/rust-type-util.cc (normalize_projection): track constrains * typecheck/rust-tyty-bounds.cc (TypeBoundPredicate::TypeBoundPredicate): new ctor (TypeBoundPredicate::operator=): likewise * typecheck/rust-tyty-subst.cc (SubstitutionArgumentMappings::get_constraint_args): new * typecheck/rust-tyty-subst.h: new * typecheck/rust-unify.cc (UnifyRules::expect_projection): fix loop gcc/testsuite/ChangeLog: * rust/compile/associated-type-bound.rs: New test. * rust/compile/issue-1726-1.rs: New test. * rust/compile/issue-1726-2.rs: New test. Signed-off-by: Philip Herron <[email protected]> Diff: --- gcc/rust/ast/rust-path.cc | 5 ++- gcc/rust/ast/rust-path.h | 20 +++++++-- gcc/rust/hir/rust-ast-lower-base.cc | 13 +++++- gcc/rust/hir/tree/rust-hir-path.cc | 8 ++-- gcc/rust/hir/tree/rust-hir-path.h | 13 +++++- gcc/rust/hir/tree/rust-hir.cc | 4 +- gcc/rust/parse/rust-parse-impl.hxx | 18 ++++++-- gcc/rust/typecheck/rust-type-util.cc | 18 ++++++++ gcc/rust/typecheck/rust-tyty-bounds.cc | 18 ++++---- gcc/rust/typecheck/rust-tyty-subst.cc | 49 ++++++++++++++------- gcc/rust/typecheck/rust-tyty-subst.h | 15 ++++--- gcc/rust/typecheck/rust-unify.cc | 6 +++ .../rust/compile/associated-type-bound.rs | 50 ++++++++++++++++++++++ gcc/testsuite/rust/compile/issue-1726-1.rs | 17 ++++++++ gcc/testsuite/rust/compile/issue-1726-2.rs | 42 ++++++++++++++++++ 15 files changed, 248 insertions(+), 48 deletions(-) diff --git a/gcc/rust/ast/rust-path.cc b/gcc/rust/ast/rust-path.cc index 5260adc8aed8..e8b885cbcd34 100644 --- a/gcc/rust/ast/rust-path.cc +++ b/gcc/rust/ast/rust-path.cc @@ -108,8 +108,9 @@ GenericArg::disambiguate_to_type () const std::string GenericArgsBinding::as_string () const { - // TODO: rewrite to work with non-literalisable types - return identifier.as_string () + " = " + type->as_string (); + auto type_string = type->as_string (); + auto separator = kind == Kind::Constraint ? " : " : " = "; + return identifier.as_string () + separator + type_string; } std::string diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h index 3ce7ed7ef347..ecb156e907cc 100644 --- a/gcc/rust/ast/rust-path.h +++ b/gcc/rust/ast/rust-path.h @@ -71,10 +71,18 @@ public: // A binding of an identifier to a type used in generic arguments in paths struct GenericArgsBinding { +public: + enum class Kind + { + Equality, + Constraint + }; + private: Identifier identifier; std::unique_ptr<Type> type; location_t locus; + Kind kind; public: // Returns whether binding is in an error state. @@ -90,7 +98,7 @@ public: if (type) new_type = type->reconstruct (); - return GenericArgsBinding (identifier, std::move (new_type), locus); + return GenericArgsBinding (identifier, std::move (new_type), locus, kind); } // Creates an error state generic args binding. @@ -101,13 +109,15 @@ public: // Pointer type for type in constructor to enable polymorphism GenericArgsBinding (Identifier ident, std::unique_ptr<Type> type_ptr, - location_t locus = UNDEF_LOCATION) - : identifier (std::move (ident)), type (std::move (type_ptr)), locus (locus) + location_t locus = UNDEF_LOCATION, + Kind kind = Kind::Equality) + : identifier (std::move (ident)), type (std::move (type_ptr)), + locus (locus), kind (kind) {} // Copy constructor has to deep copy the type as it is a unique pointer GenericArgsBinding (GenericArgsBinding const &other) - : identifier (other.identifier), locus (other.locus) + : identifier (other.identifier), locus (other.locus), kind (other.kind) { // guard to protect from null pointer dereference if (other.type != nullptr) @@ -122,6 +132,7 @@ public: { identifier = other.identifier; locus = other.locus; + kind = other.kind; // guard to protect from null pointer dereference if (other.type != nullptr) @@ -154,6 +165,7 @@ public: location_t get_locus () const { return locus; } Identifier get_identifier () const { return identifier; } + Kind get_kind () const { return kind; } }; /* Class representing a const generic application */ diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc index a4ab5d5edbc8..33b1c2f51ad4 100644 --- a/gcc/rust/hir/rust-ast-lower-base.cc +++ b/gcc/rust/hir/rust-ast-lower-base.cc @@ -651,10 +651,19 @@ ASTLoweringBase::lower_path_expr_seg (AST::PathExprSegment &s) HIR::GenericArgsBinding ASTLoweringBase::lower_binding (AST::GenericArgsBinding &binding) { - HIR::Type *lowered_type = ASTLoweringType::translate (binding.get_type ()); + auto impl_trait_allowed + = binding.get_kind () == AST::GenericArgsBinding::Kind::Constraint + ? ASTLoweringType::ImplTrait::Allow + : ASTLoweringType::ImplTrait::Forbid; + HIR::Type *lowered_type + = ASTLoweringType::translate (binding.get_type (), false, + impl_trait_allowed); + auto kind = binding.get_kind () == AST::GenericArgsBinding::Kind::Constraint + ? HIR::GenericArgsBinding::Kind::Constraint + : HIR::GenericArgsBinding::Kind::Equality; return HIR::GenericArgsBinding (binding.get_identifier (), std::unique_ptr<HIR::Type> (lowered_type), - binding.get_locus ()); + binding.get_locus (), kind); } HIR::GenericArgs diff --git a/gcc/rust/hir/tree/rust-hir-path.cc b/gcc/rust/hir/tree/rust-hir-path.cc index b887d0e07b2b..1c1117f93004 100644 --- a/gcc/rust/hir/tree/rust-hir-path.cc +++ b/gcc/rust/hir/tree/rust-hir-path.cc @@ -25,13 +25,14 @@ namespace HIR { GenericArgsBinding::GenericArgsBinding (Identifier ident, std::unique_ptr<Type> type_ptr, - location_t locus) - : identifier (std::move (ident)), type (std::move (type_ptr)), locus (locus) + location_t locus, Kind kind) + : identifier (std::move (ident)), type (std::move (type_ptr)), locus (locus), + kind (kind) {} GenericArgsBinding::GenericArgsBinding (GenericArgsBinding const &other) : identifier (other.identifier), type (other.type->clone_type ()), - locus (other.locus) + locus (other.locus), kind (other.kind) {} GenericArgsBinding & @@ -40,6 +41,7 @@ GenericArgsBinding::operator= (GenericArgsBinding const &other) identifier = other.identifier; type = other.type->clone_type (); locus = other.locus; + kind = other.kind; return *this; } diff --git a/gcc/rust/hir/tree/rust-hir-path.h b/gcc/rust/hir/tree/rust-hir-path.h index c6b3cbfab376..b9de6b90b909 100644 --- a/gcc/rust/hir/tree/rust-hir-path.h +++ b/gcc/rust/hir/tree/rust-hir-path.h @@ -63,10 +63,19 @@ public: // A binding of an identifier to a type used in generic arguments in paths class GenericArgsBinding { +public: + enum class Kind + { + Equality, + Constraint + }; + +private: Identifier identifier; std::unique_ptr<Type> type; location_t locus; + Kind kind; public: // Returns whether binding is in an error state. @@ -84,7 +93,8 @@ public: // Pointer type for type in constructor to enable polymorphism GenericArgsBinding (Identifier ident, std::unique_ptr<Type> type_ptr, - location_t locus = UNDEF_LOCATION); + location_t locus = UNDEF_LOCATION, + Kind kind = Kind::Equality); // Copy constructor has to deep copy the type as it is a unique pointer GenericArgsBinding (GenericArgsBinding const &other); @@ -116,6 +126,7 @@ public: } location_t get_locus () const { return locus; } + Kind get_kind () const { return kind; } }; class ConstGenericArg diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc index 7d611ed5c76b..00db9fc64557 100644 --- a/gcc/rust/hir/tree/rust-hir.cc +++ b/gcc/rust/hir/tree/rust-hir.cc @@ -2387,7 +2387,9 @@ GenericArgs::to_string () const std::string GenericArgsBinding::to_string () const { - return identifier.as_string () + " = " + type->to_string (); + auto type_string = type->to_string (); + auto separator = kind == Kind::Constraint ? " : " : " = "; + return identifier.as_string () + separator + type_string; } std::string diff --git a/gcc/rust/parse/rust-parse-impl.hxx b/gcc/rust/parse/rust-parse-impl.hxx index b5f41768541c..652f128c6ce1 100644 --- a/gcc/rust/parse/rust-parse-impl.hxx +++ b/gcc/rust/parse/rust-parse-impl.hxx @@ -5247,7 +5247,8 @@ Parser<ManagedTokenSource>::parse_path_generic_args () // ensure not binding being parsed as type accidently if (t->get_id () == IDENTIFIER - && lexer.peek_token (1)->get_id () == EQUAL) + && (lexer.peek_token (1)->get_id () == EQUAL + || lexer.peek_token (1)->get_id () == COLON)) break; auto arg = parse_generic_arg (); @@ -5324,12 +5325,21 @@ Parser<ManagedTokenSource>::parse_generic_args_binding () lexer.skip_token (); Identifier ident{ident_tok}; - if (!skip_token (EQUAL)) + if (lexer.peek_token ()->get_id () == COLON) { - // skip after somewhere? - return AST::GenericArgsBinding::create_error (); + lexer.skip_token (); + auto bounds_locus = lexer.peek_token ()->get_locus (); + auto bounds = parse_type_param_bounds (); + auto type = std::unique_ptr<AST::Type> ( + new AST::ImplTraitType (std::move (bounds), bounds_locus)); + return AST::GenericArgsBinding ( + std::move (ident), std::move (type), ident_tok->get_locus (), + AST::GenericArgsBinding::Kind::Constraint); } + if (!skip_token (EQUAL)) + return AST::GenericArgsBinding::create_error (); + // parse type (required) std::unique_ptr<AST::Type> type = parse_type (); if (type == nullptr) diff --git a/gcc/rust/typecheck/rust-type-util.cc b/gcc/rust/typecheck/rust-type-util.cc index 21559cb2a8df..005defb50a6b 100644 --- a/gcc/rust/typecheck/rust-type-util.cc +++ b/gcc/rust/typecheck/rust-type-util.cc @@ -679,6 +679,24 @@ normalize_projection (TyTy::ProjectionType *proj, location_t locus, auto it = binding.find (assoc_name); if (it != binding.end ()) return it->second; + + const auto &constraints + = bound.get_substitution_arguments ().get_constraint_args (); + auto constraint = constraints.find (assoc_name); + if (constraint != constraints.end ()) + { + TyTy::BaseType *constrained = proj->clone (); + constrained->inherit_bounds (*constraint->second); + + // Keep the constrained projection distinct from the canonical + // associated-type declaration. + auto &mappings = Analysis::Mappings::get (); + HirId fresh = mappings.get_next_hir_id (); + constrained->set_ref (fresh); + constrained->set_ty_ref (fresh); + ctx->insert_implicit_type (fresh, constrained); + return constrained; + } } } diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index fca42d61ad31..5a1e02fe8944 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -469,11 +469,10 @@ TypeBoundPredicate::TypeBoundPredicate (const TypeBoundPredicate &other) copied_arg_mappings.push_back (std::move (c)); } - used_arguments - = SubstitutionArgumentMappings (copied_arg_mappings, - other.used_arguments.get_binding_args (), - other.used_arguments.get_regions (), - other.used_arguments.get_locus ()); + used_arguments = SubstitutionArgumentMappings ( + copied_arg_mappings, other.used_arguments.get_binding_args (), + other.used_arguments.get_regions (), other.used_arguments.get_locus (), + nullptr, false, false, other.used_arguments.get_constraint_args ()); } TypeBoundPredicate & @@ -511,11 +510,10 @@ TypeBoundPredicate::operator= (const TypeBoundPredicate &other) copied_arg_mappings.emplace_back (&substitutions.at (i++), argument); } - used_arguments - = SubstitutionArgumentMappings (copied_arg_mappings, - other.used_arguments.get_binding_args (), - other.used_arguments.get_regions (), - other.used_arguments.get_locus ()); + used_arguments = SubstitutionArgumentMappings ( + copied_arg_mappings, other.used_arguments.get_binding_args (), + other.used_arguments.get_regions (), other.used_arguments.get_locus (), + nullptr, false, false, other.used_arguments.get_constraint_args ()); super_traits = other.super_traits; return *this; diff --git a/gcc/rust/typecheck/rust-tyty-subst.cc b/gcc/rust/typecheck/rust-tyty-subst.cc index 46e22288c2bc..bed285eeeebe 100644 --- a/gcc/rust/typecheck/rust-tyty-subst.cc +++ b/gcc/rust/typecheck/rust-tyty-subst.cc @@ -336,16 +336,18 @@ SubstitutionArgumentMappings::SubstitutionArgumentMappings ( std::vector<SubstitutionArg> mappings, std::map<std::string, BaseType *> binding_args, RegionParamList regions, location_t locus, ParamSubstCb param_subst_cb, bool trait_item_flag, - bool error_flag) + bool error_flag, std::map<std::string, BaseType *> constraint_args) : mappings (std::move (mappings)), binding_args (binding_args), - regions (regions), locus (locus), param_subst_cb (param_subst_cb), - trait_item_flag (trait_item_flag), error_flag (error_flag) + constraint_args (constraint_args), regions (regions), locus (locus), + param_subst_cb (param_subst_cb), trait_item_flag (trait_item_flag), + error_flag (error_flag) {} SubstitutionArgumentMappings::SubstitutionArgumentMappings ( const SubstitutionArgumentMappings &other) : mappings (other.mappings), binding_args (other.binding_args), - regions (other.regions), locus (other.locus), param_subst_cb (nullptr), + constraint_args (other.constraint_args), regions (other.regions), + locus (other.locus), param_subst_cb (nullptr), trait_item_flag (other.trait_item_flag), error_flag (other.error_flag) {} @@ -355,6 +357,7 @@ SubstitutionArgumentMappings::operator= ( { mappings = other.mappings; binding_args = other.binding_args; + constraint_args = other.constraint_args; regions = other.regions; locus = other.locus; param_subst_cb = nullptr; @@ -476,6 +479,12 @@ SubstitutionArgumentMappings::get_binding_args () const return binding_args; } +const std::map<std::string, BaseType *> & +SubstitutionArgumentMappings::get_constraint_args () const +{ + return constraint_args; +} + std::string SubstitutionArgumentMappings::as_string () const { @@ -685,6 +694,7 @@ SubstitutionRef::get_mappings_from_generic_args ( HIR::GenericArgs &args, const std::vector<Region> ®ions) { std::map<std::string, BaseType *> binding_arguments; + std::map<std::string, BaseType *> constraint_arguments; if (args.get_binding_args ().size () > 0) { if (supports_associated_bindings ()) @@ -721,8 +731,13 @@ SubstitutionRef::get_mappings_from_generic_args ( return SubstitutionArgumentMappings::error (); } - binding_arguments[binding.get_identifier ().as_string ()] - = resolved; + if (binding.get_kind () + == HIR::GenericArgsBinding::Kind::Constraint) + constraint_arguments[binding.get_identifier ().as_string ()] + = resolved; + else + binding_arguments[binding.get_identifier ().as_string ()] + = resolved; } } else @@ -945,10 +960,15 @@ SubstitutionRef::get_mappings_from_generic_args ( } } - return {mappings, binding_arguments, + return {mappings, + binding_arguments, RegionParamList::from_subst (used_arguments.get_regions ().size (), regions), - args.get_locus ()}; + args.get_locus (), + nullptr, + false, + false, + constraint_arguments}; } BaseType * @@ -1036,12 +1056,10 @@ SubstitutionRef::adjust_mappings_for_this ( if (resolved_mappings.empty ()) return SubstitutionArgumentMappings::error (); - return SubstitutionArgumentMappings (resolved_mappings, - mappings.get_binding_args (), - mappings.get_regions (), - mappings.get_locus (), - mappings.get_subst_cb (), - mappings.trait_item_mode ()); + return SubstitutionArgumentMappings ( + resolved_mappings, mappings.get_binding_args (), mappings.get_regions (), + mappings.get_locus (), mappings.get_subst_cb (), + mappings.trait_item_mode (), false, mappings.get_constraint_args ()); } bool @@ -1101,7 +1119,8 @@ SubstitutionRef::solve_mappings_from_receiver_for_self ( return SubstitutionArgumentMappings (resolved_mappings, mappings.get_binding_args (), mappings.get_regions (), - mappings.get_locus ()); + mappings.get_locus (), nullptr, false, + false, mappings.get_constraint_args ()); } bool diff --git a/gcc/rust/typecheck/rust-tyty-subst.h b/gcc/rust/typecheck/rust-tyty-subst.h index 8a71f8907ff2..947488afbfa9 100644 --- a/gcc/rust/typecheck/rust-tyty-subst.h +++ b/gcc/rust/typecheck/rust-tyty-subst.h @@ -175,12 +175,12 @@ typedef std::function<void (const ParamType &, const SubstitutionArg &)> class SubstitutionArgumentMappings { public: - SubstitutionArgumentMappings (std::vector<SubstitutionArg> mappings, - std::map<std::string, BaseType *> binding_args, - RegionParamList regions, location_t locus, - ParamSubstCb param_subst_cb = nullptr, - bool trait_item_flag = false, - bool error_flag = false); + SubstitutionArgumentMappings ( + std::vector<SubstitutionArg> mappings, + std::map<std::string, BaseType *> binding_args, RegionParamList regions, + location_t locus, ParamSubstCb param_subst_cb = nullptr, + bool trait_item_flag = false, bool error_flag = false, + std::map<std::string, BaseType *> constraint_args = {}); SubstitutionArgumentMappings (const SubstitutionArgumentMappings &other); SubstitutionArgumentMappings & @@ -233,6 +233,8 @@ public: const std::map<std::string, BaseType *> &get_binding_args () const; + const std::map<std::string, BaseType *> &get_constraint_args () const; + const RegionParamList &get_regions () const; RegionParamList &get_mut_regions (); @@ -247,6 +249,7 @@ public: private: std::vector<SubstitutionArg> mappings; std::map<std::string, BaseType *> binding_args; + std::map<std::string, BaseType *> constraint_args; RegionParamList regions; location_t locus; ParamSubstCb param_subst_cb; diff --git a/gcc/rust/typecheck/rust-unify.cc b/gcc/rust/typecheck/rust-unify.cc index 32aebff52593..e6a863a5bd0f 100644 --- a/gcc/rust/typecheck/rust-unify.cc +++ b/gcc/rust/typecheck/rust-unify.cc @@ -1989,6 +1989,12 @@ UnifyRules::expect_projection (TyTy::ProjectionType *ltype, { if (ltype->is_trait_position ()) { + // A trait-position projection whose Self is still generic cannot be + // normalized against a concrete impl candidate. + auto dself = ltype->get_self ()->destructure (); + if (dself->is<TyTy::ParamType> ()) + return ltype; + TyTy::BaseType *ln = normalize_projection (ltype, locus, false, false); if (ln != nullptr && ln != ltype) diff --git a/gcc/testsuite/rust/compile/associated-type-bound.rs b/gcc/testsuite/rust/compile/associated-type-bound.rs new file mode 100644 index 000000000000..43cc57533322 --- /dev/null +++ b/gcc/testsuite/rust/compile/associated-type-bound.rs @@ -0,0 +1,50 @@ +#![feature(lang_items, no_core)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} + +pub trait Iterator { + type Item; +} + +pub trait IntoIterator { + type IntoIter; +} + +pub struct FlattenCompat<I, U>(I, U); + +pub struct Flatten<I: Iterator<Item: IntoIterator>> { + pub inner: FlattenCompat<I, <I::Item as IntoIterator>::IntoIter>, +} + +pub trait Foo { + type Bar; + + fn foo(&self); +} + +pub trait Copy {} + +pub trait Container<T> { + type Item; +} + +pub fn c<F: Foo<Bar: Foo>>(value: &F::Bar) +where + F::Bar: Copy, +{ + value.foo(); +} + +pub fn nested<F: Foo<Bar: Foo>>() { + let _: *const <F::Bar as Foo>::Bar; +} + +pub fn multiple_bounds<F: Foo<Bar: Foo + Copy>>() { + let _: *const <F::Bar as Foo>::Bar; +} + +pub fn positional_and_bound<T, C: Container<T, Item: Foo>>() { + let _: *const <C::Item as Foo>::Bar; +} diff --git a/gcc/testsuite/rust/compile/issue-1726-1.rs b/gcc/testsuite/rust/compile/issue-1726-1.rs new file mode 100644 index 000000000000..0e78fff3ced7 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1726-1.rs @@ -0,0 +1,17 @@ +#![feature(lang_items, no_core)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} + +pub trait Foo { + type Bar; +} + +pub trait Copy {} + +pub fn c<F: Foo<Bar: Foo>>() +where + F::Bar: Copy, +{ +} diff --git a/gcc/testsuite/rust/compile/issue-1726-2.rs b/gcc/testsuite/rust/compile/issue-1726-2.rs new file mode 100644 index 000000000000..4808b5709f3b --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1726-2.rs @@ -0,0 +1,42 @@ +#![feature(lang_items, no_core)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} + +pub trait Foo { + type Bar; + + fn foo(&self); +} + +pub trait Copy {} + +pub fn c<F: Foo<Bar: Foo>>(value: &F::Bar) +where + F::Bar: Copy, +{ + value.foo(); +} + +pub struct Outer; +pub struct Inner; + +impl Foo for Outer { + type Bar = Inner; + + fn foo(&self) {} +} + +impl Foo for Inner { + type Bar = Inner; + + fn foo(&self) {} +} + +impl Copy for Inner {} + +pub fn main() { + let inner = Inner; + c::<Outer>(&inner); +}
