Add base class for sem Struct and StructMember

This CL splits the sem::Struct and sem::StructMember classes into having
a base class and a sem variant. The sem variant contains the
`ast::Declaration` for that sem node. This will allow the base classes
to move into the type hierarchy and keep the sem specific requirements
in the sem folder.

Bug: tint:1718
Change-Id: I83294e957a52b87b8536dbb3582daa06a8516253
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/112860
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Ben Clayton <bclayton@google.com>
This commit is contained in:
dan sinclair 2022-12-06 20:01:54 +00:00 committed by Dawn LUCI CQ
parent c07de73b0b
commit ad9cd0a141
25 changed files with 277 additions and 199 deletions

View File

@ -55,7 +55,7 @@ TEST_F(ResolverAtomicTest, GlobalStorageStruct) {
ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>()); ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
auto* str = TypeOf(g)->UnwrapRef()->As<sem::Struct>(); auto* str = TypeOf(g)->UnwrapRef()->As<sem::Struct>();
ASSERT_NE(str, nullptr); ASSERT_NE(str, nullptr);
ASSERT_EQ(str->Members().size(), 1u); ASSERT_EQ(str->Members().Length(), 1u);
auto* atomic = str->Members()[0]->Type()->As<sem::Atomic>(); auto* atomic = str->Members()[0]->Type()->As<sem::Atomic>();
ASSERT_NE(atomic, nullptr); ASSERT_NE(atomic, nullptr);
ASSERT_TRUE(atomic->Type()->Is<sem::I32>()); ASSERT_TRUE(atomic->Type()->Is<sem::I32>());

View File

@ -926,7 +926,7 @@ TEST_F(ResolverBuiltinFloatTest, FrexpScalar_f32) {
ASSERT_NE(TypeOf(call), nullptr); ASSERT_NE(TypeOf(call), nullptr);
auto* ty = TypeOf(call)->As<sem::Struct>(); auto* ty = TypeOf(call)->As<sem::Struct>();
ASSERT_NE(ty, nullptr); ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().size(), 2u); ASSERT_EQ(ty->Members().Length(), 2u);
auto* fract = ty->Members()[0]; auto* fract = ty->Members()[0];
EXPECT_TRUE(fract->Type()->Is<sem::F32>()); EXPECT_TRUE(fract->Type()->Is<sem::F32>());
@ -957,7 +957,7 @@ TEST_F(ResolverBuiltinFloatTest, FrexpScalar_f16) {
ASSERT_NE(TypeOf(call), nullptr); ASSERT_NE(TypeOf(call), nullptr);
auto* ty = TypeOf(call)->As<sem::Struct>(); auto* ty = TypeOf(call)->As<sem::Struct>();
ASSERT_NE(ty, nullptr); ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().size(), 2u); ASSERT_EQ(ty->Members().Length(), 2u);
auto* fract = ty->Members()[0]; auto* fract = ty->Members()[0];
EXPECT_TRUE(fract->Type()->Is<sem::F16>()); EXPECT_TRUE(fract->Type()->Is<sem::F16>());
@ -986,7 +986,7 @@ TEST_F(ResolverBuiltinFloatTest, FrexpVector_f32) {
ASSERT_NE(TypeOf(call), nullptr); ASSERT_NE(TypeOf(call), nullptr);
auto* ty = TypeOf(call)->As<sem::Struct>(); auto* ty = TypeOf(call)->As<sem::Struct>();
ASSERT_NE(ty, nullptr); ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().size(), 2u); ASSERT_EQ(ty->Members().Length(), 2u);
auto* fract = ty->Members()[0]; auto* fract = ty->Members()[0];
ASSERT_TRUE(fract->Type()->Is<sem::Vector>()); ASSERT_TRUE(fract->Type()->Is<sem::Vector>());
@ -1021,7 +1021,7 @@ TEST_F(ResolverBuiltinFloatTest, FrexpVector_f16) {
ASSERT_NE(TypeOf(call), nullptr); ASSERT_NE(TypeOf(call), nullptr);
auto* ty = TypeOf(call)->As<sem::Struct>(); auto* ty = TypeOf(call)->As<sem::Struct>();
ASSERT_NE(ty, nullptr); ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().size(), 2u); ASSERT_EQ(ty->Members().Length(), 2u);
auto* fract = ty->Members()[0]; auto* fract = ty->Members()[0];
ASSERT_TRUE(fract->Type()->Is<sem::Vector>()); ASSERT_TRUE(fract->Type()->Is<sem::Vector>());
@ -1058,7 +1058,7 @@ TEST_F(ResolverBuiltinFloatTest, FrexpVector_sig) {
ASSERT_NE(TypeOf(call), nullptr); ASSERT_NE(TypeOf(call), nullptr);
auto* ty = TypeOf(call)->As<sem::Struct>(); auto* ty = TypeOf(call)->As<sem::Struct>();
ASSERT_NE(ty, nullptr); ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().size(), 2u); ASSERT_EQ(ty->Members().Length(), 2u);
auto* sig = ty->Members()[0]; auto* sig = ty->Members()[0];
EXPECT_TYPE(sig->Type(), TypeOf(expr)); EXPECT_TYPE(sig->Type(), TypeOf(expr));
@ -1198,7 +1198,7 @@ TEST_F(ResolverBuiltinFloatTest, ModfScalar_f32) {
ASSERT_NE(TypeOf(call), nullptr); ASSERT_NE(TypeOf(call), nullptr);
auto* ty = TypeOf(call)->As<sem::Struct>(); auto* ty = TypeOf(call)->As<sem::Struct>();
ASSERT_NE(ty, nullptr); ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().size(), 2u); ASSERT_EQ(ty->Members().Length(), 2u);
auto* fract = ty->Members()[0]; auto* fract = ty->Members()[0];
EXPECT_TRUE(fract->Type()->Is<sem::F32>()); EXPECT_TRUE(fract->Type()->Is<sem::F32>());
@ -1229,7 +1229,7 @@ TEST_F(ResolverBuiltinFloatTest, ModfScalar_f16) {
ASSERT_NE(TypeOf(call), nullptr); ASSERT_NE(TypeOf(call), nullptr);
auto* ty = TypeOf(call)->As<sem::Struct>(); auto* ty = TypeOf(call)->As<sem::Struct>();
ASSERT_NE(ty, nullptr); ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().size(), 2u); ASSERT_EQ(ty->Members().Length(), 2u);
auto* fract = ty->Members()[0]; auto* fract = ty->Members()[0];
EXPECT_TRUE(fract->Type()->Is<sem::F16>()); EXPECT_TRUE(fract->Type()->Is<sem::F16>());
@ -1258,7 +1258,7 @@ TEST_F(ResolverBuiltinFloatTest, ModfVector_f32) {
ASSERT_NE(TypeOf(call), nullptr); ASSERT_NE(TypeOf(call), nullptr);
auto* ty = TypeOf(call)->As<sem::Struct>(); auto* ty = TypeOf(call)->As<sem::Struct>();
ASSERT_NE(ty, nullptr); ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().size(), 2u); ASSERT_EQ(ty->Members().Length(), 2u);
auto* fract = ty->Members()[0]; auto* fract = ty->Members()[0];
ASSERT_TRUE(fract->Type()->Is<sem::Vector>()); ASSERT_TRUE(fract->Type()->Is<sem::Vector>());
@ -1293,7 +1293,7 @@ TEST_F(ResolverBuiltinFloatTest, ModfVector_f16) {
ASSERT_NE(TypeOf(call), nullptr); ASSERT_NE(TypeOf(call), nullptr);
auto* ty = TypeOf(call)->As<sem::Struct>(); auto* ty = TypeOf(call)->As<sem::Struct>();
ASSERT_NE(ty, nullptr); ASSERT_NE(ty, nullptr);
ASSERT_EQ(ty->Members().size(), 2u); ASSERT_EQ(ty->Members().Length(), 2u);
auto* fract = ty->Members()[0]; auto* fract = ty->Members()[0];
ASSERT_TRUE(fract->Type()->Is<sem::Vector>()); ASSERT_TRUE(fract->Type()->Is<sem::Vector>());

View File

@ -892,8 +892,8 @@ TEST_F(ResolverBuiltinsValidationTest, Frexp_Scalar) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
auto* res_ty = TypeOf(builtin)->As<sem::Struct>(); auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
ASSERT_TRUE(res_ty != nullptr); ASSERT_TRUE(res_ty != nullptr);
auto& members = res_ty->Members(); auto members = res_ty->Members();
ASSERT_EQ(members.size(), 2u); ASSERT_EQ(members.Length(), 2u);
EXPECT_TRUE(members[0]->Type()->Is<sem::F32>()); EXPECT_TRUE(members[0]->Type()->Is<sem::F32>());
EXPECT_TRUE(members[1]->Type()->Is<sem::I32>()); EXPECT_TRUE(members[1]->Type()->Is<sem::I32>());
} }
@ -905,8 +905,8 @@ TEST_F(ResolverBuiltinsValidationTest, Frexp_Vec2) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
auto* res_ty = TypeOf(builtin)->As<sem::Struct>(); auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
ASSERT_TRUE(res_ty != nullptr); ASSERT_TRUE(res_ty != nullptr);
auto& members = res_ty->Members(); auto members = res_ty->Members();
ASSERT_EQ(members.size(), 2u); ASSERT_EQ(members.Length(), 2u);
ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>()); ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>()); ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 2u); EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 2u);
@ -922,8 +922,8 @@ TEST_F(ResolverBuiltinsValidationTest, Frexp_Vec3) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
auto* res_ty = TypeOf(builtin)->As<sem::Struct>(); auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
ASSERT_TRUE(res_ty != nullptr); ASSERT_TRUE(res_ty != nullptr);
auto& members = res_ty->Members(); auto members = res_ty->Members();
ASSERT_EQ(members.size(), 2u); ASSERT_EQ(members.Length(), 2u);
ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>()); ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>()); ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 3u); EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 3u);
@ -939,8 +939,8 @@ TEST_F(ResolverBuiltinsValidationTest, Frexp_Vec4) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
auto* res_ty = TypeOf(builtin)->As<sem::Struct>(); auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
ASSERT_TRUE(res_ty != nullptr); ASSERT_TRUE(res_ty != nullptr);
auto& members = res_ty->Members(); auto members = res_ty->Members();
ASSERT_EQ(members.size(), 2u); ASSERT_EQ(members.Length(), 2u);
ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>()); ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>()); ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 4u); EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 4u);
@ -956,8 +956,8 @@ TEST_F(ResolverBuiltinsValidationTest, Modf_Scalar) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
auto* res_ty = TypeOf(builtin)->As<sem::Struct>(); auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
ASSERT_TRUE(res_ty != nullptr); ASSERT_TRUE(res_ty != nullptr);
auto& members = res_ty->Members(); auto members = res_ty->Members();
ASSERT_EQ(members.size(), 2u); ASSERT_EQ(members.Length(), 2u);
EXPECT_TRUE(members[0]->Type()->Is<sem::F32>()); EXPECT_TRUE(members[0]->Type()->Is<sem::F32>());
EXPECT_TRUE(members[1]->Type()->Is<sem::F32>()); EXPECT_TRUE(members[1]->Type()->Is<sem::F32>());
} }
@ -969,8 +969,8 @@ TEST_F(ResolverBuiltinsValidationTest, Modf_Vec2) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
auto* res_ty = TypeOf(builtin)->As<sem::Struct>(); auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
ASSERT_TRUE(res_ty != nullptr); ASSERT_TRUE(res_ty != nullptr);
auto& members = res_ty->Members(); auto members = res_ty->Members();
ASSERT_EQ(members.size(), 2u); ASSERT_EQ(members.Length(), 2u);
ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>()); ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>()); ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 2u); EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 2u);
@ -986,8 +986,8 @@ TEST_F(ResolverBuiltinsValidationTest, Modf_Vec3) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
auto* res_ty = TypeOf(builtin)->As<sem::Struct>(); auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
ASSERT_TRUE(res_ty != nullptr); ASSERT_TRUE(res_ty != nullptr);
auto& members = res_ty->Members(); auto members = res_ty->Members();
ASSERT_EQ(members.size(), 2u); ASSERT_EQ(members.Length(), 2u);
ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>()); ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>()); ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 3u); EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 3u);
@ -1003,8 +1003,8 @@ TEST_F(ResolverBuiltinsValidationTest, Modf_Vec4) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
auto* res_ty = TypeOf(builtin)->As<sem::Struct>(); auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
ASSERT_TRUE(res_ty != nullptr); ASSERT_TRUE(res_ty != nullptr);
auto& members = res_ty->Members(); auto members = res_ty->Members();
ASSERT_EQ(members.size(), 2u); ASSERT_EQ(members.Length(), 2u);
ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>()); ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>()); ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 4u); EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 4u);

