https://gcc.gnu.org/g:8c91ed5dc39a55dfcf8d074ff38132cbc4b9e28f
commit 8c91ed5dc39a55dfcf8d074ff38132cbc4b9e28f Author: Philip Herron <herron.phi...@googlemail.com> Date: Sat Mar 22 17:40:48 2025 +0000 gccrs: support generic super traits recursively In order to handle generic super traits on any trait bound we need to ensure we track the TypeBoundPredicate as part of the TraitReference instead of just the raw TraitReferences because these will have any applied generics enplace. Then for any TypeBoundPredicate it takes a copy of the super traits because this is the usage of a TraitBound and we can apply generics which then need to be recursively applied up the chain of super predicates. The main tweak is around TypeBoundPredicate::lookup_associated_item because we need to associate the predicate with the item we are looking up so the caller can respect the generics correctly as well. Fixes Rust-GCC#3502 gcc/rust/ChangeLog: * typecheck/rust-hir-path-probe.cc: update call * typecheck/rust-hir-trait-reference.cc (TraitReference::lookup_trait_item): track predicate (TraitReference::is_equal): likewise (TraitReference::is_object_safe): likewise (TraitReference::satisfies_bound): likewise * typecheck/rust-hir-trait-reference.h: likewise * typecheck/rust-hir-trait-resolve.cc (TraitResolver::resolve_trait): likewise * typecheck/rust-tyty-bounds.cc (TypeBoundPredicate::TypeBoundPredicate): track super traits (TypeBoundPredicate::operator=): likewise (TypeBoundPredicate::apply_generic_arguments): ensure we apply to super predicates (TypeBoundPredicateItem::operator=): take copy of parent predicate (TypeBoundPredicateItem::error): pass error instead of nullptr (TypeBoundPredicateItem::is_error): update to no longer check for nullptr (TypeBoundPredicateItem::get_parent): updated (TypeBoundPredicateItem::get_tyty_for_receiver): likewise (TypeBoundPredicate::get_associated_type_items): likewise * typecheck/rust-tyty-bounds.h (class TypeBoundPredicateItem): move * typecheck/rust-tyty-subst.cc: flag to handle placeholder Self on traits * typecheck/rust-tyty-subst.h (class TypeBoundPredicateItem): likewise * typecheck/rust-tyty.h (class TypeBoundPredicateItem): refactored gcc/testsuite/ChangeLog: * rust/execute/torture/issue-3502.rs: New test. Signed-off-by: Philip Herron <herron.phi...@googlemail.com> Diff: --- gcc/rust/typecheck/rust-hir-path-probe.cc | 2 +- gcc/rust/typecheck/rust-hir-trait-reference.cc | 24 +++++---- gcc/rust/typecheck/rust-hir-trait-reference.h | 9 ++-- gcc/rust/typecheck/rust-hir-trait-resolve.cc | 7 ++- gcc/rust/typecheck/rust-tyty-bounds.cc | 67 +++++++++++++++++++----- gcc/rust/typecheck/rust-tyty-bounds.h | 25 --------- gcc/rust/typecheck/rust-tyty-subst.cc | 4 +- gcc/rust/typecheck/rust-tyty-subst.h | 4 +- gcc/rust/typecheck/rust-tyty.h | 32 +++++++++++ gcc/testsuite/rust/execute/torture/issue-3502.rs | 52 ++++++++++++++++++ 10 files changed, 166 insertions(+), 60 deletions(-) diff --git a/gcc/rust/typecheck/rust-hir-path-probe.cc b/gcc/rust/typecheck/rust-hir-path-probe.cc index cdb2c58588bb..8c3faf76c2c6 100644 --- a/gcc/rust/typecheck/rust-hir-path-probe.cc +++ b/gcc/rust/typecheck/rust-hir-path-probe.cc @@ -346,7 +346,7 @@ PathProbeType::process_associated_trait_for_candidates ( const TyTy::TypeBoundPredicate p (*trait_ref, BoundPolarity::RegularBound, UNDEF_LOCATION); - TyTy::TypeBoundPredicateItem item (&p, trait_item_ref); + TyTy::TypeBoundPredicateItem item (p, trait_item_ref); TyTy::BaseType *trait_item_tyty = item.get_raw_item ()->get_tyty (); if (receiver->get_kind () != TyTy::DYNAMIC) diff --git a/gcc/rust/typecheck/rust-hir-trait-reference.cc b/gcc/rust/typecheck/rust-hir-trait-reference.cc index e32ab5335922..b8150b9209dc 100644 --- a/gcc/rust/typecheck/rust-hir-trait-reference.cc +++ b/gcc/rust/typecheck/rust-hir-trait-reference.cc @@ -106,7 +106,7 @@ TraitItemReference::get_error () const TraitReference::TraitReference ( const HIR::Trait *hir_trait_ref, std::vector<TraitItemReference> item_refs, - std::vector<const TraitReference *> super_traits, + std::vector<TyTy::TypeBoundPredicate> super_traits, std::vector<TyTy::SubstitutionParamMapping> substs) : hir_trait_ref (hir_trait_ref), item_refs (item_refs), super_traits (super_traits) @@ -263,7 +263,8 @@ TraitReference::lookup_hir_trait_item (const HIR::TraitItem &item, bool TraitReference::lookup_trait_item (const std::string &ident, - const TraitItemReference **ref) const + const TraitItemReference **ref, + bool lookup_supers) const { for (auto &item : item_refs) { @@ -274,10 +275,13 @@ TraitReference::lookup_trait_item (const std::string &ident, } } + if (!lookup_supers) + return false; + // lookup super traits for (const auto &super_trait : super_traits) { - bool found = super_trait->lookup_trait_item (ident, ref); + bool found = super_trait.get ()->lookup_trait_item (ident, ref); if (found) return true; } @@ -302,7 +306,7 @@ TraitReference::lookup_trait_item (const std::string &ident, for (const auto &super_trait : super_traits) { const TraitItemReference *res - = super_trait->lookup_trait_item (ident, type); + = super_trait.get ()->lookup_trait_item (ident, type); if (!res->is_error ()) return res; } @@ -330,7 +334,7 @@ TraitReference::get_trait_items_and_supers ( result.push_back (&item); for (const auto &super_trait : super_traits) - super_trait->get_trait_items_and_supers (result); + super_trait.get ()->get_trait_items_and_supers (result); } void @@ -374,7 +378,7 @@ TraitReference::is_equal (const TraitReference &other) const return this_id == other_id; } -const std::vector<const TraitReference *> +std::vector<TyTy::TypeBoundPredicate> TraitReference::get_super_traits () const { return super_traits; @@ -385,10 +389,10 @@ TraitReference::is_object_safe (bool emit_error, location_t locus) const { // https: // doc.rust-lang.org/reference/items/traits.html#object-safety std::vector<const TraitReference *> non_object_super_traits; - for (auto &item : super_traits) + for (auto &super_trait : super_traits) { - if (!item->is_object_safe (false, UNDEF_LOCATION)) - non_object_super_traits.push_back (item); + if (!super_trait.get ()->is_object_safe (false, UNDEF_LOCATION)) + non_object_super_traits.push_back (super_trait.get ()); } std::vector<const Resolver::TraitItemReference *> non_object_safe_items; @@ -434,7 +438,7 @@ TraitReference::satisfies_bound (const TraitReference &reference) const for (const auto &super_trait : super_traits) { - if (super_trait->satisfies_bound (reference)) + if (super_trait.get ()->satisfies_bound (reference)) return true; } diff --git a/gcc/rust/typecheck/rust-hir-trait-reference.h b/gcc/rust/typecheck/rust-hir-trait-reference.h index b35227dcff51..307dca471607 100644 --- a/gcc/rust/typecheck/rust-hir-trait-reference.h +++ b/gcc/rust/typecheck/rust-hir-trait-reference.h @@ -144,7 +144,7 @@ class TraitReference public: TraitReference (const HIR::Trait *hir_trait_ref, std::vector<TraitItemReference> item_refs, - std::vector<const TraitReference *> super_traits, + std::vector<TyTy::TypeBoundPredicate> super_traits, std::vector<TyTy::SubstitutionParamMapping> substs); TraitReference (TraitReference const &other); @@ -196,7 +196,8 @@ public: const TraitItemReference **ref) const; bool lookup_trait_item (const std::string &ident, - const TraitItemReference **ref) const; + const TraitItemReference **ref, + bool lookup_supers = true) const; const TraitItemReference * lookup_trait_item (const std::string &ident, @@ -217,7 +218,7 @@ public: bool is_equal (const TraitReference &other) const; - const std::vector<const TraitReference *> get_super_traits () const; + std::vector<TyTy::TypeBoundPredicate> get_super_traits () const; bool is_object_safe (bool emit_error, location_t locus) const; @@ -230,7 +231,7 @@ public: private: const HIR::Trait *hir_trait_ref; std::vector<TraitItemReference> item_refs; - std::vector<const TraitReference *> super_traits; + std::vector<TyTy::TypeBoundPredicate> super_traits; std::vector<TyTy::SubstitutionParamMapping> trait_substs; }; diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc index 0ed6fa0859e4..71ae7dfe6ab4 100644 --- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc +++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc @@ -266,7 +266,7 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) specified_bounds.push_back (self_hrtb); // look for any - std::vector<const TraitReference *> super_traits; + std::vector<TyTy::TypeBoundPredicate> super_traits; if (trait_reference->has_type_param_bounds ()) { for (auto &bound : trait_reference->get_type_param_bounds ()) @@ -284,7 +284,7 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) return &TraitReference::error_node (); specified_bounds.push_back (predicate); - super_traits.push_back (predicate.get ()); + super_traits.push_back (predicate); } } } @@ -305,8 +305,7 @@ TraitResolver::resolve_trait (HIR::Trait *trait_reference) item_refs.push_back (std::move (trait_item_ref)); } - TraitReference trait_object (trait_reference, item_refs, - std::move (super_traits), + TraitReference trait_object (trait_reference, item_refs, super_traits, std::move (substitutions)); context->insert_trait_reference ( trait_reference->get_mappings ().get_defid (), std::move (trait_object)); diff --git a/gcc/rust/typecheck/rust-tyty-bounds.cc b/gcc/rust/typecheck/rust-tyty-bounds.cc index ffe3c1b4ba35..dc42941da233 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.cc +++ b/gcc/rust/typecheck/rust-tyty-bounds.cc @@ -345,7 +345,8 @@ TypeBoundPredicate::TypeBoundPredicate ( location_t locus) : SubstitutionRef ({}, SubstitutionArgumentMappings::empty (), {}), reference (trait_reference.get_mappings ().get_defid ()), locus (locus), - error_flag (false), polarity (polarity) + error_flag (false), polarity (polarity), + super_traits (trait_reference.get_super_traits ()) { rust_assert (!trait_reference.get_trait_substs ().empty ()); @@ -385,7 +386,8 @@ TypeBoundPredicate::TypeBoundPredicate (mark_is_error) TypeBoundPredicate::TypeBoundPredicate (const TypeBoundPredicate &other) : SubstitutionRef ({}, SubstitutionArgumentMappings::empty (), {}), reference (other.reference), locus (other.locus), - error_flag (other.error_flag), polarity (other.polarity) + error_flag (other.error_flag), polarity (other.polarity), + super_traits (other.super_traits) { substitutions.clear (); for (const auto &p : other.get_substs ()) @@ -455,6 +457,7 @@ TypeBoundPredicate::operator= (const TypeBoundPredicate &other) = SubstitutionArgumentMappings (copied_arg_mappings, {}, other.used_arguments.get_regions (), other.used_arguments.get_locus ()); + super_traits = other.super_traits; return *this; } @@ -521,11 +524,19 @@ TypeBoundPredicate::apply_generic_arguments (HIR::GenericArgs *generic_args, } // now actually perform a substitution - used_arguments = get_mappings_from_generic_args ( + auto args = get_mappings_from_generic_args ( *generic_args, Resolver::TypeCheckContext::get ()->regions_from_generic_args ( *generic_args)); + apply_argument_mappings (args); +} + +void +TypeBoundPredicate::apply_argument_mappings ( + SubstitutionArgumentMappings &arguments) +{ + used_arguments = arguments; error_flag |= used_arguments.is_error (); auto &subst_mappings = used_arguments; for (auto &sub : get_substs ()) @@ -549,6 +560,14 @@ TypeBoundPredicate::apply_generic_arguments (HIR::GenericArgs *generic_args, const auto item_ref = item.get_raw_item (); item_ref->associated_type_set (type); } + + for (auto &super_trait : super_traits) + { + auto adjusted + = super_trait.adjust_mappings_for_this (used_arguments, + true /*trait mode*/); + super_trait.apply_argument_mappings (adjusted); + } } bool @@ -564,34 +583,56 @@ TypeBoundPredicate::lookup_associated_item (const std::string &search) const { auto trait_ref = get (); const Resolver::TraitItemReference *trait_item_ref = nullptr; - if (!trait_ref->lookup_trait_item (search, &trait_item_ref)) - return TypeBoundPredicateItem::error (); + if (trait_ref->lookup_trait_item (search, &trait_item_ref, + false /*lookup supers*/)) + return TypeBoundPredicateItem (*this, trait_item_ref); + + for (auto &super_trait : super_traits) + { + auto lookup = super_trait.lookup_associated_item (search); + if (!lookup.is_error ()) + return lookup; + } - return TypeBoundPredicateItem (this, trait_item_ref); + return TypeBoundPredicateItem::error (); } TypeBoundPredicateItem::TypeBoundPredicateItem ( - const TypeBoundPredicate *parent, + const TypeBoundPredicate parent, const Resolver::TraitItemReference *trait_item_ref) : parent (parent), trait_item_ref (trait_item_ref) {} +TypeBoundPredicateItem::TypeBoundPredicateItem ( + const TypeBoundPredicateItem &other) + : parent (other.parent), trait_item_ref (other.trait_item_ref) +{} + +TypeBoundPredicateItem & +TypeBoundPredicateItem::operator= (const TypeBoundPredicateItem &other) +{ + parent = other.parent; + trait_item_ref = other.trait_item_ref; + + return *this; +} + TypeBoundPredicateItem TypeBoundPredicateItem::error () { - return TypeBoundPredicateItem (nullptr, nullptr); + return TypeBoundPredicateItem (TypeBoundPredicate::error (), nullptr); } bool TypeBoundPredicateItem::is_error () const { - return parent == nullptr || trait_item_ref == nullptr; + return parent.is_error () || trait_item_ref == nullptr; } const TypeBoundPredicate * TypeBoundPredicateItem::get_parent () const { - return parent; + return &parent; } TypeBoundPredicateItem @@ -605,7 +646,7 @@ BaseType * TypeBoundPredicateItem::get_tyty_for_receiver (const TyTy::BaseType *receiver) { TyTy::BaseType *trait_item_tyty = get_raw_item ()->get_tyty (); - if (parent->get_substitution_arguments ().is_empty ()) + if (parent.get_substitution_arguments ().is_empty ()) return trait_item_tyty; const Resolver::TraitItemReference *tref = get_raw_item (); @@ -614,7 +655,7 @@ TypeBoundPredicateItem::get_tyty_for_receiver (const TyTy::BaseType *receiver) return trait_item_tyty; // set up the self mapping - SubstitutionArgumentMappings gargs = parent->get_substitution_arguments (); + SubstitutionArgumentMappings gargs = parent.get_substitution_arguments (); rust_assert (!gargs.is_empty ()); // setup the adjusted mappings @@ -746,7 +787,7 @@ TypeBoundPredicate::get_associated_type_items () == Resolver::TraitItemReference::TraitItemType::TYPE; if (is_associated_type) { - TypeBoundPredicateItem item (this, &trait_item); + TypeBoundPredicateItem item (*this, &trait_item); items.push_back (std::move (item)); } } diff --git a/gcc/rust/typecheck/rust-tyty-bounds.h b/gcc/rust/typecheck/rust-tyty-bounds.h index bc63a6d412a7..65a6876361b9 100644 --- a/gcc/rust/typecheck/rust-tyty-bounds.h +++ b/gcc/rust/typecheck/rust-tyty-bounds.h @@ -34,31 +34,6 @@ namespace TyTy { class BaseType; class TypeBoundPredicate; -class TypeBoundPredicateItem -{ -public: - TypeBoundPredicateItem (const TypeBoundPredicate *parent, - const Resolver::TraitItemReference *trait_item_ref); - - static TypeBoundPredicateItem error (); - - bool is_error () const; - - BaseType *get_tyty_for_receiver (const TyTy::BaseType *receiver); - - const Resolver::TraitItemReference *get_raw_item () const; - - bool needs_implementation () const; - - const TypeBoundPredicate *get_parent () const; - - location_t get_locus () const; - -private: - const TypeBoundPredicate *parent; - const Resolver::TraitItemReference *trait_item_ref; -}; - class TypeBoundsMappings { protected: diff --git a/gcc/rust/typecheck/rust-tyty-subst.cc b/gcc/rust/typecheck/rust-tyty-subst.cc index 26afe1bd4914..fb94c14c1560 100644 --- a/gcc/rust/typecheck/rust-tyty-subst.cc +++ b/gcc/rust/typecheck/rust-tyty-subst.cc @@ -788,7 +788,7 @@ SubstitutionRef::infer_substitions (location_t locus) SubstitutionArgumentMappings SubstitutionRef::adjust_mappings_for_this ( - SubstitutionArgumentMappings &mappings) + SubstitutionArgumentMappings &mappings, bool trait_mode) { std::vector<SubstitutionArg> resolved_mappings; for (size_t i = 0; i < substitutions.size (); i++) @@ -816,7 +816,7 @@ SubstitutionRef::adjust_mappings_for_this ( } bool ok = !arg.is_error (); - if (ok) + if (ok || (trait_mode && i == 0)) { SubstitutionArg adjusted (&subst, arg.get_tyty ()); resolved_mappings.push_back (std::move (adjusted)); diff --git a/gcc/rust/typecheck/rust-tyty-subst.h b/gcc/rust/typecheck/rust-tyty-subst.h index 4f0fab37b44f..86bc08bb843f 100644 --- a/gcc/rust/typecheck/rust-tyty-subst.h +++ b/gcc/rust/typecheck/rust-tyty-subst.h @@ -253,6 +253,7 @@ private: bool error_flag; }; +class TypeBoundPredicateItem; class SubstitutionRef { public: @@ -319,7 +320,8 @@ public: // we have bindings for X Y Z and need to propagate the binding Y,Z into Foo // Which binds to A,B SubstitutionArgumentMappings - adjust_mappings_for_this (SubstitutionArgumentMappings &mappings); + adjust_mappings_for_this (SubstitutionArgumentMappings &mappings, + bool trait_mode = false); // Are the mappings here actually bound to this type. For example imagine the // case: diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 4cf472217125..a5840544de42 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -545,6 +545,8 @@ public: void apply_generic_arguments (HIR::GenericArgs *generic_args, bool has_associated_self); + void apply_argument_mappings (SubstitutionArgumentMappings &arguments); + bool contains_item (const std::string &search) const; TypeBoundPredicateItem @@ -587,6 +589,36 @@ private: location_t locus; bool error_flag; BoundPolarity polarity; + std::vector<TyTy::TypeBoundPredicate> super_traits; +}; + +class TypeBoundPredicateItem +{ +public: + TypeBoundPredicateItem (const TypeBoundPredicate parent, + const Resolver::TraitItemReference *trait_item_ref); + + TypeBoundPredicateItem (const TypeBoundPredicateItem &other); + + TypeBoundPredicateItem &operator= (const TypeBoundPredicateItem &other); + + static TypeBoundPredicateItem error (); + + bool is_error () const; + + BaseType *get_tyty_for_receiver (const TyTy::BaseType *receiver); + + const Resolver::TraitItemReference *get_raw_item () const; + + bool needs_implementation () const; + + const TypeBoundPredicate *get_parent () const; + + location_t get_locus () const; + +private: + TypeBoundPredicate parent; + const Resolver::TraitItemReference *trait_item_ref; }; // https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.VariantDef.html diff --git a/gcc/testsuite/rust/execute/torture/issue-3502.rs b/gcc/testsuite/rust/execute/torture/issue-3502.rs new file mode 100644 index 000000000000..f07a126b66a0 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-3502.rs @@ -0,0 +1,52 @@ +/* { dg-output "parent 123\r*\nchild\r*\n" } */ +extern "C" { + fn printf(s: *const i8, ...); +} + +#[lang = "sized"] +pub trait Sized {} + +struct Foo { + my_int: u32, + // { dg-warning "field is never read: .my_int." "" { target *-*-* } .-1 } +} + +trait Parent<T> { + fn parent(&self) -> T; +} + +trait Child: Parent<u32> { + fn child(&self); +} + +impl Parent<u32> for Foo { + fn parent(&self) -> u32 { + unsafe { + let parent = "parent %u\n\0"; + let msg = parent as *const str; + printf(msg as *const i8, self.my_int); + return self.my_int; + } + } +} + +impl Child for Foo { + fn child(&self) { + let _ = self; + unsafe { + let child = "child\n\0"; + let msg = child as *const str; + printf(msg as *const i8); + } + } +} + +pub fn main() -> i32 { + let a = Foo { my_int: 123 }; + let b: &dyn Child = &a; + + b.parent(); + b.child(); + + 0 +}