Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions compiler/rustc_hir_typeck/src/place_op.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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;
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/wf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 0 additions & 6 deletions tests/crashes/131103.rs

This file was deleted.

2 changes: 2 additions & 0 deletions tests/ui/const-generics/bad-subst-const-kind.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions tests/ui/const-generics/issues/index_array_bad_type.rs
Original file line number Diff line number Diff line change
@@ -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() {}
18 changes: 18 additions & 0 deletions tests/ui/const-generics/issues/index_array_bad_type.stderr
Original file line number Diff line number Diff line change
@@ -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

4 changes: 4 additions & 0 deletions tests/ui/const-generics/transmute-fail.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/const-generics/type_mismatch.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions tests/ui/consts/bad-array-size-in-type-err.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading