mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-23 23:34:29 +00:00
feat(wgsl-in): add @diagnostic(…)
checks on global decls.
Co-authored-by: Teodor Tanasoaia <28601907+teoxoy@users.noreply.github.com>
This commit is contained in:
parent
82e7aa3d5b
commit
c259f3b5a0
@ -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")]
|
||||
|
@ -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> {
|
||||
@ -1043,6 +1051,53 @@ 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 on {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 {on_what_plural} are not supported",
|
||||
),
|
||||
labels: spans
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|span| (span, "".into()))
|
||||
.collect(),
|
||||
notes: vec![
|
||||
concat!(
|
||||
"`@diagnostic(…)` attributes are only permitted on `fn`s, ",
|
||||
"some statements, and `switch`/`loop` bodies."
|
||||
)
|
||||
.into(),
|
||||
"These attributes are well-formed, you likely just need to move them.".into(),
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
@ -2324,10 +2324,29 @@ 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)?;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
match name {
|
||||
"binding" => {
|
||||
lexer.expect(Token::Paren('('))?;
|
||||
@ -2403,17 +2422,24 @@ impl Parser {
|
||||
// read item
|
||||
let start = lexer.start_byte_offset();
|
||||
let kind = match lexer.next() {
|
||||
(Token::Separator(';'), _) => None,
|
||||
(Token::Separator(';'), _) => {
|
||||
ensure_no_diag_attrs("semicolons", diagnostic_filters)?;
|
||||
None
|
||||
}
|
||||
(Token::Word(word), directive_span) if DirectiveKind::from_ident(word).is_some() => {
|
||||
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('='))?;
|
||||
@ -2422,6 +2448,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(':')) {
|
||||
@ -2438,6 +2466,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(':')) {
|
||||
@ -2462,11 +2492,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 {
|
||||
@ -2485,6 +2523,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('('));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user