diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-08-05 13:38:37 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-05 13:38:37 +0000 |
commit | 7beea479c5a1e7e415223f3fbd4e16c20c3214ec (patch) | |
tree | d0ad3824e02135310865254787603c99b27224f7 /gcc | |
parent | 8725e324aad3eac0df074e5f0a494b5e3f332a31 (diff) | |
parent | c86ac620c2bdb852b8078f37b898ab40d96ec0b0 (diff) | |
download | gcc-7beea479c5a1e7e415223f3fbd4e16c20c3214ec.zip gcc-7beea479c5a1e7e415223f3fbd4e16c20c3214ec.tar.gz gcc-7beea479c5a1e7e415223f3fbd4e16c20c3214ec.tar.bz2 |
Merge #1437
1437: Array index access does not need to unsize to a slice for access r=philberty a=philberty
When we define the core code for SliceIndex access its possible for an
array to be fully coerced into a slice DST and follow the normal slice
index access which removes support for GCC -Warray-index checks and
generates unnessecary code for array access.
Fixes #1436
Co-authored-by: Philip Herron <philip.herron@embecosm.com>
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/rust/typecheck/rust-hir-type-check-expr.cc | 63 | ||||
-rw-r--r-- | gcc/testsuite/rust/compile/usize1.rs | 2 | ||||
-rw-r--r-- | gcc/testsuite/rust/execute/torture/issue-1436.rs | 172 |
3 files changed, 209 insertions, 28 deletions
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc index 9c31284..ff1165d 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc @@ -250,6 +250,35 @@ TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr) if (index_expr_ty->get_kind () == TyTy::TypeKind::ERROR) return; + // first attempt to use direct array index logic + auto direct_array_expr_ty = array_expr_ty; + if (direct_array_expr_ty->get_kind () == TyTy::TypeKind::REF) + { + // lets try and deref it since rust allows this + auto ref = static_cast<TyTy::ReferenceType *> (direct_array_expr_ty); + auto base = ref->get_base (); + if (base->get_kind () == TyTy::TypeKind::ARRAY) + direct_array_expr_ty = base; + } + + TyTy::BaseType *size_ty; + bool ok = context->lookup_builtin ("usize", &size_ty); + rust_assert (ok); + + bool maybe_simple_array_access = index_expr_ty->can_eq (size_ty, false); + if (maybe_simple_array_access + && direct_array_expr_ty->get_kind () == TyTy::TypeKind::ARRAY) + { + auto resolved_index_expr = size_ty->unify (index_expr_ty); + if (resolved_index_expr->get_kind () == TyTy::TypeKind::ERROR) + return; + + TyTy::ArrayType *array_type + = static_cast<TyTy::ArrayType *> (direct_array_expr_ty); + infered = array_type->get_element_type ()->clone (); + return; + } + // is this a case of core::ops::index? auto lang_item_type = Analysis::RustLangItem::ItemType::INDEX; bool operator_overloaded @@ -266,33 +295,13 @@ TypeCheckExpr::visit (HIR::ArrayIndexExpr &expr) return; } - if (array_expr_ty->get_kind () == TyTy::TypeKind::REF) - { - // lets try and deref it since rust allows this - auto ref = static_cast<TyTy::ReferenceType *> (array_expr_ty); - auto base = ref->get_base (); - if (base->get_kind () == TyTy::TypeKind::ARRAY) - array_expr_ty = base; - } - - if (array_expr_ty->get_kind () != TyTy::TypeKind::ARRAY) - { - rust_error_at (expr.get_index_expr ()->get_locus (), - "expected an ArrayType got [%s]", - array_expr_ty->as_string ().c_str ()); - return; - } - - TyTy::BaseType *size_ty; - bool ok = context->lookup_builtin ("usize", &size_ty); - rust_assert (ok); - - auto resolved_index_expr = size_ty->unify (index_expr_ty); - if (resolved_index_expr->get_kind () == TyTy::TypeKind::ERROR) - return; - - TyTy::ArrayType *array_type = static_cast<TyTy::ArrayType *> (array_expr_ty); - infered = array_type->get_element_type ()->clone (); + // error[E0277]: the type `[{integer}]` cannot be indexed by `u32` + RichLocation r (expr.get_locus ()); + r.add_range (expr.get_array_expr ()->get_locus ()); + r.add_range (expr.get_index_expr ()->get_locus ()); + rust_error_at (r, "the type %<%s%> cannot be indexed by %<%s%>", + array_expr_ty->get_name ().c_str (), + index_expr_ty->get_name ().c_str ()); } void diff --git a/gcc/testsuite/rust/compile/usize1.rs b/gcc/testsuite/rust/compile/usize1.rs index c7e746b..b1c8fe8 100644 --- a/gcc/testsuite/rust/compile/usize1.rs +++ b/gcc/testsuite/rust/compile/usize1.rs @@ -1,6 +1,6 @@ fn main() { let a = [1, 2, 3]; let b: u32 = 1; - let c = a[b]; // { dg-error "expected .usize. got .u32." } + let c = a[b]; // { dg-error "the type ...integer..CAPACITY.. cannot be indexed by .u32." } // { dg-error {failed to type resolve expression} "" { target *-*-* } .-1 } } diff --git a/gcc/testsuite/rust/execute/torture/issue-1436.rs b/gcc/testsuite/rust/execute/torture/issue-1436.rs new file mode 100644 index 0000000..32da34e --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-1436.rs @@ -0,0 +1,172 @@ +// { dg-options "-w" } +// { dg-output "" } +mod intrinsics { + extern "rust-intrinsic" { + pub fn offset<T>(ptr: *const T, count: isize) -> *const T; + } +} + +mod mem { + extern "rust-intrinsic" { + fn size_of<T>() -> usize; + } +} + +extern "C" { + fn printf(s: *const i8, ...); +} + +struct FatPtr<T> { + data: *const T, + len: usize, +} + +pub union Repr<T> { + rust: *const [T], + rust_mut: *mut [T], + raw: FatPtr<T>, +} + +pub enum Option<T> { + None, + Some(T), +} + +#[lang = "Range"] +pub struct Range<Idx> { + pub start: Idx, + pub end: Idx, +} + +#[lang = "const_slice_ptr"] +impl<T> *const [T] { + pub const fn len(self) -> usize { + let a = unsafe { Repr { rust: self }.raw }; + a.len + } + + pub const fn as_ptr(self) -> *const T { + self as *const T + } +} + +#[lang = "const_ptr"] +impl<T> *const T { + pub const unsafe fn offset(self, count: isize) -> *const T { + unsafe { intrinsics::offset(self, count) } + } + + pub const unsafe fn add(self, count: usize) -> Self { + unsafe { self.offset(count as isize) } + } + + pub const fn as_ptr(self) -> *const T { + self as *const T + } +} + +const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] { + unsafe { + Repr { + raw: FatPtr { data, len }, + } + .rust + } +} + +#[lang = "index"] +trait Index<Idx> { + type Output; + + fn index(&self, index: Idx) -> &Self::Output; +} + +impl<T> [T] { + pub const fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub const fn len(&self) -> usize { + unsafe { Repr { rust: self }.raw.len } + } +} + +pub unsafe trait SliceIndex<T> { + type Output; + + fn get(self, slice: &T) -> Option<&Self::Output>; + + unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output; + + fn index(self, slice: &T) -> &Self::Output; +} + +unsafe impl<T> SliceIndex<[T]> for usize { + type Output = T; + + fn get(self, slice: &[T]) -> Option<&T> { + unsafe { Option::Some(&*self.get_unchecked(slice)) } + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { + // SAFETY: the caller guarantees that `slice` is not dangling, so it + // cannot be longer than `isize::MAX`. They also guarantee that + // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, + // so the call to `add` is safe. + unsafe { slice.as_ptr().add(self) } + } + + fn index(self, slice: &[T]) -> &T { + unsafe { &*self.get_unchecked(slice) } + } +} + +unsafe impl<T> SliceIndex<[T]> for Range<usize> { + type Output = [T]; + + fn get(self, slice: &[T]) -> Option<&[T]> { + if self.start > self.end || self.end > slice.len() { + Option::None + } else { + unsafe { Option::Some(&*self.get_unchecked(slice)) } + } + } + + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + unsafe { + let a: *const T = slice.as_ptr(); + let b: *const T = a.add(self.start); + slice_from_raw_parts(b, self.end - self.start) + } + } + + fn index(self, slice: &[T]) -> &[T] { + unsafe { &*self.get_unchecked(slice) } + } +} + +impl<T, I> Index<I> for [T] +where + I: SliceIndex<[T]>, +{ + type Output = I::Output; + + fn index(&self, index: I) -> &I::Output { + unsafe { + let a = "slice-index\n\0"; + let b = a as *const str; + let c = b as *const i8; + + printf(c); + } + + index.index(self) + } +} + +fn main() -> i32 { + let a = [1, 2, 3, 4, 5]; + let b = a[1]; + + b - 2 +} |