1
Fork 0

Properly check that array length is valid type during built-in unsizing in index

This commit is contained in:
Michael Goulet 2025-01-28 17:52:28 +00:00
parent fdd1a3b026
commit 7e68422859
13 changed files with 63 additions and 9 deletions

View file

@ -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;
}

View file

@ -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,

View file

@ -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");
}

View file

@ -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,

View file

@ -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]
}

View file

@ -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

View file

@ -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

View file

@ -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() {}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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