validation: no statically dead statement

Bug: tint:65
Change-Id: Iefc103afe77bc4423ec981eeb3bf066d239e99de
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/54981
Auto-Submit: Sarah Mashayekhi <sarahmashay@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
Sarah 2021-06-21 17:53:56 +00:00 committed by Tint LUCI CQ
parent 4d69751572
commit c3f8fdfe69
5 changed files with 75 additions and 31 deletions

View File

@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "src/ast/break_statement.h"
#include "src/ast/continue_statement.h"
#include "src/ast/fallthrough_statement.h" #include "src/ast/fallthrough_statement.h"
#include "src/ast/switch_statement.h" #include "src/ast/switch_statement.h"
#include "src/resolver/resolver_test_helper.h" #include "src/resolver/resolver_test_helper.h"
@ -108,6 +110,35 @@ TEST_F(ResolverControlBlockValidationTest, SwitchWithTwoDefault_Fail) {
"clause"); "clause");
} }
TEST_F(ResolverControlBlockValidationTest, UnreachableCode_continue) {
// loop {
// continue;
// var z : i32;
// }
WrapInFunction(Loop(Block(
create<ast::ContinueStatement>(),
Decl(Source{{12, 34}}, Var("z", ty.i32(), ast::StorageClass::kNone)))));
EXPECT_FALSE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(), "12:34 error: code is unreachable");
}
TEST_F(ResolverControlBlockValidationTest, UnreachableCode_break) {
// switch (a) {
// case 1: { break; var a : u32 = 2;}
// default: {}
// }
auto* decl = Decl(Source{{12, 34}},
Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2)));
WrapInFunction(Loop(Block(Switch(
Expr(1), Case(Literal(1), Block(create<ast::BreakStatement>(), decl)),
DefaultCase()))));
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: code is unreachable");
}
TEST_F(ResolverControlBlockValidationTest, TEST_F(ResolverControlBlockValidationTest,
SwitchConditionTypeMustMatchSelectorType2_Fail) { SwitchConditionTypeMustMatchSelectorType2_Fail) {
// var a : u32 = 2; // var a : u32 = 2;

View File

@ -133,6 +133,24 @@ TEST_F(ResolverFunctionValidationTest,
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
} }
TEST_F(ResolverFunctionValidationTest, UnreachableCode_return) {
// fn func() -> {
// return;
// var a: i32 = 2;
//}
auto* decl = Decl(Source{{12, 34}},
Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2)));
Func("func", ast::VariableList{}, ty.void_(),
ast::StatementList{
Return(),
decl,
},
ast::DecorationList{});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "12:34 error: code is unreachable");
}
TEST_F(ResolverFunctionValidationTest, FunctionEndWithoutReturnStatement_Fail) { TEST_F(ResolverFunctionValidationTest, FunctionEndWithoutReturnStatement_Fail) {
// fn func -> int { var a:i32 = 2; } // fn func -> int { var a:i32 = 2; }

View File

@ -1502,6 +1502,25 @@ bool Resolver::Statements(const ast::StatementList& stmts) {
return false; return false;
} }
} }
if (!ValidateStatements(stmts)) {
return false;
}
return true;
}
bool Resolver::ValidateStatements(const ast::StatementList& stmts) {
auto next_stmt = stmts.begin();
for (auto* stmt : stmts) {
next_stmt++;
if (stmt->IsAnyOf<ast::ReturnStatement, ast::BreakStatement,
ast::ContinueStatement>()) {
if (stmt != stmts.back()) {
diagnostics_.add_error("code is unreachable", (*next_stmt)->source());
return false;
}
}
}
return true; return true;
} }

View File

@ -277,6 +277,7 @@ class Resolver {
const sem::Matrix* matrix_type); const sem::Matrix* matrix_type);
bool ValidateParameter(const VariableInfo* info); bool ValidateParameter(const VariableInfo* info);
bool ValidateReturn(const ast::ReturnStatement* ret); bool ValidateReturn(const ast::ReturnStatement* ret);
bool ValidateStatements(const ast::StatementList& stmts);
bool ValidateStorageTexture(const ast::StorageTexture* t); bool ValidateStorageTexture(const ast::StorageTexture* t);
bool ValidateStructure(const sem::Struct* str); bool ValidateStructure(const sem::Struct* str);
bool ValidateSwitch(const ast::SwitchStatement* s); bool ValidateSwitch(const ast::SwitchStatement* s);

View File

@ -403,30 +403,6 @@ TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadIndex) {
EXPECT_EQ(r()->error(), "3:3 error: invalid vector swizzle member"); EXPECT_EQ(r()->error(), "3:3 error: invalid vector swizzle member");
} }
TEST_F(ResolverValidationTest,
Stmt_Loop_ContinueInLoopBodyBeforeDecl_UsageInContinuing) {
// loop {
// continue; // Bypasses z decl
// var z : i32;
//
// continuing {
// z = 2;
// }
// }
auto error_loc = Source{Source::Location{12, 34}};
auto* body = Block(create<ast::ContinueStatement>(),
Decl(Var("z", ty.i32(), ast::StorageClass::kNone)));
auto* continuing = Block(Assign(Expr(error_loc, "z"), 2));
auto* loop_stmt = Loop(body, continuing);
WrapInFunction(loop_stmt);
EXPECT_FALSE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(),
"12:34 error: continue statement bypasses declaration of 'z' in "
"continuing block");
}
TEST_F(ResolverValidationTest, TEST_F(ResolverValidationTest,
Stmt_Loop_ContinueInLoopBodyBeforeDeclAndAfterDecl_UsageInContinuing) { Stmt_Loop_ContinueInLoopBodyBeforeDeclAndAfterDecl_UsageInContinuing) {
// loop { // loop {
@ -440,17 +416,16 @@ TEST_F(ResolverValidationTest,
// } // }
auto error_loc = Source{Source::Location{12, 34}}; auto error_loc = Source{Source::Location{12, 34}};
auto* body = Block(create<ast::ContinueStatement>(), auto* body =
Decl(Var("z", ty.i32(), ast::StorageClass::kNone)), Block(create<ast::ContinueStatement>(),
create<ast::ContinueStatement>()); Decl(error_loc, Var("z", ty.i32(), ast::StorageClass::kNone)),
auto* continuing = Block(Assign(Expr(error_loc, "z"), 2)); create<ast::ContinueStatement>());
auto* continuing = Block(Assign(Expr("z"), 2));
auto* loop_stmt = Loop(body, continuing); auto* loop_stmt = Loop(body, continuing);
WrapInFunction(loop_stmt); WrapInFunction(loop_stmt);
EXPECT_FALSE(r()->Resolve()) << r()->error(); EXPECT_FALSE(r()->Resolve()) << r()->error();
EXPECT_EQ(r()->error(), EXPECT_EQ(r()->error(), "12:34 error: code is unreachable");
"12:34 error: continue statement bypasses declaration of 'z' in "
"continuing block");
} }
TEST_F(ResolverValidationTest, TEST_F(ResolverValidationTest,