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>
This commit is contained in:
parent
f3dcbf5c5c
commit
b350500cdb
|
@ -527,6 +527,7 @@ libtint_source_set("libtint_core_all_src") {
|
||||||
"utils/get_or_create.h",
|
"utils/get_or_create.h",
|
||||||
"utils/hash.h",
|
"utils/hash.h",
|
||||||
"utils/math.h",
|
"utils/math.h",
|
||||||
|
"utils/scoped_assignment.h",
|
||||||
"utils/unique_vector.h",
|
"utils/unique_vector.h",
|
||||||
"writer/append_vector.cc",
|
"writer/append_vector.cc",
|
||||||
"writer/append_vector.h",
|
"writer/append_vector.h",
|
||||||
|
|
|
@ -326,6 +326,7 @@ set(TINT_LIB_SRCS
|
||||||
utils/get_or_create.h
|
utils/get_or_create.h
|
||||||
utils/hash.h
|
utils/hash.h
|
||||||
utils/math.h
|
utils/math.h
|
||||||
|
utils/scoped_assignment.h
|
||||||
utils/unique_vector.h
|
utils/unique_vector.h
|
||||||
writer/append_vector.cc
|
writer/append_vector.cc
|
||||||
writer/append_vector.h
|
writer/append_vector.h
|
||||||
|
@ -595,6 +596,7 @@ if(${TINT_BUILD_TESTS})
|
||||||
utils/get_or_create_test.cc
|
utils/get_or_create_test.cc
|
||||||
utils/hash_test.cc
|
utils/hash_test.cc
|
||||||
utils/math_test.cc
|
utils/math_test.cc
|
||||||
|
utils/scoped_assignment_test.cc
|
||||||
utils/tmpfile_${TINT_OS_CC_SUFFIX}.cc
|
utils/tmpfile_${TINT_OS_CC_SUFFIX}.cc
|
||||||
utils/tmpfile_test.cc
|
utils/tmpfile_test.cc
|
||||||
utils/tmpfile.h
|
utils/tmpfile.h
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
#include "src/sem/variable.h"
|
#include "src/sem/variable.h"
|
||||||
#include "src/utils/get_or_create.h"
|
#include "src/utils/get_or_create.h"
|
||||||
#include "src/utils/math.h"
|
#include "src/utils/math.h"
|
||||||
|
#include "src/utils/scoped_assignment.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
namespace resolver {
|
namespace resolver {
|
||||||
|
@ -69,23 +70,6 @@ namespace {
|
||||||
|
|
||||||
using IntrinsicType = tint::sem::IntrinsicType;
|
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) {
|
bool IsValidStorageTextureDimension(ast::TextureDimension dim) {
|
||||||
switch (dim) {
|
switch (dim) {
|
||||||
case ast::TextureDimension::k1d:
|
case ast::TextureDimension::k1d:
|
||||||
|
@ -324,8 +308,7 @@ sem::Type* Resolver::Type(const ast::Type* ty) {
|
||||||
return Type(t->type());
|
return Type(t->type());
|
||||||
}
|
}
|
||||||
if (auto* t = ty->As<ast::AccessControl>()) {
|
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())) {
|
if (auto* el = Type(t->type())) {
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
@ -1182,7 +1165,7 @@ bool Resolver::ValidateEntryPoint(const ast::Function* func,
|
||||||
bool Resolver::Function(ast::Function* func) {
|
bool Resolver::Function(ast::Function* func) {
|
||||||
auto* info = function_infos_.Create<FunctionInfo>(func);
|
auto* info = function_infos_.Create<FunctionInfo>(func);
|
||||||
|
|
||||||
ScopedAssignment<FunctionInfo*> sa(current_function_, info);
|
TINT_SCOPED_ASSIGNMENT(current_function_, info);
|
||||||
|
|
||||||
variable_stack_.push_scope();
|
variable_stack_.push_scope();
|
||||||
for (auto* param : func->params()) {
|
for (auto* param : func->params()) {
|
||||||
|
@ -1271,8 +1254,7 @@ bool Resolver::Function(ast::Function* func) {
|
||||||
sem::BlockStatement* sem_block = builder_->create<sem::BlockStatement>(
|
sem::BlockStatement* sem_block = builder_->create<sem::BlockStatement>(
|
||||||
func->body(), nullptr, sem::BlockStatement::Type::kGeneric);
|
func->body(), nullptr, sem::BlockStatement::Type::kGeneric);
|
||||||
builder_->Sem().Add(func->body(), sem_block);
|
builder_->Sem().Add(func->body(), sem_block);
|
||||||
ScopedAssignment<sem::Statement*> sa_function_body(current_statement_,
|
TINT_SCOPED_ASSIGNMENT(current_statement_, sem_block);
|
||||||
sem_block);
|
|
||||||
if (!BlockScope(func->body(),
|
if (!BlockScope(func->body(),
|
||||||
[&] { return Statements(func->body()->list()); })) {
|
[&] { return Statements(func->body()->list()); })) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1404,7 +1386,7 @@ bool Resolver::Statement(ast::Statement* stmt) {
|
||||||
}
|
}
|
||||||
builder_->Sem().Add(stmt, sem_statement);
|
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>()) {
|
if (stmt->Is<ast::ElseStatement>()) {
|
||||||
TINT_ICE(diagnostics_)
|
TINT_ICE(diagnostics_)
|
||||||
|
@ -1489,7 +1471,7 @@ bool Resolver::CaseStatement(ast::CaseStatement* stmt) {
|
||||||
sem::BlockStatement* sem_block = builder_->create<sem::BlockStatement>(
|
sem::BlockStatement* sem_block = builder_->create<sem::BlockStatement>(
|
||||||
stmt->body(), current_statement_, sem::BlockStatement::Type::kSwitchCase);
|
stmt->body(), current_statement_, sem::BlockStatement::Type::kSwitchCase);
|
||||||
builder_->Sem().Add(stmt->body(), sem_block);
|
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 BlockScope(stmt->body(),
|
||||||
[&] { return Statements(stmt->body()->list()); });
|
[&] { return Statements(stmt->body()->list()); });
|
||||||
}
|
}
|
||||||
|
@ -1513,7 +1495,7 @@ bool Resolver::IfStatement(ast::IfStatement* stmt) {
|
||||||
sem::BlockStatement* sem_block = builder_->create<sem::BlockStatement>(
|
sem::BlockStatement* sem_block = builder_->create<sem::BlockStatement>(
|
||||||
stmt->body(), current_statement_, sem::BlockStatement::Type::kGeneric);
|
stmt->body(), current_statement_, sem::BlockStatement::Type::kGeneric);
|
||||||
builder_->Sem().Add(stmt->body(), sem_block);
|
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(),
|
if (!BlockScope(stmt->body(),
|
||||||
[&] { return Statements(stmt->body()->list()); })) {
|
[&] { return Statements(stmt->body()->list()); })) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1525,7 +1507,7 @@ bool Resolver::IfStatement(ast::IfStatement* stmt) {
|
||||||
auto* sem_else_stmt =
|
auto* sem_else_stmt =
|
||||||
builder_->create<sem::Statement>(else_stmt, current_statement_);
|
builder_->create<sem::Statement>(else_stmt, current_statement_);
|
||||||
builder_->Sem().Add(else_stmt, sem_else_stmt);
|
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()) {
|
if (auto* cond = else_stmt->condition()) {
|
||||||
Mark(cond);
|
Mark(cond);
|
||||||
if (!Expression(cond)) {
|
if (!Expression(cond)) {
|
||||||
|
@ -1547,8 +1529,7 @@ bool Resolver::IfStatement(ast::IfStatement* stmt) {
|
||||||
else_stmt->body(), current_statement_,
|
else_stmt->body(), current_statement_,
|
||||||
sem::BlockStatement::Type::kGeneric);
|
sem::BlockStatement::Type::kGeneric);
|
||||||
builder_->Sem().Add(else_stmt->body(), sem_block);
|
builder_->Sem().Add(else_stmt->body(), sem_block);
|
||||||
ScopedAssignment<sem::Statement*> sa_else_body(current_statement_,
|
TINT_SCOPED_ASSIGNMENT(current_statement_, sem_block);
|
||||||
sem_block);
|
|
||||||
if (!BlockScope(else_stmt->body(),
|
if (!BlockScope(else_stmt->body(),
|
||||||
[&] { return Statements(else_stmt->body()->list()); })) {
|
[&] { return Statements(else_stmt->body()->list()); })) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1568,7 +1549,7 @@ bool Resolver::LoopStatement(ast::LoopStatement* stmt) {
|
||||||
auto* sem_block_body = builder_->create<sem::BlockStatement>(
|
auto* sem_block_body = builder_->create<sem::BlockStatement>(
|
||||||
stmt->body(), current_statement_, sem::BlockStatement::Type::kLoop);
|
stmt->body(), current_statement_, sem::BlockStatement::Type::kLoop);
|
||||||
builder_->Sem().Add(stmt->body(), sem_block_body);
|
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(), [&] {
|
return BlockScope(stmt->body(), [&] {
|
||||||
if (!Statements(stmt->body()->list())) {
|
if (!Statements(stmt->body()->list())) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -1581,8 +1562,7 @@ bool Resolver::LoopStatement(ast::LoopStatement* stmt) {
|
||||||
stmt->continuing(), current_statement_,
|
stmt->continuing(), current_statement_,
|
||||||
sem::BlockStatement::Type::kLoopContinuing);
|
sem::BlockStatement::Type::kLoopContinuing);
|
||||||
builder_->Sem().Add(stmt->continuing(), sem_block_continuing);
|
builder_->Sem().Add(stmt->continuing(), sem_block_continuing);
|
||||||
ScopedAssignment<sem::Statement*> continuing_sa(current_statement_,
|
TINT_SCOPED_ASSIGNMENT(current_statement_, sem_block_continuing);
|
||||||
sem_block_continuing);
|
|
||||||
if (!BlockScope(stmt->continuing(),
|
if (!BlockScope(stmt->continuing(),
|
||||||
[&] { return Statements(stmt->continuing()->list()); })) {
|
[&] { return Statements(stmt->continuing()->list()); })) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -3063,7 +3043,7 @@ bool Resolver::Switch(ast::SwitchStatement* s) {
|
||||||
sem::Statement* sem_statement =
|
sem::Statement* sem_statement =
|
||||||
builder_->create<sem::Statement>(case_stmt, current_statement_);
|
builder_->create<sem::Statement>(case_stmt, current_statement_);
|
||||||
builder_->Sem().Add(case_stmt, sem_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)) {
|
if (!CaseStatement(case_stmt)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -3209,8 +3189,8 @@ bool Resolver::BlockScope(const ast::BlockStatement* block, F&& callback) {
|
||||||
"which semantic information is not available";
|
"which semantic information is not available";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ScopedAssignment<sem::BlockStatement*> sa(
|
TINT_SCOPED_ASSIGNMENT(current_block_,
|
||||||
current_block_, const_cast<sem::BlockStatement*>(sem_block));
|
const_cast<sem::BlockStatement*>(sem_block));
|
||||||
variable_stack_.push_scope();
|
variable_stack_.push_scope();
|
||||||
bool result = callback();
|
bool result = callback();
|
||||||
variable_stack_.pop_scope();
|
variable_stack_.pop_scope();
|
||||||
|
|
|
@ -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_
|
|
@ -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
|
|
@ -309,6 +309,7 @@ tint_unittests_source_set("tint_unittests_core_src") {
|
||||||
"../src/utils/get_or_create_test.cc",
|
"../src/utils/get_or_create_test.cc",
|
||||||
"../src/utils/hash_test.cc",
|
"../src/utils/hash_test.cc",
|
||||||
"../src/utils/math_test.cc",
|
"../src/utils/math_test.cc",
|
||||||
|
"../src/utils/scoped_assignment_test.cc",
|
||||||
"../src/utils/tmpfile_test.cc",
|
"../src/utils/tmpfile_test.cc",
|
||||||
"../src/utils/unique_vector_test.cc",
|
"../src/utils/unique_vector_test.cc",
|
||||||
"../src/writer/append_vector_test.cc",
|
"../src/writer/append_vector_test.cc",
|
||||||
|
|
Loading…
Reference in New Issue