tint: Add two-token form for diagnostics rule names.
Fixed: tint:1891
Change-Id: Ia3737c29b111d7b6e6b00fbd68da7f85a5a49bca
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/128301
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index 663ba05..f4526ff 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -472,6 +472,7 @@
"ast/diagnostic_attribute.h",
"ast/diagnostic_control.h",
"ast/diagnostic_directive.h",
+ "ast/diagnostic_rule_name.h",
"ast/disable_validation_attribute.h",
"ast/discard_statement.h",
"ast/enable.h",
@@ -559,6 +560,7 @@
"ast/diagnostic_attribute.cc",
"ast/diagnostic_control.cc",
"ast/diagnostic_directive.cc",
+ "ast/diagnostic_rule_name.cc",
"ast/disable_validation_attribute.cc",
"ast/discard_statement.cc",
"ast/enable.cc",
@@ -1291,6 +1293,7 @@
"ast/diagnostic_attribute_test.cc",
"ast/diagnostic_control_test.cc",
"ast/diagnostic_directive_test.cc",
+ "ast/diagnostic_rule_name_test.cc",
"ast/discard_statement_test.cc",
"ast/enable_test.cc",
"ast/float_literal_expression_test.cc",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 323ed79..7bac6ed 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -126,6 +126,8 @@
ast/diagnostic_control.h
ast/diagnostic_directive.cc
ast/diagnostic_directive.h
+ ast/diagnostic_rule_name.cc
+ ast/diagnostic_rule_name.h
ast/disable_validation_attribute.cc
ast/disable_validation_attribute.h
ast/discard_statement.cc
@@ -845,6 +847,7 @@
ast/diagnostic_attribute_test.cc
ast/diagnostic_control_test.cc
ast/diagnostic_directive_test.cc
+ ast/diagnostic_rule_name_test.cc
ast/discard_statement_test.cc
ast/enable_test.cc
ast/float_literal_expression_test.cc
diff --git a/src/tint/ast/diagnostic_attribute_test.cc b/src/tint/ast/diagnostic_attribute_test.cc
index ec6ec26..a77c025 100644
--- a/src/tint/ast/diagnostic_attribute_test.cc
+++ b/src/tint/ast/diagnostic_attribute_test.cc
@@ -20,12 +20,20 @@
using namespace tint::number_suffixes; // NOLINT
using DiagnosticAttributeTest = TestHelper;
-TEST_F(DiagnosticAttributeTest, Creation) {
- auto* name = Ident("foo");
- auto* d = DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, name);
+TEST_F(DiagnosticAttributeTest, Name) {
+ auto* d = DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, "foo");
EXPECT_EQ(d->Name(), "diagnostic");
EXPECT_EQ(d->control.severity, builtin::DiagnosticSeverity::kWarning);
- EXPECT_EQ(d->control.rule_name, name);
+ EXPECT_EQ(d->control.rule_name->category, nullptr);
+ CheckIdentifier(d->control.rule_name->name, "foo");
+}
+
+TEST_F(DiagnosticAttributeTest, CategoryAndName) {
+ auto* d = DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, "foo", "bar");
+ EXPECT_EQ(d->Name(), "diagnostic");
+ EXPECT_EQ(d->control.severity, builtin::DiagnosticSeverity::kWarning);
+ CheckIdentifier(d->control.rule_name->category, "foo");
+ CheckIdentifier(d->control.rule_name->name, "bar");
}
} // namespace
diff --git a/src/tint/ast/diagnostic_control.cc b/src/tint/ast/diagnostic_control.cc
index a2bdd46..27ec3c1 100644
--- a/src/tint/ast/diagnostic_control.cc
+++ b/src/tint/ast/diagnostic_control.cc
@@ -24,13 +24,10 @@
DiagnosticControl::DiagnosticControl() = default;
-DiagnosticControl::DiagnosticControl(builtin::DiagnosticSeverity sev, const Identifier* rule)
+DiagnosticControl::DiagnosticControl(builtin::DiagnosticSeverity sev,
+ const DiagnosticRuleName* rule)
: severity(sev), rule_name(rule) {
TINT_ASSERT(AST, rule != nullptr);
- if (rule) {
- // It is invalid for a diagnostic rule name to be templated
- TINT_ASSERT(AST, !rule->Is<TemplatedIdentifier>());
- }
}
DiagnosticControl::DiagnosticControl(DiagnosticControl&&) = default;
diff --git a/src/tint/ast/diagnostic_control.h b/src/tint/ast/diagnostic_control.h
index f99d002..2b504e4 100644
--- a/src/tint/ast/diagnostic_control.h
+++ b/src/tint/ast/diagnostic_control.h
@@ -23,7 +23,7 @@
// Forward declarations
namespace tint::ast {
-class Identifier;
+class DiagnosticRuleName;
} // namespace tint::ast
namespace tint::ast {
@@ -37,16 +37,16 @@
/// Constructor
/// @param sev the diagnostic severity
/// @param rule the diagnostic rule name
- DiagnosticControl(builtin::DiagnosticSeverity sev, const Identifier* rule);
+ DiagnosticControl(builtin::DiagnosticSeverity sev, const DiagnosticRuleName* rule);
/// Move constructor
DiagnosticControl(DiagnosticControl&&);
/// The diagnostic severity control.
- builtin::DiagnosticSeverity severity;
+ builtin::DiagnosticSeverity severity = builtin::DiagnosticSeverity::kUndefined;
/// The diagnostic rule name.
- const Identifier* rule_name;
+ const DiagnosticRuleName* rule_name = nullptr;
};
} // namespace tint::ast
diff --git a/src/tint/ast/diagnostic_control_test.cc b/src/tint/ast/diagnostic_control_test.cc
index 53afe53..d118677 100644
--- a/src/tint/ast/diagnostic_control_test.cc
+++ b/src/tint/ast/diagnostic_control_test.cc
@@ -24,12 +24,11 @@
using DiagnosticControlTest = TestHelper;
-TEST_F(DiagnosticControlTest, Assert_RuleNotTemplated) {
+TEST_F(DiagnosticControlTest, Assert_RuleNotNull) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
- DiagnosticControl control(builtin::DiagnosticSeverity::kWarning,
- b.Ident("name", "a", "b", "c"));
+ DiagnosticControl control(builtin::DiagnosticSeverity::kWarning, nullptr);
},
"internal compiler error");
}
diff --git a/src/tint/ast/diagnostic_directive.cc b/src/tint/ast/diagnostic_directive.cc
index f0ef041..8783901 100644
--- a/src/tint/ast/diagnostic_directive.cc
+++ b/src/tint/ast/diagnostic_directive.cc
@@ -34,4 +34,5 @@
DiagnosticControl dc(control.severity, rule);
return ctx->dst->create<DiagnosticDirective>(src, std::move(dc));
}
+
} // namespace tint::ast
diff --git a/src/tint/ast/diagnostic_directive_test.cc b/src/tint/ast/diagnostic_directive_test.cc
index 721a545..c423ae9 100644
--- a/src/tint/ast/diagnostic_directive_test.cc
+++ b/src/tint/ast/diagnostic_directive_test.cc
@@ -21,15 +21,28 @@
using DiagnosticDirectiveTest = TestHelper;
-TEST_F(DiagnosticDirectiveTest, Creation) {
- auto* diag = DiagnosticDirective(Source{{{10, 5}, {10, 15}}},
- builtin::DiagnosticSeverity::kWarning, "foo");
- EXPECT_EQ(diag->source.range.begin.line, 10u);
- EXPECT_EQ(diag->source.range.begin.column, 5u);
- EXPECT_EQ(diag->source.range.end.line, 10u);
- EXPECT_EQ(diag->source.range.end.column, 15u);
- EXPECT_EQ(diag->control.severity, builtin::DiagnosticSeverity::kWarning);
- CheckIdentifier(diag->control.rule_name, "foo");
+TEST_F(DiagnosticDirectiveTest, Name) {
+ auto* d = DiagnosticDirective(Source{{{10, 5}, {10, 15}}},
+ builtin::DiagnosticSeverity::kWarning, "foo");
+ EXPECT_EQ(d->source.range.begin.line, 10u);
+ EXPECT_EQ(d->source.range.begin.column, 5u);
+ EXPECT_EQ(d->source.range.end.line, 10u);
+ EXPECT_EQ(d->source.range.end.column, 15u);
+ EXPECT_EQ(d->control.severity, builtin::DiagnosticSeverity::kWarning);
+ EXPECT_EQ(d->control.rule_name->category, nullptr);
+ CheckIdentifier(d->control.rule_name->name, "foo");
+}
+
+TEST_F(DiagnosticDirectiveTest, CategoryAndName) {
+ auto* d = DiagnosticDirective(Source{{{10, 5}, {10, 15}}},
+ builtin::DiagnosticSeverity::kWarning, "foo", "bar");
+ EXPECT_EQ(d->source.range.begin.line, 10u);
+ EXPECT_EQ(d->source.range.begin.column, 5u);
+ EXPECT_EQ(d->source.range.end.line, 10u);
+ EXPECT_EQ(d->source.range.end.column, 15u);
+ EXPECT_EQ(d->control.severity, builtin::DiagnosticSeverity::kWarning);
+ CheckIdentifier(d->control.rule_name->category, "foo");
+ CheckIdentifier(d->control.rule_name->name, "bar");
}
} // namespace
diff --git a/src/tint/ast/diagnostic_rule_name.cc b/src/tint/ast/diagnostic_rule_name.cc
new file mode 100644
index 0000000..856e054
--- /dev/null
+++ b/src/tint/ast/diagnostic_rule_name.cc
@@ -0,0 +1,74 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ast/diagnostic_rule_name.h"
+
+#include <string>
+
+#include "src/tint/program_builder.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ast::DiagnosticRuleName);
+
+namespace tint::ast {
+
+DiagnosticRuleName::DiagnosticRuleName(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ const Identifier* n)
+ : Base(pid, nid, src), name(n) {
+ TINT_ASSERT(AST, name != nullptr);
+ TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, name, program_id);
+ if (name) {
+ // It is invalid for a diagnostic rule name to be templated
+ TINT_ASSERT(AST, !name->Is<TemplatedIdentifier>());
+ }
+}
+
+DiagnosticRuleName::DiagnosticRuleName(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ const Identifier* c,
+ const Identifier* n)
+ : Base(pid, nid, src), category(c), name(n) {
+ TINT_ASSERT(AST, name != nullptr);
+ TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, name, program_id);
+ if (name) {
+ // It is invalid for a diagnostic rule name to be templated
+ TINT_ASSERT(AST, !name->Is<TemplatedIdentifier>());
+ }
+ if (category) {
+ TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, category, program_id);
+ // It is invalid for a diagnostic rule category to be templated
+ TINT_ASSERT(AST, !category->Is<TemplatedIdentifier>());
+ }
+}
+
+const DiagnosticRuleName* DiagnosticRuleName::Clone(CloneContext* ctx) const {
+ auto src = ctx->Clone(source);
+ auto n = ctx->Clone(name);
+ if (auto c = ctx->Clone(category)) {
+ return ctx->dst->create<DiagnosticRuleName>(src, c, n);
+ }
+ return ctx->dst->create<DiagnosticRuleName>(src, n);
+}
+
+std::string DiagnosticRuleName::String() const {
+ if (category) {
+ return category->symbol.Name() + "." + name->symbol.Name();
+ } else {
+ return name->symbol.Name();
+ }
+}
+
+} // namespace tint::ast
diff --git a/src/tint/ast/diagnostic_rule_name.h b/src/tint/ast/diagnostic_rule_name.h
new file mode 100644
index 0000000..a3d1189
--- /dev/null
+++ b/src/tint/ast/diagnostic_rule_name.h
@@ -0,0 +1,68 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_AST_DIAGNOSTIC_RULE_NAME_H_
+#define SRC_TINT_AST_DIAGNOSTIC_RULE_NAME_H_
+
+#include <string>
+
+#include "src/tint/ast/node.h"
+
+// Forward declarations
+namespace tint::ast {
+class Identifier;
+} // namespace tint::ast
+
+namespace tint::ast {
+
+/// A diagnostic rule name used for diagnostic directives and attributes.
+class DiagnosticRuleName final : public utils::Castable<DiagnosticRuleName, Node> {
+ public:
+ /// Constructor
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
+ /// @param src the source of this node
+ /// @param name the rule name
+ DiagnosticRuleName(ProgramID pid, NodeID nid, const Source& src, const Identifier* name);
+
+ /// Constructor
+ /// @param pid the identifier of the program that owns this node
+ /// @param nid the unique node identifier
+ /// @param src the source of this node
+ /// @param category the rule category.
+ /// @param name the rule name
+ DiagnosticRuleName(ProgramID pid,
+ NodeID nid,
+ const Source& src,
+ const Identifier* category,
+ const Identifier* name);
+
+ /// Clones this node and all transitive child nodes using the `CloneContext` `ctx`.
+ /// @param ctx the clone context
+ /// @return the newly cloned node
+ const DiagnosticRuleName* Clone(CloneContext* ctx) const override;
+
+ /// @return the full name of this diagnostic rule, either as `name` or `category.name`.
+ std::string String() const;
+
+ /// The diagnostic rule category (category.name)
+ Identifier const* const category = nullptr;
+
+ /// The diagnostic rule name.
+ Identifier const* const name;
+};
+
+} // namespace tint::ast
+
+#endif // SRC_TINT_AST_DIAGNOSTIC_RULE_NAME_H_
diff --git a/src/tint/ast/diagnostic_rule_name_test.cc b/src/tint/ast/diagnostic_rule_name_test.cc
new file mode 100644
index 0000000..40caac7
--- /dev/null
+++ b/src/tint/ast/diagnostic_rule_name_test.cc
@@ -0,0 +1,50 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string>
+
+#include "gtest/gtest-spi.h"
+#include "src/tint/ast/diagnostic_rule_name.h"
+#include "src/tint/ast/test_helper.h"
+
+namespace tint::ast {
+namespace {
+
+using DiagnosticRuleNameTest = TestHelper;
+
+TEST_F(DiagnosticRuleNameTest, String) {
+ EXPECT_EQ(DiagnosticRuleName("name")->String(), "name");
+ EXPECT_EQ(DiagnosticRuleName("category", "name")->String(), "category.name");
+}
+
+TEST_F(DiagnosticRuleNameTest, Assert_NameNotTemplated) {
+ EXPECT_FATAL_FAILURE(
+ {
+ ProgramBuilder b;
+ b.create<ast::DiagnosticRuleName>(b.Ident("name", "a", "b", "c"));
+ },
+ "internal compiler error");
+}
+
+TEST_F(DiagnosticRuleNameTest, Assert_CategoryNotTemplated) {
+ EXPECT_FATAL_FAILURE(
+ {
+ ProgramBuilder b;
+ b.create<ast::DiagnosticRuleName>(b.Ident("name"), b.Ident("category", "a", "b", "c"));
+ },
+ "internal compiler error");
+}
+
+} // namespace
+} // namespace tint::ast
diff --git a/src/tint/ast/module_clone_test.cc b/src/tint/ast/module_clone_test.cc
index eb7f775..b2407bc 100644
--- a/src/tint/ast/module_clone_test.cc
+++ b/src/tint/ast/module_clone_test.cc
@@ -25,7 +25,7 @@
// Shader that exercises the bulk of the AST nodes and types.
// See also fuzzers/tint_ast_clone_fuzzer.cc for further coverage of cloning.
Source::File file("test.wgsl", R"(enable f16;
-diagnostic(off, chromium_unreachable_code);
+diagnostic(off, chromium.unreachable_code);
struct S0 {
@size(4)
@@ -65,7 +65,7 @@
return 0.0;
}
-@diagnostic(warning, chromium_unreachable_code)
+@diagnostic(warning, chromium.unreachable_code)
fn f1(p0 : f32, p1 : i32) -> f32 {
var l0 : i32 = 3;
var l1 : f32 = 8.0;
diff --git a/src/tint/builtin/diagnostic_rule.cc b/src/tint/builtin/diagnostic_rule.cc
index 69650cb..334a88a 100644
--- a/src/tint/builtin/diagnostic_rule.cc
+++ b/src/tint/builtin/diagnostic_rule.cc
@@ -28,29 +28,45 @@
namespace tint::builtin {
-/// ParseDiagnosticRule parses a DiagnosticRule from a string.
+/// ParseCoreDiagnosticRule parses a CoreDiagnosticRule from a string.
/// @param str the string to parse
-/// @returns the parsed enum, or DiagnosticRule::kUndefined if the string could not be parsed.
-DiagnosticRule ParseDiagnosticRule(std::string_view str) {
- if (str == "chromium_unreachable_code") {
- return DiagnosticRule::kChromiumUnreachableCode;
- }
+/// @returns the parsed enum, or CoreDiagnosticRule::kUndefined if the string could not be parsed.
+CoreDiagnosticRule ParseCoreDiagnosticRule(std::string_view str) {
if (str == "derivative_uniformity") {
- return DiagnosticRule::kDerivativeUniformity;
+ return CoreDiagnosticRule::kDerivativeUniformity;
}
- return DiagnosticRule::kUndefined;
+ return CoreDiagnosticRule::kUndefined;
}
-utils::StringStream& operator<<(utils::StringStream& out, DiagnosticRule value) {
+utils::StringStream& operator<<(utils::StringStream& out, CoreDiagnosticRule value) {
switch (value) {
- case DiagnosticRule::kUndefined:
+ case CoreDiagnosticRule::kUndefined:
return out << "undefined";
- case DiagnosticRule::kChromiumUnreachableCode:
- return out << "chromium_unreachable_code";
- case DiagnosticRule::kDerivativeUniformity:
+ case CoreDiagnosticRule::kDerivativeUniformity:
return out << "derivative_uniformity";
}
return out << "<unknown>";
}
+/// ParseChromiumDiagnosticRule parses a ChromiumDiagnosticRule from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or ChromiumDiagnosticRule::kUndefined if the string could not be
+/// parsed.
+ChromiumDiagnosticRule ParseChromiumDiagnosticRule(std::string_view str) {
+ if (str == "unreachable_code") {
+ return ChromiumDiagnosticRule::kUnreachableCode;
+ }
+ return ChromiumDiagnosticRule::kUndefined;
+}
+
+utils::StringStream& operator<<(utils::StringStream& out, ChromiumDiagnosticRule value) {
+ switch (value) {
+ case ChromiumDiagnosticRule::kUndefined:
+ return out << "undefined";
+ case ChromiumDiagnosticRule::kUnreachableCode:
+ return out << "unreachable_code";
+ }
+ return out << "<unknown>";
+}
+
} // namespace tint::builtin
diff --git a/src/tint/builtin/diagnostic_rule.cc.tmpl b/src/tint/builtin/diagnostic_rule.cc.tmpl
index 8705485..8e64b09 100644
--- a/src/tint/builtin/diagnostic_rule.cc.tmpl
+++ b/src/tint/builtin/diagnostic_rule.cc.tmpl
@@ -18,8 +18,12 @@
namespace tint::builtin {
-{{ Eval "ParseEnum" (Sem.Enum "diagnostic_rule")}}
+{{ Eval "ParseEnum" (Sem.Enum "core_diagnostic_rule")}}
-{{ Eval "EnumOStream" (Sem.Enum "diagnostic_rule")}}
+{{ Eval "EnumOStream" (Sem.Enum "core_diagnostic_rule")}}
+
+{{ Eval "ParseEnum" (Sem.Enum "chromium_diagnostic_rule")}}
+
+{{ Eval "EnumOStream" (Sem.Enum "chromium_diagnostic_rule")}}
} // namespace tint::builtin
diff --git a/src/tint/builtin/diagnostic_rule.h b/src/tint/builtin/diagnostic_rule.h
index 6b6d094..aa641b0 100644
--- a/src/tint/builtin/diagnostic_rule.h
+++ b/src/tint/builtin/diagnostic_rule.h
@@ -24,33 +24,56 @@
#define SRC_TINT_BUILTIN_DIAGNOSTIC_RULE_H_
#include <string>
+#include <variant>
#include "src/tint/utils/string_stream.h"
namespace tint::builtin {
-/// The diagnostic rule.
-enum class DiagnosticRule {
+/// WGSL core diagnostic rules.
+enum class CoreDiagnosticRule {
kUndefined,
- kChromiumUnreachableCode,
kDerivativeUniformity,
};
/// @param out the stream to write to
-/// @param value the DiagnosticRule
+/// @param value the CoreDiagnosticRule
/// @returns `out` so calls can be chained
-utils::StringStream& operator<<(utils::StringStream& out, DiagnosticRule value);
+utils::StringStream& operator<<(utils::StringStream& out, CoreDiagnosticRule value);
-/// ParseDiagnosticRule parses a DiagnosticRule from a string.
+/// ParseCoreDiagnosticRule parses a CoreDiagnosticRule from a string.
/// @param str the string to parse
-/// @returns the parsed enum, or DiagnosticRule::kUndefined if the string could not be parsed.
-DiagnosticRule ParseDiagnosticRule(std::string_view str);
+/// @returns the parsed enum, or CoreDiagnosticRule::kUndefined if the string could not be parsed.
+CoreDiagnosticRule ParseCoreDiagnosticRule(std::string_view str);
-constexpr const char* kDiagnosticRuleStrings[] = {
- "chromium_unreachable_code",
+constexpr const char* kCoreDiagnosticRuleStrings[] = {
"derivative_uniformity",
};
+/// Chromium-specific diagnostic rules.
+enum class ChromiumDiagnosticRule {
+ kUndefined,
+ kUnreachableCode,
+};
+
+/// @param out the stream to write to
+/// @param value the ChromiumDiagnosticRule
+/// @returns `out` so calls can be chained
+utils::StringStream& operator<<(utils::StringStream& out, ChromiumDiagnosticRule value);
+
+/// ParseChromiumDiagnosticRule parses a ChromiumDiagnosticRule from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or ChromiumDiagnosticRule::kUndefined if the string could not be
+/// parsed.
+ChromiumDiagnosticRule ParseChromiumDiagnosticRule(std::string_view str);
+
+constexpr const char* kChromiumDiagnosticRuleStrings[] = {
+ "unreachable_code",
+};
+
+/// All diagnostic rules understood by Tint.
+using DiagnosticRule = std::variant<CoreDiagnosticRule, ChromiumDiagnosticRule>;
+
} // namespace tint::builtin
#endif // SRC_TINT_BUILTIN_DIAGNOSTIC_RULE_H_
diff --git a/src/tint/builtin/diagnostic_rule.h.tmpl b/src/tint/builtin/diagnostic_rule.h.tmpl
index ba823e3..16d7f9e 100644
--- a/src/tint/builtin/diagnostic_rule.h.tmpl
+++ b/src/tint/builtin/diagnostic_rule.h.tmpl
@@ -14,13 +14,20 @@
#define SRC_TINT_BUILTIN_DIAGNOSTIC_RULE_H_
#include <string>
+#include <variant>
#include "src/tint/utils/string_stream.h"
namespace tint::builtin {
-/// The diagnostic rule.
-{{ Eval "DeclareEnum" (Sem.Enum "diagnostic_rule") }}
+/// WGSL core diagnostic rules.
+{{ Eval "DeclareEnum" (Sem.Enum "core_diagnostic_rule") }}
+
+/// Chromium-specific diagnostic rules.
+{{ Eval "DeclareEnum" (Sem.Enum "chromium_diagnostic_rule") }}
+
+/// All diagnostic rules understood by Tint.
+using DiagnosticRule = std::variant<CoreDiagnosticRule, ChromiumDiagnosticRule>;
} // namespace tint::builtin
diff --git a/src/tint/builtin/diagnostic_rule_bench.cc b/src/tint/builtin/diagnostic_rule_bench.cc
index c98bd46..fb60580 100644
--- a/src/tint/builtin/diagnostic_rule_bench.cc
+++ b/src/tint/builtin/diagnostic_rule_bench.cc
@@ -29,23 +29,36 @@
namespace tint::builtin {
namespace {
-void DiagnosticRuleParser(::benchmark::State& state) {
+void CoreDiagnosticRuleParser(::benchmark::State& state) {
const char* kStrings[] = {
- "chromium_unrachaccle_code", "clromium_unreachab3_oe", "chromium_unreachable_Vode",
- "chromium_unreachable_code", "chro1ium_unreachable_code", "chromium_unreJchableqqcde",
- "chromium77unreallhable_code", "dqqrvatiHHe_uniforppity", "deriatcv_nvformity",
- "derivatbe_unGformity", "derivative_uniformity", "derivative_iinifvrmity",
- "derivat8WWe_uniformity", "drivaxxive_uniformity",
+ "deriative_unccformity", "dlivative_3iformiy", "derivative_uniforVity",
+ "derivative_uniformity", "derivative_uniform1ty", "derivativeJunifqrmity",
+ "derivative_unifllrmit77",
};
for (auto _ : state) {
for (auto* str : kStrings) {
- auto result = ParseDiagnosticRule(str);
+ auto result = ParseCoreDiagnosticRule(str);
benchmark::DoNotOptimize(result);
}
}
}
-BENCHMARK(DiagnosticRuleParser);
+BENCHMARK(CoreDiagnosticRuleParser);
+
+void ChromiumDiagnosticRuleParser(::benchmark::State& state) {
+ const char* kStrings[] = {
+ "pqnreachableHHcode", "unrechcbe_cov", "unreachGblecode", "unreachable_code",
+ "vnriiachable_code", "unreac8ablWW_code", "unreMchablxxcode",
+ };
+ for (auto _ : state) {
+ for (auto* str : kStrings) {
+ auto result = ParseChromiumDiagnosticRule(str);
+ benchmark::DoNotOptimize(result);
+ }
+ }
+}
+
+BENCHMARK(ChromiumDiagnosticRuleParser);
} // namespace
} // namespace tint::builtin
diff --git a/src/tint/builtin/diagnostic_rule_bench.cc.tmpl b/src/tint/builtin/diagnostic_rule_bench.cc.tmpl
index 2605aae..dab6856 100644
--- a/src/tint/builtin/diagnostic_rule_bench.cc.tmpl
+++ b/src/tint/builtin/diagnostic_rule_bench.cc.tmpl
@@ -19,7 +19,9 @@
namespace tint::builtin {
namespace {
-{{ Eval "BenchmarkParseEnum" (Sem.Enum "diagnostic_rule")}}
+{{ Eval "BenchmarkParseEnum" (Sem.Enum "core_diagnostic_rule")}}
+
+{{ Eval "BenchmarkParseEnum" (Sem.Enum "chromium_diagnostic_rule")}}
} // namespace
} // namespace tint::builtin
diff --git a/src/tint/builtin/diagnostic_rule_test.cc b/src/tint/builtin/diagnostic_rule_test.cc
index 9982061..78bd3f3 100644
--- a/src/tint/builtin/diagnostic_rule_test.cc
+++ b/src/tint/builtin/diagnostic_rule_test.cc
@@ -29,13 +29,13 @@
namespace tint::builtin {
namespace {
-namespace diagnostic_rule_tests {
+namespace core_diagnostic_rule_tests {
namespace parse_print_tests {
struct Case {
const char* string;
- DiagnosticRule value;
+ CoreDiagnosticRule value;
};
inline std::ostream& operator<<(std::ostream& out, Case c) {
@@ -43,43 +43,95 @@
}
static constexpr Case kValidCases[] = {
- {"chromium_unreachable_code", DiagnosticRule::kChromiumUnreachableCode},
- {"derivative_uniformity", DiagnosticRule::kDerivativeUniformity},
+ {"derivative_uniformity", CoreDiagnosticRule::kDerivativeUniformity},
};
static constexpr Case kInvalidCases[] = {
- {"chromium_unrachaccle_code", DiagnosticRule::kUndefined},
- {"clromium_unreachab3_oe", DiagnosticRule::kUndefined},
- {"chromium_unreachable_Vode", DiagnosticRule::kUndefined},
- {"derivative_uniform1ty", DiagnosticRule::kUndefined},
- {"derivativeJunifqrmity", DiagnosticRule::kUndefined},
- {"derivative_unifllrmit77", DiagnosticRule::kUndefined},
+ {"deriative_unccformity", CoreDiagnosticRule::kUndefined},
+ {"dlivative_3iformiy", CoreDiagnosticRule::kUndefined},
+ {"derivative_uniforVity", CoreDiagnosticRule::kUndefined},
};
-using DiagnosticRuleParseTest = testing::TestWithParam<Case>;
+using CoreDiagnosticRuleParseTest = testing::TestWithParam<Case>;
-TEST_P(DiagnosticRuleParseTest, Parse) {
+TEST_P(CoreDiagnosticRuleParseTest, Parse) {
const char* string = GetParam().string;
- DiagnosticRule expect = GetParam().value;
- EXPECT_EQ(expect, ParseDiagnosticRule(string));
+ CoreDiagnosticRule expect = GetParam().value;
+ EXPECT_EQ(expect, ParseCoreDiagnosticRule(string));
}
-INSTANTIATE_TEST_SUITE_P(ValidCases, DiagnosticRuleParseTest, testing::ValuesIn(kValidCases));
-INSTANTIATE_TEST_SUITE_P(InvalidCases, DiagnosticRuleParseTest, testing::ValuesIn(kInvalidCases));
+INSTANTIATE_TEST_SUITE_P(ValidCases, CoreDiagnosticRuleParseTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases,
+ CoreDiagnosticRuleParseTest,
+ testing::ValuesIn(kInvalidCases));
-using DiagnosticRulePrintTest = testing::TestWithParam<Case>;
+using CoreDiagnosticRulePrintTest = testing::TestWithParam<Case>;
-TEST_P(DiagnosticRulePrintTest, Print) {
- DiagnosticRule value = GetParam().value;
+TEST_P(CoreDiagnosticRulePrintTest, Print) {
+ CoreDiagnosticRule value = GetParam().value;
const char* expect = GetParam().string;
EXPECT_EQ(expect, utils::ToString(value));
}
-INSTANTIATE_TEST_SUITE_P(ValidCases, DiagnosticRulePrintTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(ValidCases, CoreDiagnosticRulePrintTest, testing::ValuesIn(kValidCases));
} // namespace parse_print_tests
-} // namespace diagnostic_rule_tests
+} // namespace core_diagnostic_rule_tests
+
+namespace chromium_diagnostic_rule_tests {
+
+namespace parse_print_tests {
+
+struct Case {
+ const char* string;
+ ChromiumDiagnosticRule value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+ return out << "'" << std::string(c.string) << "'";
+}
+
+static constexpr Case kValidCases[] = {
+ {"unreachable_code", ChromiumDiagnosticRule::kUnreachableCode},
+};
+
+static constexpr Case kInvalidCases[] = {
+ {"unreacha1le_code", ChromiumDiagnosticRule::kUndefined},
+ {"unreachableJcqde", ChromiumDiagnosticRule::kUndefined},
+ {"unreachable77llode", ChromiumDiagnosticRule::kUndefined},
+};
+
+using ChromiumDiagnosticRuleParseTest = testing::TestWithParam<Case>;
+
+TEST_P(ChromiumDiagnosticRuleParseTest, Parse) {
+ const char* string = GetParam().string;
+ ChromiumDiagnosticRule expect = GetParam().value;
+ EXPECT_EQ(expect, ParseChromiumDiagnosticRule(string));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases,
+ ChromiumDiagnosticRuleParseTest,
+ testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases,
+ ChromiumDiagnosticRuleParseTest,
+ testing::ValuesIn(kInvalidCases));
+
+using ChromiumDiagnosticRulePrintTest = testing::TestWithParam<Case>;
+
+TEST_P(ChromiumDiagnosticRulePrintTest, Print) {
+ ChromiumDiagnosticRule value = GetParam().value;
+ const char* expect = GetParam().string;
+ EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases,
+ ChromiumDiagnosticRulePrintTest,
+ testing::ValuesIn(kValidCases));
+
+} // namespace parse_print_tests
+
+} // namespace chromium_diagnostic_rule_tests
} // namespace
} // namespace tint::builtin
diff --git a/src/tint/builtin/diagnostic_rule_test.cc.tmpl b/src/tint/builtin/diagnostic_rule_test.cc.tmpl
index 106f6fc..cc12bf7 100644
--- a/src/tint/builtin/diagnostic_rule_test.cc.tmpl
+++ b/src/tint/builtin/diagnostic_rule_test.cc.tmpl
@@ -19,11 +19,17 @@
namespace tint::builtin {
namespace {
-namespace diagnostic_rule_tests {
+namespace core_diagnostic_rule_tests {
-{{ Eval "TestParsePrintEnum" (Sem.Enum "diagnostic_rule")}}
+{{ Eval "TestParsePrintEnum" (Sem.Enum "core_diagnostic_rule")}}
-} // namespace diagnostic_rule_tests
+} // namespace core_diagnostic_rule_tests
+
+namespace chromium_diagnostic_rule_tests {
+
+{{ Eval "TestParsePrintEnum" (Sem.Enum "chromium_diagnostic_rule")}}
+
+} // namespace chromium_diagnostic_rule_tests
} // namespace
} // namespace tint::builtin
diff --git a/src/tint/intrinsics.def b/src/tint/intrinsics.def
index fae4ee4..dacd664 100644
--- a/src/tint/intrinsics.def
+++ b/src/tint/intrinsics.def
@@ -41,11 +41,15 @@
}
// https://gpuweb.github.io/gpuweb/wgsl/#filterable-triggering-rules
-enum diagnostic_rule {
+enum core_diagnostic_rule {
// Rules defined in the spec.
derivative_uniformity
+}
+
+// chromium-specific diagnostics
+enum chromium_diagnostic_rule {
// Chromium specific rules not defined in the spec.
- chromium_unreachable_code
+ unreachable_code
}
// https://gpuweb.github.io/gpuweb/wgsl/#syntax-severity_control_name
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index b7fda95..b4f5eea 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -39,6 +39,7 @@
#include "src/tint/ast/diagnostic_attribute.h"
#include "src/tint/ast/diagnostic_control.h"
#include "src/tint/ast/diagnostic_directive.h"
+#include "src/tint/ast/diagnostic_rule_name.h"
#include "src/tint/ast/disable_validation_attribute.h"
#include "src/tint/ast/discard_statement.h"
#include "src/tint/ast/enable.h"
@@ -3752,57 +3753,129 @@
validation);
}
- /// Creates an ast::DiagnosticAttribute
- /// @param source the source information
- /// @param severity the diagnostic severity control
- /// @param rule_name the diagnostic rule name
- /// @returns the diagnostic attribute pointer
+ /// Passthrough overload
+ /// @param name the diagnostic rule name
+ /// @returns @p name
+ const ast::DiagnosticRuleName* DiagnosticRuleName(const ast::DiagnosticRuleName* name) {
+ return name;
+ }
+
+ /// Creates an ast::DiagnosticRuleName
+ /// @param name the diagnostic rule name
+ /// @returns the diagnostic rule name
template <typename NAME>
- const ast::DiagnosticAttribute* DiagnosticAttribute(const Source& source,
- builtin::DiagnosticSeverity severity,
- NAME&& rule_name) {
+ const ast::DiagnosticRuleName* DiagnosticRuleName(NAME&& name) {
static_assert(
!utils::traits::IsType<utils::traits::PtrElTy<NAME>, ast::TemplatedIdentifier>,
"it is invalid for a diagnostic rule name to be templated");
+ auto* name_ident = Ident(std::forward<NAME>(name));
+ return create<ast::DiagnosticRuleName>(name_ident->source, name_ident);
+ }
+
+ /// Creates an ast::DiagnosticRuleName
+ /// @param category the diagnostic rule category
+ /// @param name the diagnostic rule name
+ /// @returns the diagnostic rule name
+ template <typename CATEGORY, typename NAME, typename = DisableIfSource<CATEGORY>>
+ const ast::DiagnosticRuleName* DiagnosticRuleName(CATEGORY&& category, NAME&& name) {
+ static_assert(
+ !utils::traits::IsType<utils::traits::PtrElTy<NAME>, ast::TemplatedIdentifier>,
+ "it is invalid for a diagnostic rule name to be templated");
+ static_assert(
+ !utils::traits::IsType<utils::traits::PtrElTy<CATEGORY>, ast::TemplatedIdentifier>,
+ "it is invalid for a diagnostic rule category to be templated");
+ auto* category_ident = Ident(std::forward<CATEGORY>(category));
+ auto* name_ident = Ident(std::forward<NAME>(name));
+ Source source = category_ident->source;
+ source.range.end = name_ident->source.range.end;
+ return create<ast::DiagnosticRuleName>(source, category_ident, name_ident);
+ }
+
+ /// Creates an ast::DiagnosticRuleName
+ /// @param source the source information
+ /// @param name the diagnostic rule name
+ /// @returns the diagnostic rule name
+ template <typename NAME>
+ const ast::DiagnosticRuleName* DiagnosticRuleName(const Source& source, NAME&& name) {
+ static_assert(
+ !utils::traits::IsType<utils::traits::PtrElTy<NAME>, ast::TemplatedIdentifier>,
+ "it is invalid for a diagnostic rule name to be templated");
+ auto* name_ident = Ident(std::forward<NAME>(name));
+ return create<ast::DiagnosticRuleName>(source, name_ident);
+ }
+
+ /// Creates an ast::DiagnosticRuleName
+ /// @param source the source information
+ /// @param category the diagnostic rule category
+ /// @param name the diagnostic rule name
+ /// @returns the diagnostic rule name
+ template <typename CATEGORY, typename NAME>
+ const ast::DiagnosticRuleName* DiagnosticRuleName(const Source& source,
+ CATEGORY&& category,
+ NAME&& name) {
+ static_assert(
+ !utils::traits::IsType<utils::traits::PtrElTy<NAME>, ast::TemplatedIdentifier>,
+ "it is invalid for a diagnostic rule name to be templated");
+ static_assert(
+ !utils::traits::IsType<utils::traits::PtrElTy<CATEGORY>, ast::TemplatedIdentifier>,
+ "it is invalid for a diagnostic rule category to be templated");
+ auto* category_ident = Ident(std::forward<CATEGORY>(category));
+ auto* name_ident = Ident(std::forward<NAME>(name));
+ return create<ast::DiagnosticRuleName>(source, category_ident, name_ident);
+ }
+
+ /// Creates an ast::DiagnosticAttribute
+ /// @param source the source information
+ /// @param severity the diagnostic severity control
+ /// @param rule_args the arguments used to construct the rule name
+ /// @returns the diagnostic attribute pointer
+ template <typename... RULE_ARGS>
+ const ast::DiagnosticAttribute* DiagnosticAttribute(const Source& source,
+ builtin::DiagnosticSeverity severity,
+ RULE_ARGS&&... rule_args) {
return create<ast::DiagnosticAttribute>(
- source, ast::DiagnosticControl(severity, Ident(std::forward<NAME>(rule_name))));
+ source, ast::DiagnosticControl(
+ severity, DiagnosticRuleName(std::forward<RULE_ARGS>(rule_args)...)));
}
/// Creates an ast::DiagnosticAttribute
/// @param severity the diagnostic severity control
- /// @param rule_name the diagnostic rule name
+ /// @param rule_args the arguments used to construct the rule name
/// @returns the diagnostic attribute pointer
- template <typename NAME>
+ template <typename... RULE_ARGS>
const ast::DiagnosticAttribute* DiagnosticAttribute(builtin::DiagnosticSeverity severity,
- NAME&& rule_name) {
+ RULE_ARGS&&... rule_args) {
return create<ast::DiagnosticAttribute>(
- source_, ast::DiagnosticControl(severity, Ident(std::forward<NAME>(rule_name))));
+ source_, ast::DiagnosticControl(
+ severity, DiagnosticRuleName(std::forward<RULE_ARGS>(rule_args)...)));
}
/// Add a diagnostic directive to the module.
/// @param source the source information
/// @param severity the diagnostic severity control
- /// @param rule_name the diagnostic rule name
+ /// @param rule_args the arguments used to construct the rule name
/// @returns the diagnostic directive pointer
- template <typename NAME>
+ template <typename... RULE_ARGS>
const ast::DiagnosticDirective* DiagnosticDirective(const Source& source,
builtin::DiagnosticSeverity severity,
- NAME&& rule_name) {
- auto* directive = create<ast::DiagnosticDirective>(
- source, ast::DiagnosticControl(severity, Ident(std::forward<NAME>(rule_name))));
+ RULE_ARGS&&... rule_args) {
+ auto* rule = DiagnosticRuleName(std::forward<RULE_ARGS>(rule_args)...);
+ auto* directive =
+ create<ast::DiagnosticDirective>(source, ast::DiagnosticControl(severity, rule));
AST().AddDiagnosticDirective(directive);
return directive;
}
/// Add a diagnostic directive to the module.
/// @param severity the diagnostic severity control
- /// @param rule_name the diagnostic rule name
+ /// @param rule_args the arguments used to construct the rule name
/// @returns the diagnostic directive pointer
- template <typename NAME>
+ template <typename... RULE_ARGS>
const ast::DiagnosticDirective* DiagnosticDirective(builtin::DiagnosticSeverity severity,
- NAME&& rule_name) {
- auto* directive = create<ast::DiagnosticDirective>(
- source_, ast::DiagnosticControl(severity, Ident(std::forward<NAME>(rule_name))));
+ RULE_ARGS&&... rule_args) {
+ auto* rule = DiagnosticRuleName(std::forward<RULE_ARGS>(rule_args)...);
+ auto* directive =
+ create<ast::DiagnosticDirective>(source_, ast::DiagnosticControl(severity, rule));
AST().AddDiagnosticDirective(directive);
return directive;
}
diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc
index e8a9bd4..514e7f8 100644
--- a/src/tint/reader/wgsl/parser_impl.cc
+++ b/src/tint/reader/wgsl/parser_impl.cc
@@ -3092,7 +3092,7 @@
}
// diagnostic_control
-// : PAREN_LEFT severity_control_name COMMA ident_pattern_token COMMA ? PAREN_RIGHT
+// : PAREN_LEFT severity_control_name COMMA diagnostic_rule_name COMMA ? PAREN_RIGHT
Expect<ast::DiagnosticControl> ParserImpl::expect_diagnostic_control() {
return expect_paren_block("diagnostic control", [&]() -> Expect<ast::DiagnosticControl> {
auto severity_control = expect_severity_control_name();
@@ -3104,7 +3104,7 @@
return Failure::kErrored;
}
- auto rule_name = expect_ident("diagnostic control");
+ auto rule_name = expect_diagnostic_rule_name();
if (rule_name.errored) {
return Failure::kErrored;
}
@@ -3114,6 +3114,31 @@
});
}
+// diagnostic_rule_name :
+// | diagnostic_name_token
+// | diagnostic_name_token '.' diagnostic_name_token
+Expect<const ast::DiagnosticRuleName*> ParserImpl::expect_diagnostic_rule_name() {
+ if (peek_is(Token::Type::kPeriod, 1)) {
+ auto category = expect_ident("", "diagnostic rule category");
+ if (category.errored) {
+ return Failure::kErrored;
+ }
+ if (!expect("diagnostic rule", Token::Type::kPeriod)) {
+ return Failure::kErrored;
+ }
+ auto name = expect_ident("", "diagnostic rule name");
+ if (name.errored) {
+ return Failure::kErrored;
+ }
+ return builder_.DiagnosticRuleName(category.value, name.value);
+ }
+ auto name = expect_ident("", "diagnostic rule name");
+ if (name.errored) {
+ return Failure::kErrored;
+ }
+ return builder_.DiagnosticRuleName(name.value);
+}
+
bool ParserImpl::match(Token::Type tok, Source* source /*= nullptr*/) {
auto& t = peek();
@@ -3214,7 +3239,9 @@
return {static_cast<uint32_t>(sint.value), sint.source};
}
-Expect<const ast::Identifier*> ParserImpl::expect_ident(std::string_view use) {
+Expect<const ast::Identifier*> ParserImpl::expect_ident(
+ std::string_view use,
+ std::string_view kind /* = "identifier" */) {
auto& t = peek();
if (t.IsIdentifier()) {
synchronized_ = true;
@@ -3230,7 +3257,7 @@
return Failure::kErrored;
}
synchronized_ = false;
- return add_error(t.source(), "expected identifier", use);
+ return add_error(t.source(), "expected " + std::string(kind), use);
}
template <typename F, typename T>
diff --git a/src/tint/reader/wgsl/parser_impl.h b/src/tint/reader/wgsl/parser_impl.h
index 95c4db9..c7ac96d 100644
--- a/src/tint/reader/wgsl/parser_impl.h
+++ b/src/tint/reader/wgsl/parser_impl.h
@@ -636,14 +636,17 @@
/// Parses a single attribute, reporting an error if the next token does not
/// represent a attribute.
/// @see #attribute for the full list of attributes this method parses.
- /// @return the parsed attribute, or nullptr on error.
+ /// @return the parsed attribute.
Expect<const ast::Attribute*> expect_attribute();
/// Parses a severity_control_name grammar element.
- /// @return the parsed severity control name, or nullptr on error.
+ /// @return the parsed severity control name.
Expect<builtin::DiagnosticSeverity> expect_severity_control_name();
/// Parses a diagnostic_control grammar element.
- /// @return the parsed diagnostic control, or nullptr on error.
+ /// @return the parsed diagnostic control.
Expect<ast::DiagnosticControl> expect_diagnostic_control();
+ /// Parses a diagnostic_rule_name grammar element.
+ /// @return the parsed diagnostic rule name.
+ Expect<const ast::DiagnosticRuleName*> expect_diagnostic_rule_name();
/// Splits a peekable token into to parts filling in the peekable fields.
/// @param lhs the token to set in the current position
@@ -694,8 +697,11 @@
/// Errors if the next token is not an identifier.
/// Consumes the next token on match.
/// @param use a description of what was being parsed if an error was raised
+ /// @param kind a string describing the kind of identifier.
+ /// Examples: "identifier", "diagnostic name"
/// @returns the parsed identifier.
- Expect<const ast::Identifier*> expect_ident(std::string_view use);
+ Expect<const ast::Identifier*> expect_ident(std::string_view use,
+ std::string_view kind = "identifier");
/// Parses a lexical block starting with the token `start` and ending with
/// the token `end`. `body` is called to parse the lexical block body
/// between the `start` and `end` tokens. If the `start` or `end` tokens
diff --git a/src/tint/reader/wgsl/parser_impl_diagnostic_attribute_test.cc b/src/tint/reader/wgsl/parser_impl_diagnostic_attribute_test.cc
index 991d5b6..69f0003 100644
--- a/src/tint/reader/wgsl/parser_impl_diagnostic_attribute_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_diagnostic_attribute_test.cc
@@ -20,7 +20,7 @@
namespace tint::reader::wgsl {
namespace {
-TEST_F(ParserImplTest, DiagnosticAttribute_Valid) {
+TEST_F(ParserImplTest, DiagnosticAttribute_Name) {
auto p = parser("diagnostic(off, foo)");
auto a = p->attribute();
EXPECT_FALSE(p->has_error()) << p->error();
@@ -30,7 +30,22 @@
EXPECT_EQ(d->control.severity, builtin::DiagnosticSeverity::kOff);
auto* r = d->control.rule_name;
ASSERT_NE(r, nullptr);
- ast::CheckIdentifier(r, "foo");
+ EXPECT_EQ(r->category, nullptr);
+ ast::CheckIdentifier(r->name, "foo");
+}
+
+TEST_F(ParserImplTest, DiagnosticAttribute_CategoryName) {
+ auto p = parser("diagnostic(off, foo.bar)");
+ auto a = p->attribute();
+ EXPECT_FALSE(p->has_error()) << p->error();
+ EXPECT_TRUE(a.matched);
+ auto* d = a.value->As<ast::DiagnosticAttribute>();
+ ASSERT_NE(d, nullptr);
+ EXPECT_EQ(d->control.severity, builtin::DiagnosticSeverity::kOff);
+ auto* r = d->control.rule_name;
+ ASSERT_NE(r, nullptr);
+ ast::CheckIdentifier(r->category, "foo");
+ ast::CheckIdentifier(r->name, "bar");
}
} // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_diagnostic_control_test.cc b/src/tint/reader/wgsl/parser_impl_diagnostic_control_test.cc
index e45d1e7..bad434e 100644
--- a/src/tint/reader/wgsl/parser_impl_diagnostic_control_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_diagnostic_control_test.cc
@@ -23,7 +23,7 @@
using SeverityPair = std::pair<std::string, builtin::DiagnosticSeverity>;
class DiagnosticControlParserTest : public ParserImplTestWithParam<SeverityPair> {};
-TEST_P(DiagnosticControlParserTest, DiagnosticControl_Valid) {
+TEST_P(DiagnosticControlParserTest, DiagnosticControl_Name) {
auto& params = GetParam();
auto p = parser("(" + params.first + ", foo)");
auto e = p->expect_diagnostic_control();
@@ -33,7 +33,21 @@
auto* r = e->rule_name;
ASSERT_NE(r, nullptr);
- ast::CheckIdentifier(r, "foo");
+ EXPECT_EQ(r->category, nullptr);
+ ast::CheckIdentifier(r->name, "foo");
+}
+TEST_P(DiagnosticControlParserTest, DiagnosticControl_CategoryAndName) {
+ auto& params = GetParam();
+ auto p = parser("(" + params.first + ", foo.bar)");
+ auto e = p->expect_diagnostic_control();
+ EXPECT_FALSE(e.errored);
+ EXPECT_FALSE(p->has_error()) << p->error();
+ EXPECT_EQ(e->severity, params.second);
+
+ auto* r = e->rule_name;
+ ASSERT_NE(r, nullptr);
+ ast::CheckIdentifier(r->category, "foo");
+ ast::CheckIdentifier(r->name, "bar");
}
INSTANTIATE_TEST_SUITE_P(DiagnosticControlParserTest,
DiagnosticControlParserTest,
@@ -43,7 +57,7 @@
SeverityPair{"info", builtin::DiagnosticSeverity::kInfo},
SeverityPair{"off", builtin::DiagnosticSeverity::kOff}));
-TEST_F(ParserImplTest, DiagnosticControl_Valid_TrailingComma) {
+TEST_F(ParserImplTest, DiagnosticControl_Name_TrailingComma) {
auto p = parser("(error, foo,)");
auto e = p->expect_diagnostic_control();
EXPECT_FALSE(e.errored);
@@ -52,7 +66,21 @@
auto* r = e->rule_name;
ASSERT_NE(r, nullptr);
- ast::CheckIdentifier(r, "foo");
+ EXPECT_EQ(r->category, nullptr);
+ ast::CheckIdentifier(r->name, "foo");
+}
+
+TEST_F(ParserImplTest, DiagnosticControl_CategoryAndName_TrailingComma) {
+ auto p = parser("(error, foo.bar,)");
+ auto e = p->expect_diagnostic_control();
+ EXPECT_FALSE(e.errored);
+ EXPECT_FALSE(p->has_error()) << p->error();
+ EXPECT_EQ(e->severity, builtin::DiagnosticSeverity::kError);
+
+ auto* r = e->rule_name;
+ ASSERT_NE(r, nullptr);
+ ast::CheckIdentifier(r->category, "foo");
+ ast::CheckIdentifier(r->name, "bar");
}
TEST_F(ParserImplTest, DiagnosticControl_MissingOpenParen) {
@@ -102,7 +130,15 @@
auto e = p->expect_diagnostic_control();
EXPECT_TRUE(e.errored);
EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), R"(1:6: expected identifier for diagnostic control)");
+ EXPECT_EQ(p->error(), R"(1:6: expected diagnostic rule name)");
+}
+
+TEST_F(ParserImplTest, DiagnosticControl_MissingRuleCategory) {
+ auto p = parser("(off,for.foo)");
+ auto e = p->expect_diagnostic_control();
+ EXPECT_TRUE(e.errored);
+ EXPECT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), R"(1:6: expected diagnostic rule category)");
}
TEST_F(ParserImplTest, DiagnosticControl_InvalidRuleName) {
diff --git a/src/tint/reader/wgsl/parser_impl_diagnostic_directive_test.cc b/src/tint/reader/wgsl/parser_impl_diagnostic_directive_test.cc
index 12b69f1..a965112 100644
--- a/src/tint/reader/wgsl/parser_impl_diagnostic_directive_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_diagnostic_directive_test.cc
@@ -20,7 +20,7 @@
namespace tint::reader::wgsl {
namespace {
-TEST_F(ParserImplTest, DiagnosticDirective_Valid) {
+TEST_F(ParserImplTest, DiagnosticDirective_Name) {
auto p = parser("diagnostic(off, foo);");
p->diagnostic_directive();
EXPECT_FALSE(p->has_error()) << p->error();
@@ -33,7 +33,25 @@
auto* r = directive->control.rule_name;
ASSERT_NE(r, nullptr);
- ast::CheckIdentifier(r, "foo");
+ EXPECT_EQ(r->category, nullptr);
+ ast::CheckIdentifier(r->name, "foo");
+}
+
+TEST_F(ParserImplTest, DiagnosticDirective_CategoryName) {
+ auto p = parser("diagnostic(off, foo.bar);");
+ p->diagnostic_directive();
+ EXPECT_FALSE(p->has_error()) << p->error();
+ auto& ast = p->builder().AST();
+ ASSERT_EQ(ast.DiagnosticDirectives().Length(), 1u);
+ auto* directive = ast.DiagnosticDirectives()[0];
+ EXPECT_EQ(directive->control.severity, builtin::DiagnosticSeverity::kOff);
+ ASSERT_EQ(ast.GlobalDeclarations().Length(), 1u);
+ EXPECT_EQ(ast.GlobalDeclarations()[0], directive);
+
+ auto* r = directive->control.rule_name;
+ ASSERT_NE(r, nullptr);
+ ast::CheckIdentifier(r->category, "foo");
+ ast::CheckIdentifier(r->name, "bar");
}
TEST_F(ParserImplTest, DiagnosticDirective_MissingSemicolon) {
diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc
index d6a2f0f..098ab17 100644
--- a/src/tint/resolver/attribute_validation_test.cc
+++ b/src/tint/resolver/attribute_validation_test.cc
@@ -101,7 +101,7 @@
return {builder.Builtin(source, builtin::BuiltinValue::kPosition)};
case AttributeKind::kDiagnostic:
return {builder.DiagnosticAttribute(source, builtin::DiagnosticSeverity::kInfo,
- "chromium_unreachable_code")};
+ "chromium", "unreachable_code")};
case AttributeKind::kGroup:
return {builder.Group(source, 1_a)};
case AttributeKind::kId:
diff --git a/src/tint/resolver/diagnostic_control_test.cc b/src/tint/resolver/diagnostic_control_test.cc
index d7143c7..527acd1 100644
--- a/src/tint/resolver/diagnostic_control_test.cc
+++ b/src/tint/resolver/diagnostic_control_test.cc
@@ -32,7 +32,7 @@
}
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_ErrorViaDirective) {
- DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
+ DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts);
@@ -42,7 +42,7 @@
}
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_WarningViaDirective) {
- DiagnosticDirective(builtin::DiagnosticSeverity::kWarning, "chromium_unreachable_code");
+ DiagnosticDirective(builtin::DiagnosticSeverity::kWarning, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts);
@@ -52,7 +52,7 @@
}
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_InfoViaDirective) {
- DiagnosticDirective(builtin::DiagnosticSeverity::kInfo, "chromium_unreachable_code");
+ DiagnosticDirective(builtin::DiagnosticSeverity::kInfo, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts);
@@ -62,7 +62,7 @@
}
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_OffViaDirective) {
- DiagnosticDirective(builtin::DiagnosticSeverity::kOff, "chromium_unreachable_code");
+ DiagnosticDirective(builtin::DiagnosticSeverity::kOff, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts);
@@ -73,7 +73,7 @@
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_ErrorViaAttribute) {
auto* attr =
- DiagnosticAttribute(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kError, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@@ -84,7 +84,7 @@
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_WarningViaAttribute) {
auto* attr =
- DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, "chromium_unreachable_code");
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@@ -95,7 +95,7 @@
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_InfoViaAttribute) {
auto* attr =
- DiagnosticAttribute(builtin::DiagnosticSeverity::kInfo, "chromium_unreachable_code");
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kInfo, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@@ -106,7 +106,7 @@
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_OffViaAttribute) {
auto* attr =
- DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "chromium_unreachable_code");
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@@ -116,15 +116,15 @@
}
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_ErrorViaDirective_OverriddenViaAttribute) {
- // diagnostic(error, chromium_unreachable_code);
+ // diagnostic(error, chromium.unreachable_code);
//
- // @diagnostic(off, chromium_unreachable_code) fn foo() {
+ // @diagnostic(off, chromium.unreachable_code) fn foo() {
// return;
// return; // Should produce a warning
// }
- DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
+ DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium", "unreachable_code");
auto* attr =
- DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, "chromium_unreachable_code");
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kWarning, "chromium", "unreachable_code");
auto stmts = utils::Vector{Return(), Return()};
Func("foo", {}, ty.void_(), stmts, utils::Vector{attr});
@@ -134,7 +134,7 @@
}
TEST_F(ResolverDiagnosticControlTest, FunctionAttributeScope) {
- // @diagnostic(off, chromium_unreachable_code) fn foo() {
+ // @diagnostic(off, chromium.unreachable_code) fn foo() {
// return;
// return; // Should not produce a diagnostic
// }
@@ -144,13 +144,13 @@
// return; // Should produce a warning (default severity)
// }
//
- // @diagnostic(info, chromium_unreachable_code) fn bar() {
+ // @diagnostic(info, chromium.unreachable_code) fn bar() {
// return;
// return; // Should produce an info
// }
{
auto* attr =
- DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "chromium_unreachable_code");
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "chromium", "unreachable_code");
Func("foo", {}, ty.void_(),
utils::Vector{
Return(),
@@ -167,7 +167,7 @@
}
{
auto* attr =
- DiagnosticAttribute(builtin::DiagnosticSeverity::kInfo, "chromium_unreachable_code");
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kInfo, "chromium", "unreachable_code");
Func("zoo", {}, ty.void_(),
utils::Vector{
Return(),
@@ -182,17 +182,17 @@
}
TEST_F(ResolverDiagnosticControlTest, BlockAttributeScope) {
- // fn foo() @diagnostic(off, chromium_unreachable_code) {
+ // fn foo() @diagnostic(off, chromium.unreachable_code) {
// {
// return;
// return; // Should not produce a diagnostic
// }
- // @diagnostic(warning, chromium_unreachable_code) {
- // if (true) @diagnostic(info, chromium_unreachable_code) {
+ // @diagnostic(warning, chromium.unreachable_code) {
+ // if (true) @diagnostic(info, chromium.unreachable_code) {
// return;
// return; // Should produce an info
// } else {
- // while (true) @diagnostic(off, chromium_unreachable_code) {
+ // while (true) @diagnostic(off, chromium.unreachable_code) {
// return;
// return; // Should not produce a diagnostic
// }
@@ -203,7 +203,7 @@
// }
auto attr = [&](auto severity) {
- return utils::Vector{DiagnosticAttribute(severity, "chromium_unreachable_code")};
+ return utils::Vector{DiagnosticAttribute(severity, "chromium", "unreachable_code")};
};
Func("foo", {}, ty.void_(),
utils::Vector{
@@ -241,113 +241,157 @@
78:87 warning: code is unreachable)");
}
-TEST_F(ResolverDiagnosticControlTest, UnrecognizedRuleName_Directive) {
+TEST_F(ResolverDiagnosticControlTest, UnrecognizedCoreRuleName_Directive) {
DiagnosticDirective(builtin::DiagnosticSeverity::kError,
- Ident(Source{{12, 34}}, "chromium_unreachable_cod"));
+ DiagnosticRuleName(Source{{12, 34}}, "derivative_uniform"));
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(),
- R"(12:34 warning: unrecognized diagnostic rule 'chromium_unreachable_cod'
-Did you mean 'chromium_unreachable_code'?
-Possible values: 'chromium_unreachable_code', 'derivative_uniformity')");
+ R"(12:34 warning: unrecognized diagnostic rule 'derivative_uniform'
+Did you mean 'derivative_uniformity'?
+Possible values: 'derivative_uniformity')");
}
-TEST_F(ResolverDiagnosticControlTest, UnrecognizedRuleName_Attribute) {
+TEST_F(ResolverDiagnosticControlTest, UnrecognizedCoreRuleName_Attribute) {
auto* attr = DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
- Ident(Source{{12, 34}}, "chromium_unreachable_cod"));
+ DiagnosticRuleName(Source{{12, 34}}, "derivative_uniform"));
Func("foo", {}, ty.void_(), {}, utils::Vector{attr});
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(),
- R"(12:34 warning: unrecognized diagnostic rule 'chromium_unreachable_cod'
-Did you mean 'chromium_unreachable_code'?
-Possible values: 'chromium_unreachable_code', 'derivative_uniformity')");
+ R"(12:34 warning: unrecognized diagnostic rule 'derivative_uniform'
+Did you mean 'derivative_uniformity'?
+Possible values: 'derivative_uniformity')");
+}
+
+TEST_F(ResolverDiagnosticControlTest, UnrecognizedChromiumRuleName_Directive) {
+ DiagnosticDirective(builtin::DiagnosticSeverity::kError,
+ DiagnosticRuleName(Source{{12, 34}}, "chromium", "unreachable_cod"));
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(),
+ R"(12:34 warning: unrecognized diagnostic rule 'chromium.unreachable_cod'
+Did you mean 'chromium.unreachable_code'?
+Possible values: 'chromium.unreachable_code')");
+}
+
+TEST_F(ResolverDiagnosticControlTest, UnrecognizedChromiumRuleName_Attribute) {
+ auto* attr =
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
+ DiagnosticRuleName(Source{{12, 34}}, "chromium", "unreachable_cod"));
+ Func("foo", {}, ty.void_(), {}, utils::Vector{attr});
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(),
+ R"(12:34 warning: unrecognized diagnostic rule 'chromium.unreachable_cod'
+Did you mean 'chromium.unreachable_code'?
+Possible values: 'chromium.unreachable_code')");
+}
+
+TEST_F(ResolverDiagnosticControlTest, UnrecognizedOtherRuleName_Directive) {
+ DiagnosticDirective(builtin::DiagnosticSeverity::kError,
+ DiagnosticRuleName(Source{{12, 34}}, "unknown", "unreachable_cod"));
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), "");
+}
+
+TEST_F(ResolverDiagnosticControlTest, UnrecognizedOtherRuleName_Attribute) {
+ auto* attr =
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
+ DiagnosticRuleName(Source{{12, 34}}, "unknown", "unreachable_cod"));
+ Func("foo", {}, ty.void_(), {}, utils::Vector{attr});
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), "");
}
TEST_F(ResolverDiagnosticControlTest, Conflict_SameNameSameSeverity_Directive) {
DiagnosticDirective(builtin::DiagnosticSeverity::kError,
- Ident(Source{{12, 34}}, "chromium_unreachable_code"));
+ DiagnosticRuleName(Source{{12, 34}}, "chromium", "unreachable_code"));
DiagnosticDirective(builtin::DiagnosticSeverity::kError,
- Ident(Source{{56, 78}}, "chromium_unreachable_code"));
+ DiagnosticRuleName(Source{{56, 78}}, "chromium", "unreachable_code"));
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverDiagnosticControlTest, Conflict_SameNameDifferentSeverity_Directive) {
DiagnosticDirective(builtin::DiagnosticSeverity::kError,
- Ident(Source{{12, 34}}, "chromium_unreachable_code"));
+ DiagnosticRuleName(Source{{12, 34}}, "chromium", "unreachable_code"));
DiagnosticDirective(builtin::DiagnosticSeverity::kOff,
- Ident(Source{{56, 78}}, "chromium_unreachable_code"));
+ DiagnosticRuleName(Source{{56, 78}}, "chromium", "unreachable_code"));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(56:78 error: conflicting diagnostic directive
-12:34 note: severity of 'chromium_unreachable_code' set to 'off' here)");
+12:34 note: severity of 'chromium.unreachable_code' set to 'off' here)");
}
TEST_F(ResolverDiagnosticControlTest, Conflict_SameUnknownNameDifferentSeverity_Directive) {
DiagnosticDirective(builtin::DiagnosticSeverity::kError,
- Ident(Source{{12, 34}}, "chromium_unreachable_codes"));
+ DiagnosticRuleName(Source{{12, 34}}, "chromium", "unreachable_codes"));
DiagnosticDirective(builtin::DiagnosticSeverity::kOff,
- Ident(Source{{56, 78}}, "chromium_unreachable_codes"));
+ DiagnosticRuleName(Source{{56, 78}}, "chromium", "unreachable_codes"));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 warning: unrecognized diagnostic rule 'chromium_unreachable_codes'
-Did you mean 'chromium_unreachable_code'?
-Possible values: 'chromium_unreachable_code', 'derivative_uniformity'
-56:78 warning: unrecognized diagnostic rule 'chromium_unreachable_codes'
-Did you mean 'chromium_unreachable_code'?
-Possible values: 'chromium_unreachable_code', 'derivative_uniformity'
+ R"(12:34 warning: unrecognized diagnostic rule 'chromium.unreachable_codes'
+Did you mean 'chromium.unreachable_code'?
+Possible values: 'chromium.unreachable_code'
+56:78 warning: unrecognized diagnostic rule 'chromium.unreachable_codes'
+Did you mean 'chromium.unreachable_code'?
+Possible values: 'chromium.unreachable_code'
56:78 error: conflicting diagnostic directive
-12:34 note: severity of 'chromium_unreachable_codes' set to 'off' here)");
+12:34 note: severity of 'chromium.unreachable_codes' set to 'off' here)");
}
TEST_F(ResolverDiagnosticControlTest, Conflict_DifferentUnknownNameDifferentSeverity_Directive) {
- DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium_unreachable_codes");
- DiagnosticDirective(builtin::DiagnosticSeverity::kOff, "chromium_unreachable_codex");
+ DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium", "unreachable_codes");
+ DiagnosticDirective(builtin::DiagnosticSeverity::kOff, "chromium", "unreachable_codex");
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverDiagnosticControlTest, Conflict_SameNameSameSeverity_Attribute) {
- auto* attr1 = DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
- Ident(Source{{12, 34}}, "chromium_unreachable_code"));
- auto* attr2 = DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
- Ident(Source{{56, 78}}, "chromium_unreachable_code"));
+ auto* attr1 =
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
+ DiagnosticRuleName(Source{{12, 34}}, "chromium", "unreachable_code"));
+ auto* attr2 =
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
+ DiagnosticRuleName(Source{{56, 78}}, "chromium", "unreachable_code"));
Func("foo", {}, ty.void_(), {}, utils::Vector{attr1, attr2});
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
TEST_F(ResolverDiagnosticControlTest, Conflict_SameNameDifferentSeverity_Attribute) {
- auto* attr1 = DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
- Ident(Source{{12, 34}}, "chromium_unreachable_code"));
- auto* attr2 = DiagnosticAttribute(builtin::DiagnosticSeverity::kOff,
- Ident(Source{{56, 78}}, "chromium_unreachable_code"));
+ auto* attr1 =
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
+ DiagnosticRuleName(Source{{12, 34}}, "chromium", "unreachable_code"));
+ auto* attr2 =
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kOff,
+ DiagnosticRuleName(Source{{56, 78}}, "chromium", "unreachable_code"));
Func("foo", {}, ty.void_(), {}, utils::Vector{attr1, attr2});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
R"(56:78 error: conflicting diagnostic attribute
-12:34 note: severity of 'chromium_unreachable_code' set to 'off' here)");
+12:34 note: severity of 'chromium.unreachable_code' set to 'off' here)");
}
TEST_F(ResolverDiagnosticControlTest, Conflict_SameUnknownNameDifferentSeverity_Attribute) {
- auto* attr1 = DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
- Ident(Source{{12, 34}}, "chromium_unreachable_codes"));
- auto* attr2 = DiagnosticAttribute(builtin::DiagnosticSeverity::kOff,
- Ident(Source{{56, 78}}, "chromium_unreachable_codes"));
+ auto* attr1 =
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kError,
+ DiagnosticRuleName(Source{{12, 34}}, "chromium", "unreachable_codes"));
+ auto* attr2 =
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kOff,
+ DiagnosticRuleName(Source{{56, 78}}, "chromium", "unreachable_codes"));
Func("foo", {}, ty.void_(), {}, utils::Vector{attr1, attr2});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
- R"(12:34 warning: unrecognized diagnostic rule 'chromium_unreachable_codes'
-Did you mean 'chromium_unreachable_code'?
-Possible values: 'chromium_unreachable_code', 'derivative_uniformity'
-56:78 warning: unrecognized diagnostic rule 'chromium_unreachable_codes'
-Did you mean 'chromium_unreachable_code'?
-Possible values: 'chromium_unreachable_code', 'derivative_uniformity'
+ R"(12:34 warning: unrecognized diagnostic rule 'chromium.unreachable_codes'
+Did you mean 'chromium.unreachable_code'?
+Possible values: 'chromium.unreachable_code'
+56:78 warning: unrecognized diagnostic rule 'chromium.unreachable_codes'
+Did you mean 'chromium.unreachable_code'?
+Possible values: 'chromium.unreachable_code'
56:78 error: conflicting diagnostic attribute
-12:34 note: severity of 'chromium_unreachable_codes' set to 'off' here)");
+12:34 note: severity of 'chromium.unreachable_codes' set to 'off' here)");
}
TEST_F(ResolverDiagnosticControlTest, Conflict_DifferentUnknownNameDifferentSeverity_Attribute) {
auto* attr1 =
- DiagnosticAttribute(builtin::DiagnosticSeverity::kError, "chromium_unreachable_codes");
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kError, "chromium", "unreachable_codes");
auto* attr2 =
- DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "chromium_unreachable_codex");
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kOff, "chromium", "unreachable_codex");
Func("foo", {}, ty.void_(), {}, utils::Vector{attr1, attr2});
EXPECT_TRUE(r()->Resolve()) << r()->error();
}
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index 1ec680d..19571a7 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -3466,15 +3466,33 @@
bool Resolver::DiagnosticControl(const ast::DiagnosticControl& control) {
Mark(control.rule_name);
+ Mark(control.rule_name->name);
+ auto name = control.rule_name->name->symbol.Name();
- auto rule_name = control.rule_name->symbol.Name();
- auto rule = builtin::ParseDiagnosticRule(rule_name);
- if (rule != builtin::DiagnosticRule::kUndefined) {
+ if (control.rule_name->category) {
+ Mark(control.rule_name->category);
+ if (control.rule_name->category->symbol.Name() == "chromium") {
+ auto rule = builtin::ParseChromiumDiagnosticRule(name);
+ if (rule != builtin::ChromiumDiagnosticRule::kUndefined) {
+ validator_.DiagnosticFilters().Set(rule, control.severity);
+ } else {
+ utils::StringStream ss;
+ ss << "unrecognized diagnostic rule 'chromium." << name << "'\n";
+ utils::SuggestAlternatives(name, builtin::kChromiumDiagnosticRuleStrings, ss,
+ "chromium.");
+ AddWarning(ss.str(), control.rule_name->source);
+ }
+ }
+ return true;
+ }
+
+ auto rule = builtin::ParseCoreDiagnosticRule(name);
+ if (rule != builtin::CoreDiagnosticRule::kUndefined) {
validator_.DiagnosticFilters().Set(rule, control.severity);
} else {
utils::StringStream ss;
- ss << "unrecognized diagnostic rule '" << rule_name << "'\n";
- utils::SuggestAlternatives(rule_name, builtin::kDiagnosticRuleStrings, ss);
+ ss << "unrecognized diagnostic rule '" << name << "'\n";
+ utils::SuggestAlternatives(name, builtin::kCoreDiagnosticRuleStrings, ss);
AddWarning(ss.str(), control.rule_name->source);
}
return true;
diff --git a/src/tint/resolver/uniformity.cc b/src/tint/resolver/uniformity.cc
index fc84826..45c919e 100644
--- a/src/tint/resolver/uniformity.cc
+++ b/src/tint/resolver/uniformity.cc
@@ -1563,7 +1563,7 @@
builtin->Type() == builtin::Function::kTextureSampleCompare) {
// Get the severity of derivative uniformity violations in this context.
auto severity = sem_.DiagnosticSeverity(
- call, builtin::DiagnosticRule::kDerivativeUniformity);
+ call, builtin::CoreDiagnosticRule::kDerivativeUniformity);
if (severity != builtin::DiagnosticSeverity::kOff) {
callsite_tag = {CallSiteTag::CallSiteRequiredToBeUniform, severity};
}
diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc
index f72000b..97eae88 100644
--- a/src/tint/resolver/validator.cc
+++ b/src/tint/resolver/validator.cc
@@ -159,9 +159,9 @@
atomic_composite_info_(atomic_composite_info),
valid_type_storage_layouts_(valid_type_storage_layouts) {
// Set default severities for filterable diagnostic rules.
- diagnostic_filters_.Set(builtin::DiagnosticRule::kDerivativeUniformity,
+ diagnostic_filters_.Set(builtin::CoreDiagnosticRule::kDerivativeUniformity,
builtin::DiagnosticSeverity::kError);
- diagnostic_filters_.Set(builtin::DiagnosticRule::kChromiumUnreachableCode,
+ diagnostic_filters_.Set(builtin::ChromiumDiagnosticRule::kUnreachableCode,
builtin::DiagnosticSeverity::kWarning);
}
@@ -1417,7 +1417,7 @@
bool Validator::Statements(utils::VectorRef<const ast::Statement*> stmts) const {
for (auto* stmt : stmts) {
if (!sem_.Get(stmt)->IsReachable()) {
- if (!AddDiagnostic(builtin::DiagnosticRule::kChromiumUnreachableCode,
+ if (!AddDiagnostic(builtin::ChromiumDiagnosticRule::kUnreachableCode,
"code is unreachable", stmt->source)) {
return false;
}
@@ -2530,9 +2530,12 @@
const char* use) const {
// Make sure that no two diagnostic controls conflict.
// They conflict if the rule name is the same and the severity is different.
- utils::Hashmap<Symbol, const ast::DiagnosticControl*, 8> diagnostics;
+ utils::Hashmap<std::pair<Symbol, Symbol>, const ast::DiagnosticControl*, 8> diagnostics;
for (auto* dc : controls) {
- auto diag_added = diagnostics.Add(dc->rule_name->symbol, dc);
+ auto category = dc->rule_name->category ? dc->rule_name->category->symbol : Symbol();
+ auto name = dc->rule_name->name->symbol;
+
+ auto diag_added = diagnostics.Add(std::make_pair(category, name), dc);
if (!diag_added && (*diag_added.value)->severity != dc->severity) {
{
utils::StringStream ss;
@@ -2541,8 +2544,8 @@
}
{
utils::StringStream ss;
- ss << "severity of '" << dc->rule_name->symbol.Name() << "' set to '"
- << dc->severity << "' here";
+ ss << "severity of '" << dc->rule_name->String() << "' set to '" << dc->severity
+ << "' here";
AddNote(ss.str(), (*diag_added.value)->rule_name->source);
}
return false;
diff --git a/src/tint/sem/diagnostic_severity_test.cc b/src/tint/sem/diagnostic_severity_test.cc
index 9d36ea2..a378add 100644
--- a/src/tint/sem/diagnostic_severity_test.cc
+++ b/src/tint/sem/diagnostic_severity_test.cc
@@ -23,27 +23,27 @@
class DiagnosticSeverityTest : public TestHelper {
protected:
- /// Create a program with two functions, setting the severity for "chromium_unreachable_code"
+ /// Create a program with two functions, setting the severity for "chromium.unreachable_code"
/// using an attribute. Test that we correctly track the severity of the filter for the
/// functions and the statements with them.
- /// @param global_severity the global severity of the "chromium_unreachable_code" filter
+ /// @param global_severity the global severity of the "chromium.unreachable_code" filter
void Run(builtin::DiagnosticSeverity global_severity) {
- // @diagnostic(off, chromium_unreachable_code)
+ // @diagnostic(off, chromium.unreachable_code)
// fn foo() {
- // @diagnostic(info, chromium_unreachable_code) {
- // @diagnostic(error, chromium_unreachable_code)
- // if (true) @diagnostic(warning, chromium_unreachable_code) {
+ // @diagnostic(info, chromium.unreachable_code) {
+ // @diagnostic(error, chromium.unreachable_code)
+ // if (true) @diagnostic(warning, chromium.unreachable_code) {
// return;
// } else if (false) {
// return;
- // } else @diagnostic(info, chromium_unreachable_code) {
+ // } else @diagnostic(info, chromium.unreachable_code) {
// return;
// }
// return;
//
- // @diagnostic(error, chromium_unreachable_code)
- // switch (42) @diagnostic(off, chromium_unreachable_code) {
- // case 0 @diagnostic(warning, chromium_unreachable_code) {
+ // @diagnostic(error, chromium.unreachable_code)
+ // switch (42) @diagnostic(off, chromium.unreachable_code) {
+ // case 0 @diagnostic(warning, chromium.unreachable_code) {
// return;
// }
// default {
@@ -51,21 +51,21 @@
// }
// }
//
- // @diagnostic(error, chromium_unreachable_code)
- // for (var i = 0; false; i++) @diagnostic(warning, chromium_unreachable_code) {
+ // @diagnostic(error, chromium.unreachable_code)
+ // for (var i = 0; false; i++) @diagnostic(warning, chromium.unreachable_code) {
// return;
// }
//
- // @diagnostic(warning, chromium_unreachable_code)
- // loop @diagnostic(off, chromium_unreachable_code) {
+ // @diagnostic(warning, chromium.unreachable_code)
+ // loop @diagnostic(off, chromium.unreachable_code) {
// return;
- // continuing @diagnostic(info, chromium_unreachable_code) {
+ // continuing @diagnostic(info, chromium.unreachable_code) {
// break if true;
// }
// }
//
- // @diagnostic(error, chromium_unreachable_code)
- // while (false) @diagnostic(warning, chromium_unreachable_code) {
+ // @diagnostic(error, chromium.unreachable_code)
+ // while (false) @diagnostic(warning, chromium.unreachable_code) {
// return;
// }
// }
@@ -74,7 +74,7 @@
// fn bar() {
// return;
// }
- auto rule = builtin::DiagnosticRule::kChromiumUnreachableCode;
+ auto rule = builtin::ChromiumDiagnosticRule::kUnreachableCode;
auto func_severity = builtin::DiagnosticSeverity::kOff;
auto block_severity = builtin::DiagnosticSeverity::kInfo;
auto if_severity = builtin::DiagnosticSeverity::kError;
@@ -91,7 +91,7 @@
auto while_severity = builtin::DiagnosticSeverity::kError;
auto while_body_severity = builtin::DiagnosticSeverity::kWarning;
auto attr = [&](auto severity) {
- return utils::Vector{DiagnosticAttribute(severity, "chromium_unreachable_code")};
+ return utils::Vector{DiagnosticAttribute(severity, "chromium", "unreachable_code")};
};
auto* return_foo_if = Return();
@@ -123,7 +123,7 @@
attr(while_severity));
auto* block_1 =
Block(utils::Vector{if_foo, return_foo_block, swtch, fl, l, wl}, attr(block_severity));
- auto* func_attr = DiagnosticAttribute(func_severity, "chromium_unreachable_code");
+ auto* func_attr = DiagnosticAttribute(func_severity, "chromium", "unreachable_code");
auto* foo = Func("foo", {}, ty.void_(), utils::Vector{block_1}, utils::Vector{func_attr});
auto* return_bar = Return();
@@ -173,7 +173,7 @@
};
TEST_F(DiagnosticSeverityTest, WithDirective) {
- DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
+ DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium", "unreachable_code");
Run(builtin::DiagnosticSeverity::kError);
}
diff --git a/src/tint/transform/renamer.cc b/src/tint/transform/renamer.cc
index bd74cf6..14b8c12 100644
--- a/src/tint/transform/renamer.cc
+++ b/src/tint/transform/renamer.cc
@@ -1289,10 +1289,16 @@
}
},
[&](const ast::DiagnosticAttribute* diagnostic) {
- preserved_identifiers.Add(diagnostic->control.rule_name);
+ if (auto* category = diagnostic->control.rule_name->category) {
+ preserved_identifiers.Add(category);
+ }
+ preserved_identifiers.Add(diagnostic->control.rule_name->name);
},
[&](const ast::DiagnosticDirective* diagnostic) {
- preserved_identifiers.Add(diagnostic->control.rule_name);
+ if (auto* category = diagnostic->control.rule_name->category) {
+ preserved_identifiers.Add(category);
+ }
+ preserved_identifiers.Add(diagnostic->control.rule_name->name);
},
[&](const ast::IdentifierExpression* expr) {
Switch(
diff --git a/src/tint/transform/renamer_test.cc b/src/tint/transform/renamer_test.cc
index fc34251..cd321fb 100644
--- a/src/tint/transform/renamer_test.cc
+++ b/src/tint/transform/renamer_test.cc
@@ -192,9 +192,9 @@
EXPECT_THAT(data->remappings, ContainerEq(expected_remappings));
}
-TEST_F(RenamerTest, PreserveDiagnosticControls) {
+TEST_F(RenamerTest, PreserveCoreDiagnosticRuleName) {
auto* src = R"(
-diagnostic(off, unreachable_code);
+diagnostic(off, chromium.unreachable_code);
@diagnostic(off, derivative_uniformity)
@fragment
@@ -208,7 +208,7 @@
)";
auto* expect = R"(
-diagnostic(off, unreachable_code);
+diagnostic(off, chromium.unreachable_code);
@diagnostic(off, derivative_uniformity) @fragment
fn tint_symbol(@location(0) tint_symbol_1 : f32) -> @location(0) f32 {
diff --git a/src/tint/utils/hash.h b/src/tint/utils/hash.h
index 8c9dd25..a63a303 100644
--- a/src/tint/utils/hash.h
+++ b/src/tint/utils/hash.h
@@ -134,7 +134,15 @@
}
};
-/// Hasher specialization for std::tuple
+/// Hasher specialization for std::pair
+template <typename A, typename B>
+struct Hasher<std::pair<A, B>> {
+ /// @param tuple the tuple to hash
+ /// @returns a hash of the tuple
+ size_t operator()(const std::pair<A, B>& tuple) const { return std::apply(Hash<A, B>, tuple); }
+};
+
+/// Hasher specialization for std::variant
template <typename... TYPES>
struct Hasher<std::variant<TYPES...>> {
/// @param variant the variant to hash
diff --git a/src/tint/utils/string.cc b/src/tint/utils/string.cc
index 2f28a3e..67eaf2b 100644
--- a/src/tint/utils/string.cc
+++ b/src/tint/utils/string.cc
@@ -50,7 +50,8 @@
void SuggestAlternatives(std::string_view got,
Slice<char const* const> strings,
- utils::StringStream& ss) {
+ utils::StringStream& ss,
+ std::string_view prefix /* = "" */) {
// If the string typed was within kSuggestionDistance of one of the possible enum values,
// suggest that. Don't bother with suggestions if the string was extremely long.
constexpr size_t kSuggestionDistance = 5;
@@ -66,7 +67,7 @@
}
}
if (candidate) {
- ss << "Did you mean '" << candidate << "'?\n";
+ ss << "Did you mean '" << prefix << candidate << "'?\n";
}
}
@@ -76,7 +77,7 @@
if (str != strings[0]) {
ss << ", ";
}
- ss << "'" << str << "'";
+ ss << "'" << prefix << str << "'";
}
}
diff --git a/src/tint/utils/string.h b/src/tint/utils/string.h
index 5c7255d..897d1a1 100644
--- a/src/tint/utils/string.h
+++ b/src/tint/utils/string.h
@@ -72,9 +72,11 @@
/// @param got the unrecognized string
/// @param strings the list of possible values
/// @param ss the stream to write the suggest and list of possible values to
+/// @param prefix the prefix to apply to the strings when printing (optional)
void SuggestAlternatives(std::string_view got,
Slice<char const* const> strings,
- utils::StringStream& ss);
+ utils::StringStream& ss,
+ std::string_view prefix = "");
} // namespace tint::utils
diff --git a/src/tint/writer/syntax_tree/generator_impl.cc b/src/tint/writer/syntax_tree/generator_impl.cc
index be30289..08ca8c5 100644
--- a/src/tint/writer/syntax_tree/generator_impl.cc
+++ b/src/tint/writer/syntax_tree/generator_impl.cc
@@ -66,7 +66,7 @@
void GeneratorImpl::EmitDiagnosticControl(const ast::DiagnosticControl& diagnostic) {
line() << "DiagnosticControl [severity: " << diagnostic.severity
- << ", rule: " << diagnostic.rule_name->symbol.Name() << "]";
+ << ", rule: " << diagnostic.rule_name->String() << "]";
}
void GeneratorImpl::EmitEnable(const ast::Enable* enable) {
diff --git a/src/tint/writer/wgsl/generator_impl.cc b/src/tint/writer/wgsl/generator_impl.cc
index 2a2f0e7..2703e8d 100644
--- a/src/tint/writer/wgsl/generator_impl.cc
+++ b/src/tint/writer/wgsl/generator_impl.cc
@@ -82,8 +82,7 @@
void GeneratorImpl::EmitDiagnosticControl(utils::StringStream& out,
const ast::DiagnosticControl& diagnostic) {
- out << "diagnostic(" << diagnostic.severity << ", " << diagnostic.rule_name->symbol.Name()
- << ")";
+ out << "diagnostic(" << diagnostic.severity << ", " << diagnostic.rule_name->String() << ")";
}
void GeneratorImpl::EmitEnable(const ast::Enable* enable) {
diff --git a/src/tint/writer/wgsl/generator_impl_diagnostic_test.cc b/src/tint/writer/wgsl/generator_impl_diagnostic_test.cc
index 2a2f4b6..2aeab09 100644
--- a/src/tint/writer/wgsl/generator_impl_diagnostic_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_diagnostic_test.cc
@@ -22,25 +22,25 @@
using WgslGeneratorImplTest = TestHelper;
TEST_F(WgslGeneratorImplTest, Emit_DiagnosticDirective) {
- DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
+ DiagnosticDirective(builtin::DiagnosticSeverity::kError, "chromium", "unreachable_code");
GeneratorImpl& gen = Build();
gen.Generate();
EXPECT_THAT(gen.Diagnostics(), testing::IsEmpty());
- EXPECT_EQ(gen.result(), R"(diagnostic(error, chromium_unreachable_code);
+ EXPECT_EQ(gen.result(), R"(diagnostic(error, chromium.unreachable_code);
)");
}
TEST_F(WgslGeneratorImplTest, Emit_DiagnosticAttribute) {
auto* attr =
- DiagnosticAttribute(builtin::DiagnosticSeverity::kError, "chromium_unreachable_code");
+ DiagnosticAttribute(builtin::DiagnosticSeverity::kError, "chromium", "unreachable_code");
Func("foo", {}, ty.void_(), {}, utils::Vector{attr});
GeneratorImpl& gen = Build();
gen.Generate();
EXPECT_THAT(gen.Diagnostics(), testing::IsEmpty());
- EXPECT_EQ(gen.result(), R"(@diagnostic(error, chromium_unreachable_code)
+ EXPECT_EQ(gen.result(), R"(@diagnostic(error, chromium.unreachable_code)
fn foo() {
}
)");