about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-01-28 17:52:28 +0000
committerMichael Goulet <michael@errs.io>2025-01-28 17:52:28 +0000
commit7e68422859f2e6e3514a1af68d0a7ba3629e2553 (patch)
tree97203f3bc12a3b71cf92b401e60461d0e9a94b34
parentfdd1a3b02687817cea41f6bacae3d5fbed2b2cd0 (diff)
downloadrust-7e68422859f2e6e3514a1af68d0a7ba3629e2553.tar.gz
rust-7e68422859f2e6e3514a1af68d0a7ba3629e2553.zip
Properly check that array length is valid type during built-in unsizing in index
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs11
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs2
-rw-r--r--tests/crashes/131103.rs6
-rw-r--r--tests/ui/const-generics/bad-subst-const-kind.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr2
-rw-r--r--tests/ui/const-generics/issues/index_array_bad_type.rs13
-rw-r--r--tests/ui/const-generics/issues/index_array_bad_type.stderr18
-rw-r--r--tests/ui/const-generics/transmute-fail.stderr4
-rw-r--r--tests/ui/const-generics/type_mismatch.stderr2
-rw-r--r--tests/ui/consts/bad-array-size-in-type-err.stderr4
-rw-r--r--tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.current.stderr2
13 files changed, 63 insertions, 9 deletions
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index ba635071135..e1bd9ae2e67 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -1,6 +1,7 @@
 use rustc_errors::Applicability;
 use rustc_hir_analysis::autoderef::Autoderef;
 use rustc_infer::infer::InferOk;
+use rustc_infer::traits::{Obligation, ObligationCauseCode};
 use rustc_middle::span_bug;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, OverloadedDeref,
