Skip to content

Commit f34dfd9

Browse files
[naga] Allow unreachable statements (#7718)
Allow unreachable statements after return/break/continue/discard. Fixes #7536
1 parent 38e667e commit f34dfd9

File tree

4 files changed

+33
-45
lines changed

4 files changed

+33
-45
lines changed

cts_runner/test.lst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ webgpu:api,operation,rendering,color_target_state:blend_constant,setting:*
1717
webgpu:api,operation,rendering,depth:*
1818
webgpu:api,operation,rendering,draw:*
1919
webgpu:api,operation,uncapturederror:*
20+
webgpu:shader,execution,flow_control,return:*

naga/src/valid/function.rs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,6 @@ pub enum FunctionError {
114114
name: String,
115115
space: crate::AddressSpace,
116116
},
117-
#[error("There are instructions after `return`/`break`/`continue`")]
118-
InstructionsAfterReturn,
119117
#[error("The `break` is used outside of a `loop` or `switch` context")]
120118
BreakOutsideOfLoopOrSwitch,
121119
#[error("The `continue` is used outside of a `loop` context")]
@@ -236,7 +234,6 @@ bitflags::bitflags! {
236234

237235
struct BlockInfo {
238236
stages: super::ShaderStages,
239-
finished: bool,
240237
}
241238

242239
struct BlockContext<'a> {
@@ -768,13 +765,8 @@ impl super::Validator {
768765
context: &BlockContext,
769766
) -> Result<BlockInfo, WithSpan<FunctionError>> {
770767
use crate::{AddressSpace, Statement as S, TypeInner as Ti};
771-
let mut finished = false;
772768
let mut stages = super::ShaderStages::all();
773769
for (statement, &span) in statements.span_iter() {
774-
if finished {
775-
return Err(FunctionError::InstructionsAfterReturn
776-
.with_span_static(span, "instructions after return"));
777-
}
778770
match *statement {
779771
S::Emit(ref range) => {
780772
for handle in range.clone() {
@@ -823,7 +815,6 @@ impl super::Validator {
823815
S::Block(ref block) => {
824816
let info = self.validate_block(block, context)?;
825817
stages &= info.stages;
826-
finished = info.finished;
827818
}
828819
S::If {
829820
condition,
@@ -966,14 +957,12 @@ impl super::Validator {
966957
return Err(FunctionError::BreakOutsideOfLoopOrSwitch
967958
.with_span_static(span, "invalid break"));
968959
}
969-
finished = true;
970960
}
971961
S::Continue => {
972962
if !context.abilities.contains(ControlFlowAbility::CONTINUE) {
973963
return Err(FunctionError::ContinueOutsideOfLoop
974964
.with_span_static(span, "invalid continue"));
975965
}
976-
finished = true;
977966
}
978967
S::Return { value } => {
979968
if !context.abilities.contains(ControlFlowAbility::RETURN) {
@@ -1013,11 +1002,9 @@ impl super::Validator {
10131002
.with_span_static(span, "invalid return"));
10141003
}
10151004
}
1016-
finished = true;
10171005
}
10181006
S::Kill => {
10191007
stages &= super::ShaderStages::FRAGMENT;
1020-
finished = true;
10211008
}
10221009
S::Barrier(barrier) => {
10231010
stages &= super::ShaderStages::COMPUTE;
@@ -1635,7 +1622,7 @@ impl super::Validator {
16351622
}
16361623
}
16371624
}
1638-
Ok(BlockInfo { stages, finished })
1625+
Ok(BlockInfo { stages })
16391626
}
16401627

16411628
fn validate_block(

naga/tests/naga/validation.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,3 +923,34 @@ fn main() {
923923
naga::valid::GlobalUse::QUERY
924924
);
925925
}
926+
927+
#[cfg(feature = "wgsl-in")]
928+
#[test]
929+
fn global_use_unreachable() {
930+
// We should allow statements after `return`, and such statements should
931+
// still contribute to global usage. (Unreachable statements should not
932+
// contribute to uniformity analysis, but there are multiple issues with
933+
// the current implementation of uniformity analysis, see #4369.)
934+
935+
let source = "
936+
@group(0) @binding(0)
937+
var<storage, read_write> global: u32;
938+
939+
@compute @workgroup_size(64)
940+
fn main() {
941+
var used: u32;
942+
return;
943+
used = global;
944+
}
945+
";
946+
947+
let module = naga::front::wgsl::parse_str(source).expect("module should parse");
948+
let mut validator = valid::Validator::new(Default::default(), valid::Capabilities::all());
949+
let info = validator.validate(&module).unwrap();
950+
951+
let global = module.global_variables.iter().next().unwrap().0;
952+
assert_eq!(
953+
info.get_entry_point(0)[global],
954+
naga::valid::GlobalUse::READ,
955+
);
956+
}

naga/tests/naga/wgsl_errors.rs

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,37 +1979,6 @@ fn invalid_local_vars() {
19791979
}
19801980
}
19811981

1982-
#[test]
1983-
fn dead_code() {
1984-
check_validation! {
1985-
"
1986-
fn dead_code_after_if(condition: bool) -> i32 {
1987-
if (condition) {
1988-
return 1;
1989-
} else {
1990-
return 2;
1991-
}
1992-
return 3;
1993-
}
1994-
":
1995-
Ok(_)
1996-
}
1997-
check_validation! {
1998-
"
1999-
fn dead_code_after_block() -> i32 {
2000-
{
2001-
return 1;
2002-
}
2003-
return 2;
2004-
}
2005-
":
2006-
Err(naga::valid::ValidationError::Function {
2007-
source: naga::valid::FunctionError::InstructionsAfterReturn,
2008-
..
2009-
})
2010-
}
2011-
}
2012-
20131982
#[test]
20141983
fn invalid_runtime_sized_arrays() {
20151984
// You can't have structs whose last member is an unsized struct. An unsized

0 commit comments

Comments
 (0)