View File

@ -416,7 +416,7 @@ struct Composite : ImplConstant {
conv_els.Reserve(elements.Length()); conv_els.Reserve(elements.Length());
std::function<const sem::Type*(size_t idx)> target_el_ty; std::function<const sem::Type*(size_t idx)> target_el_ty;
if (auto* str = target_ty->As<sem::Struct>()) { if (auto* str = target_ty->As<sem::Struct>()) {
if (str->Members().size() != elements.Length()) { if (str->Members().Length() != elements.Length()) {
TINT_ICE(Resolver, builder.Diagnostics()) TINT_ICE(Resolver, builder.Diagnostics())
<< "const-eval conversion of structure has mismatched element counts"; << "const-eval conversion of structure has mismatched element counts";
return utils::Failure; return utils::Failure;
@ -496,7 +496,7 @@ const ImplConstant* ZeroValue(ProgramBuilder& builder, const sem::Type* type) {
[&](const sem::Struct* s) -> const ImplConstant* { [&](const sem::Struct* s) -> const ImplConstant* {
utils::Hashmap<const sem::Type*, const ImplConstant*, 8> zero_by_type; utils::Hashmap<const sem::Type*, const ImplConstant*, 8> zero_by_type;
utils::Vector<const sem::Constant*, 4> zeros; utils::Vector<const sem::Constant*, 4> zeros;
zeros.Reserve(s->Members().size()); zeros.Reserve(s->Members().Length());
for (auto* member : s->Members()) { for (auto* member : s->Members()) {
auto* zero = zero_by_type.GetOrCreate( auto* zero = zero_by_type.GetOrCreate(
member->Type(), [&] { return ZeroValue(builder, member->Type()); }); member->Type(), [&] { return ZeroValue(builder, member->Type()); });
@ -507,7 +507,7 @@ const ImplConstant* ZeroValue(ProgramBuilder& builder, const sem::Type* type) {
} }
if (zero_by_type.Count() == 1) { if (zero_by_type.Count() == 1) {
// All members were of the same type, so the zero value is the same for all members. // All members were of the same type, so the zero value is the same for all members.
return builder.create<Splat>(type, zeros[0], s->Members().size()); return builder.create<Splat>(type, zeros[0], s->Members().Length());
} }
return CreateComposite(builder, s, std::move(zeros)); return CreateComposite(builder, s, std::move(zeros));
}, },

View File

@ -1625,7 +1625,7 @@ TEST_F(ResolverConstEvalTest, Struct_I32s_ZeroInit) {
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
auto* str = sem->Type()->As<sem::Struct>(); auto* str = sem->Type()->As<sem::Struct>();
ASSERT_NE(str, nullptr); ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().size(), 3u); EXPECT_EQ(str->Members().Length(), 3u);
ASSERT_NE(sem->ConstantValue(), nullptr); ASSERT_NE(sem->ConstantValue(), nullptr);
EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type()); EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
EXPECT_TRUE(sem->ConstantValue()->AllEqual()); EXPECT_TRUE(sem->ConstantValue()->AllEqual());
@ -1670,7 +1670,7 @@ TEST_F(ResolverConstEvalTest, Struct_MixedScalars_ZeroInit) {
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
auto* str = sem->Type()->As<sem::Struct>(); auto* str = sem->Type()->As<sem::Struct>();
ASSERT_NE(str, nullptr); ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().size(), 5u); EXPECT_EQ(str->Members().Length(), 5u);
ASSERT_NE(sem->ConstantValue(), nullptr); ASSERT_NE(sem->ConstantValue(), nullptr);
EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type()); EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
EXPECT_FALSE(sem->ConstantValue()->AllEqual()); EXPECT_FALSE(sem->ConstantValue()->AllEqual());
@ -1723,7 +1723,7 @@ TEST_F(ResolverConstEvalTest, Struct_VectorF32s_ZeroInit) {
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
auto* str = sem->Type()->As<sem::Struct>(); auto* str = sem->Type()->As<sem::Struct>();
ASSERT_NE(str, nullptr); ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().size(), 3u); EXPECT_EQ(str->Members().Length(), 3u);
ASSERT_NE(sem->ConstantValue(), nullptr); ASSERT_NE(sem->ConstantValue(), nullptr);
EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type()); EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
EXPECT_TRUE(sem->ConstantValue()->AllEqual()); EXPECT_TRUE(sem->ConstantValue()->AllEqual());
@ -1777,7 +1777,7 @@ TEST_F(ResolverConstEvalTest, Struct_MixedVectors_ZeroInit) {
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
auto* str = sem->Type()->As<sem::Struct>(); auto* str = sem->Type()->As<sem::Struct>();
ASSERT_NE(str, nullptr); ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().size(), 5u); EXPECT_EQ(str->Members().Length(), 5u);
ASSERT_NE(sem->ConstantValue(), nullptr); ASSERT_NE(sem->ConstantValue(), nullptr);
EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type()); EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
EXPECT_FALSE(sem->ConstantValue()->AllEqual()); EXPECT_FALSE(sem->ConstantValue()->AllEqual());
@ -1849,7 +1849,7 @@ TEST_F(ResolverConstEvalTest, Struct_Struct_ZeroInit) {
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
auto* str = sem->Type()->As<sem::Struct>(); auto* str = sem->Type()->As<sem::Struct>();
ASSERT_NE(str, nullptr); ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().size(), 2u); EXPECT_EQ(str->Members().Length(), 2u);
ASSERT_NE(sem->ConstantValue(), nullptr); ASSERT_NE(sem->ConstantValue(), nullptr);
EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type()); EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
EXPECT_TRUE(sem->ConstantValue()->AllEqual()); EXPECT_TRUE(sem->ConstantValue()->AllEqual());
@ -1892,7 +1892,7 @@ TEST_F(ResolverConstEvalTest, Struct_MixedScalars_Construct) {
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
auto* str = sem->Type()->As<sem::Struct>(); auto* str = sem->Type()->As<sem::Struct>();
ASSERT_NE(str, nullptr); ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().size(), 5u); EXPECT_EQ(str->Members().Length(), 5u);
ASSERT_NE(sem->ConstantValue(), nullptr); ASSERT_NE(sem->ConstantValue(), nullptr);
EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type()); EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
EXPECT_FALSE(sem->ConstantValue()->AllEqual()); EXPECT_FALSE(sem->ConstantValue()->AllEqual());
@ -1950,7 +1950,7 @@ TEST_F(ResolverConstEvalTest, Struct_MixedVectors_Construct) {
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
auto* str = sem->Type()->As<sem::Struct>(); auto* str = sem->Type()->As<sem::Struct>();
ASSERT_NE(str, nullptr); ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().size(), 5u); EXPECT_EQ(str->Members().Length(), 5u);
ASSERT_NE(sem->ConstantValue(), nullptr); ASSERT_NE(sem->ConstantValue(), nullptr);
EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type()); EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
EXPECT_FALSE(sem->ConstantValue()->AllEqual()); EXPECT_FALSE(sem->ConstantValue()->AllEqual());
@ -2024,7 +2024,7 @@ TEST_F(ResolverConstEvalTest, Struct_Struct_Construct) {
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
auto* str = sem->Type()->As<sem::Struct>(); auto* str = sem->Type()->As<sem::Struct>();
ASSERT_NE(str, nullptr); ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().size(), 2u); EXPECT_EQ(str->Members().Length(), 2u);
ASSERT_NE(sem->ConstantValue(), nullptr); ASSERT_NE(sem->ConstantValue(), nullptr);
EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type()); EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
EXPECT_FALSE(sem->ConstantValue()->AllEqual()); EXPECT_FALSE(sem->ConstantValue()->AllEqual());
@ -2064,7 +2064,7 @@ TEST_F(ResolverConstEvalTest, Struct_Array_Construct) {
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
auto* str = sem->Type()->As<sem::Struct>(); auto* str = sem->Type()->As<sem::Struct>();
ASSERT_NE(str, nullptr); ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().size(), 2u); EXPECT_EQ(str->Members().Length(), 2u);
ASSERT_NE(sem->ConstantValue(), nullptr); ASSERT_NE(sem->ConstantValue(), nullptr);
EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type()); EXPECT_TYPE(sem->ConstantValue()->Type(), sem->Type());
EXPECT_FALSE(sem->ConstantValue()->AllEqual()); EXPECT_FALSE(sem->ConstantValue()->AllEqual());

