[wgsl-reader] Add parsing of named structs.
This CL adds the parsing of structs with names. The parsing of type
aliased structs remains to allow for migration to the new system. The
named struct format is always emitted.
Bug: tint:175
Change-Id: Ic0579dedbd2dd0edc7dfd30bc2ec02972091e718
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/30341
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/ast/module.cc b/src/ast/module.cc
index 48731cc..92381a7 100644
--- a/src/ast/module.cc
+++ b/src/ast/module.cc
@@ -52,12 +52,25 @@
return false;
}
}
- for (auto* const alias : alias_types_) {
- if (alias == nullptr) {
+ for (auto* const ty : constructed_types_) {
+ if (ty == nullptr) {
return false;
}
- if (alias->type()->IsStruct() &&
- alias->type()->AsStruct()->name().empty()) {
+ if (ty->IsAlias()) {
+ auto* alias = ty->AsAlias();
+ if (alias->type() == nullptr) {
+ return false;
+ }
+ if (alias->type()->IsStruct() &&
+ alias->type()->AsStruct()->name().empty()) {
+ return false;
+ }
+ } else if (ty->IsStruct()) {
+ auto* str = ty->AsStruct();
+ if (str->name().empty()) {
+ return false;
+ }
+ } else {
return false;
}
}
@@ -74,13 +87,20 @@
out << "Module{" << std::endl;
const auto indent = 2;
- for (auto* const alias : alias_types_) {
+ for (auto* const ty : constructed_types_) {
for (size_t i = 0; i < indent; ++i) {
out << " ";
}
- out << alias->name() << " -> " << alias->type()->type_name() << std::endl;
- if (alias->type()->IsStruct()) {
- alias->type()->AsStruct()->impl()->to_str(out, indent);
+ if (ty->IsAlias()) {
+ auto* alias = ty->AsAlias();
+ out << alias->name() << " -> " << alias->type()->type_name() << std::endl;
+ if (alias->type()->IsStruct()) {
+ alias->type()->AsStruct()->impl()->to_str(out, indent);
+ }
+ } else if (ty->IsStruct()) {
+ auto* str = ty->AsStruct();
+ out << str->name() << " ";
+ str->impl()->to_str(out, indent);
}
}
for (const auto& var : global_variables_) {
diff --git a/src/ast/module.h b/src/ast/module.h
index 134e762..3dca65d 100644
--- a/src/ast/module.h
+++ b/src/ast/module.h
@@ -46,12 +46,15 @@
/// @returns the global variables for the module
VariableList& global_variables() { return global_variables_; }
- /// Adds a type alias to the module
- /// @param type the alias to add
- void AddAliasType(type::AliasType* type) { alias_types_.push_back(type); }
- /// @returns the alias types in the module
- const std::vector<type::AliasType*>& alias_types() const {
- return alias_types_;
+ /// Adds a constructed type to the module.
+ /// The type must be an alias or a struct.
+ /// @param type the constructed type to add
+ void AddConstructedType(type::Type* type) {
+ constructed_types_.push_back(type);
+ }
+ /// @returns the constructed types in the module
+ const std::vector<type::Type*>& constructed_types() const {
+ return constructed_types_;
}
/// Adds a function to the module
@@ -82,8 +85,8 @@
Module(const Module&) = delete;
VariableList global_variables_;
- // The alias types are owned by the type manager
- std::vector<type::AliasType*> alias_types_;
+ // The constructed types are owned by the type manager
+ std::vector<type::Type*> constructed_types_;
FunctionList functions_;
};
diff --git a/src/ast/module_test.cc b/src/ast/module_test.cc
index 30db2df..0787e9e 100644
--- a/src/ast/module_test.cc
+++ b/src/ast/module_test.cc
@@ -91,13 +91,13 @@
type::AliasType alias("alias", &f32);
Module m;
- m.AddAliasType(&alias);
+ m.AddConstructedType(&alias);
EXPECT_TRUE(m.IsValid());
}
TEST_F(ModuleTest, IsValid_Null_Alias) {
Module m;
- m.AddAliasType(nullptr);
+ m.AddConstructedType(nullptr);
EXPECT_FALSE(m.IsValid());
}
@@ -107,7 +107,7 @@
type::AliasType alias("name", &st);
Module m;
- m.AddAliasType(&alias);
+ m.AddConstructedType(&alias);
EXPECT_TRUE(m.IsValid());
}
@@ -117,7 +117,7 @@
type::AliasType alias("name", &st);
Module m;
- m.AddAliasType(&alias);
+ m.AddConstructedType(&alias);
EXPECT_FALSE(m.IsValid());
}
diff --git a/src/ast/struct.cc b/src/ast/struct.cc
index c16632e..cf3a02c 100644
--- a/src/ast/struct.cc
+++ b/src/ast/struct.cc
@@ -70,7 +70,6 @@
}
void Struct::to_str(std::ostream& out, size_t indent) const {
- make_indent(out, indent);
out << "Struct{" << std::endl;
for (auto deco : decorations_) {
make_indent(out, indent + 2);
diff --git a/src/ast/struct_test.cc b/src/ast/struct_test.cc
index d3bc623..0569001 100644
--- a/src/ast/struct_test.cc
+++ b/src/ast/struct_test.cc
@@ -134,7 +134,7 @@
std::ostringstream out;
s.to_str(out, 2);
- EXPECT_EQ(out.str(), R"( Struct{
+ EXPECT_EQ(out.str(), R"(Struct{
[[block]]
StructMember{a: __i32}
}
diff --git a/src/reader/spirv/function_composite_test.cc b/src/reader/spirv/function_composite_test.cc
index f9ffd29..3264693 100644
--- a/src/reader/spirv/function_composite_test.cc
+++ b/src/reader/spirv/function_composite_test.cc
@@ -218,10 +218,10 @@
Variable{
x_1
none
- __alias_S__struct_S
+ __struct_S
{
TypeConstructor{
- __alias_S__struct_S
+ __struct_S
TypeConstructor{
__vec_2__f32
ScalarConstructor{50.000000}
diff --git a/src/reader/spirv/function_memory_test.cc b/src/reader/spirv/function_memory_test.cc
index 6c6b871..5848192 100644
--- a/src/reader/spirv/function_memory_test.cc
+++ b/src/reader/spirv/function_memory_test.cc
@@ -800,8 +800,7 @@
const auto module_str = p->module().to_str();
EXPECT_THAT(module_str, HasSubstr(R"(
RTArr -> __array__u32_stride_4
- S -> __struct_S
- Struct{
+ S Struct{
[[block]]
StructMember{[[ offset 0 ]] field0: __u32}
StructMember{[[ offset 4 ]] field1: __alias_RTArr__array__u32_stride_4}
@@ -809,7 +808,7 @@
Variable{
myvar
storage_buffer
- __alias_S__struct_S
+ __struct_S
})"));
}
diff --git a/src/reader/spirv/function_misc_test.cc b/src/reader/spirv/function_misc_test.cc
index e606da7..67ce600 100644
--- a/src/reader/spirv/function_misc_test.cc
+++ b/src/reader/spirv/function_misc_test.cc
@@ -264,10 +264,10 @@
Variable{
x_11
none
- __alias_S__struct_S
+ __struct_S
{
TypeConstructor{
- __alias_S__struct_S
+ __struct_S
ScalarConstructor{false}
ScalarConstructor{0}
ScalarConstructor{0}
diff --git a/src/reader/spirv/function_var_test.cc b/src/reader/spirv/function_var_test.cc
index d4a4601..95791d2 100644
--- a/src/reader/spirv/function_var_test.cc
+++ b/src/reader/spirv/function_var_test.cc
@@ -563,10 +563,10 @@
Variable{
x_200
function
- __alias_S__struct_S
+ __struct_S
{
TypeConstructor{
- __alias_S__struct_S
+ __struct_S
ScalarConstructor{1}
ScalarConstructor{1.500000}
TypeConstructor{
@@ -602,10 +602,10 @@
Variable{
x_200
function
- __alias_S__struct_S
+ __struct_S
{
TypeConstructor{
- __alias_S__struct_S
+ __struct_S
ScalarConstructor{0}
ScalarConstructor{0.000000}
TypeConstructor{
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index a869be4..8bc65a9 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -870,6 +870,8 @@
namer_.GetName(type_id), std::move(ast_struct));
auto* result = ctx_.type_mgr().Get(std::move(ast_struct_type));
+ id_to_type_[type_id] = result;
+ ast_module_.AddConstructedType(result);
return result;
}
@@ -934,11 +936,8 @@
return;
}
- // We only care about struct, arrays, and runtime arrays.
+ // We only care about arrays, and runtime arrays.
switch (type->kind()) {
- case spvtools::opt::analysis::Type::kStruct:
- // The struct already got a name when the type was first registered.
- break;
case spvtools::opt::analysis::Type::kRuntimeArray:
// Runtime arrays are always decorated with ArrayStride so always get a
// type alias.
@@ -967,7 +966,7 @@
->AsAlias();
// Record this new alias as the AST type for this SPIR-V ID.
id_to_type_[type_id] = ast_alias_type;
- ast_module_.AddAliasType(ast_alias_type);
+ ast_module_.AddConstructedType(ast_alias_type);
}
bool ParserImpl::EmitModuleScopeVariables() {
diff --git a/src/reader/spirv/parser_impl_module_var_test.cc b/src/reader/spirv/parser_impl_module_var_test.cc
index 6831cd8..253ec6a 100644
--- a/src/reader/spirv/parser_impl_module_var_test.cc
+++ b/src/reader/spirv/parser_impl_module_var_test.cc
@@ -1058,10 +1058,10 @@
EXPECT_THAT(module_str, HasSubstr(R"(Variable{
x_200
private
- __alias_S__struct_S
+ __struct_S
{
TypeConstructor{
- __alias_S__struct_S
+ __struct_S
ScalarConstructor{1}
ScalarConstructor{1.500000}
TypeConstructor{
@@ -1087,10 +1087,10 @@
EXPECT_THAT(module_str, HasSubstr(R"(Variable{
x_200
private
- __alias_S__struct_S
+ __struct_S
{
TypeConstructor{
- __alias_S__struct_S
+ __struct_S
ScalarConstructor{0}
ScalarConstructor{0.000000}
TypeConstructor{
@@ -1116,10 +1116,10 @@
EXPECT_THAT(module_str, HasSubstr(R"(Variable{
x_200
private
- __alias_S__struct_S
+ __struct_S
{
TypeConstructor{
- __alias_S__struct_S
+ __struct_S
ScalarConstructor{0}
ScalarConstructor{0.000000}
TypeConstructor{
@@ -1203,7 +1203,7 @@
}
myvar
storage_buffer
- __alias_S__struct_S
+ __struct_S
})"))
<< module_str;
}
@@ -1257,7 +1257,7 @@
}
myvar
storage_buffer
- __alias_S__struct_S
+ __struct_S
})"))
<< module_str;
}
@@ -1305,8 +1305,7 @@
EXPECT_TRUE(p->error().empty());
const auto module_str = p->module().to_str();
EXPECT_THAT(module_str, HasSubstr(R"(
- S -> __struct_S
- Struct{
+ S Struct{
[[block]]
StructMember{field0: __u32}
StructMember{field1: __f32}
@@ -1315,7 +1314,7 @@
Variable{
myvar
storage_buffer
- __alias_S__struct_S
+ __struct_S
}
})")) << module_str;
}
@@ -1333,8 +1332,7 @@
EXPECT_TRUE(p->error().empty());
const auto module_str = p->module().to_str();
EXPECT_THAT(module_str, HasSubstr(R"(
- S -> __struct_S
- Struct{
+ S Struct{
[[block]]
StructMember{field0: __u32}
StructMember{field1: __f32}
@@ -1343,7 +1341,7 @@
Variable{
myvar
storage_buffer
- __alias_S__struct_S
+ __struct_S
}
})")) << module_str;
}
@@ -1365,15 +1363,14 @@
EXPECT_TRUE(p->error().empty());
const auto module_str = p->module().to_str();
EXPECT_THAT(module_str, HasSubstr(R"(
- S -> __struct_S
- Struct{
+ S Struct{
[[block]]
StructMember{field0: __mat_2_3__f32}
}
Variable{
myvar
storage_buffer
- __alias_S__struct_S
+ __struct_S
}
})")) << module_str;
}
@@ -1395,15 +1392,14 @@
EXPECT_TRUE(p->error().empty());
const auto module_str = p->module().to_str();
EXPECT_THAT(module_str, HasSubstr(R"(
- S -> __struct_S
- Struct{
+ S Struct{
[[block]]
StructMember{field0: __mat_2_3__f32}
}
Variable{
myvar
storage_buffer
- __alias_S__struct_S
+ __struct_S
}
})")) << module_str;
}
diff --git a/src/reader/spirv/parser_impl_named_types_test.cc b/src/reader/spirv/parser_impl_named_types_test.cc
index a942e1a..d726260 100644
--- a/src/reader/spirv/parser_impl_named_types_test.cc
+++ b/src/reader/spirv/parser_impl_named_types_test.cc
@@ -40,7 +40,7 @@
%s = OpTypeStruct %uint %uint
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
- EXPECT_THAT(p->module().to_str(), HasSubstr("S -> __struct_"));
+ EXPECT_THAT(p->module().to_str(), HasSubstr("S Struct"));
}
TEST_F(SpvParserTest, NamedTypes_NamedStruct) {
@@ -50,7 +50,7 @@
%s = OpTypeStruct %uint %uint
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
- EXPECT_THAT(p->module().to_str(), HasSubstr("mystruct -> __struct_"));
+ EXPECT_THAT(p->module().to_str(), HasSubstr("mystruct Struct"));
}
TEST_F(SpvParserTest, NamedTypes_Dup_EmitBoth) {
@@ -60,13 +60,11 @@
%s2 = OpTypeStruct %uint %uint
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
- EXPECT_THAT(p->module().to_str(), HasSubstr(R"(S -> __struct_S
- Struct{
+ EXPECT_THAT(p->module().to_str(), HasSubstr(R"(S Struct{
StructMember{field0: __u32}
StructMember{field1: __u32}
}
- S_1 -> __struct_S_1
- Struct{
+ S_1 Struct{
StructMember{field0: __u32}
StructMember{field1: __u32}
})"));
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 24ff9a8..f365cfb 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -168,17 +168,17 @@
return peek(0);
}
-void ParserImpl::register_alias(const std::string& name,
- ast::type::Type* type) {
+void ParserImpl::register_constructed(const std::string& name,
+ ast::type::Type* type) {
assert(type);
- registered_aliases_[name] = type;
+ registered_constructs_[name] = type;
}
-ast::type::Type* ParserImpl::get_alias(const std::string& name) {
- if (registered_aliases_.find(name) == registered_aliases_.end()) {
+ast::type::Type* ParserImpl::get_constructed(const std::string& name) {
+ if (registered_constructs_.find(name) == registered_constructs_.end()) {
return nullptr;
}
- return registered_aliases_[name];
+ return registered_constructs_[name];
}
bool ParserImpl::Parse() {
@@ -206,11 +206,13 @@
// | global_variable_decl SEMICLON
// | global_constant_decl SEMICOLON
// | type_alias SEMICOLON
+// | struct_decl SEMICOLON
// | function_decl
void ParserImpl::global_decl() {
auto t = peek();
- if (t.IsEof())
+ if (t.IsEof()) {
return;
+ }
if (t.IsSemicolon()) {
next(); // consume the peek
@@ -218,8 +220,9 @@
}
auto gv = global_variable_decl();
- if (has_error())
+ if (has_error()) {
return;
+ }
if (gv != nullptr) {
t = next();
if (!t.IsSemicolon()) {
@@ -231,8 +234,9 @@
}
auto gc = global_constant_decl();
- if (has_error())
+ if (has_error()) {
return;
+ }
if (gc != nullptr) {
t = next();
if (!t.IsSemicolon()) {
@@ -244,21 +248,39 @@
}
auto* ta = type_alias();
- if (has_error())
+ if (has_error()) {
return;
+ }
if (ta != nullptr) {
t = next();
if (!t.IsSemicolon()) {
set_error(t, "missing ';' for type alias");
return;
}
- module_.AddAliasType(ta);
+ module_.AddConstructedType(ta);
+ return;
+ }
+
+ auto str = struct_decl("");
+ if (has_error()) {
+ return;
+ }
+ if (str != nullptr) {
+ t = next();
+ if (!t.IsSemicolon()) {
+ set_error(t, "missing ';' for struct declaration");
+ return;
+ }
+ auto* type = ctx_.type_mgr().Get(std::move(str));
+ register_constructed(type->AsStruct()->name(), type);
+ module_.AddConstructedType(type);
return;
}
auto func = function_decl();
- if (has_error())
+ if (has_error()) {
return;
+ }
if (func != nullptr) {
module_.AddFunction(std::move(func));
return;
@@ -1059,7 +1081,7 @@
// type_alias
// : TYPE IDENT EQUAL type_decl
// | TYPE IDENT EQUAL struct_decl
-ast::type::AliasType* ParserImpl::type_alias() {
+ast::type::Type* ParserImpl::type_alias() {
auto t = peek();
if (!t.IsType())
return nullptr;
@@ -1092,6 +1114,8 @@
}
type = ctx_.type_mgr().Get(std::move(str));
+ register_constructed(name, type);
+ return type;
}
if (type == nullptr) {
set_error(peek(), "invalid type for alias");
@@ -1100,7 +1124,7 @@
auto* alias =
ctx_.type_mgr().Get(std::make_unique<ast::type::AliasType>(name, type));
- register_alias(name, alias);
+ register_constructed(name, alias);
return alias->AsAlias();
}
@@ -1133,12 +1157,12 @@
auto t = peek();
if (t.IsIdentifier()) {
next(); // Consume the peek
- auto* alias = get_alias(t.to_str());
- if (alias == nullptr) {
- set_error(t, "unknown type alias '" + t.to_str() + "'");
+ auto* ty = get_constructed(t.to_str());
+ if (ty == nullptr) {
+ set_error(t, "unknown constructed type '" + t.to_str() + "'");
return nullptr;
}
- return alias;
+ return ty;
}
if (t.IsBool()) {
next(); // Consume the peek
@@ -1494,10 +1518,25 @@
}
}
- t = next();
- if (!t.IsStruct()) {
+ t = peek();
+ if (!decos.empty() && !t.IsStruct()) {
set_error(t, "missing struct declaration");
return nullptr;
+ } else if (!t.IsStruct()) {
+ return nullptr;
+ }
+ next(); // Consume the peek
+
+ // If there is no name this is a global struct call. This check will go
+ // away when the type_alias struct entry is removed.
+ std::string str_name = name;
+ if (name.empty()) {
+ t = next();
+ if (!t.IsIdentifier()) {
+ set_error(t, "missing identifier for struct declaration");
+ return nullptr;
+ }
+ str_name = t.to_str();
}
auto body = struct_body_decl();
@@ -1506,7 +1545,7 @@
}
return std::make_unique<ast::type::StructType>(
- name,
+ str_name,
std::make_unique<ast::Struct>(source, std::move(decos), std::move(body)));
}
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h
index c9207e5..fd8661a 100644
--- a/src/reader/wgsl/parser_impl.h
+++ b/src/reader/wgsl/parser_impl.h
@@ -110,14 +110,14 @@
/// @param msg the error message
void set_error(const Token& t, const std::string& msg);
- /// Registers a type alias into the parser
- /// @param name the alias name
- /// @param type the alias'd type
- void register_alias(const std::string& name, ast::type::Type* type);
- /// Retrieves an aliased type
- /// @param name The alias name to lookup
- /// @returns the alias type for |name| or nullptr if not found
- ast::type::Type* get_alias(const std::string& name);
+ /// Registers a constructed type into the parser
+ /// @param name the constructed name
+ /// @param type the constructed type
+ void register_constructed(const std::string& name, ast::type::Type* type);
+ /// Retrieves a constructed type
+ /// @param name The name to lookup
+ /// @returns the constructed type for |name| or nullptr if not found
+ ast::type::Type* get_constructed(const std::string& name);
/// Parses the `translation_unit` grammar element
void translation_unit();
@@ -148,7 +148,7 @@
ast::StorageClass variable_storage_decoration();
/// Parses a `type_alias` grammar element
/// @returns the type alias or nullptr on error
- ast::type::AliasType* type_alias();
+ ast::type::Type* type_alias();
/// Parses a `type_decl` grammar element
/// @returns the parsed Type or nullptr if none matched.
ast::type::Type* type_decl();
@@ -410,7 +410,7 @@
std::string error_;
std::unique_ptr<Lexer> lexer_;
std::deque<Token> token_queue_;
- std::unordered_map<std::string, ast::type::Type*> registered_aliases_;
+ std::unordered_map<std::string, ast::type::Type*> registered_constructs_;
ast::Module module_;
};
diff --git a/src/reader/wgsl/parser_impl_const_expr_test.cc b/src/reader/wgsl/parser_impl_const_expr_test.cc
index 86392a3..55a1552 100644
--- a/src/reader/wgsl/parser_impl_const_expr_test.cc
+++ b/src/reader/wgsl/parser_impl_const_expr_test.cc
@@ -119,7 +119,7 @@
auto e = p->const_expr();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
- EXPECT_EQ(p->error(), "1:1: unknown type alias 'invalid'");
+ EXPECT_EQ(p->error(), "1:1: unknown constructed type 'invalid'");
}
TEST_F(ParserImplTest, ConstExpr_Recursion) {
diff --git a/src/reader/wgsl/parser_impl_function_header_test.cc b/src/reader/wgsl/parser_impl_function_header_test.cc
index 2b482f8..df0eabf 100644
--- a/src/reader/wgsl/parser_impl_function_header_test.cc
+++ b/src/reader/wgsl/parser_impl_function_header_test.cc
@@ -89,7 +89,7 @@
auto f = p->function_header();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(f, nullptr);
- EXPECT_EQ(p->error(), "1:14: unknown type alias 'invalid'");
+ EXPECT_EQ(p->error(), "1:14: unknown constructed type 'invalid'");
}
TEST_F(ParserImplTest, FunctionHeader_MissingReturnType) {
diff --git a/src/reader/wgsl/parser_impl_function_type_decl_test.cc b/src/reader/wgsl/parser_impl_function_type_decl_test.cc
index c5e4e16..30bc605 100644
--- a/src/reader/wgsl/parser_impl_function_type_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_function_type_decl_test.cc
@@ -51,7 +51,7 @@
auto* e = p->function_type_decl();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
- EXPECT_EQ(p->error(), "1:6: unknown type alias 'invalid'");
+ EXPECT_EQ(p->error(), "1:6: unknown constructed type 'invalid'");
}
} // namespace
diff --git a/src/reader/wgsl/parser_impl_global_constant_decl_test.cc b/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
index c9abe0a..f08d17c 100644
--- a/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
@@ -51,7 +51,7 @@
auto e = p->global_constant_decl();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
- EXPECT_EQ(p->error(), "1:10: unknown type alias 'invalid'");
+ EXPECT_EQ(p->error(), "1:10: unknown constructed type 'invalid'");
}
TEST_F(ParserImplTest, GlobalConstantDecl_InvalidExpression) {
diff --git a/src/reader/wgsl/parser_impl_global_decl_test.cc b/src/reader/wgsl/parser_impl_global_decl_test.cc
index 404f559..a030ed4 100644
--- a/src/reader/wgsl/parser_impl_global_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_decl_test.cc
@@ -13,6 +13,8 @@
// limitations under the License.
#include "gtest/gtest.h"
+#include "src/ast/type/array_type.h"
+#include "src/ast/type/struct_type.h"
#include "src/reader/wgsl/parser_impl.h"
#include "src/reader/wgsl/parser_impl_test_helper.h"
@@ -43,7 +45,7 @@
auto* p = parser("var<out> a : vec2<invalid>;");
p->global_decl();
ASSERT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:19: unknown type alias 'invalid'");
+ EXPECT_EQ(p->error(), "1:19: unknown constructed type 'invalid'");
}
TEST_F(ParserImplTest, GlobalDecl_GlobalVariable_MissingSemicolon) {
@@ -85,15 +87,48 @@
ASSERT_FALSE(p->has_error()) << p->error();
auto m = p->module();
- ASSERT_EQ(m.alias_types().size(), 1u);
- EXPECT_EQ(m.alias_types()[0]->name(), "A");
+ ASSERT_EQ(m.constructed_types().size(), 1u);
+ ASSERT_TRUE(m.constructed_types()[0]->IsAlias());
+ EXPECT_EQ(m.constructed_types()[0]->AsAlias()->name(), "A");
+}
+
+TEST_F(ParserImplTest, GlobalDecl_TypeAlias_Struct) {
+ auto* p = parser("type A = struct { a : f32; };");
+ p->global_decl();
+ ASSERT_FALSE(p->has_error()) << p->error();
+
+ auto m = p->module();
+ ASSERT_EQ(m.constructed_types().size(), 1u);
+ ASSERT_TRUE(m.constructed_types()[0]->IsStruct());
+ EXPECT_EQ(m.constructed_types()[0]->AsStruct()->name(), "A");
+}
+
+TEST_F(ParserImplTest, GlobalDecl_TypeAlias_StructIdent) {
+ auto* p = parser(R"(struct A {
+ a : f32;
+};
+type B = A;)");
+ p->global_decl();
+ p->global_decl();
+ ASSERT_FALSE(p->has_error()) << p->error();
+
+ auto m = p->module();
+ ASSERT_EQ(m.constructed_types().size(), 2u);
+ ASSERT_TRUE(m.constructed_types()[0]->IsStruct());
+ auto* str = m.constructed_types()[0]->AsStruct();
+ EXPECT_EQ(str->name(), "A");
+
+ ASSERT_TRUE(m.constructed_types()[1]->IsAlias());
+ auto* alias = m.constructed_types()[1]->AsAlias();
+ EXPECT_EQ(alias->name(), "B");
+ EXPECT_EQ(alias->type(), str);
}
TEST_F(ParserImplTest, GlobalDecl_TypeAlias_Invalid) {
auto* p = parser("type A = invalid;");
p->global_decl();
ASSERT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:10: unknown type alias 'invalid'");
+ EXPECT_EQ(p->error(), "1:10: unknown constructed type 'invalid'");
}
TEST_F(ParserImplTest, GlobalDecl_TypeAlias_MissingSemicolon) {
@@ -130,6 +165,95 @@
EXPECT_EQ(p->error(), "1:14: unable to determine function return type");
}
+TEST_F(ParserImplTest, GlobalDecl_ParsesStruct) {
+ auto* p = parser("struct A { b: i32; c: f32;};");
+ p->global_decl();
+ ASSERT_FALSE(p->has_error());
+
+ auto m = p->module();
+ ASSERT_EQ(m.constructed_types().size(), 1u);
+
+ auto* t = m.constructed_types()[0];
+ ASSERT_NE(t, nullptr);
+ ASSERT_TRUE(t->IsStruct());
+
+ auto* str = t->AsStruct();
+ EXPECT_EQ(str->name(), "A");
+ EXPECT_EQ(str->impl()->members().size(), 2u);
+}
+
+TEST_F(ParserImplTest, GlobalDecl_Struct_WithStride) {
+ auto* p =
+ parser("struct A { [[offset(0)]] data: [[stride(4)]] array<f32>; };");
+ p->global_decl();
+ ASSERT_FALSE(p->has_error());
+
+ auto m = p->module();
+ ASSERT_EQ(m.constructed_types().size(), 1u);
+
+ auto* t = m.constructed_types()[0];
+ ASSERT_NE(t, nullptr);
+ ASSERT_TRUE(t->IsStruct());
+
+ auto* str = t->AsStruct();
+ EXPECT_EQ(str->name(), "A");
+ EXPECT_EQ(str->impl()->members().size(), 1u);
+ EXPECT_FALSE(str->IsBlockDecorated());
+
+ const auto* ty = str->impl()->members()[0]->type();
+ ASSERT_TRUE(ty->IsArray());
+ const auto* arr = ty->AsArray();
+ EXPECT_TRUE(arr->has_array_stride());
+ EXPECT_EQ(arr->array_stride(), 4u);
+}
+
+TEST_F(ParserImplTest, GlobalDecl_Struct_WithDecoration) {
+ auto* p = parser("[[block]] struct A { [[offset(0)]] data: f32; };");
+ p->global_decl();
+ ASSERT_FALSE(p->has_error());
+
+ auto m = p->module();
+ ASSERT_EQ(m.constructed_types().size(), 1u);
+
+ auto* t = m.constructed_types()[0];
+ ASSERT_NE(t, nullptr);
+ ASSERT_TRUE(t->IsStruct());
+
+ auto* str = t->AsStruct();
+ EXPECT_EQ(str->name(), "A");
+ EXPECT_EQ(str->impl()->members().size(), 1u);
+ EXPECT_TRUE(str->IsBlockDecorated());
+}
+
+TEST_F(ParserImplTest, GlobalDecl_Struct_Invalid) {
+ auto* p = parser("[[block]] A {};");
+ p->global_decl();
+ ASSERT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:11: missing struct declaration");
+}
+
+TEST_F(ParserImplTest, GlobalDecl_StructMissing_Semi) {
+ auto* p = parser("[[block]] struct A {}");
+ p->global_decl();
+ ASSERT_TRUE(p->has_error());
+ EXPECT_EQ(p->error(), "1:22: missing ';' for struct declaration");
+}
+
+// This was failing due to not finding the missing ;. https://crbug.com/tint/218
+TEST_F(ParserImplTest, TypeDecl_Struct_Empty) {
+ auto* p = parser("type str = struct {};");
+ p->global_decl();
+ ASSERT_FALSE(p->has_error()) << p->error();
+
+ auto module = p->module();
+ ASSERT_EQ(module.constructed_types().size(), 1u);
+
+ ASSERT_TRUE(module.constructed_types()[0]->IsStruct());
+ auto* str = module.constructed_types()[0]->AsStruct();
+ EXPECT_EQ(str->name(), "str");
+ EXPECT_EQ(str->impl()->members().size(), 0u);
+}
+
} // namespace
} // namespace wgsl
} // namespace reader
diff --git a/src/reader/wgsl/parser_impl_primary_expression_test.cc b/src/reader/wgsl/parser_impl_primary_expression_test.cc
index 49737e4..4560dbe 100644
--- a/src/reader/wgsl/parser_impl_primary_expression_test.cc
+++ b/src/reader/wgsl/parser_impl_primary_expression_test.cc
@@ -221,7 +221,7 @@
auto e = p->primary_expression();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
- EXPECT_EQ(p->error(), "1:9: unknown type alias 'invalid'");
+ EXPECT_EQ(p->error(), "1:9: unknown constructed type 'invalid'");
}
TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingLeftParen) {
diff --git a/src/reader/wgsl/parser_impl_struct_decl_test.cc b/src/reader/wgsl/parser_impl_struct_decl_test.cc
index 08e069b..8a80237 100644
--- a/src/reader/wgsl/parser_impl_struct_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_struct_decl_test.cc
@@ -24,6 +24,21 @@
TEST_F(ParserImplTest, StructDecl_Parses) {
auto* p = parser(R"(
+struct S {
+ a : i32;
+ [[offset(4)]] b : f32;
+})");
+ auto s = p->struct_decl("");
+ ASSERT_FALSE(p->has_error());
+ ASSERT_NE(s, nullptr);
+ ASSERT_EQ(s->name(), "S");
+ ASSERT_EQ(s->impl()->members().size(), 2u);
+ EXPECT_EQ(s->impl()->members()[0]->name(), "a");
+ EXPECT_EQ(s->impl()->members()[1]->name(), "b");
+}
+
+TEST_F(ParserImplTest, StructDecl_Parses_WithoutName) {
+ auto* p = parser(R"(
struct {
a : i32;
[[offset(4)]] b : f32;
@@ -39,11 +54,11 @@
TEST_F(ParserImplTest, StructDecl_ParsesWithDecoration) {
auto* p = parser(R"(
-[[block]] struct {
+[[block]] struct B {
a : f32;
b : f32;
})");
- auto s = p->struct_decl("B");
+ auto s = p->struct_decl("");
ASSERT_FALSE(p->has_error());
ASSERT_NE(s, nullptr);
ASSERT_EQ(s->name(), "B");
@@ -57,11 +72,11 @@
TEST_F(ParserImplTest, StructDecl_ParsesWithMultipleDecoration) {
auto* p = parser(R"(
[[block]]
-[[block]] struct {
+[[block]] struct S {
a : f32;
b : f32;
})");
- auto s = p->struct_decl("S");
+ auto s = p->struct_decl("");
ASSERT_FALSE(p->has_error());
ASSERT_NE(s, nullptr);
ASSERT_EQ(s->name(), "S");
@@ -74,40 +89,48 @@
}
TEST_F(ParserImplTest, StructDecl_EmptyMembers) {
- auto* p = parser("struct {}");
- auto s = p->struct_decl("S");
+ auto* p = parser("struct S {}");
+ auto s = p->struct_decl("");
ASSERT_FALSE(p->has_error());
ASSERT_NE(s, nullptr);
ASSERT_EQ(s->impl()->members().size(), 0u);
}
-TEST_F(ParserImplTest, StructDecl_MissingBracketLeft) {
- auto* p = parser("struct }");
- auto s = p->struct_decl("S");
+TEST_F(ParserImplTest, StructDecl_MissingIdent) {
+ auto* p = parser("struct {}");
+ auto s = p->struct_decl("");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(s, nullptr);
- EXPECT_EQ(p->error(), "1:8: missing { for struct declaration");
+ EXPECT_EQ(p->error(), "1:8: missing identifier for struct declaration");
+}
+
+TEST_F(ParserImplTest, StructDecl_MissingBracketLeft) {
+ auto* p = parser("struct S }");
+ auto s = p->struct_decl("");
+ ASSERT_TRUE(p->has_error());
+ ASSERT_EQ(s, nullptr);
+ EXPECT_EQ(p->error(), "1:10: missing { for struct declaration");
}
TEST_F(ParserImplTest, StructDecl_InvalidStructBody) {
- auto* p = parser("struct { a : B; }");
- auto s = p->struct_decl("S");
+ auto* p = parser("struct S { a : B; }");
+ auto s = p->struct_decl("");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(s, nullptr);
- EXPECT_EQ(p->error(), "1:14: unknown type alias 'B'");
+ EXPECT_EQ(p->error(), "1:16: unknown constructed type 'B'");
}
TEST_F(ParserImplTest, StructDecl_InvalidStructDecorationDecl) {
- auto* p = parser("[[block struct { a : i32; }");
- auto s = p->struct_decl("S");
+ auto* p = parser("[[block struct S { a : i32; }");
+ auto s = p->struct_decl("");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(s, nullptr);
EXPECT_EQ(p->error(), "1:9: missing ]] for struct decoration");
}
TEST_F(ParserImplTest, StructDecl_MissingStruct) {
- auto* p = parser("[[block]] {}");
- auto s = p->struct_decl("S");
+ auto* p = parser("[[block]] S {}");
+ auto s = p->struct_decl("");
ASSERT_TRUE(p->has_error());
ASSERT_EQ(s, nullptr);
EXPECT_EQ(p->error(), "1:11: missing struct declaration");
diff --git a/src/reader/wgsl/parser_impl_struct_member_test.cc b/src/reader/wgsl/parser_impl_struct_member_test.cc
index 3c1ca11..9ee2d9f 100644
--- a/src/reader/wgsl/parser_impl_struct_member_test.cc
+++ b/src/reader/wgsl/parser_impl_struct_member_test.cc
@@ -83,7 +83,7 @@
auto m = p->struct_member();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(m, nullptr);
- EXPECT_EQ(p->error(), "1:19: unknown type alias 'B'");
+ EXPECT_EQ(p->error(), "1:19: unknown constructed type 'B'");
}
TEST_F(ParserImplTest, StructMember_MissingSemicolon) {
diff --git a/src/reader/wgsl/parser_impl_test.cc b/src/reader/wgsl/parser_impl_test.cc
index a9fb584..096a1d0 100644
--- a/src/reader/wgsl/parser_impl_test.cc
+++ b/src/reader/wgsl/parser_impl_test.cc
@@ -58,16 +58,16 @@
TEST_F(ParserImplTest, GetRegisteredType) {
auto* p = parser("");
ast::type::I32Type i32;
- p->register_alias("my_alias", &i32);
+ p->register_constructed("my_alias", &i32);
- auto* alias = p->get_alias("my_alias");
+ auto* alias = p->get_constructed("my_alias");
ASSERT_NE(alias, nullptr);
ASSERT_EQ(alias, &i32);
}
TEST_F(ParserImplTest, GetUnregisteredType) {
auto* p = parser("");
- auto* alias = p->get_alias("my_alias");
+ auto* alias = p->get_constructed("my_alias");
ASSERT_EQ(alias, nullptr);
}
diff --git a/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc b/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc
index 649920f..a5c8745 100644
--- a/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc
+++ b/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc
@@ -97,7 +97,7 @@
auto* t = p->texture_sampler_types();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(t, nullptr);
- EXPECT_EQ(p->error(), "1:20: unknown type alias 'abc'");
+ EXPECT_EQ(p->error(), "1:20: unknown constructed type 'abc'");
}
TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingType) {
@@ -140,7 +140,7 @@
auto* t = p->texture_sampler_types();
ASSERT_TRUE(p->has_error());
EXPECT_EQ(t, nullptr);
- EXPECT_EQ(p->error(), "1:25: unknown type alias 'abc'");
+ EXPECT_EQ(p->error(), "1:25: unknown constructed type 'abc'");
}
TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingType) {
diff --git a/src/reader/wgsl/parser_impl_type_alias_test.cc b/src/reader/wgsl/parser_impl_type_alias_test.cc
index f90ebac..4977b0b 100644
--- a/src/reader/wgsl/parser_impl_type_alias_test.cc
+++ b/src/reader/wgsl/parser_impl_type_alias_test.cc
@@ -33,20 +33,28 @@
auto* t = p->type_alias();
ASSERT_FALSE(p->has_error());
ASSERT_NE(t, nullptr);
- ASSERT_TRUE(t->type()->IsI32());
- ASSERT_EQ(t->type(), i32);
+ ASSERT_TRUE(t->IsAlias());
+ auto* alias = t->AsAlias();
+ ASSERT_TRUE(alias->type()->IsI32());
+ ASSERT_EQ(alias->type(), i32);
}
-TEST_F(ParserImplTest, TypeDecl_ParsesStruct) {
- auto* p = parser("type a = struct { b: i32; c: f32;}");
+TEST_F(ParserImplTest, TypeDecl_ParsesStruct_Ident) {
+ ast::type::StructType str("B", {});
+
+ auto* p = parser("type a = B");
+ p->register_constructed("B", &str);
+
auto* t = p->type_alias();
ASSERT_FALSE(p->has_error());
ASSERT_NE(t, nullptr);
- EXPECT_EQ(t->name(), "a");
- ASSERT_TRUE(t->type()->IsStruct());
+ ASSERT_TRUE(t->IsAlias());
+ auto* alias = t->AsAlias();
+ EXPECT_EQ(alias->name(), "a");
+ ASSERT_TRUE(alias->type()->IsStruct());
- auto* s = t->type()->AsStruct();
- EXPECT_EQ(s->impl()->members().size(), 2u);
+ auto* s = alias->type()->AsStruct();
+ EXPECT_EQ(s->name(), "B");
}
TEST_F(ParserImplTest, TypeDecl_MissingIdent) {
@@ -78,7 +86,18 @@
auto* t = p->type_alias();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(t, nullptr);
- EXPECT_EQ(p->error(), "1:10: unknown type alias 'B'");
+ EXPECT_EQ(p->error(), "1:10: unknown constructed type 'B'");
+}
+
+TEST_F(ParserImplTest, TypeDecl_ParsesStruct) {
+ auto* p = parser("type a = struct { b: i32; c: f32;}");
+ auto* t = p->type_alias();
+ ASSERT_FALSE(p->has_error());
+ ASSERT_NE(t, nullptr);
+ ASSERT_TRUE(t->IsStruct());
+ auto* str = t->AsStruct();
+ EXPECT_EQ(str->name(), "a");
+ EXPECT_EQ(str->impl()->members().size(), 2u);
}
TEST_F(ParserImplTest, TypeDecl_InvalidStruct) {
@@ -97,35 +116,30 @@
auto* t = p->type_alias();
ASSERT_FALSE(p->has_error());
ASSERT_NE(t, nullptr);
- EXPECT_EQ(t->name(), "a");
- ASSERT_TRUE(t->type()->IsStruct());
+ ASSERT_TRUE(t->IsStruct());
+ auto* str = t->AsStruct();
+ EXPECT_EQ(str->name(), "a");
+ EXPECT_EQ(str->impl()->members().size(), 1u);
- auto* s = t->type()->AsStruct();
- EXPECT_EQ(s->impl()->members().size(), 1u);
-
- const auto* ty = s->impl()->members()[0]->type();
+ const auto* ty = str->impl()->members()[0]->type();
ASSERT_TRUE(ty->IsArray());
const auto* arr = ty->AsArray();
EXPECT_TRUE(arr->has_array_stride());
EXPECT_EQ(arr->array_stride(), 4u);
}
-// This was failing due to not finding the missing ;. https://crbug.com/tint/218
TEST_F(ParserImplTest, TypeDecl_Struct_Empty) {
auto* p = parser("type str = struct {};");
p->global_decl();
ASSERT_FALSE(p->has_error()) << p->error();
auto module = p->module();
- ASSERT_EQ(module.alias_types().size(), 1u);
+ ASSERT_EQ(module.constructed_types().size(), 1u);
- auto* t = module.alias_types()[0];
- ASSERT_NE(t, nullptr);
- EXPECT_EQ(t->name(), "str");
-
- ASSERT_TRUE(t->type()->IsStruct());
- auto* s = t->type()->AsStruct();
- EXPECT_EQ(s->impl()->members().size(), 0u);
+ ASSERT_TRUE(module.constructed_types()[0]->IsStruct());
+ auto* str = module.constructed_types()[0]->AsStruct();
+ EXPECT_EQ(str->name(), "str");
+ EXPECT_EQ(str->impl()->members().size(), 0u);
}
} // namespace
diff --git a/src/reader/wgsl/parser_impl_type_decl_test.cc b/src/reader/wgsl/parser_impl_type_decl_test.cc
index f384803..5813451 100644
--- a/src/reader/wgsl/parser_impl_type_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_type_decl_test.cc
@@ -50,7 +50,7 @@
auto* alias_type =
tm()->Get(std::make_unique<ast::type::AliasType>("A", int_type));
- p->register_alias("A", alias_type);
+ p->register_constructed("A", alias_type);
auto* t = p->type_decl();
ASSERT_NE(t, nullptr);
@@ -68,7 +68,7 @@
auto* t = p->type_decl();
ASSERT_EQ(t, nullptr);
EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:1: unknown type alias 'B'");
+ EXPECT_EQ(p->error(), "1:1: unknown constructed type 'B'");
}
TEST_F(ParserImplTest, TypeDecl_Bool) {
@@ -248,7 +248,7 @@
auto* t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p->has_error());
- ASSERT_EQ(p->error(), "1:6: unknown type alias 'unknown'");
+ ASSERT_EQ(p->error(), "1:6: unknown constructed type 'unknown'");
}
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
VecBadType,
@@ -378,7 +378,7 @@
auto* t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p->has_error());
- ASSERT_EQ(p->error(), "1:15: unknown type alias 'unknown'");
+ ASSERT_EQ(p->error(), "1:15: unknown constructed type 'unknown'");
}
TEST_F(ParserImplTest, TypeDecl_Array) {
@@ -544,7 +544,7 @@
auto* t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p->has_error());
- ASSERT_EQ(p->error(), "1:7: unknown type alias 'unknown'");
+ ASSERT_EQ(p->error(), "1:7: unknown constructed type 'unknown'");
}
TEST_F(ParserImplTest, TypeDecl_Array_ZeroSize) {
@@ -746,7 +746,7 @@
auto* t = p->type_decl();
ASSERT_EQ(t, nullptr);
ASSERT_TRUE(p->has_error());
- ASSERT_EQ(p->error(), "1:8: unknown type alias 'unknown'");
+ ASSERT_EQ(p->error(), "1:8: unknown constructed type 'unknown'");
}
INSTANTIATE_TEST_SUITE_P(ParserImplTest,
MatrixBadType,
diff --git a/src/reader/wgsl/parser_impl_variable_ident_decl_test.cc b/src/reader/wgsl/parser_impl_variable_ident_decl_test.cc
index b3144ef..2cf0b6b 100644
--- a/src/reader/wgsl/parser_impl_variable_ident_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_ident_decl_test.cc
@@ -76,7 +76,7 @@
auto* p = parser("my_var : invalid");
auto r = p->variable_ident_decl();
ASSERT_TRUE(p->has_error());
- ASSERT_EQ(p->error(), "1:10: unknown type alias 'invalid'");
+ ASSERT_EQ(p->error(), "1:10: unknown constructed type 'invalid'");
}
} // namespace
diff --git a/src/reader/wgsl/parser_impl_variable_stmt_test.cc b/src/reader/wgsl/parser_impl_variable_stmt_test.cc
index 891d572..9e3d278 100644
--- a/src/reader/wgsl/parser_impl_variable_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_stmt_test.cc
@@ -53,7 +53,7 @@
auto e = p->variable_stmt();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
- EXPECT_EQ(p->error(), "1:9: unknown type alias 'invalid'");
+ EXPECT_EQ(p->error(), "1:9: unknown constructed type 'invalid'");
}
TEST_F(ParserImplTest, VariableStmt_VariableDecl_ConstructorInvalid) {
@@ -77,7 +77,7 @@
auto e = p->variable_stmt();
ASSERT_TRUE(p->has_error());
ASSERT_EQ(e, nullptr);
- EXPECT_EQ(p->error(), "1:11: unknown type alias 'invalid'");
+ EXPECT_EQ(p->error(), "1:11: unknown constructed type 'invalid'");
}
TEST_F(ParserImplTest, VariableStmt_Const_MissingEqual) {
diff --git a/src/transform/vertex_pulling_transform.cc b/src/transform/vertex_pulling_transform.cc
index 4de12c5..45fe5d3 100644
--- a/src/transform/vertex_pulling_transform.cc
+++ b/src/transform/vertex_pulling_transform.cc
@@ -26,7 +26,6 @@
#include "src/ast/struct_decoration.h"
#include "src/ast/struct_member.h"
#include "src/ast/struct_member_offset_decoration.h"
-#include "src/ast/type/alias_type.h"
#include "src/ast/type/array_type.h"
#include "src/ast/type/f32_type.h"
#include "src/ast/type/i32_type.h"
@@ -239,14 +238,13 @@
ctx_->type_mgr().Get(std::make_unique<ast::type::StructType>(
kStructName,
std::make_unique<ast::Struct>(std::move(decos), std::move(members))));
- auto* alias = ctx_->type_mgr().Get(
- std::make_unique<ast::type::AliasType>(kStructName, struct_type));
for (uint32_t i = 0; i < vertex_state_->vertex_buffers.size(); ++i) {
// The decorated variable with struct type
auto var = std::make_unique<ast::DecoratedVariable>(
- std::make_unique<ast::Variable>(
- GetVertexBufferName(i), ast::StorageClass::kStorageBuffer, alias));
+ std::make_unique<ast::Variable>(GetVertexBufferName(i),
+ ast::StorageClass::kStorageBuffer,
+ struct_type));
// Add decorations
ast::VariableDecorationList decorations;
@@ -256,7 +254,7 @@
mod_->AddGlobalVariable(std::move(var));
}
- mod_->AddAliasType(alias->AsAlias());
+ mod_->AddConstructedType(struct_type);
}
void VertexPullingTransform::AddVertexPullingPreamble(
diff --git a/src/transform/vertex_pulling_transform_test.cc b/src/transform/vertex_pulling_transform_test.cc
index 73fdaad..3b71cd7 100644
--- a/src/transform/vertex_pulling_transform_test.cc
+++ b/src/transform/vertex_pulling_transform_test.cc
@@ -136,8 +136,7 @@
EXPECT_TRUE(transform()->Run());
EXPECT_EQ(R"(Module{
- TintVertexData -> __struct_TintVertexData
- Struct{
+ TintVertexData Struct{
[[block]]
StructMember{[[ offset 0 ]] _tint_vertex_data: __array__u32_stride_4}
}
@@ -161,7 +160,7 @@
}
_tint_pulling_vertex_buffer_0
storage_buffer
- __alias_TintVertexData__struct_TintVertexData
+ __struct_TintVertexData
}
Function main -> __void
StageDecoration{vertex}
@@ -222,8 +221,7 @@
EXPECT_TRUE(transform()->Run());
EXPECT_EQ(R"(Module{
- TintVertexData -> __struct_TintVertexData
- Struct{
+ TintVertexData Struct{
[[block]]
StructMember{[[ offset 0 ]] _tint_vertex_data: __array__u32_stride_4}
}
@@ -247,7 +245,7 @@
}
_tint_pulling_vertex_buffer_0
storage_buffer
- __alias_TintVertexData__struct_TintVertexData
+ __struct_TintVertexData
}
Function main -> __void
StageDecoration{vertex}
@@ -308,8 +306,7 @@
EXPECT_TRUE(transform()->Run());
EXPECT_EQ(R"(Module{
- TintVertexData -> __struct_TintVertexData
- Struct{
+ TintVertexData Struct{
[[block]]
StructMember{[[ offset 0 ]] _tint_vertex_data: __array__u32_stride_4}
}
@@ -333,7 +330,7 @@
}
_tint_pulling_vertex_buffer_0
storage_buffer
- __alias_TintVertexData__struct_TintVertexData
+ __struct_TintVertexData
}
Function main -> __void
StageDecoration{vertex}
@@ -424,8 +421,7 @@
EXPECT_TRUE(transform()->Run());
EXPECT_EQ(R"(Module{
- TintVertexData -> __struct_TintVertexData
- Struct{
+ TintVertexData Struct{
[[block]]
StructMember{[[ offset 0 ]] _tint_vertex_data: __array__u32_stride_4}
}
@@ -462,7 +458,7 @@
}
_tint_pulling_vertex_buffer_0
storage_buffer
- __alias_TintVertexData__struct_TintVertexData
+ __struct_TintVertexData
}
DecoratedVariable{
Decorations{
@@ -471,7 +467,7 @@
}
_tint_pulling_vertex_buffer_1
storage_buffer
- __alias_TintVertexData__struct_TintVertexData
+ __struct_TintVertexData
}
Function main -> __void
StageDecoration{vertex}
@@ -565,8 +561,7 @@
EXPECT_TRUE(transform()->Run());
EXPECT_EQ(R"(Module{
- TintVertexData -> __struct_TintVertexData
- Struct{
+ TintVertexData Struct{
[[block]]
StructMember{[[ offset 0 ]] _tint_vertex_data: __array__u32_stride_4}
}
@@ -595,7 +590,7 @@
}
_tint_pulling_vertex_buffer_0
storage_buffer
- __alias_TintVertexData__struct_TintVertexData
+ __struct_TintVertexData
}
Function main -> __void
StageDecoration{vertex}
@@ -751,8 +746,7 @@
EXPECT_TRUE(transform()->Run());
EXPECT_EQ(R"(Module{
- TintVertexData -> __struct_TintVertexData
- Struct{
+ TintVertexData Struct{
[[block]]
StructMember{[[ offset 0 ]] _tint_vertex_data: __array__u32_stride_4}
}
@@ -786,7 +780,7 @@
}
_tint_pulling_vertex_buffer_0
storage_buffer
- __alias_TintVertexData__struct_TintVertexData
+ __struct_TintVertexData
}
DecoratedVariable{
Decorations{
@@ -795,7 +789,7 @@
}
_tint_pulling_vertex_buffer_1
storage_buffer
- __alias_TintVertexData__struct_TintVertexData
+ __struct_TintVertexData
}
DecoratedVariable{
Decorations{
@@ -804,7 +798,7 @@
}
_tint_pulling_vertex_buffer_2
storage_buffer
- __alias_TintVertexData__struct_TintVertexData
+ __struct_TintVertexData
}
Function main -> __void
StageDecoration{vertex}
diff --git a/src/validator_control_block_test.cc b/src/validator_control_block_test.cc
index da45cc1..473b9e5 100644
--- a/src/validator_control_block_test.cc
+++ b/src/validator_control_block_test.cc
@@ -404,7 +404,7 @@
block->append(
std::make_unique<ast::SwitchStatement>(std::move(cond), std::move(body)));
- mod()->AddAliasType(&my_int);
+ mod()->AddConstructedType(&my_int);
EXPECT_TRUE(td()->DetermineStatements(block.get())) << td()->error();
EXPECT_TRUE(v()->ValidateStatements(block.get())) << v()->error();
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index 1ed6c02..166f2f7 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -113,12 +113,12 @@
register_global(global.get());
}
- for (auto* const alias : module_->alias_types()) {
- if (!EmitAliasType(out, alias)) {
+ for (auto* const ty : module_->constructed_types()) {
+ if (!EmitConstructedType(out, ty)) {
return false;
}
}
- if (!module_->alias_types().empty()) {
+ if (!module_->constructed_types().empty()) {
out << std::endl;
}
@@ -196,21 +196,33 @@
return name;
}
-bool GeneratorImpl::EmitAliasType(std::ostream& out,
- const ast::type::AliasType* alias) {
+bool GeneratorImpl::EmitConstructedType(std::ostream& out,
+ const ast::type::Type* ty) {
make_indent(out);
- if (alias->type()->IsStruct()) {
- if (!EmitType(out, alias->type(), namer_.NameFor(alias->name()))) {
+ if (ty->IsAlias()) {
+ auto* alias = ty->AsAlias();
+ // This will go away once type_alias doesn't accept anonymous
+ // structs anymore
+ if (alias->type()->IsStruct() &&
+ alias->type()->AsStruct()->name() == alias->name()) {
+ if (!EmitStructType(out, alias->type()->AsStruct())) {
+ return false;
+ }
+ } else {
+ out << "typedef ";
+ if (!EmitType(out, alias->type(), "")) {
+ return false;
+ }
+ out << " " << namer_.NameFor(alias->name()) << ";" << std::endl;
+ }
+ } else if (ty->IsStruct()) {
+ if (!EmitStructType(out, ty->AsStruct())) {
return false;
}
- out << ";" << std::endl;
} else {
- out << "typedef ";
- if (!EmitType(out, alias->type(), "")) {
- return false;
- }
- out << " " << namer_.NameFor(alias->name()) << ";" << std::endl;
+ error_ = "unknown constructed type: " + ty->type_name();
+ return false;
}
return true;
@@ -1942,36 +1954,7 @@
error_ = "pointers not supported in HLSL";
return false;
} else if (type->IsStruct()) {
- auto* str = type->AsStruct()->impl();
- // TODO(dsinclair): Block decoration?
- // if (str->decoration() != ast::StructDecoration::kNone) {
- // }
- out << "struct";
- // If a name was provided for the struct emit it.
- if (!name.empty()) {
- out << " " << name;
- }
- out << " {" << std::endl;
-
- increment_indent();
- for (const auto& mem : str->members()) {
- make_indent(out);
- // TODO(dsinclair): Handle [[offset]] annotation on structs
- // https://bugs.chromium.org/p/tint/issues/detail?id=184
-
- if (!EmitType(out, mem->type(), mem->name())) {
- return false;
- }
- // Array member name will be output with the type
- if (!mem->type()->IsArray()) {
- out << " " << namer_.NameFor(mem->name());
- }
- out << ";" << std::endl;
- }
- decrement_indent();
- make_indent(out);
-
- out << "}";
+ out << type->AsStruct()->name();
} else if (type->IsU32()) {
out << "uint";
} else if (type->IsVector()) {
@@ -1991,6 +1974,36 @@
return true;
}
+bool GeneratorImpl::EmitStructType(std::ostream& out,
+ const ast::type::StructType* str) {
+ // TODO(dsinclair): Block decoration?
+ // if (str->impl()->decoration() != ast::StructDecoration::kNone) {
+ // }
+ out << "struct " << str->name() << " {" << std::endl;
+
+ increment_indent();
+ for (const auto& mem : str->impl()->members()) {
+ make_indent(out);
+ // TODO(dsinclair): Handle [[offset]] annotation on structs
+ // https://bugs.chromium.org/p/tint/issues/detail?id=184
+
+ if (!EmitType(out, mem->type(), mem->name())) {
+ return false;
+ }
+ // Array member name will be output with the type
+ if (!mem->type()->IsArray()) {
+ out << " " << namer_.NameFor(mem->name());
+ }
+ out << ";" << std::endl;
+ }
+ decrement_indent();
+ make_indent(out);
+
+ out << "};" << std::endl;
+
+ return true;
+}
+
bool GeneratorImpl::EmitUnaryOp(std::ostream& pre,
std::ostream& out,
ast::UnaryOpExpression* expr) {
diff --git a/src/writer/hlsl/generator_impl.h b/src/writer/hlsl/generator_impl.h
index 4ba5176..219a613 100644
--- a/src/writer/hlsl/generator_impl.h
+++ b/src/writer/hlsl/generator_impl.h
@@ -19,6 +19,7 @@
#include "src/ast/literal.h"
#include "src/ast/module.h"
#include "src/ast/scalar_constructor_expression.h"
+#include "src/ast/type/struct_type.h"
#include "src/ast/type_constructor_expression.h"
#include "src/scope_stack.h"
#include "src/writer/hlsl/namer.h"
@@ -60,11 +61,11 @@
/// @returns true on successful generation; false otherwise
bool Generate(std::ostream& out);
- /// Handles generating an alias
+ /// Handles generating a constructed type
/// @param out the output stream
- /// @param alias the alias to generate
- /// @returns true if the alias was emitted
- bool EmitAliasType(std::ostream& out, const ast::type::AliasType* alias);
+ /// @param ty the constructed type to generate
+ /// @returns true if the constructed type was emitted
+ bool EmitConstructedType(std::ostream& out, const ast::type::Type* ty);
/// Handles an array accessor expression
/// @param pre the preamble for the expression stream
/// @param out the output of the expression stream
@@ -260,6 +261,11 @@
bool EmitType(std::ostream& out,
ast::type::Type* type,
const std::string& name);
+ /// Handles generating a structure declaration
+ /// @param out the output stream
+ /// @param ty the struct to generate
+ /// @returns true if the struct is emitted
+ bool EmitStructType(std::ostream& out, const ast::type::StructType* ty);
/// Handles a unary op expression
/// @param pre the preamble for the expression stream
/// @param out the output of the expression stream
diff --git a/src/writer/hlsl/generator_impl_alias_type_test.cc b/src/writer/hlsl/generator_impl_alias_type_test.cc
index 5dfa239..aa4c4ad 100644
--- a/src/writer/hlsl/generator_impl_alias_type_test.cc
+++ b/src/writer/hlsl/generator_impl_alias_type_test.cc
@@ -33,7 +33,7 @@
ast::type::F32Type f32;
ast::type::AliasType alias("a", &f32);
- ASSERT_TRUE(gen().EmitAliasType(out(), &alias)) << gen().error();
+ ASSERT_TRUE(gen().EmitConstructedType(out(), &alias)) << gen().error();
EXPECT_EQ(result(), R"(typedef float a;
)");
}
@@ -42,7 +42,7 @@
ast::type::F32Type f32;
ast::type::AliasType alias("float", &f32);
- ASSERT_TRUE(gen().EmitAliasType(out(), &alias)) << gen().error();
+ ASSERT_TRUE(gen().EmitConstructedType(out(), &alias)) << gen().error();
EXPECT_EQ(result(), R"(typedef float float_tint_0;
)");
}
@@ -68,7 +68,7 @@
ast::Module m;
GeneratorImpl g(&m);
- ASSERT_TRUE(gen().EmitAliasType(out(), &alias)) << gen().error();
+ ASSERT_TRUE(gen().EmitConstructedType(out(), &alias)) << gen().error();
EXPECT_EQ(result(), R"(struct a {
float a;
int b;
diff --git a/src/writer/hlsl/generator_impl_function_test.cc b/src/writer/hlsl/generator_impl_function_test.cc
index ff1412a..2558917 100644
--- a/src/writer/hlsl/generator_impl_function_test.cc
+++ b/src/writer/hlsl/generator_impl_function_test.cc
@@ -316,7 +316,7 @@
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"uniforms", ast::StorageClass::kUniform, alias.get()));
- mod()->AddAliasType(alias.get());
+ mod()->AddConstructedType(alias.get());
ast::VariableDecorationList decos;
decos.push_back(std::make_unique<ast::BindingDecoration>(0));
diff --git a/src/writer/hlsl/generator_impl_type_test.cc b/src/writer/hlsl/generator_impl_type_test.cc
index e9e86a5..716ed7c 100644
--- a/src/writer/hlsl/generator_impl_type_test.cc
+++ b/src/writer/hlsl/generator_impl_type_test.cc
@@ -163,6 +163,32 @@
EXPECT_EQ(result(), "float*");
}
+TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl) {
+ ast::type::I32Type i32;
+ ast::type::F32Type f32;
+
+ ast::StructMemberList members;
+ members.push_back(std::make_unique<ast::StructMember>(
+ "a", &i32, ast::StructMemberDecorationList{}));
+
+ ast::StructMemberDecorationList b_deco;
+ b_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(4));
+ members.push_back(
+ std::make_unique<ast::StructMember>("b", &f32, std::move(b_deco)));
+
+ auto str = std::make_unique<ast::Struct>();
+ str->set_members(std::move(members));
+
+ ast::type::StructType s("S", std::move(str));
+
+ ASSERT_TRUE(gen().EmitStructType(out(), &s)) << gen().error();
+ EXPECT_EQ(result(), R"(struct S {
+ int a;
+ float b;
+};
+)");
+}
+
TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct) {
ast::type::I32Type i32;
ast::type::F32Type f32;
@@ -182,10 +208,7 @@
ast::type::StructType s("S", std::move(str));
ASSERT_TRUE(gen().EmitType(out(), &s, "")) << gen().error();
- EXPECT_EQ(result(), R"(struct {
- int a;
- float b;
-})");
+ EXPECT_EQ(result(), "S");
}
TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Struct_InjectPadding) {
@@ -240,11 +263,12 @@
ast::type::StructType s("S", std::move(str));
- ASSERT_TRUE(gen().EmitType(out(), &s, "")) << gen().error();
- EXPECT_EQ(result(), R"(struct {
+ ASSERT_TRUE(gen().EmitStructType(out(), &s)) << gen().error();
+ EXPECT_EQ(result(), R"(struct S {
int double_tint_0;
float float_tint_0;
-})");
+};
+)");
}
// TODO(dsinclair): How to translate [[block]]
@@ -269,8 +293,8 @@
ast::type::StructType s("S", std::move(str));
- ASSERT_TRUE(gen().EmitType(out(), &s, "")) << gen().error();
- EXPECT_EQ(result(), R"(struct {
+ ASSERT_TRUE(gen().EmitStructType(out(), &s)) << gen().error();
+ EXPECT_EQ(result(), R"(struct S {
int a;
float b;
})");
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index 092a487..0771d41 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -103,12 +103,12 @@
global_variables_.set(global->name(), global.get());
}
- for (auto* const alias : module_->alias_types()) {
- if (!EmitAliasType(alias)) {
+ for (auto* const ty : module_->constructed_types()) {
+ if (!EmitConstructedType(ty)) {
return false;
}
}
- if (!module_->alias_types().empty()) {
+ if (!module_->constructed_types().empty()) {
out_ << std::endl;
}
@@ -239,13 +239,33 @@
return 0;
}
-bool GeneratorImpl::EmitAliasType(const ast::type::AliasType* alias) {
+bool GeneratorImpl::EmitConstructedType(const ast::type::Type* ty) {
make_indent();
- out_ << "typedef ";
- if (!EmitType(alias->type(), "")) {
+
+ if (ty->IsAlias()) {
+ auto* alias = ty->AsAlias();
+
+ // This will go away once type_alias does not accept anonymous structs
+ if (alias->type()->IsStruct() &&
+ alias->type()->AsStruct()->name() == alias->name()) {
+ if (!EmitStructType(alias->type()->AsStruct())) {
+ return false;
+ }
+ } else {
+ out_ << "typedef ";
+ if (!EmitType(alias->type(), "")) {
+ return false;
+ }
+ out_ << " " << namer_.NameFor(alias->name()) << ";" << std::endl;
+ }
+ } else if (ty->IsStruct()) {
+ if (!EmitStructType(ty->AsStruct())) {
+ return false;
+ }
+ } else {
+ error_ = "unknown alias type: " + ty->type_name();
return false;
}
- out_ << " " << namer_.NameFor(alias->name()) << ";" << std::endl;
return true;
}
@@ -1701,54 +1721,10 @@
}
out_ << "*";
} else if (type->IsStruct()) {
- auto* str = type->AsStruct()->impl();
- // TODO(dsinclair): Block decoration?
- // if (str->decoration() != ast::StructDecoration::kNone) {
- // }
- out_ << "struct {" << std::endl;
+ // The struct type emits as just the name. The declaration would be emitted
+ // as part of emitting the constructed types.
+ out_ << type->AsStruct()->name();
- increment_indent();
- uint32_t current_offset = 0;
- uint32_t pad_count = 0;
- for (const auto& mem : str->members()) {
- make_indent();
- for (const auto& deco : mem->decorations()) {
- if (deco->IsOffset()) {
- uint32_t offset = deco->AsOffset()->offset();
- if (offset != current_offset) {
- out_ << "int8_t pad_" << pad_count << "["
- << (offset - current_offset) << "];" << std::endl;
- pad_count++;
- make_indent();
- }
- current_offset = offset;
- } else {
- error_ = "unsupported member decoration: " + deco->to_str();
- return false;
- }
- }
-
- if (!EmitType(mem->type(), mem->name())) {
- return false;
- }
- auto size = calculate_alignment_size(mem->type());
- if (size == 0) {
- error_ =
- "unable to calculate byte size for: " + mem->type()->type_name();
- return false;
- }
- current_offset += size;
-
- // Array member name will be output with the type
- if (!mem->type()->IsArray()) {
- out_ << " " << namer_.NameFor(mem->name());
- }
- out_ << ";" << std::endl;
- }
- decrement_indent();
- make_indent();
-
- out_ << "}";
} else if (type->IsU32()) {
out_ << "uint";
} else if (type->IsVector()) {
@@ -1767,6 +1743,56 @@
return true;
}
+bool GeneratorImpl::EmitStructType(const ast::type::StructType* str) {
+ // TODO(dsinclair): Block decoration?
+ // if (str->impl()->decoration() != ast::StructDecoration::kNone) {
+ // }
+ out_ << "struct " << str->name() << " {" << std::endl;
+
+ increment_indent();
+ uint32_t current_offset = 0;
+ uint32_t pad_count = 0;
+ for (const auto& mem : str->impl()->members()) {
+ make_indent();
+ for (const auto& deco : mem->decorations()) {
+ if (deco->IsOffset()) {
+ uint32_t offset = deco->AsOffset()->offset();
+ if (offset != current_offset) {
+ out_ << "int8_t pad_" << pad_count << "[" << (offset - current_offset)
+ << "];" << std::endl;
+ pad_count++;
+ make_indent();
+ }
+ current_offset = offset;
+ } else {
+ error_ = "unsupported member decoration: " + deco->to_str();
+ return false;
+ }
+ }
+
+ if (!EmitType(mem->type(), mem->name())) {
+ return false;
+ }
+ auto size = calculate_alignment_size(mem->type());
+ if (size == 0) {
+ error_ = "unable to calculate byte size for: " + mem->type()->type_name();
+ return false;
+ }
+ current_offset += size;
+
+ // Array member name will be output with the type
+ if (!mem->type()->IsArray()) {
+ out_ << " " << namer_.NameFor(mem->name());
+ }
+ out_ << ";" << std::endl;
+ }
+ decrement_indent();
+ make_indent();
+
+ out_ << "};" << std::endl;
+ return true;
+}
+
bool GeneratorImpl::EmitUnaryOp(ast::UnaryOpExpression* expr) {
switch (expr->op()) {
case ast::UnaryOp::kNot:
diff --git a/src/writer/msl/generator_impl.h b/src/writer/msl/generator_impl.h
index 3582e19..5fabad8 100644
--- a/src/writer/msl/generator_impl.h
+++ b/src/writer/msl/generator_impl.h
@@ -54,10 +54,10 @@
/// @returns the largest alignment value
uint32_t calculate_largest_alignment(ast::type::StructType* type);
- /// Handles generating an alias
- /// @param alias the alias to generate
- /// @returns true if the alias was emitted
- bool EmitAliasType(const ast::type::AliasType* alias);
+ /// Handles generating a constructed
+ /// @param ty the constructed type to generate
+ /// @returns true if the constructed type was emitted
+ bool EmitConstructedType(const ast::type::Type* ty);
/// Handles an array accessor expression
/// @param expr the expression to emit
/// @returns true if the array accessor was emitted
@@ -183,6 +183,10 @@
/// @param name the name of the variable, only used for array emission
/// @returns true if the type is emitted
bool EmitType(ast::type::Type* type, const std::string& name);
+ /// Handles generating a struct declaration
+ /// @param str the struct to generate
+ /// @returns true if the struct is emitted
+ bool EmitStructType(const ast::type::StructType* str);
/// Handles emitting a type constructor
/// @param expr the type constructor expression
/// @returns true if the constructor is emitted
diff --git a/src/writer/msl/generator_impl_alias_type_test.cc b/src/writer/msl/generator_impl_alias_type_test.cc
index 8b791df..0eec82f2 100644
--- a/src/writer/msl/generator_impl_alias_type_test.cc
+++ b/src/writer/msl/generator_impl_alias_type_test.cc
@@ -30,29 +30,57 @@
using MslGeneratorImplTest = testing::Test;
-TEST_F(MslGeneratorImplTest, EmitAliasType_F32) {
+TEST_F(MslGeneratorImplTest, EmitConstructedType_F32) {
ast::type::F32Type f32;
ast::type::AliasType alias("a", &f32);
ast::Module m;
GeneratorImpl g(&m);
- ASSERT_TRUE(g.EmitAliasType(&alias)) << g.error();
+ ASSERT_TRUE(g.EmitConstructedType(&alias)) << g.error();
EXPECT_EQ(g.result(), R"(typedef float a;
)");
}
-TEST_F(MslGeneratorImplTest, EmitAliasType_NameCollision) {
+TEST_F(MslGeneratorImplTest, EmitConstructedType_NameCollision) {
ast::type::F32Type f32;
ast::type::AliasType alias("float", &f32);
ast::Module m;
GeneratorImpl g(&m);
- ASSERT_TRUE(g.EmitAliasType(&alias)) << g.error();
+ ASSERT_TRUE(g.EmitConstructedType(&alias)) << g.error();
EXPECT_EQ(g.result(), R"(typedef float float_tint_0;
)");
}
-TEST_F(MslGeneratorImplTest, EmitAliasType_Struct) {
+TEST_F(MslGeneratorImplTest, EmitConstructedType_Struct) {
+ ast::type::I32Type i32;
+ ast::type::F32Type f32;
+
+ ast::StructMemberList members;
+ members.push_back(std::make_unique<ast::StructMember>(
+ "a", &f32, ast::StructMemberDecorationList{}));
+
+ ast::StructMemberDecorationList b_deco;
+ b_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(4));
+ members.push_back(
+ std::make_unique<ast::StructMember>("b", &i32, std::move(b_deco)));
+
+ auto str = std::make_unique<ast::Struct>();
+ str->set_members(std::move(members));
+
+ ast::type::StructType s("a", std::move(str));
+
+ ast::Module m;
+ GeneratorImpl g(&m);
+ ASSERT_TRUE(g.EmitConstructedType(&s)) << g.error();
+ EXPECT_EQ(g.result(), R"(struct a {
+ float a;
+ int b;
+};
+)");
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructedType_AliasMatchStruct) {
ast::type::I32Type i32;
ast::type::F32Type f32;
@@ -73,11 +101,37 @@
ast::Module m;
GeneratorImpl g(&m);
- ASSERT_TRUE(g.EmitAliasType(&alias)) << g.error();
- EXPECT_EQ(g.result(), R"(typedef struct {
+ ASSERT_TRUE(g.EmitConstructedType(&alias)) << g.error();
+ EXPECT_EQ(g.result(), R"(struct a {
float a;
int b;
-} a;
+};
+)");
+}
+
+TEST_F(MslGeneratorImplTest, EmitConstructedType_AliasStructIdent) {
+ ast::type::I32Type i32;
+ ast::type::F32Type f32;
+
+ ast::StructMemberList members;
+ members.push_back(std::make_unique<ast::StructMember>(
+ "a", &f32, ast::StructMemberDecorationList{}));
+
+ ast::StructMemberDecorationList b_deco;
+ b_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(4));
+ members.push_back(
+ std::make_unique<ast::StructMember>("b", &i32, std::move(b_deco)));
+
+ auto str = std::make_unique<ast::Struct>();
+ str->set_members(std::move(members));
+
+ ast::type::StructType s("b", std::move(str));
+ ast::type::AliasType alias("a", &s);
+
+ ast::Module m;
+ GeneratorImpl g(&m);
+ ASSERT_TRUE(g.EmitConstructedType(&alias)) << g.error();
+ EXPECT_EQ(g.result(), R"(typedef b a;
)");
}
diff --git a/src/writer/msl/generator_impl_type_test.cc b/src/writer/msl/generator_impl_type_test.cc
index baa6fb3..d49714e 100644
--- a/src/writer/msl/generator_impl_type_test.cc
+++ b/src/writer/msl/generator_impl_type_test.cc
@@ -213,10 +213,35 @@
ast::Module m;
GeneratorImpl g(&m);
ASSERT_TRUE(g.EmitType(&s, "")) << g.error();
- EXPECT_EQ(g.result(), R"(struct {
+ EXPECT_EQ(g.result(), "S");
+}
+
+TEST_F(MslGeneratorImplTest, EmitType_StructDecl) {
+ ast::type::I32Type i32;
+ ast::type::F32Type f32;
+
+ ast::StructMemberList members;
+ members.push_back(std::make_unique<ast::StructMember>(
+ "a", &i32, ast::StructMemberDecorationList{}));
+
+ ast::StructMemberDecorationList b_deco;
+ b_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(4));
+ members.push_back(
+ std::make_unique<ast::StructMember>("b", &f32, std::move(b_deco)));
+
+ auto str = std::make_unique<ast::Struct>();
+ str->set_members(std::move(members));
+
+ ast::type::StructType s("S", std::move(str));
+
+ ast::Module m;
+ GeneratorImpl g(&m);
+ ASSERT_TRUE(g.EmitStructType(&s)) << g.error();
+ EXPECT_EQ(g.result(), R"(struct S {
int a;
float b;
-})");
+};
+)");
}
TEST_F(MslGeneratorImplTest, EmitType_Struct_InjectPadding) {
@@ -245,15 +270,16 @@
ast::Module m;
GeneratorImpl g(&m);
- ASSERT_TRUE(g.EmitType(&s, "")) << g.error();
- EXPECT_EQ(g.result(), R"(struct {
+ ASSERT_TRUE(g.EmitStructType(&s)) << g.error();
+ EXPECT_EQ(g.result(), R"(struct S {
int8_t pad_0[4];
int a;
int8_t pad_1[24];
float b;
int8_t pad_2[92];
float c;
-})");
+};
+)");
}
TEST_F(MslGeneratorImplTest, EmitType_Struct_NameCollision) {
@@ -275,11 +301,12 @@
ast::Module m;
GeneratorImpl g(&m);
- ASSERT_TRUE(g.EmitType(&s, "")) << g.error();
- EXPECT_EQ(g.result(), R"(struct {
+ ASSERT_TRUE(g.EmitStructType(&s)) << g.error();
+ EXPECT_EQ(g.result(), R"(struct S {
int main_tint_0;
float float_tint_0;
-})");
+};
+)");
}
// TODO(dsinclair): How to translate [[block]]
diff --git a/src/writer/msl/generator_impl_variable_decl_statement_test.cc b/src/writer/msl/generator_impl_variable_decl_statement_test.cc
index 68606a7..50b20f9 100644
--- a/src/writer/msl/generator_impl_variable_decl_statement_test.cc
+++ b/src/writer/msl/generator_impl_variable_decl_statement_test.cc
@@ -113,10 +113,7 @@
g.increment_indent();
ASSERT_TRUE(g.EmitStatement(&stmt)) << g.error();
- EXPECT_EQ(g.result(), R"( struct {
- float a;
- float b;
- } a = {};
+ EXPECT_EQ(g.result(), R"( S a = {};
)");
}
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index b0a32f6..8708769 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -2410,11 +2410,6 @@
{result, Operand::Int(elem_type), Operand::Int(len_id)});
}
- // SPIR-V explicitly requires no array stride if the array contains a struct
- // which has a Block decoration.
- if (ary->type()->IsStruct() && ary->type()->AsStruct()->IsBlockDecorated()) {
- return true;
- }
if (ary->has_array_stride()) {
push_annot(spv::Op::OpDecorate,
{Operand::Int(result_id), Operand::Int(SpvDecorationArrayStride),
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index ae92972..f820017 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -76,12 +76,12 @@
GeneratorImpl::~GeneratorImpl() = default;
bool GeneratorImpl::Generate(const ast::Module& module) {
- for (auto* const alias : module.alias_types()) {
- if (!EmitAliasType(alias)) {
+ for (auto* const ty : module.constructed_types()) {
+ if (!EmitConstructedType(ty)) {
return false;
}
}
- if (!module.alias_types().empty())
+ if (!module.constructed_types().empty())
out_ << std::endl;
for (const auto& var : module.global_variables()) {
@@ -112,13 +112,14 @@
return false;
}
- // TODO(dsinclair): We always emit aliases even if they aren't strictly needed
- for (auto* const alias : module.alias_types()) {
- if (!EmitAliasType(alias)) {
+ // TODO(dsinclair): We always emit constructed types even if they aren't
+ // strictly needed
+ for (auto* const ty : module.constructed_types()) {
+ if (!EmitConstructedType(ty)) {
return false;
}
}
- if (!module.alias_types().empty()) {
+ if (!module.constructed_types().empty()) {
out_ << std::endl;
}
@@ -163,13 +164,33 @@
return true;
}
-bool GeneratorImpl::EmitAliasType(const ast::type::AliasType* alias) {
+bool GeneratorImpl::EmitConstructedType(const ast::type::Type* ty) {
make_indent();
- out_ << "type " << alias->name() << " = ";
- if (!EmitType(alias->type())) {
+ if (ty->IsAlias()) {
+ auto* alias = ty->AsAlias();
+ // Emitting an alias to a struct where the names are the same means we can
+ // skip emitting the alias and just emit the struct. This will go away once
+ // the anonymous structs are removed from the type alias
+ if (alias->type()->IsStruct() &&
+ alias->type()->AsStruct()->name() == alias->name()) {
+ if (!EmitStructType(alias->type()->AsStruct())) {
+ return false;
+ }
+ } else {
+ out_ << "type " << alias->name() << " = ";
+ if (!EmitType(alias->type())) {
+ return false;
+ }
+ out_ << ";" << std::endl;
+ }
+ } else if (ty->IsStruct()) {
+ if (!EmitStructType(ty->AsStruct())) {
+ return false;
+ }
+ } else {
+ error_ = "unknown constructed type: " + ty->type_name();
return false;
}
- out_ << ";" << std::endl;
return true;
}
@@ -391,8 +412,7 @@
bool GeneratorImpl::EmitType(ast::type::Type* type) {
if (type->IsAlias()) {
- auto* alias = type->AsAlias();
- out_ << alias->name();
+ out_ << type->AsAlias()->name();
} else if (type->IsArray()) {
auto* ary = type->AsArray();
@@ -439,32 +459,9 @@
out_ << "_comparison";
}
} else if (type->IsStruct()) {
- auto* str = type->AsStruct()->impl();
- for (auto deco : str->decorations()) {
- out_ << "[[" << deco << "]]" << std::endl;
- }
- out_ << "struct {" << std::endl;
-
- increment_indent();
- for (const auto& mem : str->members()) {
- for (const auto& deco : mem->decorations()) {
- make_indent();
-
- // TODO(dsinclair): Split this out when we have more then one
- assert(deco->IsOffset());
- out_ << "[[offset(" << deco->AsOffset()->offset() << ")]]" << std::endl;
- }
- make_indent();
- out_ << mem->name() << " : ";
- if (!EmitType(mem->type())) {
- return false;
- }
- out_ << ";" << std::endl;
- }
- decrement_indent();
- make_indent();
-
- out_ << "}";
+ // The struct, as a type, is just the name. We should have already emitted
+ // the declaration through a call to |EmitStructType| earlier.
+ out_ << type->AsStruct()->name();
} else if (type->IsTexture()) {
auto* texture = type->AsTexture();
@@ -563,6 +560,36 @@
return true;
}
+bool GeneratorImpl::EmitStructType(const ast::type::StructType* str) {
+ auto* impl = str->impl();
+ for (auto deco : impl->decorations()) {
+ out_ << "[[" << deco << "]]" << std::endl;
+ }
+ out_ << "struct " << str->name() << " {" << std::endl;
+
+ increment_indent();
+ for (const auto& mem : impl->members()) {
+ for (const auto& deco : mem->decorations()) {
+ make_indent();
+
+ // TODO(dsinclair): Split this out when we have more then one
+ assert(deco->IsOffset());
+ out_ << "[[offset(" << deco->AsOffset()->offset() << ")]]" << std::endl;
+ }
+ make_indent();
+ out_ << mem->name() << " : ";
+ if (!EmitType(mem->type())) {
+ return false;
+ }
+ out_ << ";" << std::endl;
+ }
+ decrement_indent();
+ make_indent();
+
+ out_ << "};" << std::endl;
+ return true;
+}
+
bool GeneratorImpl::EmitVariable(ast::Variable* var) {
make_indent();
diff --git a/src/writer/wgsl/generator_impl.h b/src/writer/wgsl/generator_impl.h
index 37be9cb..081ac4d 100644
--- a/src/writer/wgsl/generator_impl.h
+++ b/src/writer/wgsl/generator_impl.h
@@ -23,8 +23,8 @@
#include "src/ast/identifier_expression.h"
#include "src/ast/module.h"
#include "src/ast/scalar_constructor_expression.h"
-#include "src/ast/type/alias_type.h"
#include "src/ast/type/storage_texture_type.h"
+#include "src/ast/type/struct_type.h"
#include "src/ast/type/type.h"
#include "src/ast/type_constructor_expression.h"
#include "src/ast/variable.h"
@@ -55,10 +55,10 @@
ast::PipelineStage stage,
const std::string& name);
- /// Handles generating an alias
- /// @param alias the alias to generate
- /// @returns true if the alias was emitted
- bool EmitAliasType(const ast::type::AliasType* alias);
+ /// Handles generating a constructed type
+ /// @param ty the constructed to generate
+ /// @returns true if the constructed was emitted
+ bool EmitConstructedType(const ast::type::Type* ty);
/// Handles an array accessor expression
/// @param expr the expression to emit
/// @returns true if the array accessor was emitted
@@ -167,6 +167,10 @@
/// @param type the type to generate
/// @returns true if the type is emitted
bool EmitType(ast::type::Type* type);
+ /// Handles generating a struct declaration
+ /// @param str the struct
+ /// @returns true if the struct is emitted
+ bool EmitStructType(const ast::type::StructType* str);
/// Handles emitting an image format
/// @param fmt the format to generate
/// @returns true if the format is emitted
diff --git a/src/writer/wgsl/generator_impl_alias_type_test.cc b/src/writer/wgsl/generator_impl_alias_type_test.cc
index 777aec1..4b0d69a 100644
--- a/src/writer/wgsl/generator_impl_alias_type_test.cc
+++ b/src/writer/wgsl/generator_impl_alias_type_test.cc
@@ -34,11 +34,43 @@
ast::type::AliasType alias("a", &f32);
GeneratorImpl g;
- ASSERT_TRUE(g.EmitAliasType(&alias)) << g.error();
+ ASSERT_TRUE(g.EmitConstructedType(&alias)) << g.error();
EXPECT_EQ(g.result(), R"(type a = f32;
)");
}
+TEST_F(WgslGeneratorImplTest, EmitAliasType_Struct_Ident) {
+ ast::type::I32Type i32;
+ ast::type::F32Type f32;
+
+ ast::StructMemberList members;
+ members.push_back(std::make_unique<ast::StructMember>(
+ "a", &f32, ast::StructMemberDecorationList{}));
+
+ ast::StructMemberDecorationList b_deco;
+ b_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(4));
+ members.push_back(
+ std::make_unique<ast::StructMember>("b", &i32, std::move(b_deco)));
+
+ auto str = std::make_unique<ast::Struct>();
+ str->set_members(std::move(members));
+
+ ast::type::StructType s("A", std::move(str));
+ ast::type::AliasType alias("B", &s);
+
+ GeneratorImpl g;
+ ASSERT_TRUE(g.EmitConstructedType(&s)) << g.error();
+ ASSERT_TRUE(g.EmitConstructedType(&alias)) << g.error();
+ EXPECT_EQ(g.result(), R"(struct A {
+ a : f32;
+ [[offset(4)]]
+ b : i32;
+};
+type B = A;
+)");
+}
+
+// This should go away once type_alias'd anonymous structs are removed.
TEST_F(WgslGeneratorImplTest, EmitAliasType_Struct) {
ast::type::I32Type i32;
ast::type::F32Type f32;
@@ -55,12 +87,12 @@
auto str = std::make_unique<ast::Struct>();
str->set_members(std::move(members));
- ast::type::StructType s("a", std::move(str));
- ast::type::AliasType alias("a", &s);
+ ast::type::StructType s("A", std::move(str));
+ ast::type::AliasType alias("A", &s);
GeneratorImpl g;
- ASSERT_TRUE(g.EmitAliasType(&alias)) << g.error();
- EXPECT_EQ(g.result(), R"(type a = struct {
+ ASSERT_TRUE(g.EmitConstructedType(&alias)) << g.error();
+ EXPECT_EQ(g.result(), R"(struct A {
a : f32;
[[offset(4)]]
b : i32;
diff --git a/src/writer/wgsl/generator_impl_type_test.cc b/src/writer/wgsl/generator_impl_type_test.cc
index 816a041..dd8eb0e 100644
--- a/src/writer/wgsl/generator_impl_type_test.cc
+++ b/src/writer/wgsl/generator_impl_type_test.cc
@@ -159,11 +159,35 @@
GeneratorImpl g;
ASSERT_TRUE(g.EmitType(&s)) << g.error();
- EXPECT_EQ(g.result(), R"(struct {
+ EXPECT_EQ(g.result(), "S");
+}
+
+TEST_F(WgslGeneratorImplTest, EmitType_StructDecl) {
+ ast::type::I32Type i32;
+ ast::type::F32Type f32;
+
+ ast::StructMemberList members;
+ members.push_back(std::make_unique<ast::StructMember>(
+ "a", &i32, ast::StructMemberDecorationList{}));
+
+ ast::StructMemberDecorationList b_deco;
+ b_deco.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(4));
+ members.push_back(
+ std::make_unique<ast::StructMember>("b", &f32, std::move(b_deco)));
+
+ auto str = std::make_unique<ast::Struct>();
+ str->set_members(std::move(members));
+
+ ast::type::StructType s("S", std::move(str));
+
+ GeneratorImpl g;
+ ASSERT_TRUE(g.EmitStructType(&s)) << g.error();
+ EXPECT_EQ(g.result(), R"(struct S {
a : i32;
[[offset(4)]]
b : f32;
-})");
+};
+)");
}
TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithDecoration) {
@@ -188,13 +212,14 @@
ast::type::StructType s("S", std::move(str));
GeneratorImpl g;
- ASSERT_TRUE(g.EmitType(&s)) << g.error();
+ ASSERT_TRUE(g.EmitStructType(&s)) << g.error();
EXPECT_EQ(g.result(), R"([[block]]
-struct {
+struct S {
a : i32;
[[offset(4)]]
b : f32;
-})");
+};
+)");
}
TEST_F(WgslGeneratorImplTest, EmitType_U32) {
diff --git a/test/compute_boids.wgsl b/test/compute_boids.wgsl
index 653ae85..1d32673 100644
--- a/test/compute_boids.wgsl
+++ b/test/compute_boids.wgsl
@@ -39,12 +39,12 @@
}
# compute shader
-type Particle = [[block]] struct {
+[[block]] struct Particle {
[[offset(0)]] pos : vec2<f32>;
[[offset(8)]] vel : vec2<f32>;
};
-type SimParams = [[block]] struct {
+[[block]] struct SimParams {
[[offset(0)]] deltaT : f32;
[[offset(4)]] rule1Distance : f32;
[[offset(8)]] rule2Distance : f32;
@@ -54,7 +54,7 @@
[[offset(24)]] rule3Scale : f32;
};
-type Particles = [[block]] struct {
+[[block]] struct Particles {
[[offset(0)]] particles : [[stride(16)]] array<Particle, 5>;
};
diff --git a/test/cube.wgsl b/test/cube.wgsl
index 1a86a89..eb67254 100644
--- a/test/cube.wgsl
+++ b/test/cube.wgsl
@@ -13,7 +13,7 @@
# limitations under the License.
# Vertex shader
-type Uniforms = [[block]] struct {
+[[block]] struct Uniforms {
[[offset(0)]] modelViewProjectionMatrix : mat4x4<f32>;
};