Skip to content

Commit

Permalink
gccrs: Fix bad handling for recursive type query
Browse files Browse the repository at this point in the history
When resolving a type like this which is generic it causes the argument
substitution to go through bounds checking which is expected. But this
can call a type bounds probe which again calls a type query which will be
on the Impl Type on an impl block which can result in a recursive type
query which does eventually get caught and errors correctly. But this then
triggers some old error diagnositcs which are not valid error codes but old
error messages we used to catch simple errors very early on which do not
apply for this senario.

Fixes Rust-GCC#2905

gcc/rust/ChangeLog:

	* typecheck/rust-hir-type-check-item.cc (TypeCheckItem::resolve_impl_block_substitutions):
	dont check for unconstrained when the self is not resolved
	* typecheck/rust-hir-type-check-type.cc (TypeCheckType::resolve_root_path):
	remove bad debug error diagnostic
	* typecheck/rust-tyty-subst.cc: likewise

gcc/testsuite/ChangeLog:

	* rust/compile/nr2/exclude: nr2 cant handle this
	* rust/compile/issue-2905-1.rs: New test.
	* rust/compile/issue-2905-2.rs: New test.

Signed-off-by: Philip Herron <[email protected]>
  • Loading branch information
philberty committed Nov 12, 2024
1 parent b0d6abb commit 680ad46
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 8 deletions.
8 changes: 8 additions & 0 deletions gcc/rust/typecheck/rust-hir-type-check-item.cc
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,14 @@ TypeCheckItem::resolve_impl_block_substitutions (HIR::ImplBlock &impl_block,
}

TyTy::BaseType *self = TypeCheckType::Resolve (impl_block.get_type ().get ());
if (self->is<TyTy::ErrorType> ())
{
// we cannot check for unconstrained type arguments when the Self type is
// not resolved it will just add extra errors that dont help as well as
// the case where this could just be a recursive type query that should
// fail and will work later on anyway
return {substitutions, region_constraints};
}

// inherit the bounds
if (!specified_bound.is_error ())
Expand Down
7 changes: 2 additions & 5 deletions gcc/rust/typecheck/rust-hir-type-check-type.cc
Original file line number Diff line number Diff line change
Expand Up @@ -426,11 +426,8 @@ TypeCheckType::resolve_root_path (HIR::TypePath &path, size_t *offset,
if (!query_type (ref, &lookup))
{
if (is_root)
{
rust_error_at (seg->get_locus (),
"failed to resolve root segment");
return new TyTy::ErrorType (path.get_mappings ().get_hirid ());
}
return new TyTy::ErrorType (path.get_mappings ().get_hirid ());

return root_tyty;
}

Expand Down
3 changes: 0 additions & 3 deletions gcc/rust/typecheck/rust-tyty-subst.cc
Original file line number Diff line number Diff line change
Expand Up @@ -634,8 +634,6 @@ SubstitutionRef::get_mappings_from_generic_args (
if (resolved == nullptr
|| resolved->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (binding.get_locus (),
"failed to resolve type arguments");
return SubstitutionArgumentMappings::error ();
}

Expand Down Expand Up @@ -701,7 +699,6 @@ SubstitutionRef::get_mappings_from_generic_args (
BaseType *resolved = Resolver::TypeCheckType::Resolve (arg.get ());
if (resolved == nullptr || resolved->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (args.get_locus (), "failed to resolve type arguments");
return SubstitutionArgumentMappings::error ();
}

Expand Down
27 changes: 27 additions & 0 deletions gcc/testsuite/rust/compile/issue-2905-1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#![feature(lang_items)]

#[lang = "sized"]
trait Sized {}

pub struct A<T>(T);

pub trait B {
type C;
}

// ------
// swap these two items

impl B for i32 {
type C = Weird<i32>;
}

pub struct Weird<T>(A<(T,)>);

// ------

trait Foo {}

impl Foo for Weird<i32> {}

fn main() {}
136 changes: 136 additions & 0 deletions gcc/testsuite/rust/compile/issue-2905-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// { dg-options "-w" }
#![feature(intrinsics)]
#![feature(lang_items)]

#[lang = "sized"]
trait Sized {}

extern "rust-intrinsic" {
fn transmute<T, U>(_: T) -> U;
fn offset<T>(src: *const T, offset: isize) -> *const T;
}

pub mod core {
pub mod marker {
#[lang = "phantom_data"]
pub struct PhantomData<T>;
}

pub mod slice {
use core::marker::PhantomData;
use core::option::Option;

impl<T> core::iter::IntoIterator for &[T] {
type Item = &T;
type IntoIter = Weird<T>;

fn into_iter(self) -> Weird<T> {
self.iter()
}
}

pub struct Weird<T> {
ptr: *const T, // should be NonNull<T> but here it does not matter
end: *const T,
_marker: PhantomData<&T>,
}

impl<T> Weird<T> {
pub(super) fn new(slice: &[T]) -> Self {
let ptr = slice.as_ptr();
// SAFETY: Similar to `IterMut::new`.
unsafe {
// should be: ptr.add(slice.len())
let end = transmute::<*const T, usize>(ptr) + slice.len(); // TODO(Arthur): Missing `* size_of::<T>()`?
let end = transmute::<usize, *const T>(end);

Self {
ptr,
end,
_marker: PhantomData,
}
}
}

fn is_empty(&self) -> bool {
self.ptr == self.end
}

fn next_unchecked(&mut self) -> *const T {
let old = self.ptr;

self.ptr = unsafe { offset(self.ptr, 1) };

old
}
}

trait Foo {}

impl<T> Foo for Weird<T> {}

// impl<T> core::iter::Iterator for Iter<T> {
// type Item = &T;

// fn next(&mut self) -> Option<&T> {
// if self.is_empty() {
// Option::None
// } else {
// Option::Some(&*self.next_unchecked())
// }
// }
// }

union Repr<T> {
pub(crate) rust: *const [T],
rust_mut: *mut [T],
pub(crate) raw: FatPtr<T>,
}

struct FatPtr<T> {
data: *const T,
pub(crate) len: usize,
}

impl<T> [T] {
pub fn iter(&self) -> Weird<T> {
Weird::new(self)
}

pub fn as_ptr(&self) -> *const T {
self as *const [T] as *const T
}

pub fn len(&self) -> usize {
unsafe { Repr { rust: self }.raw.len }
}
}
}

pub mod iter {
use option::Option;

pub trait IntoIterator {
type Item;

type IntoIter: Iterator<Item = Self::Item>;

fn into_iter(self) -> Self::IntoIter;
}

pub trait Iterator {
type Item;

fn next(&mut self) -> Option<Self::Item>;
}
}

pub mod option {
pub enum Option<T> {
Some(T),
None,
}
}
}

fn main() {}
2 changes: 2 additions & 0 deletions gcc/testsuite/rust/compile/nr2/exclude
Original file line number Diff line number Diff line change
Expand Up @@ -217,4 +217,6 @@ issue-2323.rs
issue-2953-1.rs
issue-2953-2.rs
issue-1773.rs
issue-2905-1.rs
issue-2905-2.rs
# please don't delete the trailing newline

0 comments on commit 680ad46

Please sign in to comment.