From: Utkarsh Bahuguna <[email protected]>

Associated types that use the impl's params, like type Searcher = Srch<C>,
kept the C instead of the real type, so codegen crashed on it.

Fixes Rust-GCC/gccrs#5022

Assisted-by: Claude Opus (Anthropic)

gcc/rust/ChangeLog:

        * typecheck/rust-hir-trait-resolve.cc
        (AssociatedImplTrait::bind_impl_for_projection): Fix the ref of
        bound args.
        * typecheck/rust-hir-type-check-type.cc
        (TypeCheckType::visit (QualifiedPathInType)): Give the result its
        own ref.
        * typecheck/rust-type-util.cc (normalize_projection): Check the
        impl first if it hasn't been yet.

gcc/testsuite/ChangeLog:

        * rust/compile/issues/issue-5022.rs: New test.
        * rust/compile/issues/issue-5022-2.rs: New test.
        * rust/execute/torture/issue-5022.rs: New test.

Signed-off-by: Utkarsh Bahuguna <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/52a684bea62ea5d0832beaec0904467d4b1574f5

The commit has been mentioned in the following issue(s):
 - Rust-GCC/gccrs#5022: https://github.com/Rust-GCC/gccrs/issues/5022

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/5038

 gcc/rust/typecheck/rust-hir-trait-resolve.cc  |  8 +++
 .../typecheck/rust-hir-type-check-type.cc     |  5 ++
 gcc/rust/typecheck/rust-type-util.cc          | 12 +++-
 .../rust/compile/issues/issue-5022-2.rs       | 57 +++++++++++++++++++
 .../rust/compile/issues/issue-5022.rs         | 51 +++++++++++++++++
 .../rust/execute/torture/issue-5022.rs        | 30 ++++++++++
 6 files changed, 160 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/issues/issue-5022-2.rs
 create mode 100644 gcc/testsuite/rust/compile/issues/issue-5022.rs
 create mode 100644 gcc/testsuite/rust/execute/torture/issue-5022.rs

diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc 
b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
index 4393333d1..2137e6ed3 100644
--- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc
+++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
@@ -738,6 +738,14 @@ AssociatedImplTrait::bind_impl_for_projection 
(TyTy::ProjectionType &proj,
       bool ok = context->lookup_type (it->second, &r);
       if (!ok)
        continue;
+
+      // r can keep the ref of whatever it was unified with, which may not
+      // map back to r, so point it at the infer var that does
+      if (r->get_ref () != it->second)
+       {
+         r = r->clone ();
+         r->set_ref (it->second);
+       }
       resolved_args.emplace_back (&p, r);
     }
 
diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.cc 
b/gcc/rust/typecheck/rust-hir-type-check-type.cc
index d4c2c3588..135cbc290 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-type.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-type.cc
@@ -265,6 +265,11 @@ TypeCheckType::visit (HIR::QualifiedPathInType &path)
   else
     translated = rebased_item;
 
