]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: fix unconstrained generics check to handle recursive generics
authorPhilip Herron <herron.philip@googlemail.com>
Thu, 13 Feb 2025 14:09:17 +0000 (14:09 +0000)
committerArthur Cohen <arthur.cohen@embecosm.com>
Mon, 24 Mar 2025 12:07:05 +0000 (13:07 +0100)
Generics can be constrained within other generic types so this check needs
to be recursive.

Fixes Rust-GCC#3031

gcc/rust/ChangeLog:

* typecheck/rust-hir-type-check-base.cc (walk_types_to_constrain): recursive walker
* typecheck/rust-tyty.cc (BaseType::get_subst_argument_mappings): new helper
* typecheck/rust-tyty.h: prototype

gcc/testsuite/ChangeLog:

* rust/compile/issue-3031.rs: New test.

Signed-off-by: Philip Herron <herron.philip@googlemail.com>
gcc/rust/typecheck/rust-hir-type-check-base.cc
gcc/rust/typecheck/rust-tyty.cc
gcc/rust/typecheck/rust-tyty.h
gcc/testsuite/rust/compile/issue-3031.rs [new file with mode: 0644]

index 34f629c051939785df255743fd6d9f2dd83dd1eb..8f2471d54d551b5d080314157dbb9559dd41a67a 100644 (file)
@@ -31,6 +31,26 @@ TypeCheckBase::TypeCheckBase ()
     context (TypeCheckContext::get ())
 {}
 
+static void
+walk_types_to_constrain (std::set<HirId> &constrained_symbols,
+                        const TyTy::SubstitutionArgumentMappings &constraints)
+{
+  for (const auto &c : constraints.get_mappings ())
+    {
+      const TyTy::BaseType *arg = c.get_tyty ();
+      if (arg != nullptr)
+       {
+         const TyTy::BaseType *p = arg->get_root ();
+         constrained_symbols.insert (p->get_ty_ref ());
+         if (p->has_substitutions_defined ())
+           {
+             walk_types_to_constrain (constrained_symbols,
+                                      p->get_subst_argument_mappings ());
+           }
+       }
+    }
+}
+
 bool
 TypeCheckBase::check_for_unconstrained (
   const std::vector<TyTy::SubstitutionParamMapping> &params_to_constrain,
@@ -52,28 +72,14 @@ TypeCheckBase::check_for_unconstrained (
       HirId ref = p.get_param_ty ()->get_ref ();
       symbols_to_constrain.insert (ref);
       symbol_to_location.insert ({ref, p.get_param_locus ()});
+
+      rust_debug_loc (p.get_param_locus (), "XX constrain THIS");
     }
 
   // set up the set of constrained symbols
   std::set<HirId> constrained_symbols;
-  for (const auto &c : constraint_a.get_mappings ())
-    {
-      const TyTy::BaseType *arg = c.get_tyty ();
-      if (arg != nullptr)
-       {
-         const TyTy::BaseType *p = arg->get_root ();
-         constrained_symbols.insert (p->get_ty_ref ());
-       }
-    }
-  for (const auto &c : constraint_b.get_mappings ())
-    {
-      const TyTy::BaseType *arg = c.get_tyty ();
-      if (arg != nullptr)
-       {
-         const TyTy::BaseType *p = arg->get_root ();
-         constrained_symbols.insert (p->get_ty_ref ());
-       }
-    }
+  walk_types_to_constrain (constrained_symbols, constraint_a);
+  walk_types_to_constrain (constrained_symbols, constraint_b);
 
   const auto root = reference->get_root ();
   if (root->get_kind () == TyTy::TypeKind::PARAM)
index 8f388120a41c7a67bb4d7ab3f5615294336ff901..fe4b8fca1391892b061eeb73cabc4186843ae812 100644 (file)
@@ -888,6 +888,48 @@ BaseType::needs_generic_substitutions () const
   return false;
 }
 
+const SubstitutionArgumentMappings &
+BaseType::get_subst_argument_mappings () const
+{
+  static auto empty = SubstitutionArgumentMappings::empty ();
+  const TyTy::BaseType *x = destructure ();
+  switch (x->get_kind ())
+    {
+      case PROJECTION: {
+       const auto &p = *static_cast<const ProjectionType *> (x);
+       const auto &ref = static_cast<const SubstitutionRef &> (p);
+       return ref.get_substitution_arguments ();
+      }
+      break;
+
+      case FNDEF: {
+       const auto &fn = *static_cast<const FnType *> (x);
+       const auto &ref = static_cast<const SubstitutionRef &> (fn);
+       return ref.get_substitution_arguments ();
+      }
+      break;
+
+      case ADT: {
+       const auto &adt = *static_cast<const ADTType *> (x);
+       const auto &ref = static_cast<const SubstitutionRef &> (adt);
+       return ref.get_substitution_arguments ();
+      }
+      break;
+
+      case CLOSURE: {
+       const auto &closure = *static_cast<const ClosureType *> (x);
+       const auto &ref = static_cast<const SubstitutionRef &> (closure);
+       return ref.get_substitution_arguments ();
+      }
+      break;
+
+    default:
+      return empty;
+    }
+
+  return empty;
+}
+
 // InferType
 
 InferType::InferType (HirId ref, InferTypeKind infer_kind, TypeHint hint,
index 93c4a15a4607aa057fffef72cc629270f44e6f69..504a14e3773b8241ce30c71743c76dfb6ea4bd97 100644 (file)
@@ -174,6 +174,7 @@ public:
 
   bool has_substitutions_defined () const;
   bool needs_generic_substitutions () const;
+  const SubstitutionArgumentMappings &get_subst_argument_mappings () const;
 
   std::string mangle_string () const
   {
diff --git a/gcc/testsuite/rust/compile/issue-3031.rs b/gcc/testsuite/rust/compile/issue-3031.rs
new file mode 100644 (file)
index 0000000..33f5bf0
--- /dev/null
@@ -0,0 +1,15 @@
+#![feature(no_core)]
+#![feature(lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+trait A<T: ?Sized> {}
+
+struct Cell<X> {
+    // { dg-warning "struct is never constructed" "" { target *-*-* } .-1 }
+    x: X,
+}
+
+impl<T, U> A<Cell<U>> for Cell<T> where T: A<U> {}