]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: support generic super traits recursively
authorPhilip Herron <herron.philip@googlemail.com>
Sat, 22 Mar 2025 17:40:48 +0000 (17:40 +0000)
committerArthur Cohen <arthur.cohen@embecosm.com>
Mon, 24 Mar 2025 12:30:44 +0000 (13:30 +0100)
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.philip@googlemail.com>
gcc/rust/typecheck/rust-hir-path-probe.cc
gcc/rust/typecheck/rust-hir-trait-reference.cc
gcc/rust/typecheck/rust-hir-trait-reference.h
gcc/rust/typecheck/rust-hir-trait-resolve.cc
gcc/rust/typecheck/rust-tyty-bounds.cc
gcc/rust/typecheck/rust-tyty-bounds.h
gcc/rust/typecheck/rust-tyty-subst.cc
gcc/rust/typecheck/rust-tyty-subst.h
gcc/rust/typecheck/rust-tyty.h
gcc/testsuite/rust/execute/torture/issue-3502.rs [new file with mode: 0644]

index 0465d2f5786f5191371b34b34f2e283ef3fb4c5e..32e23997cb77a40f37d5863d5d6fc01fc3688ae7 100644 (file)
@@ -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)
index 2ac086cf9313940d84112a44c3dc43e452e30ca3..83985f009893bb47ce44a58cfea5e843f0b8a355 100644 (file)
@@ -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;
     }
 
index 419703353752940364163a2e46e0851a392a4e61..6a570ed0fdbea799c220f0ccb28e53fef9253830 100644 (file)
@@ -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;
 };
 
index 58a0f0149265eabf076af1bed0e543334cdddc02..c07425d48b7a8b3495f50ec52960d6b2eff519f0 100644 (file)
@@ -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));
index d70078792286e2a8064aec59c51929c9f99996ea..65f24c0aa2ac93499f5b696e7f90dc9432bb7f31 100644 (file)
@@ -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));
        }
     }
index be309b2d5a8b2764a04be3a163d413f0deb2d5c6..6392af1fed4f1a5f9cf64bd39fa4bf207f184c32 100644 (file)
@@ -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:
index eb9e9dc9278399fc959251875421a1a96083a218..95f18b9d29fc3d4a9a12c406387713606113aa94 100644 (file)
@@ -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));
index ab535024bceee266c2b7a31d10389cf2006d18cb..b8e928d60f03fef1dbd221f43bf3150a65b02c9d 100644 (file)
@@ -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:
index def7cb2169ca6fe9ad5ce281faef5303d6be408e..0bfd29d98bb5f9c3d1fcb00d19f4adc696064730 100644 (file)
@@ -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 (file)
index 0000000..f07a126
--- /dev/null
@@ -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
+}