+  // like a TypePath, give the result its own ref so &T and *T look up the
+  // substituted type and not the one the impl declared
+  translated = translated->clone ();
+  translated->set_ref (path.get_mappings ().get_hirid ());
+
   // turbo-fish segment path::<ty>
   if (item_seg.get_type () == HIR::TypePathSegment::SegmentType::GENERIC)
     {
diff --git a/gcc/rust/typecheck/rust-type-util.cc 
b/gcc/rust/typecheck/rust-type-util.cc
index bdfab3a0c..737f559c9 100644
--- a/gcc/rust/typecheck/rust-type-util.cc
+++ b/gcc/rust/typecheck/rust-type-util.cc
@@ -780,10 +780,16 @@ normalize_projection (TyTy::ProjectionType *proj, 
location_t locus,
                  if (query_type (impl_item->get_impl_mappings ().get_hirid (),
                                  &result))
                    {
+                     // the impl might not have been checked yet, e.g. when a
+                     // bounds probe resolves a struct field before it
+                     HirId impl_id = impl_block->get_mappings ().get_hirid ();
                      AssociatedImplTrait *associated = nullptr;
-                     if (ctx->lookup_associated_trait_impl (
-                           impl_block->get_mappings ().get_hirid (),
-                           &associated)
+                     if (!ctx->lookup_associated_trait_impl (impl_id,
+                                                             &associated))
+                       TypeCheckItem::Resolve (*impl_block);
+
+                     if (ctx->lookup_associated_trait_impl (impl_id,
+                                                            &associated)
                          && associated != nullptr)
                        {
                          auto mapping
diff --git a/gcc/testsuite/rust/compile/issues/issue-5022-2.rs 
b/gcc/testsuite/rust/compile/issues/issue-5022-2.rs
new file mode 100644
index 000000000..6ba18d6b7
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issues/issue-5022-2.rs
@@ -0,0 +1,57 @@
+// { dg-additional-options "-w" }
+#![feature(no_core, lang_items)]
+#![no_core]
+
+// Rust-GCC/gccrs#5022: same as issue-5022.rs, but the bound check in g
+// resolved W's field before the Pattern impl had been checked, so the
+// impl's params were never bound.
+
+#[lang = "sized"]
+pub trait Sized {}
+
+pub mod clone {
+    #[lang = "clone"]
+    pub trait Clone: crate::Sized {
+        fn clone(&self) -> Self;
+    }
+}
+
+impl clone::Clone for u32 {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+fn need<X: clone::Clone>(_x: X) {}
+
+pub fn g(x: u32) {
+    need(x);
+}
+
+pub trait Pattern {
+    type Searcher;
+}
+
+pub struct Pat<C>(C);
+
+pub struct Srch<C> {
+    c: *const C,
+}
+
+impl<C> Pattern for Pat<C> {
+    type Searcher = Srch<C>;
+}
+
+impl<C> clone::Clone for Srch<C> {
+    fn clone(&self) -> Self {
+        Srch { c: self.c }
+    }
+}
+
+pub struct W(<Pat<u8> as Pattern>::Searcher);
+
+impl clone::Clone for W {
+    fn clone(&self) -> Self {
+        W(clone::Clone::clone(&self.0))
+    }
+}
diff --git a/gcc/testsuite/rust/compile/issues/issue-5022.rs 
b/gcc/testsuite/rust/compile/issues/issue-5022.rs
new file mode 100644
index 000000000..514cc7cf8
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issues/issue-5022.rs
@@ -0,0 +1,51 @@
+// { dg-additional-options "-w" }
+#![feature(no_core, lang_items)]
+#![no_core]
+
+// Rust-GCC/gccrs#5022: a projection to an impl type that uses the impl's
+// params, like <Pat<u8> as Pattern>::Searcher with Searcher = Srch<C>,
+// kept C instead of u8 and codegen ICEd on it.
+
+#[lang = "sized"]
+pub trait Sized {}
+
+pub mod clone {
+    #[lang = "clone"]
+    pub trait Clone: crate::Sized {
+        fn clone(&self) -> Self;
+    }
+}
+
+pub trait Pattern {
+    type Searcher;
+}
+
+pub struct Pat<C>(C);
+
+pub struct Srch<C> {
+    c: *const C,
+}
+
+impl<C> Pattern for Pat<C> {
+    type Searcher = Srch<C>;
+}
+
+impl<C> clone::Clone for Srch<C> {
+    fn clone(&self) -> Self {
+        Srch { c: self.c }
+    }
+}
+
+pub fn by_value(_s: <Pat<u8> as Pattern>::Searcher) {}
+
+pub fn by_ref(s: &<Pat<u8> as Pattern>::Searcher) {
+    let _c = clone::Clone::clone(s);
+}
+
+pub struct W(<Pat<u8> as Pattern>::Searcher);
+
+impl clone::Clone for W {
+    fn clone(&self) -> Self {
+        W(clone::Clone::clone(&self.0))
+    }
+}
diff --git a/gcc/testsuite/rust/execute/torture/issue-5022.rs 
b/gcc/testsuite/rust/execute/torture/issue-5022.rs
new file mode 100644
index 000000000..3edf54957
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/issue-5022.rs
@@ -0,0 +1,30 @@
+#![feature(no_core, lang_items)]
+#![no_core]
+
+// Rust-GCC/gccrs#5022: reading through a projection to a generic impl type
+
+#[lang = "sized"]
+pub trait Sized {}
+
+pub trait Pattern {
+    type Searcher;
+}
+
+pub struct Pat<C>(C);
+
+pub struct Srch<C> {
+    c: (C,),
+}
+
+impl<C> Pattern for Pat<C> {
+    type Searcher = Srch<C>;
+}
+
+fn get(s: &<Pat<i32> as Pattern>::Searcher) -> i32 {
+    s.c.0
+}
+
+fn main() -> i32 {
+    let s = Srch { c: (7,) };
+    get(&s) - 7
+}

base-commit: 73d92a68d41785df58d1b356a57b78a80d3142e9
-- 
2.56.0

Reply via email to