Add semantic::VariableUser Derives from semantic::Expression. Maps to ast::IdentifierExpressions that resolve to a variable. Breaks pure-immutability of semantic::Variable, as we have discussed in the past. Change-Id: I362d4d1ed61291282a60626b84fb15566655fb14 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/46627 Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc index 87322b6..7011e46 100644 --- a/src/resolver/resolver.cc +++ b/src/resolver/resolver.cc
@@ -1631,20 +1631,30 @@ for (auto it : variable_to_info_) { auto* var = it.first; auto* info = it.second; - std::vector<const semantic::Expression*> users; + auto* sem_var = builder_->create<semantic::Variable>(var, info->type, + info->storage_class); + std::vector<const semantic::VariableUser*> users; for (auto* user : info->users) { // Create semantic node for the identifier expression if necessary auto* sem_expr = sem.Get(user); if (sem_expr == nullptr) { auto* type = expr_info_.at(user).type; auto* stmt = expr_info_.at(user).statement; - sem_expr = builder_->create<semantic::Expression>(user, type, stmt); - sem.Add(user, sem_expr); + auto* sem_user = + builder_->create<semantic::VariableUser>(user, type, stmt, sem_var); + sem_var->AddUser(sem_user); + sem.Add(user, sem_user); + } else { + auto* sem_user = sem_expr->As<semantic::VariableUser>(); + if (!sem_user) { + TINT_ICE(builder_->Diagnostics()) + << "expected semantic::VariableUser, got " + << sem_expr->TypeInfo().name; + } + sem_var->AddUser(sem_user); } - users.push_back(sem_expr); } - sem.Add(var, builder_->create<semantic::Variable>( - var, info->type, info->storage_class, std::move(users))); + sem.Add(var, sem_var); } auto remap_vars = [&sem](const std::vector<VariableInfo*>& in) {
diff --git a/src/resolver/resolver.h b/src/resolver/resolver.h index e3d7edf..76c99c3 100644 --- a/src/resolver/resolver.h +++ b/src/resolver/resolver.h
@@ -135,7 +135,7 @@ StructInfo(); ~StructInfo(); - std::vector<semantic::StructMember*> members; + std::vector<const semantic::StructMember*> members; uint32_t align = 0; uint32_t size = 0; uint32_t size_no_padding = 0;
diff --git a/src/resolver/resolver_test.cc b/src/resolver/resolver_test.cc index fd2c151..8b02b93 100644 --- a/src/resolver/resolver_test.cc +++ b/src/resolver/resolver_test.cc
@@ -338,6 +338,10 @@ EXPECT_EQ(StmtOf(bar_f32_init), bar_f32_decl); EXPECT_TRUE(CheckVarUsers(foo_i32, {bar_i32->constructor()})); EXPECT_TRUE(CheckVarUsers(foo_f32, {bar_f32->constructor()})); + ASSERT_NE(VarOf(bar_i32->constructor()), nullptr); + EXPECT_EQ(VarOf(bar_i32->constructor())->Declaration(), foo_i32); + ASSERT_NE(VarOf(bar_f32->constructor()), nullptr); + EXPECT_EQ(VarOf(bar_f32->constructor())->Declaration(), foo_f32); } TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScopeAfterFunctionScope) { @@ -383,6 +387,8 @@ EXPECT_EQ(StmtOf(fn_f32_init), fn_f32_decl); EXPECT_TRUE(CheckVarUsers(fn_i32, {})); EXPECT_TRUE(CheckVarUsers(mod_f32, {fn_f32->constructor()})); + ASSERT_NE(VarOf(fn_f32->constructor()), nullptr); + EXPECT_EQ(VarOf(fn_f32->constructor())->Declaration(), mod_f32); } TEST_F(ResolverTest, Expr_ArrayAccessor_Array) { @@ -612,6 +618,8 @@ EXPECT_TRUE(TypeOf(ident)->Is<type::Pointer>()); EXPECT_TRUE(TypeOf(ident)->As<type::Pointer>()->type()->Is<type::F32>()); EXPECT_TRUE(CheckVarUsers(my_var, {ident})); + ASSERT_NE(VarOf(ident), nullptr); + EXPECT_EQ(VarOf(ident)->Declaration(), my_var); } TEST_F(ResolverTest, Expr_Identifier_GlobalConstant) { @@ -625,6 +633,8 @@ ASSERT_NE(TypeOf(ident), nullptr); EXPECT_TRUE(TypeOf(ident)->Is<type::F32>()); EXPECT_TRUE(CheckVarUsers(my_var, {ident})); + ASSERT_NE(VarOf(ident), nullptr); + EXPECT_EQ(VarOf(ident)->Declaration(), my_var); } TEST_F(ResolverTest, Expr_Identifier_FunctionVariable_Const) { @@ -645,6 +655,8 @@ EXPECT_TRUE(TypeOf(my_var_a)->Is<type::F32>()); EXPECT_EQ(StmtOf(my_var_a), decl); EXPECT_TRUE(CheckVarUsers(var, {my_var_a})); + ASSERT_NE(VarOf(my_var_a), nullptr); + EXPECT_EQ(VarOf(my_var_a)->Declaration(), var); } TEST_F(ResolverTest, Expr_Identifier_FunctionVariable) { @@ -672,6 +684,10 @@ EXPECT_TRUE(TypeOf(my_var_b)->As<type::Pointer>()->type()->Is<type::F32>()); EXPECT_EQ(StmtOf(my_var_b), assign); EXPECT_TRUE(CheckVarUsers(var, {my_var_a, my_var_b})); + ASSERT_NE(VarOf(my_var_a), nullptr); + EXPECT_EQ(VarOf(my_var_a)->Declaration(), var); + ASSERT_NE(VarOf(my_var_b), nullptr); + EXPECT_EQ(VarOf(my_var_b)->Declaration(), var); } TEST_F(ResolverTest, Expr_Identifier_Function_Ptr) {
diff --git a/src/resolver/resolver_test_helper.h b/src/resolver/resolver_test_helper.h index 79afa79..cbcb2a6 100644 --- a/src/resolver/resolver_test_helper.h +++ b/src/resolver/resolver_test_helper.h
@@ -67,6 +67,17 @@ return sem_stmt ? sem_stmt->Block() : nullptr; } + /// Returns the semantic variable for the given identifier expression. + /// @param expr the identifier expression + /// @return the resolved semantic::Variable of the identifier, or nullptr if + /// the expression did not resolve to a variable. + const semantic::Variable* VarOf(ast::Expression* expr) { + auto* sem_ident = Sem().Get(expr); + auto* var_user = + sem_ident ? sem_ident->As<semantic::VariableUser>() : nullptr; + return var_user ? var_user->Variable() : nullptr; + } + /// Checks that all the users of the given variable are as expected /// @param var the variable to check /// @param expected_users the expected users of the variable
diff --git a/src/semantic/expression.h b/src/semantic/expression.h index 6b9b4b1..e361658 100644 --- a/src/semantic/expression.h +++ b/src/semantic/expression.h
@@ -37,9 +37,9 @@ /// @param declaration the AST node /// @param type the resolved type of the expression /// @param statement the statement that owns this expression - explicit Expression(ast::Expression* declaration, - type::Type* type, - Statement* statement); + Expression(ast::Expression* declaration, + type::Type* type, + Statement* statement); /// @return the resolved type of the expression type::Type* Type() const { return type_; }
diff --git a/src/semantic/sem_variable.cc b/src/semantic/sem_variable.cc index 03dc034..13b3820 100644 --- a/src/semantic/sem_variable.cc +++ b/src/semantic/sem_variable.cc
@@ -14,21 +14,26 @@ #include "src/semantic/variable.h" +#include "src/ast/identifier_expression.h" + TINT_INSTANTIATE_TYPEINFO(tint::semantic::Variable); +TINT_INSTANTIATE_TYPEINFO(tint::semantic::VariableUser); namespace tint { namespace semantic { Variable::Variable(const ast::Variable* declaration, type::Type* type, - ast::StorageClass storage_class, - std::vector<const Expression*> users) - : declaration_(declaration), - type_(type), - storage_class_(storage_class), - users_(std::move(users)) {} + ast::StorageClass storage_class) + : declaration_(declaration), type_(type), storage_class_(storage_class) {} Variable::~Variable() = default; +VariableUser::VariableUser(ast::IdentifierExpression* declaration, + type::Type* type, + Statement* statement, + semantic::Variable* variable) + : Base(declaration, type, statement), variable_(variable) {} + } // namespace semantic } // namespace tint
diff --git a/src/semantic/struct.h b/src/semantic/struct.h index 58cd91e..3cd1696 100644 --- a/src/semantic/struct.h +++ b/src/semantic/struct.h
@@ -38,7 +38,7 @@ class StructMember; /// A vector of StructMember pointers. -using StructMemberList = std::vector<StructMember*>; +using StructMemberList = std::vector<const StructMember*>; /// Metadata to capture how a structure is used in a shader module. enum class PipelineStageUsage {
diff --git a/src/semantic/variable.h b/src/semantic/variable.h index 0e606a2..7cae490 100644 --- a/src/semantic/variable.h +++ b/src/semantic/variable.h
@@ -24,6 +24,7 @@ // Forward declarations namespace ast { +class IdentifierExpression; class Variable; } // namespace ast namespace type { @@ -32,6 +33,8 @@ namespace semantic { +class VariableUser; + /// Variable holds the semantic information for variables. class Variable : public Castable<Variable, Node> { public: @@ -39,11 +42,9 @@ /// @param declaration the AST declaration node /// @param type the variable type /// @param storage_class the variable storage class - /// @param users the expressions that use the variable - explicit Variable(const ast::Variable* declaration, - type::Type* type, - ast::StorageClass storage_class, - std::vector<const Expression*> users); + Variable(const ast::Variable* declaration, + type::Type* type, + ast::StorageClass storage_class); /// Destructor ~Variable() override; @@ -58,13 +59,37 @@ ast::StorageClass StorageClass() const { return storage_class_; } /// @returns the expressions that use the variable - const std::vector<const Expression*>& Users() const { return users_; } + const std::vector<const VariableUser*>& Users() const { return users_; } + + /// @param user the user to add + void AddUser(const VariableUser* user) { users_.emplace_back(user); } private: const ast::Variable* const declaration_; type::Type* const type_; ast::StorageClass const storage_class_; - std::vector<const Expression*> const users_; + std::vector<const VariableUser*> users_; +}; + +/// VariableUser holds the semantic information for an identifier expression +/// node that resolves to a variable. +class VariableUser : public Castable<VariableUser, Expression> { + public: + /// Constructor + /// @param declaration the AST identifier node + /// @param type the resolved type of the expression + /// @param statement the statement that owns this expression + /// @param variable the semantic variable + VariableUser(ast::IdentifierExpression* declaration, + type::Type* type, + Statement* statement, + semantic::Variable* variable); + + /// @returns the variable that this expression refers to + const semantic::Variable* Variable() const { return variable_; } + + private: + semantic::Variable const* const variable_; }; } // namespace semantic