aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-08-05 13:38:37 +0000
committerGitHub <noreply@github.com>2022-08-05 13:38:37 +0000
commit7beea479c5a1e7e415223f3fbd4e16c20c3214ec (patch)
treed0ad3824e02135310865254787603c99b27224f7 /gcc
parent8725e324aad3eac0df074e5f0a494b5e3f332a31 (diff)
parentc86ac620c2bdb852b8078f37b898ab40d96ec0b0 (diff)
downloadgcc-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.cc63
-rw-r--r--gcc/testsuite/rust/compile/usize1.rs2
-rw-r--r--gcc/testsuite/rust/execute/torture/issue-1436.rs172
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
+}