diff --git a/naga/src/front/wgsl/lower/construction.rs b/naga/src/front/wgsl/lower/construction.rs index c3208ac3fb4..2819f1fe3bf 100644 --- a/naga/src/front/wgsl/lower/construction.rs +++ b/naga/src/front/wgsl/lower/construction.rs @@ -527,15 +527,25 @@ impl<'source> Lowerer<'source, '_> { let base = ctx.register_type(components[0])?; + ctx.layouter.update(ctx.module.to_ctx()).map_err(|err| { + let crate::proc::LayoutErrorInner::TooLarge = err.inner else { + unreachable!("unexpected layout error: {err:?}"); + }; + // This error could be for any type that was pending layout. Lots of + // type definitions don't get spans, so the error message may not be + // very useful. + Box::new(Error::TypeTooLarge { + span: ctx.module.types.get_span(err.ty), + }) + })?; + let stride = ctx.layouter[base].to_stride(); + let inner = crate::TypeInner::Array { base, size: crate::ArraySize::Constant( NonZeroU32::new(u32::try_from(components.len()).unwrap()).unwrap(), ), - stride: { - ctx.layouter.update(ctx.module.to_ctx()).unwrap(); - ctx.layouter[base].to_stride() - }, + stride, }; let ty = ctx.ensure_type_exists(inner); diff --git a/naga/src/front/wgsl/lower/conversion.rs b/naga/src/front/wgsl/lower/conversion.rs index f8408695e7d..87697b7ba45 100644 --- a/naga/src/front/wgsl/lower/conversion.rs +++ b/naga/src/front/wgsl/lower/conversion.rs @@ -277,6 +277,13 @@ impl<'source> super::ExpressionContext<'source, '_, '_> { .cast_array(expr, *concrete_scalar, expr_span) { Ok(expr) => return Ok(expr), + Err(crate::proc::ConstantEvaluatorError::TypeTooLarge(ty)) => { + // Special case where the error is not actually related to the + // particular scalar we tried to concretize. + return Err(Box::new(super::Error::TypeTooLarge { + span: self.module.types.get_span(ty), + })); + } Err(err) => { errors.push((concrete_scalar.to_wgsl_for_diagnostics(), err)); } diff --git a/naga/src/proc/constant_evaluator.rs b/naga/src/proc/constant_evaluator.rs index 7b7c7e895f1..9ccdda3d566 100644 --- a/naga/src/proc/constant_evaluator.rs +++ b/naga/src/proc/constant_evaluator.rs @@ -952,6 +952,8 @@ pub enum ConstantEvaluatorError { SelectAcceptRejectTypeMismatch, #[error("Cooperative operations can't be constant")] CooperativeOperation, + #[error("Type is too large")] + TypeTooLarge(Handle), } impl<'a> ConstantEvaluator<'a> { @@ -2652,7 +2654,14 @@ impl<'a> ConstantEvaluator<'a> { } }; let mut layouter = core::mem::take(self.layouter); - layouter.update(self.to_ctx()).unwrap(); + layouter.update(self.to_ctx()).map_err(|err| { + // The layouter operates lazily, so the error + // could be for any pending type. + let crate::proc::LayoutErrorInner::TooLarge = err.inner else { + unreachable!("unexpected layout error: {err:?}"); + }; + ConstantEvaluatorError::TypeTooLarge(err.ty) + })?; *self.layouter = layouter; let new_base_stride = self.layouter[new_base].to_stride(); diff --git a/naga/tests/naga/wgsl_errors.rs b/naga/tests/naga/wgsl_errors.rs index 3ab89f11f5d..67d1ffcbf40 100644 --- a/naga/tests/naga/wgsl_errors.rs +++ b/naga/tests/naga/wgsl_errors.rs @@ -4714,6 +4714,50 @@ fn max_type_size_array_of_structs() { } } +#[test] +fn max_type_size_array_constructor_with_oversize_type() { + // An `array(...)` constructor expression invokes the layouter to compute + // the stride of the constructed array. If a previously declared type is + // oversize, the layouter encounters it and the error must be reported + // rather than panicking. + // + // Regression test for . + check( + r#" + var big: array; + const A = array(1); + "#, + r#"error: type is too large + = note: the maximum size is 2147483647 bytes + +"#, + ); +} + +#[test] +fn max_type_size_concretize_with_oversize_type() { + // Concretizing an abstract array (here, indexing it with a non-constant + // index forces concretization to a concrete element type) invokes the + // layouter to compute the new array's stride. If a previously declared + // type is oversize, the layouter encounters it and the error must be + // reported rather than panicking. + // + // Regression test for . + check( + r#" + const a = array(0.); + var big: array; + fn main(i: u32) { + let x = a[i]; + } + "#, + r#"error: type is too large + = note: the maximum size is 2147483647 bytes + +"#, + ); +} + #[test] fn source_with_control_char() { check(