Skip to content

Commit

Permalink
feat(wgsl-in): add @diagnostic(…) checks on global decls.
Browse files Browse the repository at this point in the history
  • Loading branch information
ErichDonGubler committed Nov 12, 2024
1 parent 67f2a79 commit e4ad51d
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 1 deletion.
12 changes: 12 additions & 0 deletions naga/src/diagnostic_filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,18 @@ impl DiagnosticFilterMap {
}
Ok(())
}

/// Were any rules specified?
pub(crate) fn is_empty(&self) -> bool {
let &Self(ref map) = self;
map.is_empty()
}

/// Returns the spans of all contained rules.
pub(crate) fn spans(&self) -> impl Iterator<Item = Span> + '_ {
let &Self(ref map) = self;
map.iter().map(|(_, &(_, span))| span)
}
}

#[cfg(feature = "wgsl-in")]
Expand Down
52 changes: 52 additions & 0 deletions naga/src/front/wgsl/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,14 @@ pub(crate) enum Error<'a> {
severity_control_name_span: Span,
},
DiagnosticDuplicateTriggeringRule(ConflictingDiagnosticRuleError),
DiagnosticAttributeNotYetImplementedAtParseSite {
site_name_plural: &'static str,
spans: Vec<Span>,
},
DiagnosticAttributeNotSupported {
on_what_plural: &'static str,
spans: Vec<Span>,
},
}

impl<'a> From<ConflictingDiagnosticRuleError> for Error<'a> {
Expand Down Expand Up @@ -1043,6 +1051,50 @@ impl<'a> Error<'a> {
.into()],
}
}
Error::DiagnosticAttributeNotYetImplementedAtParseSite {
site_name_plural,
ref spans,
} => ParseError {
message: "`@diagnostic(…)` attribute(s) not yet implemented".into(),
labels: {
let mut spans = spans.iter().cloned();
let first = spans
.next()
.map(|span| {
(
span,
format!("can't use this for {site_name_plural} (yet)").into(),
)
})
.expect("internal error: diag. attr. rejection on empty map");
std::iter::once(first)
.chain(spans.map(|span| (span, "".into())))
.collect()
},
notes: vec![format!(concat!(
"Let Naga maintainers know that you ran into this at ",
"<https://github.com/gfx-rs/wgpu/issues/5320>, ",
"so they can prioritize it!"
))],
},
Error::DiagnosticAttributeNotSupported {
on_what_plural,
ref spans,
} => ParseError {
message: format!(
"`@diagnostic(…)` attribute(s) {on_what_plural}, which are not supported"
),
labels: spans
.iter()
.cloned()
.map(|span| (span, "".into()))
.collect(),
notes: vec![
"`@diagnostic(…)` attributes are only permitted on `fn`s and statements."
.into(),
"These attributes are well-formed, you likely just need to move them.".into(),
],
},
}
}
}
Expand Down
38 changes: 37 additions & 1 deletion naga/src/front/wgsl/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1698,7 +1698,7 @@ impl Parser {
let _ = lexer.next();
self.pop_rule_span(lexer);
}
(Token::Paren('{'), _) => {
(Token::Paren('{') | Token::Attribute, _) => {
let (inner, span) = self.block(lexer, ctx, brace_nesting_level)?;
block.stmts.push(ast::Statement {
kind: ast::StatementKind::Block(inner),
Expand Down Expand Up @@ -2324,10 +2324,28 @@ impl Parser {
types: &mut out.types,
unresolved: &mut dependencies,
};
let mut diagnostic_filters = DiagnosticFilterMap::new();
let ensure_no_diag_attrs =
|on_what_plural, filters: DiagnosticFilterMap| -> Result<(), Error> {
if filters.is_empty() {
Ok(())
} else {
Err(Error::DiagnosticAttributeNotSupported {
on_what_plural,
spans: filters.spans().collect(),
})
}
};

self.push_rule_span(Rule::Attribute, lexer);
while lexer.skip(Token::Attribute) {
let (name, name_span) = lexer.next_ident_with_span()?;
if let Some(DirectiveKind::Diagnostic) = DirectiveKind::from_ident(name) {
if let Some(filter) = self.diagnostic_filter(lexer)? {
let span = self.peek_rule_span(lexer);
diagnostic_filters.add(filter, span)?;
}
}
match name {
"binding" => {
lexer.expect(Token::Paren('('))?;
Expand Down Expand Up @@ -2408,12 +2426,16 @@ impl Parser {
return Err(Error::DirectiveAfterFirstGlobalDecl { directive_span });
}
(Token::Word("struct"), _) => {
ensure_no_diag_attrs("`struct`s", diagnostic_filters)?;

let name = lexer.next_ident()?;

let members = self.struct_body(lexer, &mut ctx)?;
Some(ast::GlobalDeclKind::Struct(ast::Struct { name, members }))
}
(Token::Word("alias"), _) => {
ensure_no_diag_attrs("`alias`es", diagnostic_filters)?;

let name = lexer.next_ident()?;

lexer.expect(Token::Operation('='))?;
Expand All @@ -2422,6 +2444,8 @@ impl Parser {
Some(ast::GlobalDeclKind::Type(ast::TypeAlias { name, ty }))
}
(Token::Word("const"), _) => {
ensure_no_diag_attrs("`const`s", diagnostic_filters)?;

let name = lexer.next_ident()?;

let ty = if lexer.skip(Token::Separator(':')) {
Expand All @@ -2438,6 +2462,8 @@ impl Parser {
Some(ast::GlobalDeclKind::Const(ast::Const { name, ty, init }))
}
(Token::Word("override"), _) => {
ensure_no_diag_attrs("`override`s", diagnostic_filters)?;

let name = lexer.next_ident()?;

let ty = if lexer.skip(Token::Separator(':')) {
Expand All @@ -2462,11 +2488,19 @@ impl Parser {
}))
}
(Token::Word("var"), _) => {
ensure_no_diag_attrs("`var`s", diagnostic_filters)?;

let mut var = self.variable_decl(lexer, &mut ctx)?;
var.binding = binding.take();
Some(ast::GlobalDeclKind::Var(var))
}
(Token::Word("fn"), _) => {
if !diagnostic_filters.is_empty() {
return Err(Error::DiagnosticAttributeNotYetImplementedAtParseSite {
site_name_plural: "functions",
spans: diagnostic_filters.spans().collect(),
});
}
let function = self.function_decl(lexer, out, &mut dependencies)?;
Some(ast::GlobalDeclKind::Fn(ast::Function {
entry_point: if let Some(stage) = stage.value {
Expand All @@ -2485,6 +2519,8 @@ impl Parser {
}))
}
(Token::Word("const_assert"), _) => {
ensure_no_diag_attrs("`const_assert`s", diagnostic_filters)?;

// parentheses are optional
let paren = lexer.skip(Token::Paren('('));

Expand Down

0 comments on commit e4ad51d

Please sign in to comment.