@@ -136,8 +137,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let mut self_ty = adjusted_ty;
             if unsize {
                 // We only unsize arrays here.
-                if let ty::Array(element_ty, _) = adjusted_ty.kind() {
-                    self_ty = Ty::new_slice(self.tcx, *element_ty);
+                if let ty::Array(element_ty, ct) = *adjusted_ty.kind() {
+                    self.register_predicate(Obligation::new(
+                        self.tcx,
+                        self.cause(base_expr.span, ObligationCauseCode::ArrayLen(adjusted_ty)),
+                        self.param_env,
+                        ty::ClauseKind::ConstArgHasType(ct, self.tcx.types.usize),
+                    ));
+                    self_ty = Ty::new_slice(self.tcx, element_ty);
                 } else {
                     continue;
                 }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 55d78e083e0..8a9110f842a 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -194,6 +194,9 @@ pub enum ObligationCauseCode<'tcx> {
     /// A slice or array is WF only if `T: Sized`.
     SliceOrArrayElem,
 
+    /// An array `[T; N]` can only be indexed (and is only well-formed if) `N` has type usize.
+    ArrayLen(Ty<'tcx>),
+
     /// A tuple is WF only if its middle elements are `Sized`.
     TupleElem,
 
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 471105773e2..67c870f387e 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -2770,6 +2770,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             ObligationCauseCode::SliceOrArrayElem => {
                 err.note("slice and array elements must have `Sized` type");
             }
+            ObligationCauseCode::ArrayLen(array_ty) => {
+                err.note(format!("the length of array `{array_ty}` must be type `usize`"));
+            }
             ObligationCauseCode::TupleElem => {
                 err.note("only the last element of a tuple may have a dynamically sized type");
             }
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 9d32eb05386..20b675bcb76 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -689,7 +689,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 self.require_sized(subty, ObligationCauseCode::SliceOrArrayElem);
                 // Note that the len being WF is implicitly checked while visiting.
                 // Here we just check that it's of type usize.
-                let cause = self.cause(ObligationCauseCode::Misc);
+                let cause = self.cause(ObligationCauseCode::ArrayLen(t));
                 self.out.push(traits::Obligation::with_depth(
                     tcx,
                     cause,
diff --git a/tests/crashes/131103.rs b/tests/crashes/131103.rs
deleted file mode 100644
index 70193e8b3bd..00000000000
--- a/tests/crashes/131103.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//@ known-bug: #131103
-struct Struct<const N: i128>(pub [u8; N]);
-
-pub fn function(value: Struct<3>) -> u8 {
-    value.0[0]
-}
diff --git a/tests/ui/const-generics/bad-subst-const-kind.stderr b/tests/ui/const-generics/bad-subst-const-kind.stderr
index 5c8d9c90363..b3605269642 100644
--- a/tests/ui/const-generics/bad-subst-const-kind.stderr
+++ b/tests/ui/const-generics/bad-subst-const-kind.stderr
@@ -3,6 +3,8 @@ error: the constant `N` is not of type `usize`
    |
 LL | impl<const N: u64> Q for [u8; N] {
    |                          ^^^^^^^ expected `usize`, found `u64`
+   |
+   = note: the length of array `[u8; N]` must be type `usize`
 
 error: the constant `13` is not of type `u64`
   --> $DIR/bad-subst-const-kind.rs:13:24
diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr
index e03580ec007..7cb67252da5 100644
--- a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr
@@ -3,6 +3,8 @@ error: the constant `N` is not of type `usize`
    |
 LL | impl<const N: u64> Q for [u8; N] {}
    |                          ^^^^^^^ expected `usize`, found `u64`
+   |
+   = note: the length of array `[u8; N]` must be type `usize`
 
 error[E0046]: not all trait items implemented, missing: `ASSOC`
   --> $DIR/type_mismatch.rs:8:1
diff --git a/tests/ui/const-generics/issues/index_array_bad_type.rs b/tests/ui/const-generics/issues/index_array_bad_type.rs
new file mode 100644
index 00000000000..91b89cd3fff
--- /dev/null
+++ b/tests/ui/const-generics/issues/index_array_bad_type.rs
@@ -0,0 +1,13 @@
+struct Struct<const N: i128>(pub [u8; N]);
+//~^ ERROR the constant `N` is not of type `usize`
+
+pub fn function(value: Struct<3>) -> u8 {
+    value.0[0]
+    //~^ ERROR the constant `3` is not of type `usize`
+
+    // FIXME(const_generics): Ideally we wouldn't report the above error
+    // b/c `Struct<_>` is never well formed, but I'd rather report too many
+    // errors rather than ICE the compiler.
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/issues/index_array_bad_type.stderr b/tests/ui/const-generics/issues/index_array_bad_type.stderr
new file mode 100644
index 00000000000..ceea0973377
--- /dev/null
+++ b/tests/ui/const-generics/issues/index_array_bad_type.stderr
@@ -0,0 +1,18 @@
+error: the constant `N` is not of type `usize`
+  --> $DIR/index_array_bad_type.rs:1:34
+   |
+LL | struct Struct<const N: i128>(pub [u8; N]);
+   |                                  ^^^^^^^ expected `usize`, found `i128`
+   |
+   = note: the length of array `[u8; N]` must be type `usize`
+
+error: the constant `3` is not of type `usize`
+  --> $DIR/index_array_bad_type.rs:5:5
+   |
+LL |     value.0[0]
+   |     ^^^^^^^ expected `usize`, found `i128`
+   |
+   = note: the length of array `[u8; 3]` must be type `usize`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr
index 978a9744e88..0e26daa3a0f 100644
--- a/tests/ui/const-generics/transmute-fail.stderr
+++ b/tests/ui/const-generics/transmute-fail.stderr
@@ -3,6 +3,8 @@ error: the constant `W` is not of type `usize`
    |
 LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] {
    |                                          ^^^^^^^^^^^^^ expected `usize`, found `bool`
+   |
+   = note: the length of array `[[u32; H]; W]` must be type `usize`
 
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
   --> $DIR/transmute-fail.rs:11:9
@@ -18,6 +20,8 @@ error: the constant `W` is not of type `usize`
    |
 LL |         std::mem::transmute(v)
    |         ^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
+   |
+   = note: the length of array `[[u32; H]; W]` must be type `usize`
 
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
   --> $DIR/transmute-fail.rs:26:9
diff --git a/tests/ui/const-generics/type_mismatch.stderr b/tests/ui/const-generics/type_mismatch.stderr
index d1bb5c1242f..bd169ed2ec8 100644
--- a/tests/ui/const-generics/type_mismatch.stderr
+++ b/tests/ui/const-generics/type_mismatch.stderr
@@ -3,6 +3,8 @@ error: the constant `N` is not of type `usize`
    |
 LL | fn bar<const N: u8>() -> [u8; N] {}
    |                          ^^^^^^^ expected `usize`, found `u8`
+   |
+   = note: the length of array `[u8; N]` must be type `usize`
 
 error: the constant `N` is not of type `u8`
   --> $DIR/type_mismatch.rs:2:11
diff --git a/tests/ui/consts/bad-array-size-in-type-err.stderr b/tests/ui/consts/bad-array-size-in-type-err.stderr
index 25d14d80c3e..c3ff216432e 100644
--- a/tests/ui/consts/bad-array-size-in-type-err.stderr
+++ b/tests/ui/consts/bad-array-size-in-type-err.stderr
@@ -3,6 +3,8 @@ error: the constant `N` is not of type `usize`
    |
 LL |     arr: [i32; N],
    |          ^^^^^^^^ expected `usize`, found `u8`
+   |
+   = note: the length of array `[i32; N]` must be type `usize`
 
 error[E0308]: mismatched types
   --> $DIR/bad-array-size-in-type-err.rs:7:38
@@ -15,6 +17,8 @@ error: the constant `2` is not of type `usize`
    |
 LL |     let _ = BadArraySize::<2> { arr: [0, 0, 0] };
    |                                      ^^^^^^^^^ expected `usize`, found `u8`
+   |
+   = note: the length of array `[i32; 2]` must be type `usize`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.current.stderr b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.current.stderr
index 1bcc0dbaf67..92ad83c3300 100644
--- a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.current.stderr
+++ b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.current.stderr
@@ -9,6 +9,8 @@ error: the constant `N` is not of type `usize`
    |
 LL |     fn func<const N: u32>() -> [(); N];
    |                                ^^^^^^^ expected `usize`, found `u32`
+   |
+   = note: the length of array `[(); N]` must be type `usize`
 
 error: aborting due to 2 previous errors