From 1e87fe5517ea68606d8a85f16b73293deec149e9 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Tue, 24 Nov 2020 15:15:36 +0000 Subject: [PATCH] reader/wgsl: Abort after raising too many errors Change-Id: I641ee8c2e34e059a02742d06c24f96acecb39cd3 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/33720 Commit-Queue: David Neto Reviewed-by: David Neto Auto-Submit: Ben Clayton --- src/diagnostic/diagnostic.h | 8 ++++--- src/reader/wgsl/parser_impl.cc | 11 +++++++++- src/reader/wgsl/parser_impl.h | 10 +++++++++ src/reader/wgsl/parser_impl_error_msg_test.cc | 21 +++++++++++++++++++ 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/diagnostic/diagnostic.h b/src/diagnostic/diagnostic.h index 21ce75b2e6..6fea75ffc1 100644 --- a/src/diagnostic/diagnostic.h +++ b/src/diagnostic/diagnostic.h @@ -83,13 +83,15 @@ class List { void add(Diagnostic&& diag) { entries_.emplace_back(std::move(diag)); if (diag.severity >= Severity::Error) { - contains_errors_ = true; + error_count_++; } } /// @returns true iff the diagnostic list contains errors diagnostics (or of /// higher severity). - bool contains_errors() const { return contains_errors_; } + bool contains_errors() const { return error_count_ > 0; } + /// @returns the number of error diagnostics (or of higher severity). + size_t error_count() const { return error_count_; } /// @returns the number of entries in the list. size_t count() const { return entries_.size(); } /// @returns the first diagnostic in the list. @@ -99,7 +101,7 @@ class List { private: std::vector entries_; - bool contains_errors_ = false; + size_t error_count_ = 0; }; } // namespace diag diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc index 8e5c0cf672..6aab58963a 100644 --- a/src/reader/wgsl/parser_impl.cc +++ b/src/reader/wgsl/parser_impl.cc @@ -238,8 +238,17 @@ bool ParserImpl::Parse() { // translation_unit // : global_decl* EOF void ParserImpl::translation_unit() { - while (!peek().IsEof() && synchronized_) { + while (synchronized_) { + auto p = peek(); + if (p.IsEof()) { + break; + } expect_global_decl(); + if (diags_.error_count() >= max_errors_) { + add_error(Source{{}, p.source().file}, + "stopping after " + std::to_string(max_errors_) + " errors"); + break; + } } assert(module_.IsValid()); diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h index 9b6a841b85..e533847a06 100644 --- a/src/reader/wgsl/parser_impl.h +++ b/src/reader/wgsl/parser_impl.h @@ -233,6 +233,15 @@ class ParserImpl { /// @returns true if the parse was successful, false otherwise. bool Parse(); + /// set_max_diagnostics sets the maximum number of reported errors before + /// aborting parsing. + /// @param limit the new maximum number of errors + void set_max_errors(size_t limit) { max_errors_ = limit; } + + /// @return the number of maximum number of reported errors before aborting + /// parsing. + size_t get_max_errors() const { return max_errors_; } + /// @returns true if an error was encountered. bool has_error() const { return diags_.contains_errors(); } @@ -779,6 +788,7 @@ class ParserImpl { int silence_errors_ = 0; std::unordered_map registered_constructs_; ast::Module module_; + size_t max_errors_ = 25; }; } // namespace wgsl diff --git a/src/reader/wgsl/parser_impl_error_msg_test.cc b/src/reader/wgsl/parser_impl_error_msg_test.cc index 8a533358b4..d43d60f170 100644 --- a/src/reader/wgsl/parser_impl_error_msg_test.cc +++ b/src/reader/wgsl/parser_impl_error_msg_test.cc @@ -28,6 +28,7 @@ class ParserImplErrorTest : public ParserImplTest {}; std::string source = SOURCE; \ std::string expected = EXPECTED; \ auto p = parser(source); \ + p->set_max_errors(5); \ EXPECT_EQ(false, p->Parse()); \ EXPECT_EQ(true, p->diagnostics().contains_errors()); \ EXPECT_EQ(expected, diag::Formatter().format(p->diagnostics())); \ @@ -1168,6 +1169,26 @@ TEST_F(ParserImplErrorTest, LoopMissingRBrace) { " ^\n"); } +TEST_F(ParserImplErrorTest, MaxErrorsReached) { + EXPECT("x; x; x; x; x; x; x; x;", + "test.wgsl:1:1 error: unexpected token\n" + "x; x; x; x; x; x; x; x;\n" + "^\n\n" + "test.wgsl:1:4 error: unexpected token\n" + "x; x; x; x; x; x; x; x;\n" + " ^\n\n" + "test.wgsl:1:7 error: unexpected token\n" + "x; x; x; x; x; x; x; x;\n" + " ^\n\n" + "test.wgsl:1:10 error: unexpected token\n" + "x; x; x; x; x; x; x; x;\n" + " ^\n\n" + "test.wgsl:1:13 error: unexpected token\n" + "x; x; x; x; x; x; x; x;\n" + " ^\n\n" + "test.wgsl error: stopping after 5 errors"); +} + TEST_F(ParserImplErrorTest, MemberExprMissingIdentifier) { EXPECT("fn f() -> void { x = a.; }", "test.wgsl:1:24 error: expected identifier for member accessor\n"