View File

@ -43,7 +43,7 @@ TEST_F(ResolverConstEvalTest, MemberAccess) {
ASSERT_NE(outer, nullptr); ASSERT_NE(outer, nullptr);
auto* str = outer->Type()->As<sem::Struct>(); auto* str = outer->Type()->As<sem::Struct>();
ASSERT_NE(str, nullptr); ASSERT_NE(str, nullptr);
EXPECT_EQ(str->Members().size(), 2u); EXPECT_EQ(str->Members().Length(), 2u);
ASSERT_NE(outer->ConstantValue(), nullptr); ASSERT_NE(outer->ConstantValue(), nullptr);
EXPECT_TYPE(outer->ConstantValue()->Type(), outer->Type()); EXPECT_TYPE(outer->ConstantValue()->Type(), outer->Type());
EXPECT_FALSE(outer->ConstantValue()->AllEqual()); EXPECT_FALSE(outer->ConstantValue()->AllEqual());

View File

@ -150,12 +150,11 @@ TEST_F(ResolverInferredTypeTest, InferStruct_Pass) {
auto* member = Member("x", ty.i32()); auto* member = Member("x", ty.i32());
auto* str = Structure("S", utils::Vector{member}); auto* str = Structure("S", utils::Vector{member});
auto* expected_type = auto* expected_type = create<sem::Struct>(
create<sem::Struct>(str, str->source, str->name, str, str->source, str->name,
sem::StructMemberList{create<sem::StructMember>( utils::Vector{create<sem::StructMember>(member, member->source, member->symbol,
member, member->source, member->symbol, create<sem::I32>(), 0u, 0u, create<sem::I32>(), 0u, 0u, 0u, 4u, std::nullopt)},
0u, 4u, std::nullopt)}, 0u, 4u, 4u);
0u, 4u, 4u);
auto* ctor_expr = Construct(ty.Of(str)); auto* ctor_expr = Construct(ty.Of(str));

View File

@ -802,18 +802,18 @@ sem::Struct* build_struct(ProgramBuilder& b,
std::initializer_list<NameAndType> member_names_and_types) { std::initializer_list<NameAndType> member_names_and_types) {
uint32_t offset = 0; uint32_t offset = 0;
uint32_t max_align = 0; uint32_t max_align = 0;
sem::StructMemberList members; utils::Vector<const sem::StructMember*, 4> members;
for (auto& m : member_names_and_types) { for (auto& m : member_names_and_types) {
uint32_t align = std::max<uint32_t>(m.type->Align(), 1); uint32_t align = std::max<uint32_t>(m.type->Align(), 1);
uint32_t size = m.type->Size(); uint32_t size = m.type->Size();
offset = utils::RoundUp(align, offset); offset = utils::RoundUp(align, offset);
max_align = std::max(max_align, align); max_align = std::max(max_align, align);
members.emplace_back(b.create<sem::StructMember>( members.Push(b.create<sem::StructMember>(
/* declaration */ nullptr, /* declaration */ nullptr,
/* source */ Source{}, /* source */ Source{},
/* name */ b.Sym(m.name), /* name */ b.Sym(m.name),
/* type */ m.type, /* type */ m.type,
/* index */ static_cast<uint32_t>(members.size()), /* index */ static_cast<uint32_t>(members.Length()),
/* offset */ offset, /* offset */ offset,
/* align */ align, /* align */ align,
/* size */ size, /* size */ size,
@ -826,7 +826,7 @@ sem::Struct* build_struct(ProgramBuilder& b,
/* declaration */ nullptr, /* declaration */ nullptr,
/* source */ Source{}, /* source */ Source{},
/* name */ b.Sym(name), /* name */ b.Sym(name),
/* members */ members, /* members */ std::move(members),
/* align */ max_align, /* align */ max_align,
/* size */ size_with_padding, /* size */ size_with_padding,
/* size_no_padding */ size_without_padding); /* size_no_padding */ size_without_padding);

View File

@ -2069,7 +2069,7 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
StructInitializerSig{{str, args.Length(), args_stage}}, StructInitializerSig{{str, args.Length(), args_stage}},
[&]() -> sem::TypeInitializer* { [&]() -> sem::TypeInitializer* {
utils::Vector<const sem::Parameter*, 8> params; utils::Vector<const sem::Parameter*, 8> params;
params.Resize(std::min(args.Length(), str->Members().size())); params.Resize(std::min(args.Length(), str->Members().Length()));
for (size_t i = 0, n = params.Length(); i < n; i++) { for (size_t i = 0, n = params.Length(); i < n; i++) {
params[i] = builder_->create<sem::Parameter>( params[i] = builder_->create<sem::Parameter>(
nullptr, // declaration nullptr, // declaration
@ -3097,19 +3097,15 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
Mark(attr); Mark(attr);
} }
sem::StructMemberList sem_members; utils::Vector<const sem::StructMember*, 8> sem_members;
sem_members.reserve(str->members.Length()); sem_members.Reserve(str->members.Length());
// Calculate the effective size and alignment of each field, and the overall // Calculate the effective size and alignment of each field, and the overall size of the
// size of the structure. // structure. For size, use the size attribute if provided, otherwise use the default size for
// For size, use the size attribute if provided, otherwise use the default // the type. For alignment, use the alignment attribute if provided, otherwise use the default
// size for the type. // alignment for the member type. Diagnostic errors are raised if a basic rule is violated.
// For alignment, use the alignment attribute if provided, otherwise use the // Validation of storage-class rules requires analyzing the actual variable usage of the
// default alignment for the member type. // structure, and so is performed as part of the variable validation.
// Diagnostic errors are raised if a basic rule is violated.
// Validation of storage-class rules requires analyzing the actual variable
// usage of the structure, and so is performed as part of the variable
// validation.
uint64_t struct_size = 0; uint64_t struct_size = 0;
uint64_t struct_align = 1; uint64_t struct_align = 1;
utils::Hashmap<Symbol, const ast::StructMember*, 8> member_map; utils::Hashmap<Symbol, const ast::StructMember*, 8> member_map;
@ -3274,11 +3270,11 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
} }
auto* sem_member = builder_->create<sem::StructMember>( auto* sem_member = builder_->create<sem::StructMember>(
member, member->source, member->symbol, type, static_cast<uint32_t>(sem_members.size()), member, member->source, member->symbol, type,
static_cast<uint32_t>(offset), static_cast<uint32_t>(align), static_cast<uint32_t>(sem_members.Length()), static_cast<uint32_t>(offset),
static_cast<uint32_t>(size), location); static_cast<uint32_t>(align), static_cast<uint32_t>(size), location);
builder_->Sem().Add(member, sem_member); builder_->Sem().Add(member, sem_member);
sem_members.emplace_back(sem_member); sem_members.Push(sem_member);
struct_size = offset + size; struct_size = offset + size;
struct_align = std::max(struct_align, align); struct_align = std::max(struct_align, align);
@ -3299,10 +3295,10 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
} }
auto* out = builder_->create<sem::Struct>( auto* out = builder_->create<sem::Struct>(
str, str->source, str->name, sem_members, static_cast<uint32_t>(struct_align), str, str->source, str->name, std::move(sem_members), static_cast<uint32_t>(struct_align),
static_cast<uint32_t>(struct_size), static_cast<uint32_t>(size_no_padding)); static_cast<uint32_t>(struct_size), static_cast<uint32_t>(size_no_padding));
for (size_t i = 0; i < sem_members.size(); i++) { for (size_t i = 0; i < sem_members.Length(); i++) {
auto* mem_type = sem_members[i]->Type(); auto* mem_type = sem_members[i]->Type();
if (mem_type->Is<sem::Atomic>()) { if (mem_type->Is<sem::Atomic>()) {
atomic_composite_info_.Add(out, &sem_members[i]->Source()); atomic_composite_info_.Add(out, &sem_members[i]->Source());

View File

@ -39,7 +39,7 @@ TEST_F(ResolverStructLayoutTest, Scalars) {
EXPECT_EQ(sem->Size(), 12u); EXPECT_EQ(sem->Size(), 12u);
EXPECT_EQ(sem->SizeNoPadding(), 12u); EXPECT_EQ(sem->SizeNoPadding(), 12u);
EXPECT_EQ(sem->Align(), 4u); EXPECT_EQ(sem->Align(), 4u);
ASSERT_EQ(sem->Members().size(), 3u); ASSERT_EQ(sem->Members().Length(), 3u);
EXPECT_EQ(sem->Members()[0]->Offset(), 0u); EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u); EXPECT_EQ(sem->Members()[0]->Align(), 4u);
EXPECT_EQ(sem->Members()[0]->Size(), 4u); EXPECT_EQ(sem->Members()[0]->Size(), 4u);
@ -74,7 +74,7 @@ TEST_F(ResolverStructLayoutTest, ScalarsWithF16) {
EXPECT_EQ(sem->Size(), 24u); EXPECT_EQ(sem->Size(), 24u);
EXPECT_EQ(sem->SizeNoPadding(), 22u); EXPECT_EQ(sem->SizeNoPadding(), 22u);
EXPECT_EQ(sem->Align(), 4u); EXPECT_EQ(sem->Align(), 4u);
ASSERT_EQ(sem->Members().size(), 7u); ASSERT_EQ(sem->Members().Length(), 7u);
// f32 // f32
EXPECT_EQ(sem->Members()[0]->Offset(), 0u); EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u); EXPECT_EQ(sem->Members()[0]->Align(), 4u);
@ -121,7 +121,7 @@ TEST_F(ResolverStructLayoutTest, Alias) {
EXPECT_EQ(sem->Size(), 8u); EXPECT_EQ(sem->Size(), 8u);
EXPECT_EQ(sem->SizeNoPadding(), 8u); EXPECT_EQ(sem->SizeNoPadding(), 8u);
EXPECT_EQ(sem->Align(), 4u); EXPECT_EQ(sem->Align(), 4u);
ASSERT_EQ(sem->Members().size(), 2u); ASSERT_EQ(sem->Members().Length(), 2u);
EXPECT_EQ(sem->Members()[0]->Offset(), 0u); EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u); EXPECT_EQ(sem->Members()[0]->Align(), 4u);
EXPECT_EQ(sem->Members()[0]->Size(), 4u); EXPECT_EQ(sem->Members()[0]->Size(), 4u);
@ -150,7 +150,7 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayStaticSize) {
EXPECT_EQ(sem->Size(), 52u); EXPECT_EQ(sem->Size(), 52u);
EXPECT_EQ(sem->SizeNoPadding(), 52u); EXPECT_EQ(sem->SizeNoPadding(), 52u);
EXPECT_EQ(sem->Align(), 4u); EXPECT_EQ(sem->Align(), 4u);
ASSERT_EQ(sem->Members().size(), 4u); ASSERT_EQ(sem->Members().Length(), 4u);
// array<i32, 3> // array<i32, 3>
EXPECT_EQ(sem->Members()[0]->Offset(), 0u); EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u); EXPECT_EQ(sem->Members()[0]->Align(), 4u);
@ -190,7 +190,7 @@ TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayStaticSize) {
EXPECT_EQ(sem->Size(), 164u); EXPECT_EQ(sem->Size(), 164u);
EXPECT_EQ(sem->SizeNoPadding(), 164u); EXPECT_EQ(sem->SizeNoPadding(), 164u);
EXPECT_EQ(sem->Align(), 4u); EXPECT_EQ(sem->Align(), 4u);
ASSERT_EQ(sem->Members().size(), 4u); ASSERT_EQ(sem->Members().Length(), 4u);
// array<i32, 3>, stride = 8 // array<i32, 3>, stride = 8
EXPECT_EQ(sem->Members()[0]->Offset(), 0u); EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u); EXPECT_EQ(sem->Members()[0]->Align(), 4u);
@ -225,7 +225,7 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayRuntimeSized) {
EXPECT_EQ(sem->Size(), 4u); EXPECT_EQ(sem->Size(), 4u);
EXPECT_EQ(sem->SizeNoPadding(), 4u); EXPECT_EQ(sem->SizeNoPadding(), 4u);
EXPECT_EQ(sem->Align(), 4u); EXPECT_EQ(sem->Align(), 4u);
ASSERT_EQ(sem->Members().size(), 1u); ASSERT_EQ(sem->Members().Length(), 1u);
EXPECT_EQ(sem->Members()[0]->Offset(), 0u); EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u); EXPECT_EQ(sem->Members()[0]->Align(), 4u);
EXPECT_EQ(sem->Members()[0]->Size(), 4u); EXPECT_EQ(sem->Members()[0]->Size(), 4u);
@ -246,7 +246,7 @@ TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayRuntimeSized) {
EXPECT_EQ(sem->Size(), 32u); EXPECT_EQ(sem->Size(), 32u);
EXPECT_EQ(sem->SizeNoPadding(), 32u); EXPECT_EQ(sem->SizeNoPadding(), 32u);
EXPECT_EQ(sem->Align(), 4u); EXPECT_EQ(sem->Align(), 4u);
ASSERT_EQ(sem->Members().size(), 1u); ASSERT_EQ(sem->Members().Length(), 1u);
EXPECT_EQ(sem->Members()[0]->Offset(), 0u); EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u); EXPECT_EQ(sem->Members()[0]->Align(), 4u);
EXPECT_EQ(sem->Members()[0]->Size(), 32u); EXPECT_EQ(sem->Members()[0]->Size(), 32u);
@ -269,7 +269,7 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfExplicitStrideArray) {
EXPECT_EQ(sem->Size(), 384u); EXPECT_EQ(sem->Size(), 384u);
EXPECT_EQ(sem->SizeNoPadding(), 384u); EXPECT_EQ(sem->SizeNoPadding(), 384u);
EXPECT_EQ(sem->Align(), 4u); EXPECT_EQ(sem->Align(), 4u);
ASSERT_EQ(sem->Members().size(), 1u); ASSERT_EQ(sem->Members().Length(), 1u);
EXPECT_EQ(sem->Members()[0]->Offset(), 0u); EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u); EXPECT_EQ(sem->Members()[0]->Align(), 4u);
EXPECT_EQ(sem->Members()[0]->Size(), 384u); EXPECT_EQ(sem->Members()[0]->Size(), 384u);
@ -296,7 +296,7 @@ TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfStructure) {
EXPECT_EQ(sem->Size(), 576u); EXPECT_EQ(sem->Size(), 576u);
EXPECT_EQ(sem->SizeNoPadding(), 576u); EXPECT_EQ(sem->SizeNoPadding(), 576u);
EXPECT_EQ(sem->Align(), 16u); EXPECT_EQ(sem->Align(), 16u);
ASSERT_EQ(sem->Members().size(), 1u); ASSERT_EQ(sem->Members().Length(), 1u);
EXPECT_EQ(sem->Members()[0]->Offset(), 0u); EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 16u); EXPECT_EQ(sem->Members()[0]->Align(), 16u);
EXPECT_EQ(sem->Members()[0]->Size(), 576u); EXPECT_EQ(sem->Members()[0]->Size(), 576u);
@ -319,7 +319,7 @@ TEST_F(ResolverStructLayoutTest, Vector) {
EXPECT_EQ(sem->Size(), 48u); EXPECT_EQ(sem->Size(), 48u);
EXPECT_EQ(sem->SizeNoPadding(), 48u); EXPECT_EQ(sem->SizeNoPadding(), 48u);
EXPECT_EQ(sem->Align(), 16u); EXPECT_EQ(sem->Align(), 16u);
ASSERT_EQ(sem->Members().size(), 3u); ASSERT_EQ(sem->Members().Length(), 3u);
EXPECT_EQ(sem->Members()[0]->Offset(), 0u); // vec2 EXPECT_EQ(sem->Members()[0]->Offset(), 0u); // vec2
EXPECT_EQ(sem->Members()[0]->Align(), 8u); EXPECT_EQ(sem->Members()[0]->Align(), 8u);
EXPECT_EQ(sem->Members()[0]->Size(), 8u); EXPECT_EQ(sem->Members()[0]->Size(), 8u);
@ -365,7 +365,7 @@ TEST_F(ResolverStructLayoutTest, Matrix) {
EXPECT_EQ(sem->Size(), 576u); EXPECT_EQ(sem->Size(), 576u);
EXPECT_EQ(sem->SizeNoPadding(), 576u); EXPECT_EQ(sem->SizeNoPadding(), 576u);
EXPECT_EQ(sem->Align(), 16u); EXPECT_EQ(sem->Align(), 16u);
ASSERT_EQ(sem->Members().size(), 18u); ASSERT_EQ(sem->Members().Length(), 18u);
EXPECT_EQ(sem->Members()[0]->Offset(), 0u); // mat2x2<f32> EXPECT_EQ(sem->Members()[0]->Offset(), 0u); // mat2x2<f32>
EXPECT_EQ(sem->Members()[0]->Align(), 8u); EXPECT_EQ(sem->Members()[0]->Align(), 8u);
EXPECT_EQ(sem->Members()[0]->Size(), 16u); EXPECT_EQ(sem->Members()[0]->Size(), 16u);
@ -443,7 +443,7 @@ TEST_F(ResolverStructLayoutTest, NestedStruct) {
EXPECT_EQ(sem->Size(), 80u); EXPECT_EQ(sem->Size(), 80u);
EXPECT_EQ(sem->SizeNoPadding(), 68u); EXPECT_EQ(sem->SizeNoPadding(), 68u);
EXPECT_EQ(sem->Align(), 16u); EXPECT_EQ(sem->Align(), 16u);
ASSERT_EQ(sem->Members().size(), 3u); ASSERT_EQ(sem->Members().Length(), 3u);
EXPECT_EQ(sem->Members()[0]->Offset(), 0u); EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u); EXPECT_EQ(sem->Members()[0]->Align(), 4u);
EXPECT_EQ(sem->Members()[0]->Size(), 4u); EXPECT_EQ(sem->Members()[0]->Size(), 4u);
@ -478,7 +478,7 @@ TEST_F(ResolverStructLayoutTest, SizeAttributes) {
EXPECT_EQ(sem->Size(), 76u); EXPECT_EQ(sem->Size(), 76u);
EXPECT_EQ(sem->SizeNoPadding(), 76u); EXPECT_EQ(sem->SizeNoPadding(), 76u);
EXPECT_EQ(sem->Align(), 4u); EXPECT_EQ(sem->Align(), 4u);
ASSERT_EQ(sem->Members().size(), 4u); ASSERT_EQ(sem->Members().Length(), 4u);
EXPECT_EQ(sem->Members()[0]->Offset(), 0u); EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u); EXPECT_EQ(sem->Members()[0]->Align(), 4u);
EXPECT_EQ(sem->Members()[0]->Size(), 4u); EXPECT_EQ(sem->Members()[0]->Size(), 4u);
@ -516,7 +516,7 @@ TEST_F(ResolverStructLayoutTest, AlignAttributes) {
EXPECT_EQ(sem->Size(), 96u); EXPECT_EQ(sem->Size(), 96u);
EXPECT_EQ(sem->SizeNoPadding(), 68u); EXPECT_EQ(sem->SizeNoPadding(), 68u);
EXPECT_EQ(sem->Align(), 32u); EXPECT_EQ(sem->Align(), 32u);
ASSERT_EQ(sem->Members().size(), 4u); ASSERT_EQ(sem->Members().Length(), 4u);
EXPECT_EQ(sem->Members()[0]->Offset(), 0u); EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u); EXPECT_EQ(sem->Members()[0]->Align(), 4u);
EXPECT_EQ(sem->Members()[0]->Size(), 4u); EXPECT_EQ(sem->Members()[0]->Size(), 4u);
@ -546,7 +546,7 @@ TEST_F(ResolverStructLayoutTest, StructWithLotsOfPadding) {
EXPECT_EQ(sem->Size(), 1024u); EXPECT_EQ(sem->Size(), 1024u);
EXPECT_EQ(sem->SizeNoPadding(), 4u); EXPECT_EQ(sem->SizeNoPadding(), 4u);
EXPECT_EQ(sem->Align(), 1024u); EXPECT_EQ(sem->Align(), 1024u);
ASSERT_EQ(sem->Members().size(), 1u); ASSERT_EQ(sem->Members().Length(), 1u);
EXPECT_EQ(sem->Members()[0]->Offset(), 0u); EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
EXPECT_EQ(sem->Members()[0]->Align(), 1024u); EXPECT_EQ(sem->Members()[0]->Align(), 1024u);
EXPECT_EQ(sem->Members()[0]->Size(), 4u); EXPECT_EQ(sem->Members()[0]->Size(), 4u);
@ -576,7 +576,7 @@ TEST_F(ResolverStructLayoutTest, OffsetAttributes) {
EXPECT_EQ(sem->Size(), 132u); EXPECT_EQ(sem->Size(), 132u);
EXPECT_EQ(sem->SizeNoPadding(), 132u); EXPECT_EQ(sem->SizeNoPadding(), 132u);
EXPECT_EQ(sem->Align(), 4u); EXPECT_EQ(sem->Align(), 4u);
ASSERT_EQ(sem->Members().size(), 5u); ASSERT_EQ(sem->Members().Length(), 5u);
EXPECT_EQ(sem->Members()[0]->Offset(), 4u); EXPECT_EQ(sem->Members()[0]->Offset(), 4u);
EXPECT_EQ(sem->Members()[0]->Align(), 4u); EXPECT_EQ(sem->Members()[0]->Align(), 4u);
EXPECT_EQ(sem->Members()[0]->Size(), 4u); EXPECT_EQ(sem->Members()[0]->Size(), 4u);

View File

@ -184,7 +184,7 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderParamLocationSet) {
auto* sem = TypeOf(s)->As<sem::Struct>(); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
ASSERT_EQ(1u, sem->Members().size()); ASSERT_EQ(1u, sem->Members().Length());
EXPECT_EQ(3u, sem->Members()[0]->Location()); EXPECT_EQ(3u, sem->Members()[0]->Location());
} }
@ -214,7 +214,7 @@ TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderReturnTypeLocationSet) {
auto* sem = TypeOf(s)->As<sem::Struct>(); auto* sem = TypeOf(s)->As<sem::Struct>();
ASSERT_NE(sem, nullptr); ASSERT_NE(sem, nullptr);
ASSERT_EQ(1u, sem->Members().size()); ASSERT_EQ(1u, sem->Members().Length());
EXPECT_EQ(3u, sem->Members()[0]->Location()); EXPECT_EQ(3u, sem->Members()[0]->Location());
} }

View File

@ -440,7 +440,7 @@ bool Validator::AddressSpaceLayout(const sem::Type* store_ty,
} }
if (auto* str = store_ty->As<sem::Struct>()) { if (auto* str = store_ty->As<sem::Struct>()) {
for (size_t i = 0; i < str->Members().size(); ++i) { for (size_t i = 0; i < str->Members().Length(); ++i) {
auto* const m = str->Members()[i]; auto* const m = str->Members()[i];
uint32_t required_align = required_alignment_of(m->Type()); uint32_t required_align = required_alignment_of(m->Type());
@ -1724,10 +1724,10 @@ bool Validator::StructureInitializer(const ast::CallExpression* ctor,
} }
if (ctor->args.Length() > 0) { if (ctor->args.Length() > 0) {
if (ctor->args.Length() != struct_type->Members().size()) { if (ctor->args.Length() != struct_type->Members().Length()) {
std::string fm = ctor->args.Length() < struct_type->Members().size() ? "few" : "many"; std::string fm = ctor->args.Length() < struct_type->Members().Length() ? "few" : "many";
AddError("struct initializer has too " + fm + " inputs: expected " + AddError("struct initializer has too " + fm + " inputs: expected " +
std::to_string(struct_type->Members().size()) + ", found " + std::to_string(struct_type->Members().Length()) + ", found " +
std::to_string(ctor->args.Length()), std::to_string(ctor->args.Length()),
ctor->source); ctor->source);
return false; return false;
@ -2019,7 +2019,7 @@ bool Validator::Alias(const ast::Alias*) const {
} }
bool Validator::Structure(const sem::Struct* str, ast::PipelineStage stage) const { bool Validator::Structure(const sem::Struct* str, ast::PipelineStage stage) const {
if (str->Members().empty()) { if (str->Members().IsEmpty()) {
AddError("structures must have at least one member", str->Source()); AddError("structures must have at least one member", str->Source());
return false; return false;
} }
@ -2028,7 +2028,7 @@ bool Validator::Structure(const sem::Struct* str, ast::PipelineStage stage) cons
for (auto* member : str->Members()) { for (auto* member : str->Members()) {
if (auto* r = member->Type()->As<sem::Array>()) { if (auto* r = member->Type()->As<sem::Array>()) {
if (r->Count()->Is<sem::RuntimeArrayCount>()) { if (r->Count()->Is<sem::RuntimeArrayCount>()) {
if (member != str->Members().back()) { if (member != str->Members().Back()) {
AddError("runtime arrays may only appear as the last member of a struct", AddError("runtime arrays may only appear as the last member of a struct",
member->Source()); member->Source());
return false; return false;

View File

@ -23,13 +23,15 @@
#include "src/tint/symbol_table.h" #include "src/tint/symbol_table.h"
#include "src/tint/utils/hash.h" #include "src/tint/utils/hash.h"
TINT_INSTANTIATE_TYPEINFO(tint::sem::StructBase);
TINT_INSTANTIATE_TYPEINFO(tint::sem::Struct); TINT_INSTANTIATE_TYPEINFO(tint::sem::Struct);
TINT_INSTANTIATE_TYPEINFO(tint::sem::StructMemberBase);
TINT_INSTANTIATE_TYPEINFO(tint::sem::StructMember); TINT_INSTANTIATE_TYPEINFO(tint::sem::StructMember);
namespace tint::sem { namespace tint::sem {
namespace { namespace {
TypeFlags FlagsFrom(const StructMemberList& members) { TypeFlags FlagsFrom(utils::VectorRef<const StructMemberBase*> members) {
TypeFlags flags{ TypeFlags flags{
TypeFlag::kConstructable, TypeFlag::kConstructable,
TypeFlag::kCreationFixedFootprint, TypeFlag::kCreationFixedFootprint,
@ -54,12 +56,21 @@ TypeFlags FlagsFrom(const StructMemberList& members) {
Struct::Struct(const ast::Struct* declaration, Struct::Struct(const ast::Struct* declaration,
tint::Source source, tint::Source source,
Symbol name, Symbol name,
StructMemberList members, utils::VectorRef<const StructMember*> members,
uint32_t align, uint32_t align,
uint32_t size, uint32_t size,
uint32_t size_no_padding) uint32_t size_no_padding)
: Base(source, name, members, align, size, size_no_padding), declaration_(declaration) {}
Struct::~Struct() = default;
StructBase::StructBase(tint::Source source,
Symbol name,
utils::VectorRef<const StructMemberBase*> members,
uint32_t align,
uint32_t size,
uint32_t size_no_padding)
: Base(FlagsFrom(members)), : Base(FlagsFrom(members)),
declaration_(declaration),
source_(source), source_(source),
name_(name), name_(name),
members_(std::move(members)), members_(std::move(members)),
@ -67,20 +78,20 @@ Struct::Struct(const ast::Struct* declaration,
size_(size), size_(size),
size_no_padding_(size_no_padding) {} size_no_padding_(size_no_padding) {}
Struct::~Struct() = default; StructBase::~StructBase() = default;
size_t Struct::Hash() const { size_t StructBase::Hash() const {
return utils::Hash(TypeInfo::Of<Struct>().full_hashcode, name_); return utils::Hash(TypeInfo::Of<Struct>().full_hashcode, name_);
} }
bool Struct::Equals(const sem::Type& other) const { bool StructBase::Equals(const sem::Type& other) const {
if (auto* o = other.As<Struct>()) { if (auto* o = other.As<Struct>()) {
return o->name_ == name_; return o->name_ == name_;
} }
return false; return false;
} }
const StructMember* Struct::FindMember(Symbol name) const { const StructMemberBase* StructBase::FindMember(Symbol name) const {
for (auto* member : members_) { for (auto* member : members_) {
if (member->Name() == name) { if (member->Name() == name) {
return member; return member;
@ -89,27 +100,29 @@ const StructMember* Struct::FindMember(Symbol name) const {
return nullptr; return nullptr;
} }
uint32_t Struct::Align() const { uint32_t StructBase::Align() const {
return align_; return align_;
} }
uint32_t Struct::Size() const { uint32_t StructBase::Size() const {
return size_; return size_;
} }
std::string Struct::FriendlyName(const SymbolTable& symbols) const { std::string StructBase::FriendlyName(const SymbolTable& symbols) const {
return symbols.NameFor(name_); return symbols.NameFor(name_);
} }
std::string Struct::Layout(const tint::SymbolTable& symbols) const { std::string StructBase::Layout(const tint::SymbolTable& symbols) const {
std::stringstream ss; std::stringstream ss;
auto member_name_of = [&](const sem::StructMember* sm) { return symbols.NameFor(sm->Name()); }; auto member_name_of = [&](const sem::StructMemberBase* sm) {
return symbols.NameFor(sm->Name());
};
if (Members().empty()) { if (Members().IsEmpty()) {
return {}; return {};
} }
const auto* const last_member = Members().back(); const auto* const last_member = Members().Back();
const uint32_t last_member_struct_padding_offset = last_member->Offset() + last_member->Size(); const uint32_t last_member_struct_padding_offset = last_member->Offset() + last_member->Size();
// Compute max widths to align output // Compute max widths to align output
@ -135,7 +148,7 @@ std::string Struct::Layout(const tint::SymbolTable& symbols) const {
print_struct_begin_line(Align(), Size(), UnwrapRef()->FriendlyName(symbols)); print_struct_begin_line(Align(), Size(), UnwrapRef()->FriendlyName(symbols));
for (size_t i = 0; i < Members().size(); ++i) { for (size_t i = 0; i < Members().Length(); ++i) {
auto* const m = Members()[i]; auto* const m = Members()[i];
// Output field alignment padding, if any // Output field alignment padding, if any
@ -176,8 +189,19 @@ StructMember::StructMember(const ast::StructMember* declaration,
uint32_t align, uint32_t align,
uint32_t size, uint32_t size,
std::optional<uint32_t> location) std::optional<uint32_t> location)
: declaration_(declaration), : Base(source, name, type, index, offset, align, size, location), declaration_(declaration) {}
source_(source),
StructMember::~StructMember() = default;
StructMemberBase::StructMemberBase(tint::Source source,
Symbol name,
const sem::Type* type,
uint32_t index,
uint32_t offset,
uint32_t align,
uint32_t size,
std::optional<uint32_t> location)
: source_(source),
name_(name), name_(name),
type_(type), type_(type),
index_(index), index_(index),
@ -186,6 +210,6 @@ StructMember::StructMember(const ast::StructMember* declaration,
size_(size), size_(size),
location_(location) {} location_(location) {}
StructMember::~StructMember() = default; StructMemberBase::~StructMemberBase() = default;
} // namespace tint::sem } // namespace tint::sem

View File

@ -20,13 +20,13 @@
#include <optional> #include <optional>
#include <string> #include <string>
#include <unordered_set> #include <unordered_set>
#include <vector>
#include "src/tint/ast/address_space.h" #include "src/tint/ast/address_space.h"
#include "src/tint/ast/struct.h" #include "src/tint/ast/struct.h"
#include "src/tint/sem/node.h" #include "src/tint/sem/node.h"
#include "src/tint/sem/type.h" #include "src/tint/sem/type.h"
#include "src/tint/symbol.h" #include "src/tint/symbol.h"
#include "src/tint/utils/vector.h"
// Forward declarations // Forward declarations
namespace tint::ast { namespace tint::ast {
@ -34,14 +34,12 @@ class StructMember;
} // namespace tint::ast } // namespace tint::ast
namespace tint::sem { namespace tint::sem {
class StructMember; class StructMember;
class StructMemberBase;
class Type; class Type;
} // namespace tint::sem } // namespace tint::sem
namespace tint::sem { namespace tint::sem {
/// A vector of StructMember pointers.
using StructMemberList = std::vector<const StructMember*>;
/// Metadata to capture how a structure is used in a shader module. /// Metadata to capture how a structure is used in a shader module.
enum class PipelineStageUsage { enum class PipelineStageUsage {
kVertexInput, kVertexInput,
@ -52,11 +50,10 @@ enum class PipelineStageUsage {
kComputeOutput, kComputeOutput,
}; };
/// Struct holds the semantic information for structures. /// StructBase holds the semantic information for structures.
class Struct final : public Castable<Struct, Type> { class StructBase : public Castable<StructBase, Type> {
public: public:
/// Constructor /// Constructor
/// @param declaration the AST structure declaration
/// @param source the source of the structure /// @param source the source of the structure
/// @param name the name of the structure /// @param name the name of the structure
/// @param members the structure members /// @param members the structure members
@ -64,16 +61,15 @@ class Struct final : public Castable<Struct, Type> {
/// @param size the byte size of the structure /// @param size the byte size of the structure
/// @param size_no_padding size of the members without the end of structure /// @param size_no_padding size of the members without the end of structure
/// alignment padding /// alignment padding
Struct(const ast::Struct* declaration, StructBase(tint::Source source,
tint::Source source, Symbol name,
Symbol name, utils::VectorRef<const StructMemberBase*> members,
StructMemberList members, uint32_t align,
uint32_t align, uint32_t size,
uint32_t size, uint32_t size_no_padding);
uint32_t size_no_padding);
/// Destructor /// Destructor
~Struct() override; ~StructBase() override;
/// @returns a hash of the type. /// @returns a hash of the type.
size_t Hash() const override; size_t Hash() const override;
@ -82,9 +78,6 @@ class Struct final : public Castable<Struct, Type> {
/// @returns true if the this type is equal to the given type /// @returns true if the this type is equal to the given type
bool Equals(const Type& other) const override; bool Equals(const Type& other) const override;
/// @returns the struct
const ast::Struct* Declaration() const { return declaration_; }
/// @returns the source of the structure /// @returns the source of the structure
tint::Source Source() const { return source_; } tint::Source Source() const { return source_; }
@ -92,11 +85,11 @@ class Struct final : public Castable<Struct, Type> {
Symbol Name() const { return name_; } Symbol Name() const { return name_; }
/// @returns the members of the structure /// @returns the members of the structure
const StructMemberList& Members() const { return members_; } utils::VectorRef<const StructMemberBase*> Members() const { return members_; }
/// @param name the member name to look for /// @param name the member name to look for
/// @returns the member with the given name, or nullptr if it was not found. /// @returns the member with the given name, or nullptr if it was not found.
const StructMember* FindMember(Symbol name) const; const StructMemberBase* FindMember(Symbol name) const;
/// @returns the byte alignment of the structure /// @returns the byte alignment of the structure
/// @note this may differ from the alignment of a structure member of this /// @note this may differ from the alignment of a structure member of this
@ -158,28 +151,131 @@ class Struct final : public Castable<Struct, Type> {
std::string Layout(const tint::SymbolTable& symbols) const; std::string Layout(const tint::SymbolTable& symbols) const;
/// @param concrete the conversion-rank ordered concrete versions of this abstract structure. /// @param concrete the conversion-rank ordered concrete versions of this abstract structure.
void SetConcreteTypes(utils::VectorRef<const Struct*> concrete) { concrete_types_ = concrete; } void SetConcreteTypes(utils::VectorRef<const StructBase*> concrete) {
concrete_types_ = concrete;
}
/// @returns the conversion-rank ordered concrete versions of this abstract structure, or an /// @returns the conversion-rank ordered concrete versions of this abstract structure, or an
/// empty vector if this structure is not abstract. /// empty vector if this structure is not abstract.
/// @note only structures returned by builtins may be abstract (e.g. modf, frexp) /// @note only structures returned by builtins may be abstract (e.g. modf, frexp)
utils::VectorRef<const Struct*> ConcreteTypes() const { return concrete_types_; } utils::VectorRef<const StructBase*> ConcreteTypes() const { return concrete_types_; }
private: private:
ast::Struct const* const declaration_;
const tint::Source source_; const tint::Source source_;
const Symbol name_; const Symbol name_;
const StructMemberList members_; const utils::Vector<const StructMemberBase*, 4> members_;
const uint32_t align_; const uint32_t align_;
const uint32_t size_; const uint32_t size_;
const uint32_t size_no_padding_; const uint32_t size_no_padding_;
std::unordered_set<ast::AddressSpace> address_space_usage_; std::unordered_set<ast::AddressSpace> address_space_usage_;
std::unordered_set<PipelineStageUsage> pipeline_stage_uses_; std::unordered_set<PipelineStageUsage> pipeline_stage_uses_;
utils::Vector<const Struct*, 2> concrete_types_; utils::Vector<const StructBase*, 2> concrete_types_;
};
/// Struct holds the semantic information for structures.
class Struct final : public Castable<Struct, StructBase> {
public:
/// Constructor
/// @param declaration the AST structure declaration
/// @param source the source of the structure
/// @param name the name of the structure
/// @param members the structure members
/// @param align the byte alignment of the structure
/// @param size the byte size of the structure
/// @param size_no_padding size of the members without the end of structure
/// alignment padding
Struct(const ast::Struct* declaration,
tint::Source source,
Symbol name,
utils::VectorRef<const StructMember*> members,
uint32_t align,
uint32_t size,
uint32_t size_no_padding);
/// Destructor
~Struct() override;
/// @returns the struct
const ast::Struct* Declaration() const { return declaration_; }
/// @returns the members of the structure
utils::VectorRef<const StructMember*> Members() const {
return Base::Members().ReinterpretCast<const StructMember*>();
}
private:
ast::Struct const* const declaration_;
};
/// StructMemberBase holds the semantic information for structure members.
class StructMemberBase : public Castable<StructMemberBase, Node> {
public:
/// Constructor
/// @param source the source of the struct member
/// @param name the name of the structure member
/// @param type the type of the member
/// @param index the index of the member in the structure
/// @param offset the byte offset from the base of the structure
/// @param align the byte alignment of the member
/// @param size the byte size of the member
/// @param location the location attribute, if present
StructMemberBase(tint::Source source,
Symbol name,
const sem::Type* type,
uint32_t index,
uint32_t offset,
uint32_t align,
uint32_t size,
std::optional<uint32_t> location);
/// Destructor
~StructMemberBase() override;
/// @returns the source the struct member
const tint::Source& Source() const { return source_; }
/// @returns the name of the structure member
Symbol Name() const { return name_; }
/// Sets the owning structure to `s`
/// @param s the new structure owner
void SetStruct(const sem::StructBase* s) { struct_ = s; }
/// @returns the structure that owns this member
const sem::StructBase* Struct() const { return struct_; }
/// @returns the type of the member
const sem::Type* Type() const { return type_; }
/// @returns the member index
uint32_t Index() const { return index_; }
/// @returns byte offset from base of structure
uint32_t Offset() const { return offset_; }
/// @returns the alignment of the member in bytes
uint32_t Align() const { return align_; }
/// @returns byte size
uint32_t Size() const { return size_; }
/// @returns the location, if set
std::optional<uint32_t> Location() const { return location_; }
private:
const tint::Source source_;
const Symbol name_;
const sem::StructBase* struct_;
const sem::Type* type_;
const uint32_t index_;
const uint32_t offset_;
const uint32_t align_;
const uint32_t size_;
const std::optional<uint32_t> location_;
}; };
/// StructMember holds the semantic information for structure members. /// StructMember holds the semantic information for structure members.
class StructMember final : public Castable<StructMember, Node> { class StructMember final : public Castable<StructMember, StructMemberBase> {
public: public:
/// Constructor /// Constructor
/// @param declaration the AST declaration node /// @param declaration the AST declaration node
@ -207,48 +303,11 @@ class StructMember final : public Castable<StructMember, Node> {
/// @returns the AST declaration node /// @returns the AST declaration node
const ast::StructMember* Declaration() const { return declaration_; } const ast::StructMember* Declaration() const { return declaration_; }
/// @returns the source the struct member
const tint::Source& Source() const { return source_; }
/// @returns the name of the structure member
Symbol Name() const { return name_; }
/// Sets the owning structure to `s`
/// @param s the new structure owner
void SetStruct(const sem::Struct* s) { struct_ = s; }
/// @returns the structure that owns this member /// @returns the structure that owns this member
const sem::Struct* Struct() const { return struct_; } const sem::Struct* Struct() const { return static_cast<const sem::Struct*>(Base::Struct()); }
/// @returns the type of the member
const sem::Type* Type() const { return type_; }
/// @returns the member index
uint32_t Index() const { return index_; }
/// @returns byte offset from base of structure
uint32_t Offset() const { return offset_; }
/// @returns the alignment of the member in bytes
uint32_t Align() const { return align_; }
/// @returns byte size
uint32_t Size() const { return size_; }
/// @returns the location, if set
std::optional<uint32_t> Location() const { return location_; }
private: private:
const ast::StructMember* const declaration_; const ast::StructMember* const declaration_;
const tint::Source source_;
const Symbol name_;
const sem::Struct* struct_;
const sem::Type* type_;
const uint32_t index_;
const uint32_t offset_;
const uint32_t align_;
const uint32_t size_;
const std::optional<uint32_t> location_;
}; };
} // namespace tint::sem } // namespace tint::sem

View File

@ -26,8 +26,8 @@ TEST_F(StructTest, Creation) {
auto name = Sym("S"); auto name = Sym("S");
auto* impl = create<ast::Struct>(name, utils::Empty, utils::Empty); auto* impl = create<ast::Struct>(name, utils::Empty, utils::Empty);
auto* ptr = impl; auto* ptr = impl;
auto* s = create<sem::Struct>(impl, impl->source, impl->name, StructMemberList{}, auto* s = create<sem::Struct>(impl, impl->source, impl->name, utils::Empty, 4u /* align */,
4u /* align */, 8u /* size */, 16u /* size_no_padding */); 8u /* size */, 16u /* size_no_padding */);
EXPECT_EQ(s->Declaration(), ptr); EXPECT_EQ(s->Declaration(), ptr);
EXPECT_EQ(s->Align(), 4u); EXPECT_EQ(s->Align(), 4u);
EXPECT_EQ(s->Size(), 8u); EXPECT_EQ(s->Size(), 8u);
@ -36,10 +36,10 @@ TEST_F(StructTest, Creation) {
TEST_F(StructTest, Hash) { TEST_F(StructTest, Hash) {
auto* a_impl = create<ast::Struct>(Sym("a"), utils::Empty, utils::Empty); auto* a_impl = create<ast::Struct>(Sym("a"), utils::Empty, utils::Empty);
auto* a = create<sem::Struct>(a_impl, a_impl->source, a_impl->name, StructMemberList{}, auto* a = create<sem::Struct>(a_impl, a_impl->source, a_impl->name, utils::Empty,
4u /* align */, 4u /* size */, 4u /* size_no_padding */); 4u /* align */, 4u /* size */, 4u /* size_no_padding */);
auto* b_impl = create<ast::Struct>(Sym("b"), utils::Empty, utils::Empty); auto* b_impl = create<ast::Struct>(Sym("b"), utils::Empty, utils::Empty);
auto* b = create<sem::Struct>(b_impl, b_impl->source, b_impl->name, StructMemberList{}, auto* b = create<sem::Struct>(b_impl, b_impl->source, b_impl->name, utils::Empty,
4u /* align */, 4u /* size */, 4u /* size_no_padding */); 4u /* align */, 4u /* size */, 4u /* size_no_padding */);
EXPECT_NE(a->Hash(), b->Hash()); EXPECT_NE(a->Hash(), b->Hash());
@ -47,10 +47,10 @@ TEST_F(StructTest, Hash) {
TEST_F(StructTest, Equals) { TEST_F(StructTest, Equals) {
auto* a_impl = create<ast::Struct>(Sym("a"), utils::Empty, utils::Empty); auto* a_impl = create<ast::Struct>(Sym("a"), utils::Empty, utils::Empty);
auto* a = create<sem::Struct>(a_impl, a_impl->source, a_impl->name, StructMemberList{}, auto* a = create<sem::Struct>(a_impl, a_impl->source, a_impl->name, utils::Empty,
4u /* align */, 4u /* size */, 4u /* size_no_padding */); 4u /* align */, 4u /* size */, 4u /* size_no_padding */);
auto* b_impl = create<ast::Struct>(Sym("b"), utils::Empty, utils::Empty); auto* b_impl = create<ast::Struct>(Sym("b"), utils::Empty, utils::Empty);
auto* b = create<sem::Struct>(b_impl, b_impl->source, b_impl->name, StructMemberList{}, auto* b = create<sem::Struct>(b_impl, b_impl->source, b_impl->name, utils::Empty,
4u /* align */, 4u /* size */, 4u /* size_no_padding */); 4u /* align */, 4u /* size */, 4u /* size_no_padding */);
EXPECT_TRUE(a->Equals(*a)); EXPECT_TRUE(a->Equals(*a));
@ -61,8 +61,8 @@ TEST_F(StructTest, Equals) {
TEST_F(StructTest, FriendlyName) { TEST_F(StructTest, FriendlyName) {
auto name = Sym("my_struct"); auto name = Sym("my_struct");
auto* impl = create<ast::Struct>(name, utils::Empty, utils::Empty); auto* impl = create<ast::Struct>(name, utils::Empty, utils::Empty);
auto* s = create<sem::Struct>(impl, impl->source, impl->name, StructMemberList{}, auto* s = create<sem::Struct>(impl, impl->source, impl->name, utils::Empty, 4u /* align */,
4u /* align */, 4u /* size */, 4u /* size_no_padding */); 4u /* size */, 4u /* size_no_padding */);
EXPECT_EQ(s->FriendlyName(Symbols()), "my_struct"); EXPECT_EQ(s->FriendlyName(Symbols()), "my_struct");
} }
@ -116,7 +116,7 @@ TEST_F(StructTest, Location) {
ASSERT_TRUE(p.IsValid()) << p.Diagnostics().str(); ASSERT_TRUE(p.IsValid()) << p.Diagnostics().str();
auto* sem = p.Sem().Get(st); auto* sem = p.Sem().Get(st);
ASSERT_EQ(2u, sem->Members().size()); ASSERT_EQ(2u, sem->Members().Length());
EXPECT_TRUE(sem->Members()[0]->Location().has_value()); EXPECT_TRUE(sem->Members()[0]->Location().has_value());
EXPECT_EQ(sem->Members()[0]->Location().value(), 1u); EXPECT_EQ(sem->Members()[0]->Location().value(), 1u);

View File

@ -47,7 +47,7 @@ struct TypeTest : public TestHelper {
const sem::Struct* str_f32 = create<Struct>(nullptr, const sem::Struct* str_f32 = create<Struct>(nullptr,
Source{}, Source{},
Sym("str_f32"), Sym("str_f32"),
StructMemberList{ utils::Vector{
create<StructMember>( create<StructMember>(
/* declaration */ nullptr, /* declaration */ nullptr,
/* source */ Source{}, /* source */ Source{},
@ -65,7 +65,7 @@ struct TypeTest : public TestHelper {
const sem::Struct* str_f16 = create<Struct>(nullptr, const sem::Struct* str_f16 = create<Struct>(nullptr,
Source{}, Source{},
Sym("str_f16"), Sym("str_f16"),
StructMemberList{ utils::Vector{
create<StructMember>( create<StructMember>(
/* declaration */ nullptr, /* declaration */ nullptr,
/* source */ Source{}, /* source */ Source{},
@ -83,7 +83,7 @@ struct TypeTest : public TestHelper {
sem::Struct* str_af = create<Struct>(nullptr, sem::Struct* str_af = create<Struct>(nullptr,
Source{}, Source{},
Sym("str_af"), Sym("str_af"),
StructMemberList{ utils::Vector{
create<StructMember>( create<StructMember>(
/* declaration */ nullptr, /* declaration */ nullptr,
/* source */ Source{}, /* source */ Source{},

View File

@ -145,7 +145,7 @@ struct ArrayLengthFromUniform::State {
if (auto* str = storage_buffer_type->As<sem::Struct>()) { if (auto* str = storage_buffer_type->As<sem::Struct>()) {
// The variable is a struct, so subtract the byte offset of the array // The variable is a struct, so subtract the byte offset of the array
// member. // member.
auto* array_member_sem = str->Members().back(); auto* array_member_sem = str->Members().Back();
array_type = array_member_sem->Type()->As<sem::Array>(); array_type = array_member_sem->Type()->As<sem::Array>();
total_size = b.Sub(total_storage_buffer_size, u32(array_member_sem->Offset())); total_size = b.Sub(total_storage_buffer_size, u32(array_member_sem->Offset()));
} else if (auto* arr = storage_buffer_type->As<sem::Array>()) { } else if (auto* arr = storage_buffer_type->As<sem::Array>()) {

View File

@ -207,7 +207,7 @@ Transform::ApplyResult CalculateArrayLength::Apply(const Program* src,
[&](const sem::Struct* str) { [&](const sem::Struct* str) {
// The variable is a struct, so subtract the byte offset of // The variable is a struct, so subtract the byte offset of
// the array member. // the array member.
auto* array_member_sem = str->Members().back(); auto* array_member_sem = str->Members().Back();
total_size = b.Sub(total_size, u32(array_member_sem->Offset())); total_size = b.Sub(total_size, u32(array_member_sem->Offset()));
return array_member_sem->Type()->As<sem::Array>(); return array_member_sem->Type()->As<sem::Array>();
}, },

View File

@ -714,7 +714,7 @@ struct DecomposeMemoryAccess::State {
TINT_ASSERT(Transform, str && str->Declaration() == nullptr); TINT_ASSERT(Transform, str && str->Declaration() == nullptr);
utils::Vector<const ast::StructMember*, 8> ast_members; utils::Vector<const ast::StructMember*, 8> ast_members;
ast_members.Reserve(str->Members().size()); ast_members.Reserve(str->Members().Length());
for (auto& m : str->Members()) { for (auto& m : str->Members()) {
ast_members.Push( ast_members.Push(
b.Member(ctx.Clone(m->Name()), CreateASTTypeFor(ctx, m->Type()))); b.Member(ctx.Clone(m->Name()), CreateASTTypeFor(ctx, m->Type())));

View File

@ -117,7 +117,7 @@ Transform::ApplyResult NumWorkgroupsFromUniform::Apply(const Program* src,
ctx.Remove(str->Declaration()->members, member->Declaration()); ctx.Remove(str->Declaration()->members, member->Declaration());
// If this is the only member, remove the struct and parameter too. // If this is the only member, remove the struct and parameter too.
if (str->Members().size() == 1) { if (str->Members().Length() == 1) {
ctx.Remove(func->params, param->Declaration()); ctx.Remove(func->params, param->Declaration());
ctx.Remove(src->AST().GlobalDeclarations(), str->Declaration()); ctx.Remove(src->AST().GlobalDeclarations(), str->Declaration());
} }

View File

@ -122,8 +122,8 @@ TEST_F(CreateASTTypeForTest, AliasedArrayWithComplexOverrideLength) {
TEST_F(CreateASTTypeForTest, Struct) { TEST_F(CreateASTTypeForTest, Struct) {
auto* str = create([](ProgramBuilder& b) { auto* str = create([](ProgramBuilder& b) {
auto* decl = b.Structure("S", {}); auto* decl = b.Structure("S", {});
return b.create<sem::Struct>(decl, decl->source, decl->name, sem::StructMemberList{}, return b.create<sem::Struct>(decl, decl->source, decl->name, utils::Empty, 4u /* align */,
4u /* align */, 4u /* size */, 4u /* size_no_padding */); 4u /* size */, 4u /* size_no_padding */);
}); });
ASSERT_TRUE(str->Is<ast::TypeName>()); ASSERT_TRUE(str->Is<ast::TypeName>());
EXPECT_EQ(ast_type_builder.Symbols().NameFor(str->As<ast::TypeName>()->name), "S"); EXPECT_EQ(ast_type_builder.Symbols().NameFor(str->As<ast::TypeName>()->name), "S");

View File

@ -295,7 +295,7 @@ bool GeneratorImpl::Generate() {
} else if (auto* str = decl->As<ast::Struct>()) { } else if (auto* str = decl->As<ast::Struct>()) {
auto* sem = builder_.Sem().Get(str); auto* sem = builder_.Sem().Get(str);
bool has_rt_arr = false; bool has_rt_arr = false;
if (auto* arr = sem->Members().back()->Type()->As<sem::Array>()) { if (auto* arr = sem->Members().Back()->Type()->As<sem::Array>()) {
has_rt_arr = arr->Count()->Is<sem::RuntimeArrayCount>(); has_rt_arr = arr->Count()->Is<sem::RuntimeArrayCount>();
} }
bool is_block = bool is_block =
@ -2385,7 +2385,7 @@ bool GeneratorImpl::EmitConstant(std::ostream& out, const sem::Constant* constan
ScopedParen sp(out); ScopedParen sp(out);
for (size_t i = 0; i < s->Members().size(); i++) { for (size_t i = 0; i < s->Members().Length(); i++) {
if (i > 0) { if (i > 0) {
out << ", "; out << ", ";
} }

View File

@ -3380,7 +3380,7 @@ bool GeneratorImpl::EmitConstant(std::ostream& out,
auto emit_member_values = [&](std::ostream& o) { auto emit_member_values = [&](std::ostream& o) {
o << "{"; o << "{";
for (size_t i = 0; i < s->Members().size(); i++) { for (size_t i = 0; i < s->Members().Length(); i++) {
if (i > 0) { if (i > 0) {
o << ", "; o << ", ";
} }

View File

@ -1761,8 +1761,8 @@ bool GeneratorImpl::EmitConstant(std::ostream& out, const sem::Constant* constan
return true; return true;
} }
auto& members = s->Members(); auto members = s->Members();
for (size_t i = 0; i < members.size(); i++) { for (size_t i = 0; i < members.Length(); i++) {
if (i > 0) { if (i > 0) {
out << ", "; out << ", ";
} }

View File

@ -1706,7 +1706,7 @@ uint32_t Builder::GenerateConstantIfNeeded(const sem::Constant* constant) {
} }
return composite(count.value()); return composite(count.value());
}, },
[&](const sem::Struct* s) { return composite(s->Members().size()); }, [&](const sem::Struct* s) { return composite(s->Members().Length()); },
[&](Default) { [&](Default) {
error_ = "unhandled constant type: " + builder_.FriendlyName(ty); error_ = "unhandled constant type: " + builder_.FriendlyName(ty);
return 0; return 0;
@ -3922,7 +3922,7 @@ bool Builder::GenerateStructType(const sem::Struct* struct_type, const Operand&
push_annot(spv::Op::OpDecorate, {Operand(struct_id), U32Operand(SpvDecorationBlock)}); push_annot(spv::Op::OpDecorate, {Operand(struct_id), U32Operand(SpvDecorationBlock)});
} }
for (uint32_t i = 0; i < struct_type->Members().size(); ++i) { for (uint32_t i = 0; i < struct_type->Members().Length(); ++i) {
auto mem_id = GenerateStructMember(struct_id, i, struct_type->Members()[i]); auto mem_id = GenerateStructMember(struct_id, i, struct_type->Members()[i]);
if (mem_id == 0) { if (mem_id == 0) {
return false; return false;