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