Skip to content

Commit 77d04a7

Browse files
Merge branch 'trunk' into various-present-fixes
2 parents 34745e8 + d199493 commit 77d04a7

File tree

8 files changed

+165
-44
lines changed

8 files changed

+165
-44
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ Bottom level categories:
7070

7171
- Fixed overflow detection and argument domain validation for `acosh`, `length`, `normalize`, and `pow` in constant evaluation. By @ecoricemon in [#9249](https://github.com/gfx-rs/wgpu/pull/9249).
7272

73+
#### Metal
74+
75+
- Added guards to avoid calling some feature detection methods that are not implemented on `CaptureMTLDevice`. By @andyleiserson in [#9284](https://github.com/gfx-rs/wgpu/pull/9284).
76+
7377
## v29.0.0 (2026-03-18)
7478

7579
### Major Changes

Cargo.lock

Lines changed: 52 additions & 30 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cts_runner/revision.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
e9adcf85f5d3698da4dbd7d0e2de0ef0350c3d90
1+
149749467725050bcfa5649ed355035cd408f531

examples/features/src/framework.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub trait Example: 'static + Sized {
5353
fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue);
5454
}
5555

56-
// Initialize logging in platform dependant ways.
56+
// Initialize logging in platform dependent ways.
5757
fn init_logger() {
5858
cfg_if::cfg_if! {
5959
if #[cfg(target_arch = "wasm32")] {

naga/src/proc/constant_evaluator.rs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2696,6 +2696,19 @@ impl<'a> ConstantEvaluator<'a> {
26962696
return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
26972697
}
26982698

2699+
if matches!(
2700+
(left_value, op),
2701+
(
2702+
Literal::Bool(_),
2703+
BinaryOperator::Less
2704+
| BinaryOperator::LessEqual
2705+
| BinaryOperator::Greater
2706+
| BinaryOperator::GreaterEqual
2707+
)
2708+
) {
2709+
return Err(ConstantEvaluatorError::InvalidBinaryOpArgs);
2710+
}
2711+
26992712
let literal = match op {
27002713
BinaryOperator::Equal => Literal::Bool(left_value == right_value),
27012714
BinaryOperator::NotEqual => Literal::Bool(left_value != right_value),
@@ -2709,20 +2722,20 @@ impl<'a> ConstantEvaluator<'a> {
27092722
BinaryOperator::Add => a.wrapping_add(b),
27102723
BinaryOperator::Subtract => a.wrapping_sub(b),
27112724
BinaryOperator::Multiply => a.wrapping_mul(b),
2712-
BinaryOperator::Divide => {
2725+
BinaryOperator::Divide => a.checked_div(b).ok_or_else(|| {
27132726
if b == 0 {
2714-
return Err(ConstantEvaluatorError::DivisionByZero);
2727+
ConstantEvaluatorError::DivisionByZero
27152728
} else {
2716-
a.wrapping_div(b)
2729+
ConstantEvaluatorError::Overflow("division".into())
27172730
}
2718-
}
2719-
BinaryOperator::Modulo => {
2731+
})?,
2732+
BinaryOperator::Modulo => a.checked_rem(b).ok_or_else(|| {
27202733
if b == 0 {
2721-
return Err(ConstantEvaluatorError::RemainderByZero);
2734+
ConstantEvaluatorError::RemainderByZero
27222735
} else {
2723-
a.wrapping_rem(b)
2736+
ConstantEvaluatorError::Overflow("remainder".into())
27242737
}
2725-
}
2738+
})?,
27262739
BinaryOperator::And => a & b,
27272740
BinaryOperator::ExclusiveOr => a ^ b,
27282741
BinaryOperator::InclusiveOr => a | b,
@@ -2849,6 +2862,8 @@ impl<'a> ConstantEvaluator<'a> {
28492862
(Literal::Bool(a), Literal::Bool(b)) => Literal::Bool(match op {
28502863
BinaryOperator::LogicalAnd => a && b,
28512864
BinaryOperator::LogicalOr => a || b,
2865+
BinaryOperator::And => a & b,
2866+
BinaryOperator::InclusiveOr => a | b,
28522867
_ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),
28532868
}),
28542869
_ => return Err(ConstantEvaluatorError::InvalidBinaryOpArgs),

naga/src/valid/expression.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ pub enum ExpressionError {
156156
lhs_type: crate::TypeInner,
157157
rhs_expr: Handle<crate::Expression>,
158158
},
159+
#[error("Division by zero")]
160+
DivideByZero,
159161
}
160162

161163
#[derive(Clone, Debug, thiserror::Error)]
@@ -319,6 +321,60 @@ impl super::Validator {
319321
}
320322
}
321323

324+
/// Return an error if a constant divisor in `right` evaluates to zero for
325+
/// an integer division or remainder operation.
326+
///
327+
/// This function promises to return an error in cases where (1) the
328+
/// expression is well-typed, (2) `left_ty` is a concrete integer or a
329+
/// vector, and (3) `right` is a const-expression that evaluates to zero.
330+
/// It does not return an error in cases where the expression is not
331+
/// well-typed (e.g. vector dimension mismatch), because those will be
332+
/// rejected elsewhere.
333+
fn validate_constant_divisor(
334+
left_ty: &crate::TypeInner,
335+
right: Handle<crate::Expression>,
336+
module: &crate::Module,
337+
function: &crate::Function,
338+
) -> Result<(), ExpressionError> {
339+
fn contains_zero(
340+
handle: Handle<crate::Expression>,
341+
expressions: &crate::Arena<crate::Expression>,
342+
module: &crate::Module,
343+
) -> bool {
344+
match expressions[handle] {
345+
crate::Expression::Literal(_) | crate::Expression::ZeroValue(_) => module
346+
.to_ctx()
347+
.get_const_val_from::<u32, _>(handle, expressions)
348+
.ok()
349+
.is_some_and(|v| v == 0),
350+
crate::Expression::Splat { value, .. } => contains_zero(value, expressions, module),
351+
crate::Expression::Compose { ref components, .. } => components
352+
.iter()
353+
.any(|&comp| contains_zero(comp, expressions, module)),
354+
crate::Expression::Constant(c) => {
355+
contains_zero(module.constants[c].init, &module.global_expressions, module)
356+
}
357+
_ => false,
358+
}
359+
}
360+
361+
let Some((_, scalar)) = left_ty.vector_size_and_scalar() else {
362+
return Ok(());
363+
};
364+
if !matches!(
365+
scalar.kind,
366+
crate::ScalarKind::Sint | crate::ScalarKind::Uint
367+
) {
368+
return Ok(());
369+
}
370+
371+
if contains_zero(right, &function.expressions, module) {
372+
Err(ExpressionError::DivideByZero)
373+
} else {
374+
Ok(())
375+
}
376+
}
377+
322378
#[allow(clippy::too_many_arguments)]
323379
pub(super) fn validate_expression(
324380
&self,
@@ -1071,6 +1127,10 @@ impl super::Validator {
10711127
if matches!(op, Bo::ShiftLeft | Bo::ShiftRight) {
10721128
Self::validate_constant_shift_amounts(left_inner, right, module, function)?;
10731129
}
1130+
// For integer division or remainder, check if the constant divisor is zero
1131+
if matches!(op, Bo::Divide | Bo::Modulo) {
1132+
Self::validate_constant_divisor(left_inner, right, module, function)?;
1133+
}
10741134
ShaderStages::all()
10751135
}
10761136
E::Select {

0 commit comments

Comments
 (0)