Skip to content
Open
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
4 changes: 4 additions & 0 deletions naga/src/front/glsl/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ pub struct HirExpr {

#[derive(Debug, Clone)]
pub enum HirExprKind {
/// helper to represent a sequence of expressions where side effects matter, the last one is return to the caller
Sequence {
exprs: Vec<Handle<HirExpr>>,
},
Access {
base: Handle<HirExpr>,
index: Handle<HirExpr>,
Expand Down
18 changes: 18 additions & 0 deletions naga/src/front/glsl/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1333,6 +1333,7 @@ impl<'a> Context<'a> {
}
}
}

_ => {
return Err(Error {
kind: ErrorKind::SemanticError(
Expand All @@ -1343,6 +1344,23 @@ impl<'a> Context<'a> {
}
}
}
HirExprKind::Sequence { ref exprs } if pos != ExprPos::Lhs => {
let mut last_handle = None;
for expr in exprs.iter() {
let (handle, _) =
self.lower_expect_inner(stmt, frontend, *expr, ExprPos::Rhs)?;
last_handle = Some(handle);
}
match last_handle {
Some(handle) => handle,
None => {
return Err(Error {
kind: ErrorKind::SemanticError("Empty expression sequence".into()),
meta,
})
Comment on lines +1357 to +1360
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this can't be produced by the parser its more clear to say unreachable!()

}
}
}
_ => {
return Err(Error {
kind: ErrorKind::SemanticError(
Expand Down
25 changes: 24 additions & 1 deletion naga/src/front/glsl/parser/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,20 +511,43 @@ impl ParsingContext<'_> {
})
}

// shader grammar :-
// expression :
// assignment_expression
// expression COMMA assignment_expression
pub fn parse_expression(
&mut self,
frontend: &mut Frontend,
ctx: &mut Context,
stmt: &mut StmtContext,
) -> Result<Handle<HirExpr>> {
let mut exprs = Vec::new();
let mut expr = self.parse_assignment(frontend, ctx, stmt)?;
exprs.push(expr);

while let TokenValue::Comma = self.expect_peek(frontend)?.value {
self.bump(frontend)?;
expr = self.parse_assignment(frontend, ctx, stmt)?;
exprs.push(expr);
}

Ok(expr)
if exprs.len() == 1 {
Ok(expr)
} else {
let mut meta = stmt.hir_exprs[exprs[0]].meta;
for &e in &exprs[1..] {
meta.subsume(stmt.hir_exprs[e].meta);
}
Comment on lines +538 to +540
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for handling the spans correctly

expr = stmt.hir_exprs.append(
HirExpr {
kind: HirExprKind::Sequence { exprs },
meta,
},
Default::default(),
);

Ok(expr)
}
}
}

Expand Down
22 changes: 20 additions & 2 deletions naga/src/front/glsl/parser/functions.rs
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of non-functional changes here, see overall review comment

Original file line number Diff line number Diff line change
Expand Up @@ -432,23 +432,40 @@ impl ParsingContext<'_> {

meta
}

// shader grammar :-
// iteration_statement : (third option only)
// FOR LEFT_PAREN for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope
TokenValue::For => {
//FOR
let mut meta = self.bump(frontend)?.meta;

ctx.symbol_table.push_scope();
self.expect(frontend, TokenValue::LeftParen)?;
self.expect(frontend, TokenValue::LeftParen)?; // LEFT_PAREN

// shader grammar :-
// for_init_statement :
// expression_statement
// declaration_statement
if self.bump_if(frontend, TokenValue::Semicolon).is_none() {
if self.peek_type_name(frontend) || self.peek_type_qualifier(frontend) {
self.parse_declaration(frontend, ctx, false, is_inside_loop)?;
// declaration_statement (basically the same as `declaration`)
} else {
// shader grammar :-
// expression_statement :
// SEMICOLON
// expression SEMICOLON
let mut stmt = ctx.stmt_ctx();
let expr = self.parse_expression(frontend, ctx, &mut stmt)?;
ctx.lower(stmt, frontend, expr, ExprPos::Rhs)?;
self.expect(frontend, TokenValue::Semicolon)?;
}
}

// shader grammar :-
// for_rest_statement :
// conditionopt SEMICOLON
// conditionopt SEMICOLON expression
let loop_body = ctx.new_body(|ctx| {
if self.bump_if(frontend, TokenValue::Semicolon).is_none() {
let (expr, expr_meta) = if self.peek_type_name(frontend)
Expand Down Expand Up @@ -508,6 +525,7 @@ impl ParsingContext<'_> {
Ok(())
})?;

// shader grammar just has a single expression here, which can be multiple expressions separated by commas...
let continuing = ctx.new_body(|ctx| {
match self.expect_peek(frontend)?.value {
TokenValue::RightParen => {}
Expand Down
19 changes: 19 additions & 0 deletions naga/tests/in/glsl/multipart-for-loop.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// issue #6208 https://github.com/gfx-rs/wgpu/issues/6208
# version 460
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


void main() {
float a = 1.0;
float b = 0.25;
float c = 1.5;
int i = 20;

// tests for multiple expressions in first part (if it's a expression, not declaration)!
// also the third part!
for (i = 0, c-=1.0; i < 25; i++, b+=0.01) {
a -= 0.02;
}

// a, b and c should be all ~0.5!
// right now it only ever takes the last expression in the block...
// leading to infinite loops, lost devices and incorrect results.
}
33 changes: 33 additions & 0 deletions naga/tests/out/wgsl/glsl-multipart-for-loop.frag.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
fn main_1() {
var a: f32 = 1f;
var b: f32 = 0.25f;
var c: f32 = 1.5f;
var i: i32 = 20i;

i = 0i;
let _e9 = c;
c = (_e9 - 1f);
loop {
let _e12 = i;
if !((_e12 < 25i)) {
break;
}
{
let _e22 = a;
a = (_e22 - 0.02f);
}
continuing {
let _e16 = i;
i = (_e16 + 1i);
let _e19 = b;
b = (_e19 + 0.01f);
}
}
return;
}

@fragment
fn main() {
main_1();
return;
}
Loading