diff --git a/src/tint/resolver/diagnostic_control_test.cc b/src/tint/resolver/diagnostic_control_test.cc index b02a5e85d8..6c217e6849 100644 --- a/src/tint/resolver/diagnostic_control_test.cc +++ b/src/tint/resolver/diagnostic_control_test.cc @@ -71,5 +71,115 @@ TEST_F(ResolverDiagnosticControlTest, UnreachableCode_OffViaDirective) { EXPECT_TRUE(r()->error().empty()); } +TEST_F(ResolverDiagnosticControlTest, UnreachableCode_ErrorViaAttribute) { + auto* attr = + DiagnosticAttribute(ast::DiagnosticSeverity::kError, Expr("chromium_unreachable_code")); + + auto stmts = utils::Vector{Return(), Return()}; + Func("foo", {}, ty.void_(), stmts, utils::Vector{attr}); + + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ(r()->error(), R"(error: code is unreachable)"); +} + +TEST_F(ResolverDiagnosticControlTest, UnreachableCode_WarningViaAttribute) { + auto* attr = + DiagnosticAttribute(ast::DiagnosticSeverity::kWarning, Expr("chromium_unreachable_code")); + + auto stmts = utils::Vector{Return(), Return()}; + Func("foo", {}, ty.void_(), stmts, utils::Vector{attr}); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + EXPECT_EQ(r()->error(), R"(warning: code is unreachable)"); +} + +TEST_F(ResolverDiagnosticControlTest, UnreachableCode_InfoViaAttribute) { + auto* attr = + DiagnosticAttribute(ast::DiagnosticSeverity::kInfo, Expr("chromium_unreachable_code")); + + auto stmts = utils::Vector{Return(), Return()}; + Func("foo", {}, ty.void_(), stmts, utils::Vector{attr}); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + EXPECT_EQ(r()->error(), R"(note: code is unreachable)"); +} + +TEST_F(ResolverDiagnosticControlTest, UnreachableCode_OffViaAttribute) { + auto* attr = + DiagnosticAttribute(ast::DiagnosticSeverity::kOff, Expr("chromium_unreachable_code")); + + auto stmts = utils::Vector{Return(), Return()}; + Func("foo", {}, ty.void_(), stmts, utils::Vector{attr}); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + EXPECT_TRUE(r()->error().empty()); +} + +TEST_F(ResolverDiagnosticControlTest, UnreachableCode_ErrorViaDirective_OverriddenViaAttribute) { + // diagnostic(error, chromium_unreachable_code); + // + // @diagnostic(off, chromium_unreachable_code) fn foo() { + // return; + // return; // Should produce a warning + // } + DiagnosticDirective(ast::DiagnosticSeverity::kError, Expr("chromium_unreachable_code")); + auto* attr = + DiagnosticAttribute(ast::DiagnosticSeverity::kWarning, Expr("chromium_unreachable_code")); + + auto stmts = utils::Vector{Return(), Return()}; + Func("foo", {}, ty.void_(), stmts, utils::Vector{attr}); + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + EXPECT_EQ(r()->error(), R"(warning: code is unreachable)"); +} + +TEST_F(ResolverDiagnosticControlTest, FunctionAttributeScope) { + // @diagnostic(off, chromium_unreachable_code) fn foo() { + // return; + // return; // Should not produce a diagnostic + // } + // + // fn zoo() { + // return; + // return; // Should produce a warning (default severity) + // } + // + // @diagnostic(info, chromium_unreachable_code) fn bar() { + // return; + // return; // Should produce an info + // } + { + auto* attr = + DiagnosticAttribute(ast::DiagnosticSeverity::kOff, Expr("chromium_unreachable_code")); + Func("foo", {}, ty.void_(), + utils::Vector{ + Return(), + Return(Source{{12, 34}}), + }, + utils::Vector{attr}); + } + { + Func("bar", {}, ty.void_(), + utils::Vector{ + Return(), + Return(Source{{45, 67}}), + }); + } + { + auto* attr = + DiagnosticAttribute(ast::DiagnosticSeverity::kInfo, Expr("chromium_unreachable_code")); + Func("zoo", {}, ty.void_(), + utils::Vector{ + Return(), + Return(Source{{89, 10}}), + }, + utils::Vector{attr}); + } + + EXPECT_TRUE(r()->Resolve()) << r()->error(); + EXPECT_EQ(r()->error(), R"(45:67 warning: code is unreachable +89:10 note: code is unreachable)"); +} + } // namespace } // namespace tint::resolver diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc index b80db263a6..357da57136 100644 --- a/src/tint/resolver/resolver.cc +++ b/src/tint/resolver/resolver.cc @@ -966,6 +966,21 @@ sem::Function* Resolver::Function(const ast::Function* decl) { utils::Hashmap parameter_names; utils::Vector parameters; + validator_.DiagnosticFilters().Push(); + TINT_DEFER(validator_.DiagnosticFilters().Pop()); + for (auto* attr : decl->attributes) { + Mark(attr); + if (auto* dc = attr->As()) { + Mark(dc->control); + if (!DiagnosticControl(dc->control)) { + return nullptr; + } + } + } + if (!validator_.NoDuplicateAttributes(decl->attributes)) { + return nullptr; + } + // Resolve all the parameters for (auto* param : decl->params) { Mark(param); @@ -1032,9 +1047,6 @@ sem::Function* Resolver::Function(const ast::Function* decl) { return_location = value.Get(); } } - if (!validator_.NoDuplicateAttributes(decl->attributes)) { - return nullptr; - } if (auto* str = return_type->As()) { if (!ApplyAddressSpaceUsageToType(type::AddressSpace::kNone, str, decl->source)) { @@ -1096,10 +1108,6 @@ sem::Function* Resolver::Function(const ast::Function* decl) { } } - for (auto* attr : decl->attributes) { - Mark(attr); - } - if (!validator_.NoDuplicateAttributes(decl->return_type_attributes)) { return nullptr; } diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc index 4b769d1c37..4adc76549d 100644 --- a/src/tint/resolver/validator.cc +++ b/src/tint/resolver/validator.cc @@ -1004,7 +1004,8 @@ bool Validator::Function(const sem::Function* func, ast::PipelineStage stage) co attr->source); return false; } - } else if (!attr->IsAnyOf()) { + } else if (!attr->IsAnyOf()) { AddError("attribute is not valid for functions", attr->source); return false; }