Repository: gfx-rs/wgpu
Pull request #6537 (2024-11-13 17:04:40)

fix(wgsl-in): include user and unknown rules in `diagnostic(…)` tracking
**Connections**

- Contributes (but does not fully resolve) #5320.

**Description**

Prior to this PR, unknown and user `diagnostic(…)` triggering rules for filters would get ignored, and certain important validations like this were not rejecting the program properly:

```wgsl
fn myfunc() {
	if (true) @diagnostic(off, my.lint) {
		//    ^^^^^^^^^^^^^^^^^^^^^^^^^ not yet supported, should report an error
	}
}
```

```
fn myfunc() {
	if (true) @diagnostic(off, wtf) {
		//    ^^^^^^^^^^^^^^^^^^^^^ should emit a warning
	}
}
```

```wgsl
diagnostic(off, my.lint);
diagnostic(warning, my.lint); // should report a conflict error
```

```wgsl
diagnostic(off, wat_is_this);
diagnostic(warning, wat_is_this); // should report a conflict error
```

**Testing**

- Tests have been added for the above cases, and a bit more. N.B. that operation and validation coverage is missing for standard rule cases still.

<!--
Thanks for filing! The codeowners file will automatically request reviews from the appropriate teams.

After you get a review and have addressed any comments, please explicitly re-request a review from the
person(s) who reviewed your changes. This will make sure it gets re-added to their review queue - you're no bothering us!
-->

**Checklist**

- [x] Run `cargo fmt`.
- [x] Run `taplo format`.
- [x] Run `cargo clippy`. If applicable, add:
  - [x] `--target wasm32-unknown-unknown`
  - [x] `--target wasm32-unknown-emscripten`
