diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 6875532e28a..4ad5d8443b2 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -5,7 +5,6 @@ use rustc_error_messages::MultiSpan; use rustc_macros::HashStable; use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; -use crate::mir::interpret::Scalar; use crate::ty::{self, Ty, TyCtxt}; mod int; @@ -230,12 +229,6 @@ impl<'tcx> Const<'tcx> { } } - #[inline] - pub fn try_to_scalar(self) -> Option<(Scalar, Ty<'tcx>)> { - let cv = self.try_to_value()?; - Some((cv.valtree.try_to_scalar()?, cv.ty)) - } - #[inline] pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option { self.try_to_value()?.try_to_target_usize(tcx) diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 425b68a951c..d914b7576dc 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -117,9 +117,13 @@ pub struct Value<'tcx> { impl<'tcx> Value<'tcx> { /// Attempts to extract the raw bits from the constant. /// - /// Fails if the value can't be represented as bits (e.g. because it is an aggregate). + /// Fails if the value can't be represented as bits (e.g. because it is a reference + /// or an aggregate). #[inline] pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option { + let (ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Float(_)) = self.ty.kind() else { + return None; + }; let scalar = self.valtree.try_to_scalar_int()?; let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty); let size = tcx.layout_of(input).ok()?.size; @@ -127,10 +131,16 @@ impl<'tcx> Value<'tcx> { } pub fn try_to_bool(self) -> Option { + if !self.ty.is_bool() { + return None; + } self.valtree.try_to_scalar_int()?.try_to_bool().ok() } pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option { + if !self.ty.is_usize() { + return None; + } self.valtree.try_to_scalar_int().map(|s| s.to_target_usize(tcx)) } } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 9c6186d6882..b711c238d59 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -51,8 +51,7 @@ impl<'tcx> TypeFolder> for TransformTy<'tcx> { // Transforms a ty:Ty for being encoded and used in the substitution dictionary. fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match t.kind() { - ty::Array(..) - | ty::Closure(..) + ty::Closure(..) | ty::Coroutine(..) | ty::CoroutineClosure(..) | ty::CoroutineWitness(..) @@ -67,6 +66,13 @@ impl<'tcx> TypeFolder> for TransformTy<'tcx> { | ty::Tuple(..) | ty::UnsafeBinder(_) => t.super_fold_with(self), + // Don't transform the type of the array length and keep it as `usize`. + // This is required for `try_to_target_usize` to work correctly. + &ty::Array(inner, len) => { + let inner = self.fold_ty(inner); + Ty::new_array_with_const_len(self.tcx, inner, len) + } + ty::Bool => { if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { // Note: on all platforms that Rust's currently supports, its size and alignment diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 9eacd377361..117b6a76425 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -2023,14 +2023,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => None, }; if let Some(tykind) = tykind - && let hir::TyKind::Array(_, length) = tykind - && let Some((scalar, ty)) = sz.found.try_to_scalar() - && ty == self.tcx.types.usize + && let hir::TyKind::Array(_, length_arg) = tykind + && let Some(length_val) = sz.found.try_to_target_usize(self.tcx) { - let span = length.span(); Some(TypeErrorAdditionalDiags::ConsiderSpecifyingLength { - span, - length: scalar.to_target_usize(&self.tcx).unwrap(), + span: length_arg.span(), + length: length_val, }) } else { None diff --git a/tests/crashes/131102.rs b/tests/crashes/131102.rs deleted file mode 100644 index 12b35f8d1b2..00000000000 --- a/tests/crashes/131102.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #131102 -pub struct Blorb([String; N]); -pub struct Wrap(Blorb<0>); -pub const fn i(_: Wrap) {} diff --git a/tests/ui/consts/bad-array-size-in-type-err.rs b/tests/ui/consts/bad-array-size-in-type-err.rs index cb02ad3205d..0490a9d3620 100644 --- a/tests/ui/consts/bad-array-size-in-type-err.rs +++ b/tests/ui/consts/bad-array-size-in-type-err.rs @@ -8,3 +8,14 @@ fn main() { //~^ ERROR mismatched types //~| ERROR the constant `2` is not of type `usize` } + +fn iter(val: BadArraySize::<2>) { + for _ in val.arr {} + //~^ ERROR the constant `2` is not of type `usize` + //~| ERROR `[i32; 2]` is not an iterator +} + +// issue #131102 +pub struct Blorb([String; N]); //~ ERROR the constant `N` is not of type `usize` +pub struct Wrap(Blorb<0>); +pub const fn i(_: Wrap) {} //~ ERROR destructor of `Wrap` cannot be evaluated at compile-time 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 c3ff216432e..84e16f8d931 100644 --- a/tests/ui/consts/bad-array-size-in-type-err.stderr +++ b/tests/ui/consts/bad-array-size-in-type-err.stderr @@ -6,6 +6,14 @@ LL | arr: [i32; N], | = note: the length of array `[i32; N]` must be type `usize` +error: the constant `N` is not of type `usize` + --> $DIR/bad-array-size-in-type-err.rs:19:32 + | +LL | pub struct Blorb([String; N]); + | ^^^^^^^^^^^ expected `usize`, found `u16` + | + = note: the length of array `[String; N]` must be type `usize` + error[E0308]: mismatched types --> $DIR/bad-array-size-in-type-err.rs:7:38 | @@ -20,6 +28,37 @@ LL | let _ = BadArraySize::<2> { arr: [0, 0, 0] }; | = note: the length of array `[i32; 2]` must be type `usize` -error: aborting due to 3 previous errors +error: the constant `2` is not of type `usize` + --> $DIR/bad-array-size-in-type-err.rs:13:14 + | +LL | for _ in val.arr {} + | ^^^^^^^ expected `usize`, found `u8` + | + = note: the length of array `[i32; 2]` must be type `usize` -For more information about this error, try `rustc --explain E0308`. +error[E0277]: `[i32; 2]` is not an iterator + --> $DIR/bad-array-size-in-type-err.rs:13:14 + | +LL | for _ in val.arr {} + | ^^^^^^^ `[i32; 2]` is not an iterator; try calling `.into_iter()` or `.iter()` + | + = help: the trait `IntoIterator` is not implemented for `[i32; 2]` + = help: the following other types implement trait `IntoIterator`: + &[T; N] + &[T] + &mut [T; N] + &mut [T] + [T; N] + +error[E0493]: destructor of `Wrap` cannot be evaluated at compile-time + --> $DIR/bad-array-size-in-type-err.rs:21:16 + | +LL | pub const fn i(_: Wrap) {} + | ^ - value is dropped here + | | + | the destructor for this type cannot be evaluated in constant functions + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0277, E0308, E0493. +For more information about an error, try `rustc --explain E0277`.