mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-20 18:29:23 +00:00
tint/resolver: Handle diagnostic directives
The Resolver parses the diagnostic rule and sets the updated severity in a ScopeStack, which is stored in the Validator. Automatically generate the diagnostic rule enum and its parsing logic using intrinsics.def. Add a "chromium_unreachable_code" diagnostic rule to test this. Bug: tint:1809 Change-Id: Ia94db4321b8019f01d31a84da0fda25dfdf72f5c Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/117566 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
75
src/tint/resolver/diagnostic_control_test.cc
Normal file
75
src/tint/resolver/diagnostic_control_test.cc
Normal file
@@ -0,0 +1,75 @@
|
||||
// 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/resolver/resolver.h"
|
||||
|
||||
#include "src/tint/resolver/resolver_test_helper.h"
|
||||
|
||||
using namespace tint::number_suffixes; // NOLINT
|
||||
|
||||
namespace tint::resolver {
|
||||
namespace {
|
||||
|
||||
using ResolverDiagnosticControlTest = ResolverTest;
|
||||
|
||||
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_DefaultSeverity) {
|
||||
auto stmts = utils::Vector{Return(), Return()};
|
||||
Func("foo", {}, ty.void_(), stmts);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
EXPECT_EQ(r()->error(), R"(warning: code is unreachable)");
|
||||
}
|
||||
|
||||
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_ErrorViaDirective) {
|
||||
DiagnosticDirective(ast::DiagnosticSeverity::kError, Expr("chromium_unreachable_code"));
|
||||
|
||||
auto stmts = utils::Vector{Return(), Return()};
|
||||
Func("foo", {}, ty.void_(), stmts);
|
||||
|
||||
EXPECT_FALSE(r()->Resolve());
|
||||
EXPECT_EQ(r()->error(), R"(error: code is unreachable)");
|
||||
}
|
||||
|
||||
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_WarningViaDirective) {
|
||||
DiagnosticDirective(ast::DiagnosticSeverity::kWarning, Expr("chromium_unreachable_code"));
|
||||
|
||||
auto stmts = utils::Vector{Return(), Return()};
|
||||
Func("foo", {}, ty.void_(), stmts);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
EXPECT_EQ(r()->error(), R"(warning: code is unreachable)");
|
||||
}
|
||||
|
||||
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_InfoViaDirective) {
|
||||
DiagnosticDirective(ast::DiagnosticSeverity::kInfo, Expr("chromium_unreachable_code"));
|
||||
|
||||
auto stmts = utils::Vector{Return(), Return()};
|
||||
Func("foo", {}, ty.void_(), stmts);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
EXPECT_EQ(r()->error(), R"(note: code is unreachable)");
|
||||
}
|
||||
|
||||
TEST_F(ResolverDiagnosticControlTest, UnreachableCode_OffViaDirective) {
|
||||
DiagnosticDirective(ast::DiagnosticSeverity::kOff, Expr("chromium_unreachable_code"));
|
||||
|
||||
auto stmts = utils::Vector{Return(), Return()};
|
||||
Func("foo", {}, ty.void_(), stmts);
|
||||
|
||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||
EXPECT_TRUE(r()->error().empty());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::resolver
|
||||
@@ -151,6 +151,7 @@ bool Resolver::ResolveInternal() {
|
||||
Mark(decl);
|
||||
if (!Switch<bool>(
|
||||
decl, //
|
||||
[&](const ast::DiagnosticControl* dc) { return DiagnosticControl(dc); },
|
||||
[&](const ast::Enable* e) { return Enable(e); },
|
||||
[&](const ast::TypeDecl* td) { return TypeDecl(td); },
|
||||
[&](const ast::Function* func) { return Function(func); },
|
||||
@@ -3050,6 +3051,16 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
||||
return sem;
|
||||
}
|
||||
|
||||
bool Resolver::DiagnosticControl(const ast::DiagnosticControl* control) {
|
||||
Mark(control->rule_name);
|
||||
auto rule_name = builder_->Symbols().NameFor(control->rule_name->symbol);
|
||||
auto rule = ast::ParseDiagnosticRule(rule_name);
|
||||
if (rule != ast::DiagnosticRule::kUndefined) {
|
||||
validator_.DiagnosticFilters().Set(rule, control->severity);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Resolver::Enable(const ast::Enable* enable) {
|
||||
enabled_extensions_.Add(enable->extension);
|
||||
return true;
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "src/tint/resolver/intrinsic_table.h"
|
||||
#include "src/tint/resolver/sem_helper.h"
|
||||
#include "src/tint/resolver/validator.h"
|
||||
#include "src/tint/scope_stack.h"
|
||||
#include "src/tint/sem/binding_point.h"
|
||||
#include "src/tint/sem/block_statement.h"
|
||||
#include "src/tint/sem/function.h"
|
||||
@@ -262,6 +261,10 @@ class Resolver {
|
||||
/// @param ty the ast::Type
|
||||
type::Type* Type(const ast::Type* ty);
|
||||
|
||||
/// @param control the diagnostic control
|
||||
/// @returns true on success, false on failure
|
||||
bool DiagnosticControl(const ast::DiagnosticControl* control);
|
||||
|
||||
/// @param enable the enable declaration
|
||||
/// @returns the resolved extension
|
||||
bool Enable(const ast::Enable* enable);
|
||||
|
||||
@@ -166,7 +166,11 @@ Validator::Validator(
|
||||
sem_(sem),
|
||||
enabled_extensions_(enabled_extensions),
|
||||
atomic_composite_info_(atomic_composite_info),
|
||||
valid_type_storage_layouts_(valid_type_storage_layouts) {}
|
||||
valid_type_storage_layouts_(valid_type_storage_layouts) {
|
||||
// Set default severities for filterable diagnostic rules.
|
||||
diagnostic_filters_.Set(ast::DiagnosticRule::kChromiumUnreachableCode,
|
||||
ast::DiagnosticSeverity::kWarning);
|
||||
}
|
||||
|
||||
Validator::~Validator() = default;
|
||||
|
||||
@@ -182,6 +186,24 @@ void Validator::AddNote(const std::string& msg, const Source& source) const {
|
||||
diagnostics_.add_note(diag::System::Resolver, msg, source);
|
||||
}
|
||||
|
||||
bool Validator::AddDiagnostic(ast::DiagnosticRule rule,
|
||||
const std::string& msg,
|
||||
const Source& source) const {
|
||||
auto severity = diagnostic_filters_.Get(rule);
|
||||
if (severity != ast::DiagnosticSeverity::kOff) {
|
||||
diag::Diagnostic d{};
|
||||
d.severity = ToSeverity(severity);
|
||||
d.system = diag::System::Resolver;
|
||||
d.source = source;
|
||||
d.message = msg;
|
||||
diagnostics_.add(std::move(d));
|
||||
if (severity == ast::DiagnosticSeverity::kError) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://gpuweb.github.io/gpuweb/wgsl/#plain-types-section
|
||||
bool Validator::IsPlain(const type::Type* type) const {
|
||||
return type->is_scalar() ||
|
||||
@@ -1358,9 +1380,10 @@ bool Validator::EvaluationStage(const sem::Expression* expr,
|
||||
bool Validator::Statements(utils::VectorRef<const ast::Statement*> stmts) const {
|
||||
for (auto* stmt : stmts) {
|
||||
if (!sem_.Get(stmt)->IsReachable()) {
|
||||
/// TODO(https://github.com/gpuweb/gpuweb/issues/2378): This may need to
|
||||
/// become an error.
|
||||
AddWarning("code is unreachable", stmt->source);
|
||||
if (!AddDiagnostic(ast::DiagnosticRule::kChromiumUnreachableCode, "code is unreachable",
|
||||
stmt->source)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "src/tint/ast/pipeline_stage.h"
|
||||
#include "src/tint/program_builder.h"
|
||||
#include "src/tint/resolver/sem_helper.h"
|
||||
#include "src/tint/scope_stack.h"
|
||||
#include "src/tint/sem/evaluation_stage.h"
|
||||
#include "src/tint/source.h"
|
||||
#include "src/tint/utils/hash.h"
|
||||
@@ -84,6 +85,9 @@ struct TypeAndAddressSpace {
|
||||
}
|
||||
};
|
||||
|
||||
/// DiagnosticFilterStack is a scoped stack of diagnostic filters.
|
||||
using DiagnosticFilterStack = ScopeStack<ast::DiagnosticRule, ast::DiagnosticSeverity>;
|
||||
|
||||
/// Validation logic for various ast nodes. The validations in general should
|
||||
/// be shallow and depend on the resolver to call on children. The validations
|
||||
/// also assume that sem changes have already been made. The validation checks
|
||||
@@ -118,6 +122,18 @@ class Validator {
|
||||
/// @param source the note source
|
||||
void AddNote(const std::string& msg, const Source& source) const;
|
||||
|
||||
/// Adds the given message to the diagnostics with current severity for the given rule.
|
||||
/// @param rule the diagnostic trigger rule
|
||||
/// @param msg the diagnostic message
|
||||
/// @param source the diagnostic source
|
||||
/// @returns false if the diagnostic is an error for the given trigger rule
|
||||
bool AddDiagnostic(ast::DiagnosticRule rule,
|
||||
const std::string& msg,
|
||||
const Source& source) const;
|
||||
|
||||
/// @returns the diagnostic filter stack
|
||||
DiagnosticFilterStack& DiagnosticFilters() { return diagnostic_filters_; }
|
||||
|
||||
/// @param type the given type
|
||||
/// @returns true if the given type is a plain type
|
||||
bool IsPlain(const type::Type* type) const;
|
||||
@@ -525,6 +541,7 @@ class Validator {
|
||||
SymbolTable& symbols_;
|
||||
diag::List& diagnostics_;
|
||||
SemHelper& sem_;
|
||||
DiagnosticFilterStack diagnostic_filters_;
|
||||
const ast::Extensions& enabled_extensions_;
|
||||
const utils::Hashmap<const type::Type*, const Source*, 8>& atomic_composite_info_;
|
||||
utils::Hashset<TypeAndAddressSpace, 8>& valid_type_storage_layouts_;
|
||||
|
||||
Reference in New Issue
Block a user