- [x] Run `cargo xtask test` to run tests.
- [x] Add change to `CHANGELOG.md`. See simple instructions inside file.



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5149ae6c4..e0d478649 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -90,7 +90,7 @@ There are some limitations to keep in mind with this new functionality:
 - Not all lints can be controlled with `diagnostic(…)` rules. In fact, only the `derivative_uniformity` triggering rule exists in the WGSL standard. That said, Naga contributors are excited to see how this level of control unlocks a new ecosystem of configurable diagnostics.
 - Finally, `diagnostic(…)` rules are not yet emitted in WGSL output. This means that `wgsl-in` → `wgsl-out` is currently a lossy process. We felt that it was important to unblock users who needed `diagnostic(…)` rules (i.e., <https://github.com/gfx-rs/wgpu/issues/3135>) before we took significant effort to fix this (tracked in <https://github.com/gfx-rs/wgpu/issues/6496>).
 
-By @ErichDonGubler in [#6456](https://github.com/gfx-rs/wgpu/pull/6456), [#6148](https://github.com/gfx-rs/wgpu/pull/6148), [#6533](https://github.com/gfx-rs/wgpu/pull/6533), [#6353](https://github.com/gfx-rs/wgpu/pull/6353).
+By @ErichDonGubler in [#6456](https://github.com/gfx-rs/wgpu/pull/6456), [#6148](https://github.com/gfx-rs/wgpu/pull/6148), [#6533](https://github.com/gfx-rs/wgpu/pull/6533), [#6353](https://github.com/gfx-rs/wgpu/pull/6353), [#6537](https://github.com/gfx-rs/wgpu/pull/6537).
 
 ### New Features
 
@@ -3482,4 +3482,4 @@ DeviceDescriptor {
 - concept of the storage hub
 - basic recording of passes and command buffers
 - submission-based lifetime tracking and command buffer recycling
-- automatic resource transitions
\ No newline at end of file
+- automatic resource transitions
diff --git a/naga/src/diagnostic_filter.rs b/naga/src/diagnostic_filter.rs
index 29499fbae..2fa5464cd 100644
--- a/naga/src/diagnostic_filter.rs
+++ b/naga/src/diagnostic_filter.rs
@@ -54,27 +54,40 @@ impl Severity {
 /// A filterable triggering rule in a [`DiagnosticFilter`].
 ///
 /// <https://www.w3.org/TR/WGSL/#filterable-triggering-rules>
-#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[derive(Clone, 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 FilterableTriggeringRule {
+    Standard(StandardFilterableTriggeringRule),
+    Unknown(Box<str>),
+    User(Box<[Box<str>; 2]>),
+}
+
+/// A filterable triggering rule in a [`DiagnosticFilter`].
+///
+/// <https://www.w3.org/TR/WGSL/#filterable-triggering-rules>
+#[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 StandardFilterableTriggeringRule {
     DerivativeUniformity,
 }
 
-impl FilterableTriggeringRule {
+impl StandardFilterableTriggeringRule {
     /// The default severity associated with this triggering rule.
     ///
     /// See <https://www.w3.org/TR/WGSL/#filterable-triggering-rules> for a table of default
     /// severities.
     pub(crate) const fn default_severity(self) -> Severity {
         match self {
-            FilterableTriggeringRule::DerivativeUniformity => Severity::Error,
+            Self::DerivativeUniformity => Severity::Error,
         }
     }
 }
 
-/// A filter that modifies how diagnostics are emitted for shaders.
+/// A filtering rule that modifies how diagnostics are emitted for shaders.
 ///
 /// <https://www.w3.org/TR/WGSL/#diagnostic-filter>
 #[derive(Clone, Debug)]
@@ -140,7 +153,7 @@ impl DiagnosticFilterMap {
             triggering_rule,
         } = diagnostic_filter;
 
-        match diagnostic_filters.entry(triggering_rule) {
+        match diagnostic_filters.entry(triggering_rule.clone()) {
             Entry::Vacant(entry) => {
                 entry.insert((new_severity, span));
             }
@@ -152,7 +165,6 @@ impl DiagnosticFilterMap {
                 };
                 if first_severity != new_severity || should_conflict_on_full_duplicate {
                     return Err(ConflictingDiagnosticRuleError {
-                        triggering_rule,
                         triggering_rule_spans: [first_span, span],
                     });
                 }
@@ -190,7 +202,6 @@ impl IntoIterator for DiagnosticFilterMap {
 #[cfg(feature = "wgsl-in")]
 #[derive(Clone, Debug)]
 pub(crate) struct ConflictingDiagnosticRuleError {
-    pub triggering_rule: FilterableTriggeringRule,
     pub triggering_rule_spans: [Span; 2],
 }
 
@@ -232,24 +243,24 @@ pub struct DiagnosticFilterNode {
 impl DiagnosticFilterNode {
     /// Finds the most specific filter rule applicable to `triggering_rule` from the chain of
     /// diagnostic filter rules in `arena`, starting with `node`, and returns its severity. If none
-    /// is found, return the value of [`FilterableTriggeringRule::default_severity`].
+    /// is found, return the value of [`StandardFilterableTriggeringRule::default_severity`].
     ///
     /// When `triggering_rule` is not applicable to this node, its parent is consulted recursively.
     pub(crate) fn search(
         node: Option<Handle<Self>>,
         arena: &Arena<Self>,
-        triggering_rule: FilterableTriggeringRule,
+        triggering_rule: StandardFilterableTriggeringRule,
     ) -> Severity {
         let mut next = node;
         while let Some(handle) = next {
             let node = &arena[handle];
             let &Self { ref inner, parent } = node;
             let &DiagnosticFilter {
-                triggering_rule: rule,
+                triggering_rule: ref rule,
                 new_severity,
             } = inner;
 
-            if rule == triggering_rule {
+            if rule == &FilterableTriggeringRule::Standard(triggering_rule) {
                 return new_severity;
             }
 
diff --git a/naga/src/front/wgsl/diagnostic_filter.rs b/naga/src/front/wgsl/diagnostic_filter.rs
index f505205b6..b3cd7956b 100644
--- a/naga/src/front/wgsl/diagnostic_filter.rs
+++ b/naga/src/front/wgsl/diagnostic_filter.rs
@@ -1,4 +1,8 @@
-use crate::diagnostic_filter::{FilterableTriggeringRule, Severity};
+use std::fmt::{self, Display, Formatter};
+
+use crate::diagnostic_filter::{
+    FilterableTriggeringRule, Severity, StandardFilterableTriggeringRule,
+};
 
 impl Severity {
     const ERROR: &'static str = "error";
@@ -18,10 +22,34 @@ impl Severity {
     }
 }
 
+struct DisplayFilterableTriggeringRule<'a>(&'a FilterableTriggeringRule);
+
+impl Display for DisplayFilterableTriggeringRule<'_> {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        let &Self(inner) = self;
+        match *inner {
+            FilterableTriggeringRule::Standard(rule) => write!(f, "{}", rule.to_wgsl_ident()),
+            FilterableTriggeringRule::Unknown(ref rule) => write!(f, "{rule}"),
+            FilterableTriggeringRule::User(ref rules) => {
+                let &[ref seg1, ref seg2] = rules.as_ref();
+                write!(f, "{seg1}.{seg2}")
+            }
+        }
+    }
+}
+
 impl FilterableTriggeringRule {
+    /// [`Display`] this rule's identifiers in WGSL.
+    pub const fn display_wgsl_ident(&self) -> impl Display + '_ {
+        DisplayFilterableTriggeringRule(self)
+    }
+}
+
+impl StandardFilterableTriggeringRule {
     const DERIVATIVE_UNIFORMITY: &'static str = "derivative_uniformity";
 
-    /// Convert from a sentinel word in WGSL into its associated [`FilterableTriggeringRule`], if possible.
+    /// Convert from a sentinel word in WGSL into its associated
+    /// [`StandardFilterableTriggeringRule`], if possible.
     pub fn from_wgsl_ident(s: &str) -> Option<Self> {
         Some(match s {
             Self::DERIVATIVE_UNIFORMITY => Self::DerivativeUniformity,
@@ -29,10 +57,152 @@ impl FilterableTriggeringRule {
         })
     }
 
-    /// Maps this [`FilterableTriggeringRule`] into the sentinel word associated with it in WGSL.
+    /// Maps this [`StandardFilterableTriggeringRule`] into the sentinel word associated with it in
+    /// WGSL.
     pub const fn to_wgsl_ident(self) -> &'static str {
         match self {
             Self::DerivativeUniformity => Self::DERIVATIVE_UNIFORMITY,
         }
     }
 }
+
+#[cfg(test)]
+mod test {
+    mod parse_sites_not_yet_supported {
+        use crate::front::wgsl::assert_parse_err;
+
+        #[test]
+        fn user_rules() {
+            let shader = "
+fn myfunc() {
+    if (true) @diagnostic(off, my.lint) {
+        //    ^^^^^^^^^^^^^^^^^^^^^^^^^ not yet supported, should report an error
+    }
+}
+";
+            assert_parse_err(shader, "\
+error: `@diagnostic(…)` attribute(s) not yet implemented
+  ┌─ wgsl:3:15
+  │
+3 │     if (true) @diagnostic(off, my.lint) {
+  │               ^^^^^^^^^^^^^^^^^^^^^^^^^ can't use this on compound statements (yet)
+  │
+  = note: Let Naga maintainers know that you ran into this at <https://github.com/gfx-rs/wgpu/issues/5320>, so they can prioritize it!
+
+");
+        }
+
+        #[test]
+        fn unknown_rules() {
+            let shader = "
+fn myfunc() {
+	if (true) @diagnostic(off, wat_is_this) {
+		//    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ should emit a warning
+	}
+}
+";
+            assert_parse_err(shader, "\
+error: `@diagnostic(…)` attribute(s) not yet implemented
+  ┌─ wgsl:3:12
+  │
+3 │     if (true) @diagnostic(off, wat_is_this) {
+  │               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't use this on compound statements (yet)
+  │
+  = note: Let Naga maintainers know that you ran into this at <https://github.com/gfx-rs/wgpu/issues/5320>, so they can prioritize it!
+
+");
+        }
+    }
+
+    mod directive_conflict {
+        use crate::front::wgsl::assert_parse_err;
+
+        #[test]
+        fn user_rules() {
+            let shader = "
+diagnostic(off, my.lint);
+diagnostic(warning, my.lint);
+";
+            assert_parse_err(shader, "\
+error: found conflicting `diagnostic(…)` rule(s)
+  ┌─ wgsl:2:1
+  │
+2 │ diagnostic(off, my.lint);
+  │ ^^^^^^^^^^^^^^^^^^^^^^^^ first rule
+3 │ diagnostic(warning, my.lint);
+  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ second rule
+  │
+  = note: Multiple `diagnostic(…)` rules with the same rule name conflict unless they are directives and the severity is the same.
+  = note: You should delete the rule you don't want.
+
+");
+        }
+
+        #[test]
+        fn unknown_rules() {
+            let shader = "
+diagnostic(off, wat_is_this);
+diagnostic(warning, wat_is_this);
+";
+            assert_parse_err(shader, "\
+error: found conflicting `diagnostic(…)` rule(s)
+  ┌─ wgsl:2:1
+  │
+2 │ diagnostic(off, wat_is_this);
+  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ first rule
+3 │ diagnostic(warning, wat_is_this);
+  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ second rule
+  │
+  = note: Multiple `diagnostic(…)` rules with the same rule name conflict unless they are directives and the severity is the same.
+  = note: You should delete the rule you don't want.
+
+");
+        }
+    }
+
+    mod attribute_conflict {
+        use crate::front::wgsl::assert_parse_err;
+
+        #[test]
+        fn user_rules() {
+            let shader = "
+diagnostic(off, my.lint);
+diagnostic(warning, my.lint);
+";
+            assert_parse_err(shader, "\
+error: found conflicting `diagnostic(…)` rule(s)
+  ┌─ wgsl:2:1
+  │
+2 │ diagnostic(off, my.lint);
+  │ ^^^^^^^^^^^^^^^^^^^^^^^^ first rule
+3 │ diagnostic(warning, my.lint);
+  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ second rule
+  │
+  = note: Multiple `diagnostic(…)` rules with the same rule name conflict unless they are directives and the severity is the same.
+  = note: You should delete the rule you don't want.
+
+");
+        }
+
+        #[test]
+        fn unknown_rules() {
+            let shader = "
+diagnostic(off, wat_is_this);
+diagnostic(warning, wat_is_this);
+";
+            assert_parse_err(shader, "\
+error: found conflicting `diagnostic(…)` rule(s)
+  ┌─ wgsl:2:1
+  │
+2 │ diagnostic(off, wat_is_this);
+  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ first rule
+3 │ diagnostic(warning, wat_is_this);
+  │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ second rule
+  │
+  = note: Multiple `diagnostic(…)` rules with the same rule name conflict unless they are directives and the severity is the same.
+  = note: You should delete the rule you don't want.
+
+");
+        }
+    }
+}
diff --git a/naga/src/front/wgsl/error.rs b/naga/src/front/wgsl/error.rs
index 26199b5e5..f827ca50f 100644
--- a/naga/src/front/wgsl/error.rs
+++ b/naga/src/front/wgsl/error.rs
@@ -1034,15 +1034,11 @@ impl<'a> Error<'a> {
                 .into()],
             },
             Error::DiagnosticDuplicateTriggeringRule(ConflictingDiagnosticRuleError {
-                triggering_rule,
                 triggering_rule_spans,
             }) => {
                 let [first_span, second_span] = triggering_rule_spans;
                 ParseError {
-                    message: format!(
-                        "found conflicting `diagnostic(…)` rule(s) for `{}`",
-                        triggering_rule.to_wgsl_ident()
-                    ),
+                    message: "found conflicting `diagnostic(…)` rule(s)".into(),
                     labels: vec![
                         (first_span, "first rule".into()),
                         (second_span, "second rule".into()),
@@ -1050,7 +1046,7 @@ impl<'a> Error<'a> {
                     notes: vec![
                         concat!(
                             "Multiple `diagnostic(…)` rules with the same rule name ",
-                            "conflict unless it is a directive and the severity is the same.",
+                            "conflict unless they are directives and the severity is the same.",
                         )
                         .into(),
                         "You should delete the rule you don't want.".into(),
diff --git a/naga/src/front/wgsl/parse/mod.rs b/naga/src/front/wgsl/parse/mod.rs
index ae22eb38e..93b934332 100644
--- a/naga/src/front/wgsl/parse/mod.rs
+++ b/naga/src/front/wgsl/parse/mod.rs
@@ -1,6 +1,6 @@
 use crate::diagnostic_filter::{
     self, DiagnosticFilter, DiagnosticFilterMap, DiagnosticFilterNode, FilterableTriggeringRule,
-    ShouldConflictOnFullDuplicate,
+    ShouldConflictOnFullDuplicate, StandardFilterableTriggeringRule,
 };
 use crate::front::wgsl::error::{Error, ExpectedToken};
 use crate::front::wgsl::parse::directive::enable_extension::{
@@ -2166,10 +2166,9 @@ impl Parser {
         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, ShouldConflictOnFullDuplicate::Yes)?;
-                }
+                let filter = self.diagnostic_filter(lexer)?;
+                let span = self.peek_rule_span(lexer);
+                diagnostic_filters.add(filter, span, ShouldConflictOnFullDuplicate::Yes)?;
             } else {
                 return Err(Error::Unexpected(
                     name_span,
@@ -2370,10 +2369,9 @@ impl Parser {
         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, ShouldConflictOnFullDuplicate::Yes)?;
-                }
+                let filter = self.diagnostic_filter(lexer)?;
+                let span = self.peek_rule_span(lexer);
+                diagnostic_filters.add(filter, span, ShouldConflictOnFullDuplicate::Yes)?;
                 continue;
             }
             match name {
@@ -2603,14 +2601,13 @@ impl Parser {
                 let _ = lexer.next_ident_with_span().unwrap();
                 match kind {
                     DirectiveKind::Diagnostic => {
-                        if let Some(diagnostic_filter) = self.diagnostic_filter(&mut lexer)? {
-                            let span = self.peek_rule_span(&lexer);
-                            diagnostic_filters.add(
-                                diagnostic_filter,
-                                span,
-                                ShouldConflictOnFullDuplicate::No,
-                            )?;
-                        }
+                        let diagnostic_filter = self.diagnostic_filter(&mut lexer)?;
+                        let span = self.peek_rule_span(&lexer);
+                        diagnostic_filters.add(
+                            diagnostic_filter,
+                            span,
+                            ShouldConflictOnFullDuplicate::No,
+                        )?;
                         lexer.expect(Token::Separator(';'))?;
                     }
                     DirectiveKind::Enable => {
@@ -2698,10 +2695,7 @@ impl Parser {
         Ok(brace_nesting_level + 1)
     }
 
-    fn diagnostic_filter<'a>(
-        &self,
-        lexer: &mut Lexer<'a>,
-    ) -> Result<Option<DiagnosticFilter>, Error<'a>> {
+    fn diagnostic_filter<'a>(&self, lexer: &mut Lexer<'a>) -> Result<DiagnosticFilter, Error<'a>> {
         lexer.expect(Token::Paren('('))?;
 
         let (severity_control_name, severity_control_name_span) = lexer.next_ident_with_span()?;
@@ -2713,35 +2707,28 @@ impl Parser {
         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
+        let triggering_rule = if lexer.skip(Token::Separator('.')) {
+            let (ident, _span) = lexer.next_ident_with_span()?;
+            FilterableTriggeringRule::User(Box::new([diagnostic_name_token.into(), ident.into()]))
         } else {
-            Some(diagnostic_name_token)
+            let diagnostic_rule_name = diagnostic_name_token;
+            let diagnostic_rule_name_span = diagnostic_name_token_span;
+            if let Some(triggering_rule) =
+                StandardFilterableTriggeringRule::from_wgsl_ident(diagnostic_rule_name)
+            {
+                FilterableTriggeringRule::Standard(triggering_rule)
+            } else {
+                diagnostic_filter::Severity::Warning.report_wgsl_parse_diag(
+                    Error::UnknownDiagnosticRuleName(diagnostic_rule_name_span),
+                    lexer.source,
+                )?;
+                FilterableTriggeringRule::Unknown(diagnostic_rule_name.into())
+            }
+        };
+        let filter = DiagnosticFilter {
+            triggering_rule,
+            new_severity,
         };
-        let diagnostic_rule_name_span = diagnostic_name_token_span;
-
-        let filter = diagnostic_rule_name
-            .and_then(|name| {
-                FilterableTriggeringRule::from_wgsl_ident(name)
-                    .map(Ok)
-                    .or_else(|| {
-                        diagnostic_filter::Severity::Warning
-                            .report_wgsl_parse_diag(
-                                Error::UnknownDiagnosticRuleName(diagnostic_rule_name_span),
-                                lexer.source,
-                            )
-                            .err()
-                            .map(Err)
-                    })
-            })
-            .transpose()?
-            .map(|triggering_rule| DiagnosticFilter {
-                new_severity,
-                triggering_rule,
-            });
         lexer.skip(Token::Separator(','));
         lexer.expect(Token::Paren(')'))?;
 
diff --git a/naga/src/valid/analyzer.rs b/naga/src/valid/analyzer.rs
index 0ca9829d6..ac9bb9cd5 100644
--- a/naga/src/valid/analyzer.rs
+++ b/naga/src/valid/analyzer.rs
@@ -6,7 +6,7 @@
 //! - expression reference counts
 
 use super::{ExpressionError, FunctionError, ModuleInfo, ShaderStages, ValidationFlags};
-use crate::diagnostic_filter::{DiagnosticFilterNode, FilterableTriggeringRule};
+use crate::diagnostic_filter::{DiagnosticFilterNode, StandardFilterableTriggeringRule};
 use crate::span::{AddSpan as _, WithSpan};
 use crate::{
     arena::{Arena, Handle},
@@ -852,7 +852,7 @@ impl FunctionInfo {
                                 let severity = DiagnosticFilterNode::search(
                                     self.diagnostic_filter_leaf,
                                     diagnostic_filter_arena,
-                                    FilterableTriggeringRule::DerivativeUniformity,
+                                    StandardFilterableTriggeringRule::DerivativeUniformity,
                                 );
                                 severity.report_diag(
                                     FunctionError::NonUniformControlFlow(req, expr, cause)
@@ -1372,7 +1372,10 @@ fn uniform_control_flow() {
                 DiagnosticFilterNode {
                     inner: crate::diagnostic_filter::DiagnosticFilter {
                         new_severity: crate::diagnostic_filter::Severity::Off,
-                        triggering_rule: FilterableTriggeringRule::DerivativeUniformity,
+                        triggering_rule:
+                            crate::diagnostic_filter::FilterableTriggeringRule::Standard(
+                                StandardFilterableTriggeringRule::DerivativeUniformity,
+                            ),
                     },
                     parent: None,
                 },


Test patch:
diff --git a/naga/tests/out/ir/diagnostic-filter.compact.ron b/naga/tests/out/ir/diagnostic-filter.compact.ron
index 4294b06e9..315c8b342 100644
--- a/naga/tests/out/ir/diagnostic-filter.compact.ron
+++ b/naga/tests/out/ir/diagnostic-filter.compact.ron
@@ -44,14 +44,14 @@
         (
             inner: (
                 new_severity: Off,
-                triggering_rule: DerivativeUniformity,
+                triggering_rule: Standard(DerivativeUniformity),
             ),
             parent: None,
         ),
         (
             inner: (
                 new_severity: Warning,
-                triggering_rule: DerivativeUniformity,
+                triggering_rule: Standard(DerivativeUniformity),
             ),
             parent: Some(0),
         ),
diff --git a/naga/tests/out/ir/diagnostic-filter.ron b/naga/tests/out/ir/diagnostic-filter.ron
index 4294b06e9..315c8b342 100644
--- a/naga/tests/out/ir/diagnostic-filter.ron
+++ b/naga/tests/out/ir/diagnostic-filter.ron
@@ -44,14 +44,14 @@
         (
             inner: (
                 new_severity: Off,
-                triggering_rule: DerivativeUniformity,
+                triggering_rule: Standard(DerivativeUniformity),
             ),
             parent: None,
         ),
         (
             inner: (
                 new_severity: Warning,
-                triggering_rule: DerivativeUniformity,
+                triggering_rule: Standard(DerivativeUniformity),
             ),
             parent: Some(0),
         ),