utils: Add TINT_SCOPED_ASSIGNMENT() A helper class and macro used to simplify scope-based assignment of variables. Change-Id: I02b3a05240a2c4628f813de931c40d8fba3cb07b Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/51480 Auto-Submit: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Antonio Maiorano <amaiorano@google.com> Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/BUILD.gn b/src/BUILD.gn index 8c0a9fe..4d415b8 100644 --- a/src/BUILD.gn +++ b/src/BUILD.gn
@@ -527,6 +527,7 @@ "utils/get_or_create.h", "utils/hash.h", "utils/math.h", + "utils/scoped_assignment.h", "utils/unique_vector.h", "writer/append_vector.cc", "writer/append_vector.h",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9927bdd..2b4254d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt
@@ -326,6 +326,7 @@ utils/get_or_create.h utils/hash.h utils/math.h + utils/scoped_assignment.h utils/unique_vector.h writer/append_vector.cc writer/append_vector.h @@ -595,6 +596,7 @@ utils/get_or_create_test.cc utils/hash_test.cc utils/math_test.cc + utils/scoped_assignment_test.cc utils/tmpfile_${TINT_OS_CC_SUFFIX}.cc utils/tmpfile_test.cc utils/tmpfile.h
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc index 227331b..2450f14 100644 --- a/src/resolver/resolver.cc +++ b/src/resolver/resolver.cc
@@ -62,6 +62,7 @@ #include "src/sem/variable.h" #include "src/utils/get_or_create.h" #include "src/utils/math.h" +#include "src/utils/scoped_assignment.h" namespace tint { namespace resolver { @@ -69,23 +70,6 @@ using IntrinsicType = tint::sem::IntrinsicType; -// Helper class that temporarily assigns a value to a reference for the scope of -// the object. Once the ScopedAssignment is destructed, the original value is -// restored. -template <typename T> -class ScopedAssignment { - public: - ScopedAssignment(T& ref, T val) : ref_(ref) { - old_value_ = ref; - ref = val; - } - ~ScopedAssignment() { ref_ = old_value_; } - - private: - T& ref_; - T old_value_; -}; - bool IsValidStorageTextureDimension(ast::TextureDimension dim) { switch (dim) { case ast::TextureDimension::k1d: @@ -324,8 +308,7 @@ return Type(t->type()); } if (auto* t = ty->As<ast::AccessControl>()) { - ScopedAssignment<const ast::AccessControl*> sa(curent_access_control_, t); - + TINT_SCOPED_ASSIGNMENT(curent_access_control_, t); if (auto* el = Type(t->type())) { return el; } @@ -1182,7 +1165,7 @@ bool Resolver::Function(ast::Function* func) { auto* info = function_infos_.Create<FunctionInfo>(func); - ScopedAssignment<FunctionInfo*> sa(current_function_, info); + TINT_SCOPED_ASSIGNMENT(current_function_, info); variable_stack_.push_scope(); for (auto* param : func->params()) { @@ -1271,8 +1254,7 @@ sem::BlockStatement* sem_block = builder_->create<sem::BlockStatement>( func->body(), nullptr, sem::BlockStatement::Type::kGeneric); builder_->Sem().Add(func->body(), sem_block); - ScopedAssignment<sem::Statement*> sa_function_body(current_statement_, - sem_block); + TINT_SCOPED_ASSIGNMENT(current_statement_, sem_block); if (!BlockScope(func->body(), [&] { return Statements(func->body()->list()); })) { return false; @@ -1404,7 +1386,7 @@ } builder_->Sem().Add(stmt, sem_statement); - ScopedAssignment<sem::Statement*> sa(current_statement_, sem_statement); + TINT_SCOPED_ASSIGNMENT(current_statement_, sem_statement); if (stmt->Is<ast::ElseStatement>()) { TINT_ICE(diagnostics_) @@ -1489,7 +1471,7 @@ sem::BlockStatement* sem_block = builder_->create<sem::BlockStatement>( stmt->body(), current_statement_, sem::BlockStatement::Type::kSwitchCase); builder_->Sem().Add(stmt->body(), sem_block); - ScopedAssignment<sem::Statement*> sa(current_statement_, sem_block); + TINT_SCOPED_ASSIGNMENT(current_statement_, sem_block); return BlockScope(stmt->body(), [&] { return Statements(stmt->body()->list()); }); } @@ -1513,7 +1495,7 @@ sem::BlockStatement* sem_block = builder_->create<sem::BlockStatement>( stmt->body(), current_statement_, sem::BlockStatement::Type::kGeneric); builder_->Sem().Add(stmt->body(), sem_block); - ScopedAssignment<sem::Statement*> sa(current_statement_, sem_block); + TINT_SCOPED_ASSIGNMENT(current_statement_, sem_block); if (!BlockScope(stmt->body(), [&] { return Statements(stmt->body()->list()); })) { return false; @@ -1525,7 +1507,7 @@ auto* sem_else_stmt = builder_->create<sem::Statement>(else_stmt, current_statement_); builder_->Sem().Add(else_stmt, sem_else_stmt); - ScopedAssignment<sem::Statement*> sa(current_statement_, sem_else_stmt); + TINT_SCOPED_ASSIGNMENT(current_statement_, sem_else_stmt); if (auto* cond = else_stmt->condition()) { Mark(cond); if (!Expression(cond)) { @@ -1547,8 +1529,7 @@ else_stmt->body(), current_statement_, sem::BlockStatement::Type::kGeneric); builder_->Sem().Add(else_stmt->body(), sem_block); - ScopedAssignment<sem::Statement*> sa_else_body(current_statement_, - sem_block); + TINT_SCOPED_ASSIGNMENT(current_statement_, sem_block); if (!BlockScope(else_stmt->body(), [&] { return Statements(else_stmt->body()->list()); })) { return false; @@ -1568,7 +1549,7 @@ auto* sem_block_body = builder_->create<sem::BlockStatement>( stmt->body(), current_statement_, sem::BlockStatement::Type::kLoop); builder_->Sem().Add(stmt->body(), sem_block_body); - ScopedAssignment<sem::Statement*> body_sa(current_statement_, sem_block_body); + TINT_SCOPED_ASSIGNMENT(current_statement_, sem_block_body); return BlockScope(stmt->body(), [&] { if (!Statements(stmt->body()->list())) { return false; @@ -1581,8 +1562,7 @@ stmt->continuing(), current_statement_, sem::BlockStatement::Type::kLoopContinuing); builder_->Sem().Add(stmt->continuing(), sem_block_continuing); - ScopedAssignment<sem::Statement*> continuing_sa(current_statement_, - sem_block_continuing); + TINT_SCOPED_ASSIGNMENT(current_statement_, sem_block_continuing); if (!BlockScope(stmt->continuing(), [&] { return Statements(stmt->continuing()->list()); })) { return false; @@ -3063,7 +3043,7 @@ sem::Statement* sem_statement = builder_->create<sem::Statement>(case_stmt, current_statement_); builder_->Sem().Add(case_stmt, sem_statement); - ScopedAssignment<sem::Statement*> sa(current_statement_, sem_statement); + TINT_SCOPED_ASSIGNMENT(current_statement_, sem_statement); if (!CaseStatement(case_stmt)) { return false; } @@ -3209,8 +3189,8 @@ "which semantic information is not available"; return false; } - ScopedAssignment<sem::BlockStatement*> sa( - current_block_, const_cast<sem::BlockStatement*>(sem_block)); + TINT_SCOPED_ASSIGNMENT(current_block_, + const_cast<sem::BlockStatement*>(sem_block)); variable_stack_.push_scope(); bool result = callback(); variable_stack_.pop_scope();
diff --git a/src/utils/scoped_assignment.h b/src/utils/scoped_assignment.h new file mode 100644 index 0000000..58e7cdd --- /dev/null +++ b/src/utils/scoped_assignment.h
@@ -0,0 +1,64 @@ +// Copyright 2021 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. + +#ifndef SRC_UTILS_SCOPED_ASSIGNMENT_H_ +#define SRC_UTILS_SCOPED_ASSIGNMENT_H_ + +#include <type_traits> + +namespace tint { +namespace utils { + +/// Helper class that temporarily assigns a value to a variable for the lifetime +/// of the ScopedAssignment object. Once the ScopedAssignment is destructed, the +/// original value is restored. +template <typename T> +class ScopedAssignment { + public: + /// Constructor + /// @param var the variable to temporarily assign a new value to + /// @param val the value to assign to `ref` for the lifetime of this + /// ScopedAssignment. + ScopedAssignment(T& var, T val) : ref_(var) { + old_value_ = var; + var = val; + } + + /// Destructor + /// Restores the original value of the variable. + ~ScopedAssignment() { ref_ = old_value_; } + + private: + ScopedAssignment(const ScopedAssignment&) = delete; + ScopedAssignment& operator=(const ScopedAssignment&) = delete; + + T& ref_; + T old_value_; +}; + +} // namespace utils +} // namespace tint + +#define TINT_CONCAT_2(a, b) a##b +#define TINT_CONCAT(a, b) TINT_CONCAT_2(a, b) + +/// TINT_SCOPED_ASSIGNMENT(var, val) assigns `val` to `var`, and automatically +/// restores the original value of `var` when exiting the current lexical scope. +#define TINT_SCOPED_ASSIGNMENT(var, val) \ + ::tint::utils::ScopedAssignment<std::remove_reference_t<decltype(var)>> \ + TINT_CONCAT(tint_scoped_assignment_, __COUNTER__) { \ + var, val \ + } + +#endif // SRC_UTILS_SCOPED_ASSIGNMENT_H_
diff --git a/src/utils/scoped_assignment_test.cc b/src/utils/scoped_assignment_test.cc new file mode 100644 index 0000000..b75bec9 --- /dev/null +++ b/src/utils/scoped_assignment_test.cc
@@ -0,0 +1,47 @@ +// Copyright 2021 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/utils/scoped_assignment.h" + +#include "gtest/gtest.h" + +namespace tint { +namespace utils { +namespace { + +TEST(ScopedAssignmentTest, Scopes) { + int i = 0; + EXPECT_EQ(i, 0); + { + EXPECT_EQ(i, 0); + TINT_SCOPED_ASSIGNMENT(i, 1); + EXPECT_EQ(i, 1); + { + EXPECT_EQ(i, 1); + TINT_SCOPED_ASSIGNMENT(i, 2); + EXPECT_EQ(i, 2); + } + { + EXPECT_EQ(i, 1); + TINT_SCOPED_ASSIGNMENT(i, 3); + EXPECT_EQ(i, 3); + } + EXPECT_EQ(i, 1); + } + EXPECT_EQ(i, 0); +} + +} // namespace +} // namespace utils +} // namespace tint
diff --git a/test/BUILD.gn b/test/BUILD.gn index 867e8d7..88723f7 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn
@@ -309,6 +309,7 @@ "../src/utils/get_or_create_test.cc", "../src/utils/hash_test.cc", "../src/utils/math_test.cc", + "../src/utils/scoped_assignment_test.cc", "../src/utils/tmpfile_test.cc", "../src/utils/unique_vector_test.cc", "../src/writer/append_vector_test.cc",