validation: Fix continue-bypasses-decl check

An expression that is inside an if-statement condition does not have a
"current block", which is what we were using to see if the usage was
inside a continuing block. Use the current statement to find the
containing block instead.

Fixed: chromium:1251664
Change-Id: Icc808ca1cf6a1b51757da8303901fa5ecb693e83
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/65520
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
James Price 2021-09-30 17:29:50 +00:00
parent 1ca6fbad8f
commit 7166f6ba93
2 changed files with 32 additions and 2 deletions

View File

@ -2971,12 +2971,12 @@ bool Resolver::Identifier(ast::IdentifierExpression* expr) {
var->users.push_back(expr); var->users.push_back(expr);
set_referenced_from_function_if_needed(var, true); set_referenced_from_function_if_needed(var, true);
if (current_block_) { if (current_statement_) {
// If identifier is part of a loop continuing block, make sure it // If identifier is part of a loop continuing block, make sure it
// doesn't refer to a variable that is bypassed by a continue statement // doesn't refer to a variable that is bypassed by a continue statement
// in the loop's body block. // in the loop's body block.
if (auto* continuing_block = if (auto* continuing_block =
current_block_ current_statement_
->FindFirstParent<sem::LoopContinuingBlockStatement>()) { ->FindFirstParent<sem::LoopContinuingBlockStatement>()) {
auto* loop_block = auto* loop_block =
continuing_block->FindFirstParent<sem::LoopBlockStatement>(); continuing_block->FindFirstParent<sem::LoopBlockStatement>();

View File

@ -615,6 +615,36 @@ TEST_F(
"continuing block"); "continuing block");
} }
TEST_F(ResolverValidationTest,
Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageOutsideBlock) {
// loop {
// if (true) {
// continue; // bypasses z decl (if we reach here)
// }
// var z : i32;
// continuing {
// // Must fail even if z is used in an expression that isn't
// // directly contained inside a block.
// if (z < 2) {
// }
// }
// }
auto error_loc = Source{Source::Location{12, 34}};
auto* body = Block(If(Expr(true), Block(create<ast::ContinueStatement>())),
Decl(Var("z", ty.i32(), ast::StorageClass::kNone)));
auto* compare = create<ast::BinaryExpression>(ast::BinaryOp::kLessThan,
Expr(error_loc, "z"), Expr(2));
auto* continuing = Block(If(compare, Block()));
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_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuingLoop) { Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuingLoop) {
// loop { // loop {