From fc4f8117a3eee488e50226a42df9c472062ee140 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Tue, 1 Oct 2024 10:21:49 -0400 Subject: [PATCH 01/12] WIP: refactor(wgsl-in): add peeking variants of `Lexer::next_ident*` 1. Break out `word_as_ident*` helpers to keep validation of identifiers DRY. 2. Add `peek_*` variants. TODO: Pending validation from @jimb at --- naga/src/front/wgsl/parse/lexer.rs | 45 ++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/naga/src/front/wgsl/parse/lexer.rs b/naga/src/front/wgsl/parse/lexer.rs index d03a448561..e6af75215a 100644 --- a/naga/src/front/wgsl/parse/lexer.rs +++ b/naga/src/front/wgsl/parse/lexer.rs @@ -350,27 +350,50 @@ impl<'a> Lexer<'a> { &mut self, ) -> Result<(&'a str, Span), Error<'a>> { match self.next() { - (Token::Word("_"), span) => Err(Error::InvalidIdentifierUnderscore(span)), - (Token::Word(word), span) if word.starts_with("__") => { - Err(Error::ReservedIdentifierPrefix(span)) - } - (Token::Word(word), span) => Ok((word, span)), + (Token::Word(word), span) => Self::word_as_ident_with_span(word, span), + other => Err(Error::Unexpected(other.1, ExpectedToken::Identifier)), + } + } + + pub(in crate::front::wgsl) fn peek_ident_with_span( + &mut self, + ) -> Result<(&'a str, Span), Error<'a>> { + match self.peek() { + (Token::Word(word), span) => Self::word_as_ident_with_span(word, span), other => Err(Error::Unexpected(other.1, ExpectedToken::Identifier)), } } + fn word_as_ident_with_span(word: &'a str, span: Span) -> Result<(&'a str, Span), Error<'a>> { + match word { + "_" => Err(Error::InvalidIdentifierUnderscore(span)), + word if word.starts_with("__") => Err(Error::ReservedIdentifierPrefix(span)), + word => Ok((word, span)), + } + } + pub(in crate::front::wgsl) fn next_ident( &mut self, ) -> Result, Error<'a>> { - let ident = self - .next_ident_with_span() - .map(|(name, span)| super::ast::Ident { name, span })?; + self.next_ident_with_span() + .and_then(|(word, span)| Self::word_as_ident(word, span)) + .map(|(name, span)| super::ast::Ident { name, span }) + } - if crate::keywords::wgsl::RESERVED.contains(&ident.name) { - return Err(Error::ReservedKeyword(ident.span)); + fn word_as_ident(word: &'a str, span: Span) -> Result<(&'a str, Span), Error<'a>> { + if crate::keywords::wgsl::RESERVED.contains(&word) { + Err(Error::ReservedKeyword(span)) + } else { + Ok((word, span)) } + } - Ok(ident) + pub(in crate::front::wgsl) fn peek_ident( + &mut self, + ) -> Result, Error<'a>> { + self.peek_ident_with_span() + .and_then(|(word, span)| Self::word_as_ident(word, span)) + .map(|(name, span)| super::ast::Ident { name, span }) } /// Parses a generic scalar type, for example ``. From d8e73a7db50e714d1049d6bea52ce84723b2f1cf Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 23 Aug 2024 13:04:50 -0400 Subject: [PATCH 02/12] feat(wgsl-in): create skeleton for parsing directives --- naga/src/front/wgsl/error.rs | 43 ++++++++++++++++++++++++++ naga/src/front/wgsl/parse/directive.rs | 41 ++++++++++++++++++++++++ naga/src/front/wgsl/parse/mod.rs | 29 +++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 naga/src/front/wgsl/parse/directive.rs diff --git a/naga/src/front/wgsl/error.rs b/naga/src/front/wgsl/error.rs index 7c65d93de3..3c08d3d338 100644 --- a/naga/src/front/wgsl/error.rs +++ b/naga/src/front/wgsl/error.rs @@ -265,6 +265,14 @@ pub(crate) enum Error<'a> { PipelineConstantIDValue(Span), NotBool(Span), ConstAssertFailed(Span), + DirectiveNotYetImplemented { + kind: &'static str, + span: Span, + tracking_issue_num: u16, + }, + DirectiveAfterFirstGlobalDecl { + directive_span: Span, + }, } #[derive(Clone, Debug)] @@ -861,6 +869,41 @@ impl<'a> Error<'a> { labels: vec![(span, "evaluates to false".into())], notes: vec![], }, + Error::DirectiveNotYetImplemented { + kind, + span, + tracking_issue_num, + } => ParseError { + message: format!("`{kind}` global directives are not yet supported (sorry!)"), + labels: vec![( + span, + concat!( + "this directive specifies standard functionality ", + "which is not yet implemented in Naga" + ) + .into(), + )], + notes: vec![format!( + concat!( + "Let Naga maintainers know that you ran into this at ", + ", ", + "so they can prioritize it!" + ), + tracking_issue_num + )], + }, + Error::DirectiveAfterFirstGlobalDecl { directive_span } => ParseError { + message: "expected global declaration, but found a global directive".into(), + labels: vec![( + directive_span, + "this directive was written after global declaration parsing started".into(), + )], + notes: vec![concat!( + "global directives are only allowed before global declarations; ", + "maybe hoist this closer to the top of the shader?" + ) + .into()], + }, } } } diff --git a/naga/src/front/wgsl/parse/directive.rs b/naga/src/front/wgsl/parse/directive.rs new file mode 100644 index 0000000000..128d7e2f72 --- /dev/null +++ b/naga/src/front/wgsl/parse/directive.rs @@ -0,0 +1,41 @@ +#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +pub enum DirectiveKind { + Unimplemented(UnimplementedDirectiveKind), +} + +impl DirectiveKind { + pub fn from_ident(s: &str) -> Option<(Self, &'static str)> { + Some(match s { + "diagnostic" => ( + Self::Unimplemented(UnimplementedDirectiveKind::Diagnostic), + "diagnostic", + ), + "enable" => ( + Self::Unimplemented(UnimplementedDirectiveKind::Enable), + "enable", + ), + "requires" => ( + Self::Unimplemented(UnimplementedDirectiveKind::Requires), + "requires", + ), + _ => return None, + }) + } +} + +#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +pub enum UnimplementedDirectiveKind { + Diagnostic, + Enable, + Requires, +} + +impl UnimplementedDirectiveKind { + pub const fn tracking_issue_num(self) -> u16 { + match self { + Self::Diagnostic => 5320, + Self::Requires => 6350, + Self::Enable => 5476, + } + } +} diff --git a/naga/src/front/wgsl/parse/mod.rs b/naga/src/front/wgsl/parse/mod.rs index 3b1d60620b..07ef04132b 100644 --- a/naga/src/front/wgsl/parse/mod.rs +++ b/naga/src/front/wgsl/parse/mod.rs @@ -1,4 +1,5 @@ use crate::front::wgsl::error::{Error, ExpectedToken}; +use crate::front::wgsl::parse::directive::DirectiveKind; use crate::front::wgsl::parse::lexer::{Lexer, Token}; use crate::front::wgsl::parse::number::Number; use crate::front::wgsl::Scalar; @@ -7,6 +8,7 @@ use crate::{Arena, FastIndexSet, Handle, ShaderStage, Span}; pub mod ast; pub mod conv; +pub mod directive; pub mod lexer; pub mod number; @@ -136,6 +138,7 @@ enum Rule { SingularExpr, UnaryExpr, GeneralExpr, + Directive, } struct ParsedAttribute { @@ -2357,6 +2360,9 @@ impl Parser { let start = lexer.start_byte_offset(); let kind = match lexer.next() { (Token::Separator(';'), _) => None, + (Token::Word(word), directive_span) if DirectiveKind::from_ident(word).is_some() => { + return Err(Error::DirectiveAfterFirstGlobalDecl { directive_span }); + } (Token::Word("struct"), _) => { let name = lexer.next_ident()?; @@ -2474,6 +2480,29 @@ impl Parser { let mut lexer = Lexer::new(source); let mut tu = ast::TranslationUnit::default(); + + // Parse directives. + #[allow(clippy::never_loop)] + loop { + if let Ok(ident) = lexer.peek_ident() { + self.push_rule_span(Rule::Directive, &mut lexer); + if let Some((kind, name)) = DirectiveKind::from_ident(ident.name) { + match kind { + DirectiveKind::Unimplemented(unimplemented) => { + return Err(Error::DirectiveNotYetImplemented { + kind: name, + span: ident.span, + tracking_issue_num: unimplemented.tracking_issue_num(), + }) + } + } + } + // TODO: add directives to set of expected things in errors later + self.pop_rule_span(&lexer); + } + break; + } + loop { match self.global_decl(&mut lexer, &mut tu) { Err(error) => return Err(error), From b0c008bacff84f62c7a20c7af0cd6c61cdacd3c4 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Tue, 1 Oct 2024 15:02:51 -0400 Subject: [PATCH 03/12] WIP: add tests for unsupported and out-of-order directives From 50e70f858a55cc098e02267b4d2701b54f9d70ee Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Tue, 1 Oct 2024 07:27:33 -0400 Subject: [PATCH 04/12] refactor(wgsl-in): specify more closure ret. types in parsing This resolves ambiguity that will be introduced in the subsequent commit that adds `impl From for naga::Error`. --- naga/src/front/wgsl/lower/mod.rs | 4 ++-- naga/src/front/wgsl/parse/mod.rs | 12 +++++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/naga/src/front/wgsl/lower/mod.rs b/naga/src/front/wgsl/lower/mod.rs index 78e81350b4..e800796587 100644 --- a/naga/src/front/wgsl/lower/mod.rs +++ b/naga/src/front/wgsl/lower/mod.rs @@ -1244,7 +1244,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { .arguments .iter() .enumerate() - .map(|(i, arg)| { + .map(|(i, arg)| -> Result<_, Error<'_>> { let ty = self.resolve_ast_type(arg.ty, ctx)?; let expr = expressions .append(crate::Expression::FunctionArgument(i as u32), arg.name.span); @@ -1263,7 +1263,7 @@ impl<'source, 'temp> Lowerer<'source, 'temp> { let result = f .result .as_ref() - .map(|res| { + .map(|res| -> Result<_, Error<'_>> { let ty = self.resolve_ast_type(res.ty, ctx)?; Ok(crate::FunctionResult { ty, diff --git a/naga/src/front/wgsl/parse/mod.rs b/naga/src/front/wgsl/parse/mod.rs index 07ef04132b..3c04845b1b 100644 --- a/naga/src/front/wgsl/parse/mod.rs +++ b/naga/src/front/wgsl/parse/mod.rs @@ -1894,10 +1894,8 @@ impl Parser { let _ = lexer.next(); let mut body = ast::Block::default(); - let (condition, span) = lexer.capture_span(|lexer| { - let condition = self.general_expression(lexer, ctx)?; - Ok(condition) - })?; + let (condition, span) = + lexer.capture_span(|lexer| self.general_expression(lexer, ctx))?; let mut reject = ast::Block::default(); reject.stmts.push(ast::Statement { kind: ast::StatementKind::Break, @@ -1954,9 +1952,9 @@ impl Parser { let mut body = ast::Block::default(); if !lexer.skip(Token::Separator(';')) { let (condition, span) = lexer.capture_span(|lexer| { - let condition = self.general_expression(lexer, ctx)?; - lexer.expect(Token::Separator(';'))?; - Ok(condition) + self.general_expression(lexer, ctx).and_then(|condition| { + lexer.expect(Token::Separator(';')).map(|()| condition) + }) })?; let mut reject = ast::Block::default(); reject.stmts.push(ast::Statement { From e9852b78c17d160ffc7a0ee7e963e10e349daa7f Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Mon, 30 Sep 2024 09:29:13 -0400 Subject: [PATCH 05/12] feat: `impl Eq for naga::Span` --- naga/src/span.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/naga/src/span.rs b/naga/src/span.rs index f8a0f67fbe..252884871a 100644 --- a/naga/src/span.rs +++ b/naga/src/span.rs @@ -2,7 +2,7 @@ use crate::{Arena, Handle, UniqueArena}; use std::{error::Error, fmt, ops::Range}; /// A source code span, used for error reporting. -#[derive(Clone, Copy, Debug, PartialEq, Default)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Default)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] pub struct Span { start: u32, @@ -83,6 +83,12 @@ impl Span { length: self.end - self.start, } } + + pub fn contains(&self, other: &Self) -> bool { + self.is_defined() || { + other.is_defined() && self.start <= other.start && self.end >= other.end + } + } } impl From> for Span { From 7e54abf2fcbb53bea292f9b88ae025134d4c417c Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Mon, 30 Sep 2024 09:29:13 -0400 Subject: [PATCH 06/12] feat: `impl Hash for naga::Span` --- naga/src/span.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/naga/src/span.rs b/naga/src/span.rs index 252884871a..31f5f4cc80 100644 --- a/naga/src/span.rs +++ b/naga/src/span.rs @@ -2,7 +2,7 @@ use crate::{Arena, Handle, UniqueArena}; use std::{error::Error, fmt, ops::Range}; /// A source code span, used for error reporting. -#[derive(Clone, Copy, Debug, Eq, PartialEq, Default)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Default)] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] pub struct Span { start: u32, From 9805368c6b373cb2e96b6009fd631b0379fc5239 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 23 Aug 2024 12:25:08 -0400 Subject: [PATCH 07/12] =?UTF-8?q?WIP:=20feat(wgsl-in):=20parse=20`diagnost?= =?UTF-8?q?ic(=E2=80=A6)`=20directives=20(with=20no=20effect)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- naga/src/diagnostic_filter.rs | 89 ++++++++++++++++++++++++++ naga/src/front/wgsl/error.rs | 70 ++++++++++++++++++++ naga/src/front/wgsl/parse/directive.rs | 8 +-- naga/src/front/wgsl/parse/mod.rs | 71 +++++++++++++++++++- naga/src/lib.rs | 1 + 5 files changed, 232 insertions(+), 7 deletions(-) create mode 100644 naga/src/diagnostic_filter.rs diff --git a/naga/src/diagnostic_filter.rs b/naga/src/diagnostic_filter.rs new file mode 100644 index 0000000000..685c90fb3f --- /dev/null +++ b/naga/src/diagnostic_filter.rs @@ -0,0 +1,89 @@ +use crate::{Handle, Span}; + +use indexmap::IndexMap; + +// TODO: docs +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub enum Severity { + Off, + Info, + Warning, + Error, +} + +impl Severity { + pub fn from_ident(s: &str) -> Option { + Some(match s { + "error" => Self::Error, + "warning" => Self::Warning, + "info" => Self::Info, + "off" => Self::Off, + _ => return None, + }) + } +} + +// TODO: docs +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub enum DiagnosticTriggeringRule { + DerivativeUniformity, +} + +// TODO: docs +#[derive(Clone, Debug)] +pub struct DiagnosticFilter { + pub new_severity: Severity, + pub triggering_rule: DiagnosticTriggeringRule, +} + +// TODO: docs +#[derive(Clone, Debug, Default)] +// TODO: `FastIndexMap` mebbe? +pub(crate) struct DiagnosticFilterMap(IndexMap); + +#[cfg(feature = "wgsl-in")] +impl DiagnosticFilterMap { + pub(crate) fn new() -> Self { + Self::default() + } + + pub(crate) fn add( + &mut self, + diagnostic_filter: DiagnosticFilter, + span: Span, + ) -> Result<(), ConflictingDiagnosticRuleError> { + use indexmap::map::Entry; + + let &mut Self(ref mut diagnostic_filters) = self; + let DiagnosticFilter { + new_severity, + triggering_rule, + } = diagnostic_filter; + + match diagnostic_filters.entry(triggering_rule) { + Entry::Vacant(entry) => { + entry.insert((new_severity, span)); + Ok(()) + } + Entry::Occupied(entry) => { + return Err(ConflictingDiagnosticRuleError { + triggering_rule, + triggering_rule_spans: [entry.get().1, span], + }) + } + } + } +} +#[cfg(feature = "wgsl-in")] +#[derive(Clone, Debug)] +pub(crate) struct ConflictingDiagnosticRuleError { + pub triggering_rule: DiagnosticTriggeringRule, + pub triggering_rule_spans: [Span; 2], +} + +// TODO: docs +#[derive(Clone, Debug)] +pub struct DiagnosticFilterNode { + pub inner: DiagnosticFilter, + pub parent: Option>, +} diff --git a/naga/src/front/wgsl/error.rs b/naga/src/front/wgsl/error.rs index 3c08d3d338..e70425f188 100644 --- a/naga/src/front/wgsl/error.rs +++ b/naga/src/front/wgsl/error.rs @@ -1,3 +1,4 @@ +use crate::diagnostic_filter::{ConflictingDiagnosticRuleError, DiagnosticTriggeringRule}; use crate::front::wgsl::parse::lexer::Token; use crate::front::wgsl::Scalar; use crate::proc::{Alignment, ConstantEvaluatorError, ResolveError}; @@ -273,6 +274,30 @@ pub(crate) enum Error<'a> { DirectiveAfterFirstGlobalDecl { directive_span: Span, }, + DiagnosticInvalidSeverity { + severity_control_name_span: Span, + }, + DiagnosticInvalidRuleName { + diagnostic_rule_name_span: Span, + }, + DiagnosticDuplicateTriggeringRule { + triggering_rule: DiagnosticTriggeringRule, + triggering_rule_spans: [Span; 2], + }, +} + +// TODO: better place +impl<'a> From for Error<'a> { + fn from(value: ConflictingDiagnosticRuleError) -> Self { + let ConflictingDiagnosticRuleError { + triggering_rule, + triggering_rule_spans, + } = value; + Self::DiagnosticDuplicateTriggeringRule { + triggering_rule, + triggering_rule_spans, + } + } } #[derive(Clone, Debug)] @@ -904,6 +929,51 @@ impl<'a> Error<'a> { ) .into()], }, + Error::DiagnosticInvalidSeverity { + severity_control_name_span, + } => ParseError { + message: "invalid identifier in `diagnostic(…)` rule severity".into(), + labels: vec![( + severity_control_name_span, + "not a valid severity level".into(), + )], + // TODO: note expected values + notes: vec![], + }, + Error::DiagnosticInvalidRuleName { + diagnostic_rule_name_span, + } => ParseError { + // TODO: This should be a warning, not an error! + message: "invalid `diagnostic(…)` rule name".into(), + labels: vec![(diagnostic_rule_name_span, "not a valid rule name".into())], + // TODO: note expected values + notes: vec![], + }, + Error::DiagnosticDuplicateTriggeringRule { + triggering_rule, + triggering_rule_spans, + } => { + let [first_span, second_span] = triggering_rule_spans; + ParseError { + message: format!( + "found conflicting `@diagnostic(…)` rules for {triggering_rule:?}" + ), + // TODO: consider carrying spans for the rule name, too + labels: vec![ + (first_span, "first rule's severity".into()), + ( + second_span, + "second rule's severity, which conflicts".into(), + ), + ], + notes: vec![concat!( + "`@diagnostic(…)` rules conflict unless the severity is the same; ", + "delete a rule, or ", + "ensure that all severities with the same rule name match" + ) + .into()], + } + } } } } diff --git a/naga/src/front/wgsl/parse/directive.rs b/naga/src/front/wgsl/parse/directive.rs index 128d7e2f72..a20ef89860 100644 --- a/naga/src/front/wgsl/parse/directive.rs +++ b/naga/src/front/wgsl/parse/directive.rs @@ -1,15 +1,13 @@ #[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] pub enum DirectiveKind { Unimplemented(UnimplementedDirectiveKind), + Diagnostic, } impl DirectiveKind { pub fn from_ident(s: &str) -> Option<(Self, &'static str)> { Some(match s { - "diagnostic" => ( - Self::Unimplemented(UnimplementedDirectiveKind::Diagnostic), - "diagnostic", - ), + "diagnostic" => (Self::Diagnostic, "diagnostic"), "enable" => ( Self::Unimplemented(UnimplementedDirectiveKind::Enable), "enable", @@ -25,7 +23,6 @@ impl DirectiveKind { #[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] pub enum UnimplementedDirectiveKind { - Diagnostic, Enable, Requires, } @@ -33,7 +30,6 @@ pub enum UnimplementedDirectiveKind { impl UnimplementedDirectiveKind { pub const fn tracking_issue_num(self) -> u16 { match self { - Self::Diagnostic => 5320, Self::Requires => 6350, Self::Enable => 5476, } diff --git a/naga/src/front/wgsl/parse/mod.rs b/naga/src/front/wgsl/parse/mod.rs index 3c04845b1b..5d4e00dd6e 100644 --- a/naga/src/front/wgsl/parse/mod.rs +++ b/naga/src/front/wgsl/parse/mod.rs @@ -1,3 +1,6 @@ +use crate::diagnostic_filter::{ + DiagnosticFilter, DiagnosticFilterMap, DiagnosticTriggeringRule, Severity, +}; use crate::front::wgsl::error::{Error, ExpectedToken}; use crate::front::wgsl::parse::directive::DirectiveKind; use crate::front::wgsl::parse::lexer::{Lexer, Token}; @@ -2478,14 +2481,24 @@ impl Parser { let mut lexer = Lexer::new(source); let mut tu = ast::TranslationUnit::default(); + let mut diagnostic_filters = DiagnosticFilterMap::new(); // Parse directives. - #[allow(clippy::never_loop)] loop { if let Ok(ident) = lexer.peek_ident() { self.push_rule_span(Rule::Directive, &mut lexer); if let Some((kind, name)) = DirectiveKind::from_ident(ident.name) { match kind { + DirectiveKind::Diagnostic => { + let _ = lexer.next_ident().unwrap(); + if let Some(diagnostic_filter) = self.diagnostic_filter(&mut lexer)? { + let span = self.peek_rule_span(&lexer); + diagnostic_filters.add(diagnostic_filter, span)?; + } + lexer.expect(Token::Separator(';'))?; + self.pop_rule_span(&lexer); + continue; + } DirectiveKind::Unimplemented(unimplemented) => { return Err(Error::DirectiveNotYetImplemented { kind: name, @@ -2540,4 +2553,60 @@ impl Parser { } Ok(brace_nesting_level + 1) } + + fn diagnostic_filter<'a>( + &self, + lexer: &mut Lexer<'a>, + ) -> Result, Error<'a>> { + lexer.expect(Token::Paren('('))?; + + let (severity_control_name, severity_control_name_span) = lexer.next_ident_with_span()?; + let new_severity = Severity::from_ident(severity_control_name).ok_or( + Error::DiagnosticInvalidSeverity { + severity_control_name_span, + }, + )?; + + lexer.expect(Token::Separator(','))?; + + let (diagnostic_name_token, diagnostic_name_token_span) = lexer.next_ident_with_span()?; + let diagnostic_rule_name = if lexer.skip(Token::Separator('.')) { + // Don't try to validate these name tokens on two tokens, which is conventionally used + // for third-party tooling. + lexer.next_ident_with_span()?; + None + } else { + Some(diagnostic_name_token) + }; + let diagnostic_rule_name_span = diagnostic_name_token_span; + + // // TODO: nicer error when we have too many diagnostic name tokens + // match segments.try_push(segment) { + // Ok(()) => (), + // Err(_e) => { + // lexer; + // return Err(Error::DiagnosticTooManyNameTokens { + // overflow_span: asdf, + // }); + // } + // } + + let filter = diagnostic_rule_name + .map(|name| match name { + "derivative_uniformity" => Ok(DiagnosticTriggeringRule::DerivativeUniformity), + _ => Err(Error::DiagnosticInvalidRuleName { + diagnostic_rule_name_span, + }), + }) + .transpose()? + .map(|triggering_rule| DiagnosticFilter { + new_severity, + triggering_rule, + }); + lexer.skip(Token::Separator(',')); + lexer.expect(Token::Paren(')'))?; + + // TODO: tests + Ok(filter) + } } diff --git a/naga/src/lib.rs b/naga/src/lib.rs index 038e215a6a..1640073d4d 100644 --- a/naga/src/lib.rs +++ b/naga/src/lib.rs @@ -255,6 +255,7 @@ pub mod back; mod block; #[cfg(feature = "compact")] pub mod compact; +pub mod diagnostic_filter; pub mod error; pub mod front; pub mod keywords; From 2e7f0c81d2f5d654a78d5ed724333f5cbdbd8097 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Tue, 1 Oct 2024 15:02:34 -0400 Subject: [PATCH 08/12] WIP: add tests for `diagnostic` directives From 9a40cf0cf93c98b1fc91620e17b7a6b4763f8d57 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 23 Aug 2024 13:44:48 -0400 Subject: [PATCH 09/12] WIP: refactor(wgsl-in): track parsed `diagnostic` directives --- naga/src/diagnostic_filter.rs | 31 +++++++++++++++++++ naga/src/front/wgsl/parse/ast.rs | 8 +++++ naga/src/front/wgsl/parse/mod.rs | 26 +++++++++++++++- naga/src/lib.rs | 7 +++++ naga/src/valid/handles.rs | 17 ++++++++++ naga/tests/out/ir/access.compact.ron | 2 ++ naga/tests/out/ir/access.ron | 2 ++ .../out/ir/atomic_i_increment.compact.ron | 2 ++ naga/tests/out/ir/atomic_i_increment.ron | 2 ++ naga/tests/out/ir/collatz.compact.ron | 2 ++ naga/tests/out/ir/collatz.ron | 2 ++ naga/tests/out/ir/const_assert.compact.ron | 2 ++ naga/tests/out/ir/const_assert.ron | 2 ++ naga/tests/out/ir/local-const.compact.ron | 2 ++ naga/tests/out/ir/local-const.ron | 2 ++ ...ides-atomicCompareExchangeWeak.compact.ron | 2 ++ .../overrides-atomicCompareExchangeWeak.ron | 2 ++ .../out/ir/overrides-ray-query.compact.ron | 2 ++ naga/tests/out/ir/overrides-ray-query.ron | 2 ++ naga/tests/out/ir/overrides.compact.ron | 2 ++ naga/tests/out/ir/overrides.ron | 2 ++ naga/tests/out/ir/shadow.compact.ron | 2 ++ naga/tests/out/ir/shadow.ron | 2 ++ naga/tests/out/ir/spec-constants.compact.ron | 2 ++ naga/tests/out/ir/spec-constants.ron | 2 ++ 25 files changed, 128 insertions(+), 1 deletion(-) diff --git a/naga/src/diagnostic_filter.rs b/naga/src/diagnostic_filter.rs index 685c90fb3f..c305fb65c0 100644 --- a/naga/src/diagnostic_filter.rs +++ b/naga/src/diagnostic_filter.rs @@ -1,9 +1,18 @@ use crate::{Handle, Span}; +#[cfg(feature = "arbitrary")] +use arbitrary::Arbitrary; use indexmap::IndexMap; +#[cfg(feature = "deserialize")] +use serde::Deserialize; +#[cfg(feature = "serialize")] +use serde::Serialize; // TODO: docs #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pub enum Severity { Off, Info, @@ -25,12 +34,18 @@ impl Severity { // TODO: docs #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pub enum DiagnosticTriggeringRule { DerivativeUniformity, } // TODO: docs #[derive(Clone, Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pub struct DiagnosticFilter { pub new_severity: Severity, pub triggering_rule: DiagnosticTriggeringRule, @@ -74,6 +89,19 @@ impl DiagnosticFilterMap { } } } + +#[cfg(feature = "wgsl-in")] +impl IntoIterator for DiagnosticFilterMap { + type Item = (DiagnosticTriggeringRule, (Severity, Span)); + + type IntoIter = indexmap::map::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + let Self(this) = self; + this.into_iter() + } +} + #[cfg(feature = "wgsl-in")] #[derive(Clone, Debug)] pub(crate) struct ConflictingDiagnosticRuleError { @@ -83,6 +111,9 @@ pub(crate) struct ConflictingDiagnosticRuleError { // TODO: docs #[derive(Clone, Debug)] +#[cfg_attr(feature = "serialize", derive(Serialize))] +#[cfg_attr(feature = "deserialize", derive(Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(Arbitrary))] pub struct DiagnosticFilterNode { pub inner: DiagnosticFilter, pub parent: Option>, diff --git a/naga/src/front/wgsl/parse/ast.rs b/naga/src/front/wgsl/parse/ast.rs index 4307ca3d9f..e1619d31ae 100644 --- a/naga/src/front/wgsl/parse/ast.rs +++ b/naga/src/front/wgsl/parse/ast.rs @@ -1,3 +1,4 @@ +use crate::diagnostic_filter::DiagnosticFilterNode; use crate::front::wgsl::parse::number::Number; use crate::front::wgsl::Scalar; use crate::{Arena, FastIndexSet, Handle, Span}; @@ -24,6 +25,13 @@ pub struct TranslationUnit<'a> { /// These are referred to by `Handle>` values. /// User-defined types are referred to by name until lowering. pub types: Arena>, + + /// Arena for all diagnostic filter rules parsed in this module, including those in functions. + pub diagnostic_filters: Arena, + /// The head of a linked list of `diagnostic(…)` directives parsed in this module. + /// + /// TODO: doc more + pub diagnostic_filter_head: Option>, } #[derive(Debug, Clone, Copy)] diff --git a/naga/src/front/wgsl/parse/mod.rs b/naga/src/front/wgsl/parse/mod.rs index 5d4e00dd6e..28f5d699f6 100644 --- a/naga/src/front/wgsl/parse/mod.rs +++ b/naga/src/front/wgsl/parse/mod.rs @@ -1,5 +1,5 @@ use crate::diagnostic_filter::{ - DiagnosticFilter, DiagnosticFilterMap, DiagnosticTriggeringRule, Severity, + DiagnosticFilter, DiagnosticFilterMap, DiagnosticFilterNode, DiagnosticTriggeringRule, Severity, }; use crate::front::wgsl::error::{Error, ExpectedToken}; use crate::front::wgsl::parse::directive::DirectiveKind; @@ -2514,6 +2514,9 @@ impl Parser { break; } + tu.diagnostic_filter_head = + Self::write_diagnostic_filters(&mut tu.diagnostic_filters, diagnostic_filters, None); + loop { match self.global_decl(&mut lexer, &mut tu) { Err(error) => return Err(error), @@ -2609,4 +2612,25 @@ impl Parser { // TODO: tests Ok(filter) } + + pub(crate) fn write_diagnostic_filters( + arena: &mut Arena, + filters: DiagnosticFilterMap, + parent: Option>, + ) -> Option> { + filters + .into_iter() + .fold(parent, |acc, (triggering_rule, (new_severity, span))| { + Some(arena.append( + DiagnosticFilterNode { + inner: DiagnosticFilter { + new_severity, + triggering_rule, + }, + parent: acc, + }, + span, + )) + }) + } } diff --git a/naga/src/lib.rs b/naga/src/lib.rs index 1640073d4d..d5686ba61b 100644 --- a/naga/src/lib.rs +++ b/naga/src/lib.rs @@ -269,6 +269,7 @@ pub use crate::arena::{Arena, Handle, Range, UniqueArena}; pub use crate::span::{SourceLocation, Span, SpanContext, WithSpan}; #[cfg(feature = "arbitrary")] use arbitrary::Arbitrary; +use diagnostic_filter::DiagnosticFilterNode; #[cfg(feature = "deserialize")] use serde::Deserialize; #[cfg(feature = "serialize")] @@ -2270,4 +2271,10 @@ pub struct Module { pub functions: Arena, /// Entry points. pub entry_points: Vec, + /// Arena for all diagnostic filter rules parsed in this module, including those in functions. + pub diagnostic_filters: Arena, + /// The head of a linked list of `diagnostic(…)` directives parsed in this module. + /// + /// TODO: doc more + pub diagnostic_filter_head: Option>, } diff --git a/naga/src/valid/handles.rs b/naga/src/valid/handles.rs index f8be76d026..1d24d76722 100644 --- a/naga/src/valid/handles.rs +++ b/naga/src/valid/handles.rs @@ -2,6 +2,7 @@ use crate::{ arena::{BadHandle, BadRangeError}, + diagnostic_filter::DiagnosticFilterNode, Handle, }; @@ -39,6 +40,8 @@ impl super::Validator { ref types, ref special_types, ref global_expressions, + ref diagnostic_filters, + ref diagnostic_filter_head, } = module; // NOTE: Types being first is important. All other forms of validation depend on this. @@ -180,6 +183,20 @@ impl super::Validator { validate_type(ty)?; } + for (handle, _node) in diagnostic_filters.iter() { + handle.check_valid_for(diagnostic_filters)?; + let DiagnosticFilterNode { + inner: _, + parent: previous, + } = diagnostic_filters[handle]; + if let Some(handle) = previous { + handle.check_valid_for(diagnostic_filters)?; + } + } + if let Some(handle) = *diagnostic_filter_head { + handle.check_valid_for(diagnostic_filters)?; + } + Ok(()) } diff --git a/naga/tests/out/ir/access.compact.ron b/naga/tests/out/ir/access.compact.ron index 2d066b8ffa..1c5e177029 100644 --- a/naga/tests/out/ir/access.compact.ron +++ b/naga/tests/out/ir/access.compact.ron @@ -2348,4 +2348,6 @@ ), ), ], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/access.ron b/naga/tests/out/ir/access.ron index 2d066b8ffa..1c5e177029 100644 --- a/naga/tests/out/ir/access.ron +++ b/naga/tests/out/ir/access.ron @@ -2348,4 +2348,6 @@ ), ), ], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/atomic_i_increment.compact.ron b/naga/tests/out/ir/atomic_i_increment.compact.ron index 12a4692a3e..e1d6f1248b 100644 --- a/naga/tests/out/ir/atomic_i_increment.compact.ron +++ b/naga/tests/out/ir/atomic_i_increment.compact.ron @@ -279,4 +279,6 @@ ), ), ], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/atomic_i_increment.ron b/naga/tests/out/ir/atomic_i_increment.ron index 82fa975024..fbe52bf329 100644 --- a/naga/tests/out/ir/atomic_i_increment.ron +++ b/naga/tests/out/ir/atomic_i_increment.ron @@ -304,4 +304,6 @@ ), ), ], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/collatz.compact.ron b/naga/tests/out/ir/collatz.compact.ron index 5999cf85a2..337f541639 100644 --- a/naga/tests/out/ir/collatz.compact.ron +++ b/naga/tests/out/ir/collatz.compact.ron @@ -330,4 +330,6 @@ ), ), ], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/collatz.ron b/naga/tests/out/ir/collatz.ron index 5999cf85a2..337f541639 100644 --- a/naga/tests/out/ir/collatz.ron +++ b/naga/tests/out/ir/collatz.ron @@ -330,4 +330,6 @@ ), ), ], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/const_assert.compact.ron b/naga/tests/out/ir/const_assert.compact.ron index 9dce67b5f9..95085618ce 100644 --- a/naga/tests/out/ir/const_assert.compact.ron +++ b/naga/tests/out/ir/const_assert.compact.ron @@ -51,4 +51,6 @@ ), ], entry_points: [], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/const_assert.ron b/naga/tests/out/ir/const_assert.ron index 9dce67b5f9..95085618ce 100644 --- a/naga/tests/out/ir/const_assert.ron +++ b/naga/tests/out/ir/const_assert.ron @@ -51,4 +51,6 @@ ), ], entry_points: [], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/local-const.compact.ron b/naga/tests/out/ir/local-const.compact.ron index a9b9f32af8..3508836f7a 100644 --- a/naga/tests/out/ir/local-const.compact.ron +++ b/naga/tests/out/ir/local-const.compact.ron @@ -136,4 +136,6 @@ ), ], entry_points: [], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/local-const.ron b/naga/tests/out/ir/local-const.ron index a9b9f32af8..3508836f7a 100644 --- a/naga/tests/out/ir/local-const.ron +++ b/naga/tests/out/ir/local-const.ron @@ -136,4 +136,6 @@ ), ], entry_points: [], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/overrides-atomicCompareExchangeWeak.compact.ron b/naga/tests/out/ir/overrides-atomicCompareExchangeWeak.compact.ron index 33846ef305..13f2c989b8 100644 --- a/naga/tests/out/ir/overrides-atomicCompareExchangeWeak.compact.ron +++ b/naga/tests/out/ir/overrides-atomicCompareExchangeWeak.compact.ron @@ -125,4 +125,6 @@ ), ), ], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/overrides-atomicCompareExchangeWeak.ron b/naga/tests/out/ir/overrides-atomicCompareExchangeWeak.ron index 33846ef305..13f2c989b8 100644 --- a/naga/tests/out/ir/overrides-atomicCompareExchangeWeak.ron +++ b/naga/tests/out/ir/overrides-atomicCompareExchangeWeak.ron @@ -125,4 +125,6 @@ ), ), ], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/overrides-ray-query.compact.ron b/naga/tests/out/ir/overrides-ray-query.compact.ron index 544f63ede9..7c5ed0b08b 100644 --- a/naga/tests/out/ir/overrides-ray-query.compact.ron +++ b/naga/tests/out/ir/overrides-ray-query.compact.ron @@ -256,4 +256,6 @@ ), ), ], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/overrides-ray-query.ron b/naga/tests/out/ir/overrides-ray-query.ron index 544f63ede9..7c5ed0b08b 100644 --- a/naga/tests/out/ir/overrides-ray-query.ron +++ b/naga/tests/out/ir/overrides-ray-query.ron @@ -256,4 +256,6 @@ ), ), ], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/overrides.compact.ron b/naga/tests/out/ir/overrides.compact.ron index e7921e7325..ee62061781 100644 --- a/naga/tests/out/ir/overrides.compact.ron +++ b/naga/tests/out/ir/overrides.compact.ron @@ -196,4 +196,6 @@ ), ), ], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/overrides.ron b/naga/tests/out/ir/overrides.ron index e7921e7325..ee62061781 100644 --- a/naga/tests/out/ir/overrides.ron +++ b/naga/tests/out/ir/overrides.ron @@ -196,4 +196,6 @@ ), ), ], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/shadow.compact.ron b/naga/tests/out/ir/shadow.compact.ron index a33b7d9968..529d32ad2f 100644 --- a/naga/tests/out/ir/shadow.compact.ron +++ b/naga/tests/out/ir/shadow.compact.ron @@ -1026,4 +1026,6 @@ ), ), ], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/shadow.ron b/naga/tests/out/ir/shadow.ron index 7662f586f1..c950db5aa8 100644 --- a/naga/tests/out/ir/shadow.ron +++ b/naga/tests/out/ir/shadow.ron @@ -1304,4 +1304,6 @@ ), ), ], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/spec-constants.compact.ron b/naga/tests/out/ir/spec-constants.compact.ron index e33bec6578..fc131734a9 100644 --- a/naga/tests/out/ir/spec-constants.compact.ron +++ b/naga/tests/out/ir/spec-constants.compact.ron @@ -609,4 +609,6 @@ ), ), ], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file diff --git a/naga/tests/out/ir/spec-constants.ron b/naga/tests/out/ir/spec-constants.ron index 8319c7bd3d..2cc95f85de 100644 --- a/naga/tests/out/ir/spec-constants.ron +++ b/naga/tests/out/ir/spec-constants.ron @@ -715,4 +715,6 @@ ), ), ], + diagnostic_filters: [], + diagnostic_filter_head: None, ) \ No newline at end of file From cf23d9747722b08fbfc2f846f37057f1e8eff533 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 23 Aug 2024 13:45:19 -0400 Subject: [PATCH 10/12] WIP: feat: filter uniformity analysis errors with `derivative_uniformity` From 3cc85233687f326ace35ba1f397ded3b0e7f59c9 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Fri, 23 Aug 2024 13:46:24 -0400 Subject: [PATCH 11/12] WIP: feat(wgsl-in): parse `diagnostic` attrs. on `fn`s --- naga/src/front/wgsl/parse/ast.rs | 1 + naga/src/front/wgsl/parse/mod.rs | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/naga/src/front/wgsl/parse/ast.rs b/naga/src/front/wgsl/parse/ast.rs index e1619d31ae..80ef10f195 100644 --- a/naga/src/front/wgsl/parse/ast.rs +++ b/naga/src/front/wgsl/parse/ast.rs @@ -127,6 +127,7 @@ pub struct Function<'a> { pub arguments: Vec>, pub result: Option>, pub body: Block<'a>, + pub diagnostic_filter_head: Option>, } #[derive(Debug)] diff --git a/naga/src/front/wgsl/parse/mod.rs b/naga/src/front/wgsl/parse/mod.rs index 28f5d699f6..61f9e5123e 100644 --- a/naga/src/front/wgsl/parse/mod.rs +++ b/naga/src/front/wgsl/parse/mod.rs @@ -2179,6 +2179,7 @@ impl Parser { fn function_decl<'a>( &mut self, lexer: &mut Lexer<'a>, + diagnostic_filter_head: Option>, out: &mut ast::TranslationUnit<'a>, dependencies: &mut FastIndexSet>, ) -> Result, Error<'a>> { @@ -2251,6 +2252,7 @@ impl Parser { arguments, result, body, + diagnostic_filter_head, }; // done @@ -2282,6 +2284,7 @@ impl Parser { types: &mut out.types, unresolved: &mut dependencies, }; + let mut diagnostic_filters = DiagnosticFilterMap::new(); self.push_rule_span(Rule::Attribute, lexer); while lexer.skip(Token::Attribute) { @@ -2291,6 +2294,13 @@ impl Parser { bind_index.set(self.general_expression(lexer, &mut ctx)?, name_span)?; lexer.expect(Token::Paren(')'))?; } + ("diagnostic", _name_span) => { + if let Some(filter) = self.diagnostic_filter(lexer)? { + let span = self.peek_rule_span(lexer); + diagnostic_filters.add(filter, span)?; + // TODO: ensure that it makes sense to apply this attribute + } + } ("group", name_span) => { lexer.expect(Token::Paren('('))?; bind_group.set(self.general_expression(lexer, &mut ctx)?, name_span)?; @@ -2424,7 +2434,13 @@ impl Parser { Some(ast::GlobalDeclKind::Var(var)) } (Token::Word("fn"), _) => { - let function = self.function_decl(lexer, out, &mut dependencies)?; + let diagnostic_filter_head = Self::write_diagnostic_filters( + &mut out.diagnostic_filters, + diagnostic_filters, + out.diagnostic_filter_head, + ); + let function = + self.function_decl(lexer, diagnostic_filter_head, out, &mut dependencies)?; Some(ast::GlobalDeclKind::Fn(ast::Function { entry_point: if let Some(stage) = stage.value { if stage == ShaderStage::Compute && workgroup_size.value.is_none() { From a954d8969062d026fb6a81132ffe8860ca0dcdb6 Mon Sep 17 00:00:00 2001 From: Erich Gubler Date: Mon, 30 Sep 2024 14:20:58 -0400 Subject: [PATCH 12/12] feat: `impl FromStr for naga::wgsl::error::Severity` --- naga/src/diagnostic_filter.rs | 10 ++++++++++ naga/src/front/wgsl/parse/mod.rs | 13 +++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/naga/src/diagnostic_filter.rs b/naga/src/diagnostic_filter.rs index c305fb65c0..68b34a468e 100644 --- a/naga/src/diagnostic_filter.rs +++ b/naga/src/diagnostic_filter.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use crate::{Handle, Span}; #[cfg(feature = "arbitrary")] @@ -32,6 +34,14 @@ impl Severity { } } +impl FromStr for Severity { + type Err = (); + + fn from_str(s: &str) -> Result { + Self::from_ident(s).ok_or(()) + } +} + // TODO: docs #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[cfg_attr(feature = "serialize", derive(Serialize))] diff --git a/naga/src/front/wgsl/parse/mod.rs b/naga/src/front/wgsl/parse/mod.rs index 61f9e5123e..379666a6b5 100644 --- a/naga/src/front/wgsl/parse/mod.rs +++ b/naga/src/front/wgsl/parse/mod.rs @@ -1,5 +1,5 @@ use crate::diagnostic_filter::{ - DiagnosticFilter, DiagnosticFilterMap, DiagnosticFilterNode, DiagnosticTriggeringRule, Severity, + DiagnosticFilter, DiagnosticFilterMap, DiagnosticFilterNode, DiagnosticTriggeringRule, }; use crate::front::wgsl::error::{Error, ExpectedToken}; use crate::front::wgsl::parse::directive::DirectiveKind; @@ -2580,11 +2580,12 @@ impl Parser { lexer.expect(Token::Paren('('))?; let (severity_control_name, severity_control_name_span) = lexer.next_ident_with_span()?; - let new_severity = Severity::from_ident(severity_control_name).ok_or( - Error::DiagnosticInvalidSeverity { - severity_control_name_span, - }, - )?; + let new_severity = + severity_control_name + .parse() + .map_err(|()| Error::DiagnosticInvalidSeverity { + severity_control_name_span, + })?; lexer.expect(Token::Separator(','))?;