mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[wgsl-in] Refuse to apply postfix expressions to WGSL pointers.
Fixes #1356. Output for the test case in that issue is now: error: the value indexed by a `[]` subscripting expression must not be a pointer ┌─ wgsl:5:14 │ 5 │ let a = *pv[3]; // Problematic line │ ^^ expression is a pointer Could not parse WGSL
This commit is contained in:
committed by
Dzmitry Malyshau
parent
08c1a1e9a3
commit
d31121df77
@@ -165,9 +165,9 @@ pub enum Error<'a> {
|
||||
MissingType(Span),
|
||||
InvalidAtomicPointer(Span),
|
||||
InvalidAtomicOperandType(Span),
|
||||
Pointer(&'static str, Span),
|
||||
NotPointer(Span),
|
||||
AddressOfNotReference(Span),
|
||||
AssignmentNotReference(Span),
|
||||
NotReference(&'static str, Span),
|
||||
Other,
|
||||
}
|
||||
|
||||
@@ -419,14 +419,14 @@ impl<'a> Error<'a> {
|
||||
labels: vec![(span.clone(), "expression is not a pointer".into())],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::AddressOfNotReference(ref span) => ParseError {
|
||||
message: "the operand of the `&` operator must be a reference".to_string(),
|
||||
Error::NotReference(what, ref span) => ParseError {
|
||||
message: format!("{} must be a reference", what),
|
||||
labels: vec![(span.clone(), "expression is not a reference".into())],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::AssignmentNotReference(ref span) => ParseError {
|
||||
message: "the left-hand side of an assignment be a reference".to_string(),
|
||||
labels: vec![(span.clone(), "expression is not a reference".into())],
|
||||
Error::Pointer(what, ref span) => ParseError {
|
||||
message: format!("{} must not be a pointer", what),
|
||||
labels: vec![(span.clone(), "expression is a pointer".into())],
|
||||
notes: vec![],
|
||||
},
|
||||
Error::Other => ParseError {
|
||||
@@ -2135,43 +2135,56 @@ impl Parser {
|
||||
mut handle,
|
||||
mut is_reference,
|
||||
} = expr;
|
||||
let mut prefix_span = lexer.span_from(span_start);
|
||||
|
||||
loop {
|
||||
// Step lightly around `resolve_type`'s mutable borrow.
|
||||
ctx.resolve_type(handle)?;
|
||||
|
||||
// Find the type of the composite whose elements, components or members we're
|
||||
// accessing, skipping through references: except for swizzles, the `Access`
|
||||
// or `AccessIndex` expressions we'd generate are the same either way.
|
||||
//
|
||||
// Pointers, however, are not permitted. For error checks below, note whether
|
||||
// the base expression is a WGSL pointer.
|
||||
let temp_inner;
|
||||
let (composite, wgsl_pointer) = match *ctx.typifier.get(handle, ctx.types) {
|
||||
crate::TypeInner::Pointer { base, .. } => (&ctx.types[base].inner, !is_reference),
|
||||
crate::TypeInner::ValuePointer {
|
||||
size: None,
|
||||
kind,
|
||||
width,
|
||||
..
|
||||
} => {
|
||||
temp_inner = crate::TypeInner::Scalar { kind, width };
|
||||
(&temp_inner, !is_reference)
|
||||
}
|
||||
crate::TypeInner::ValuePointer {
|
||||
size: Some(size),
|
||||
kind,
|
||||
width,
|
||||
..
|
||||
} => {
|
||||
temp_inner = crate::TypeInner::Vector { size, kind, width };
|
||||
(&temp_inner, !is_reference)
|
||||
}
|
||||
ref other => (other, false),
|
||||
};
|
||||
|
||||
let expression = match lexer.peek().0 {
|
||||
Token::Separator('.') => {
|
||||
let _ = lexer.next();
|
||||
let (name, name_span) = lexer.next_ident_with_span()?;
|
||||
|
||||
// Step lightly around `resolve_type`'s mutable borrow.
|
||||
ctx.resolve_type(handle)?;
|
||||
|
||||
// Find the type of the composite whose components or members we're
|
||||
// accessing, skipping through pointers: except for swizzles, the
|
||||
// `Access` or `AccessIndex` expressions we'd generate are the same
|
||||
// either way.
|
||||
let temp_inner;
|
||||
let composite = match *ctx.typifier.get(handle, ctx.types) {
|
||||
crate::TypeInner::Pointer { base, .. } => &ctx.types[base].inner,
|
||||
crate::TypeInner::ValuePointer {
|
||||
size: None,
|
||||
kind,
|
||||
width,
|
||||
..
|
||||
} => {
|
||||
temp_inner = crate::TypeInner::Scalar { kind, width };
|
||||
&temp_inner
|
||||
}
|
||||
crate::TypeInner::ValuePointer {
|
||||
size: Some(size),
|
||||
kind,
|
||||
width,
|
||||
..
|
||||
} => {
|
||||
temp_inner = crate::TypeInner::Vector { size, kind, width };
|
||||
&temp_inner
|
||||
}
|
||||
ref other => other,
|
||||
};
|
||||
// WGSL doesn't allow accessing members on pointers, or swizzling
|
||||
// them. But Naga IR doesn't distinguish pointers and references, so
|
||||
// we must check here.
|
||||
if wgsl_pointer {
|
||||
return Err(Error::Pointer(
|
||||
"the value accessed by a `.member` expression",
|
||||
prefix_span,
|
||||
));
|
||||
}
|
||||
|
||||
let access = match *composite {
|
||||
crate::TypeInner::Struct { ref members, .. } => {
|
||||
@@ -2219,6 +2232,15 @@ impl Parser {
|
||||
let index = self.parse_general_expression(lexer, ctx.reborrow())?;
|
||||
let close_brace_span = lexer.expect_span(Token::Paren(']'))?;
|
||||
|
||||
// WGSL doesn't allow pointers to be subscripted. But Naga IR doesn't
|
||||
// distinguish pointers and references, so we must check here.
|
||||
if wgsl_pointer {
|
||||
return Err(Error::Pointer(
|
||||
"the value indexed by a `[]` subscripting expression",
|
||||
prefix_span,
|
||||
));
|
||||
}
|
||||
|
||||
if let crate::Expression::Constant(constant) = ctx.expressions[index] {
|
||||
let expr_span = open_brace_span.end..close_brace_span.start;
|
||||
|
||||
@@ -2248,9 +2270,10 @@ impl Parser {
|
||||
_ => break,
|
||||
};
|
||||
|
||||
prefix_span = lexer.span_from(span_start);
|
||||
handle = ctx
|
||||
.expressions
|
||||
.append(expression, NagaSpan::from(lexer.span_from(span_start)));
|
||||
.append(expression, NagaSpan::from(prefix_span.clone()));
|
||||
}
|
||||
|
||||
Ok(TypedExpression {
|
||||
@@ -2327,7 +2350,7 @@ impl Parser {
|
||||
.get_span(operand.handle)
|
||||
.to_range()
|
||||
.unwrap_or_else(|| self.peek_scope(lexer));
|
||||
return Err(Error::AddressOfNotReference(span));
|
||||
return Err(Error::NotReference("the operand of the `&` operator", span));
|
||||
}
|
||||
|
||||
// No code is generated. We just declare the pointer a reference now.
|
||||
@@ -3065,7 +3088,10 @@ impl Parser {
|
||||
// The left hand side of an assignment must be a reference.
|
||||
if !reference.is_reference {
|
||||
let span = span_start..lexer.current_byte_offset();
|
||||
return Err(Error::AssignmentNotReference(span));
|
||||
return Err(Error::NotReference(
|
||||
"the left-hand side of an assignment",
|
||||
span,
|
||||
));
|
||||
}
|
||||
lexer.expect(Token::Operation('='))?;
|
||||
let value = self.parse_general_expression(lexer, context.reborrow())?;
|
||||
|
||||
@@ -493,6 +493,44 @@ fn local_var_missing_type() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn postfix_pointers() {
|
||||
check(
|
||||
r#"
|
||||
fn main() {
|
||||
var v: vec4<f32> = vec4<f32>(1.0, 1.0, 1.0, 1.0);
|
||||
let pv = &v;
|
||||
let a = *pv[3]; // Problematic line
|
||||
}
|
||||
"#,
|
||||
r#"error: the value indexed by a `[]` subscripting expression must not be a pointer
|
||||
┌─ wgsl:5:26
|
||||
│
|
||||
5 │ let a = *pv[3]; // Problematic line
|
||||
│ ^^ expression is a pointer
|
||||
|
||||
"#,
|
||||
);
|
||||
|
||||
check(
|
||||
r#"
|
||||
struct S { m: i32; };
|
||||
fn main() {
|
||||
var s: S = S(42);
|
||||
let ps = &s;
|
||||
let a = *ps.m; // Problematic line
|
||||
}
|
||||
"#,
|
||||
r#"error: the value accessed by a `.member` expression must not be a pointer
|
||||
┌─ wgsl:6:26
|
||||
│
|
||||
6 │ let a = *ps.m; // Problematic line
|
||||
│ ^^ expression is a pointer
|
||||
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! check_validation_error {
|
||||
// We want to support an optional guard expression after the pattern, so
|
||||
// that we can check values we can't match against, like strings.
|
||||
@@ -778,6 +816,13 @@ fn valid_access() {
|
||||
// `Access` to a `ValuePointer`.
|
||||
return temp[i][j];
|
||||
}
|
||||
",
|
||||
"
|
||||
fn main() {
|
||||
var v: vec4<f32> = vec4<f32>(1.0, 1.0, 1.0, 1.0);
|
||||
let pv = &v;
|
||||
let a = (*pv)[3];
|
||||
}
|
||||
":
|
||||
Ok(_)
|
||||
}
|
||||
@@ -789,7 +834,7 @@ fn invalid_local_vars() {
|
||||
"
|
||||
struct Unsized { data: array<f32>; };
|
||||
fn local_ptr_dynamic_array(okay: ptr<storage, Unsized>) {
|
||||
var not_okay: ptr<storage, array<f32>> = okay.data;
|
||||
var not_okay: ptr<storage, array<f32>> = &(*okay).data;
|
||||
}
|
||||
":
|
||||
Err(naga::valid::ValidationError::Function {
|
||||
|
||||
Reference in New Issue
Block a user