mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-07-04 12:16:10 +00:00
tint: validate max nesting depth of composite types
Also increased stack size for windows + debug GN builds of tint_unittests to 4 MB, which matches what we do in the CMake build. Required, otherwise some of my new tests stack overflow. Bug: tint:1209 Change-Id: I3b98000a989aa8b42b20cc4e2219c91887e52451 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/121360 Reviewed-by: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
0b3400c56e
commit
6b304e9ffd
@ -2051,6 +2051,12 @@ if (tint_build_unittests) {
|
|||||||
configs += [ "//build/config/compiler:no_chromium_code" ]
|
configs += [ "//build/config/compiler:no_chromium_code" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_win && is_debug) {
|
||||||
|
# TODO(crbug.com/tint/1749): both msvc and clang builds stack overflow on debug builds.
|
||||||
|
# Increase the initial stack size to 4 MB (default is 1MB).
|
||||||
|
ldflags = [ "/STACK:4194304" ]
|
||||||
|
}
|
||||||
|
|
||||||
testonly = true
|
testonly = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,6 +99,7 @@ namespace {
|
|||||||
|
|
||||||
constexpr int64_t kMaxArrayElementCount = 65536;
|
constexpr int64_t kMaxArrayElementCount = 65536;
|
||||||
constexpr uint32_t kMaxStatementDepth = 127;
|
constexpr uint32_t kMaxStatementDepth = 127;
|
||||||
|
constexpr size_t kMaxNestDepthOfCompositeType = 255;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -1697,7 +1698,7 @@ const type::Type* Resolver::ConcreteType(const type::Type* ty,
|
|||||||
target_el_ty = target_arr_ty->ElemType();
|
target_el_ty = target_arr_ty->ElemType();
|
||||||
}
|
}
|
||||||
if (auto* el_ty = ConcreteType(a->ElemType(), target_el_ty, source)) {
|
if (auto* el_ty = ConcreteType(a->ElemType(), target_el_ty, source)) {
|
||||||
return Array(source, source, el_ty, a->Count(), /* explicit_stride */ 0);
|
return Array(source, source, source, el_ty, a->Count(), /* explicit_stride */ 0);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
},
|
},
|
||||||
@ -2129,7 +2130,8 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
|
|||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto* arr = Array(expr->source, expr->source, el_ty, el_count, /* explicit_stride */ 0);
|
auto* arr = Array(expr->source, expr->source, expr->source, el_ty, el_count,
|
||||||
|
/* explicit_stride */ 0);
|
||||||
if (!arr) {
|
if (!arr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -2446,7 +2448,8 @@ type::Type* Resolver::BuiltinType(builtin::Builtin builtin_ty, const ast::Identi
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* out = Array(ast_el_ty->source, //
|
auto* out = Array(tmpl_ident->source, //
|
||||||
|
ast_el_ty->source, //
|
||||||
ast_count ? ast_count->source : ident->source, //
|
ast_count ? ast_count->source : ident->source, //
|
||||||
el_ty, el_count, explicit_stride);
|
el_ty, el_count, explicit_stride);
|
||||||
if (!out) {
|
if (!out) {
|
||||||
@ -2726,6 +2729,19 @@ type::Type* Resolver::BuiltinType(builtin::Builtin builtin_ty, const ast::Identi
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t Resolver::NestDepth(const type::Type* ty) const {
|
||||||
|
return Switch(
|
||||||
|
ty, //
|
||||||
|
[](const type::Vector*) { return size_t{1}; },
|
||||||
|
[](const type::Matrix*) { return size_t{2}; },
|
||||||
|
[&](Default) {
|
||||||
|
if (auto d = nest_depth_.Get(ty)) {
|
||||||
|
return *d;
|
||||||
|
}
|
||||||
|
return size_t{0};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void Resolver::CollectTextureSamplerPairs(
|
void Resolver::CollectTextureSamplerPairs(
|
||||||
const sem::Builtin* builtin,
|
const sem::Builtin* builtin,
|
||||||
utils::VectorRef<const sem::ValueExpression*> args) const {
|
utils::VectorRef<const sem::ValueExpression*> args) const {
|
||||||
@ -3528,7 +3544,8 @@ bool Resolver::ArrayAttributes(utils::VectorRef<const ast::Attribute*> attribute
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
type::Array* Resolver::Array(const Source& el_source,
|
type::Array* Resolver::Array(const Source& array_source,
|
||||||
|
const Source& el_source,
|
||||||
const Source& count_source,
|
const Source& count_source,
|
||||||
const type::Type* el_ty,
|
const type::Type* el_ty,
|
||||||
const type::ArrayCount* el_count,
|
const type::ArrayCount* el_count,
|
||||||
@ -3555,6 +3572,17 @@ type::Array* Resolver::Array(const Source& el_source,
|
|||||||
el_ty, el_count, el_align, static_cast<uint32_t>(size), static_cast<uint32_t>(stride),
|
el_ty, el_count, el_align, static_cast<uint32_t>(size), static_cast<uint32_t>(stride),
|
||||||
static_cast<uint32_t>(implicit_stride));
|
static_cast<uint32_t>(implicit_stride));
|
||||||
|
|
||||||
|
// Maximum nesting depth of composite types
|
||||||
|
// https://gpuweb.github.io/gpuweb/wgsl/#limits
|
||||||
|
const size_t nest_depth = 1 + NestDepth(el_ty);
|
||||||
|
if (nest_depth > kMaxNestDepthOfCompositeType) {
|
||||||
|
AddError("array has nesting depth of " + std::to_string(nest_depth) + ", maximum is " +
|
||||||
|
std::to_string(kMaxNestDepthOfCompositeType),
|
||||||
|
array_source);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
nest_depth_.Add(out, nest_depth);
|
||||||
|
|
||||||
if (!validator_.Array(out, el_source)) {
|
if (!validator_.Array(out, el_source)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -3574,15 +3602,18 @@ type::Type* Resolver::Alias(const ast::Alias* alias) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sem::Struct* Resolver::Structure(const ast::Struct* str) {
|
sem::Struct* Resolver::Structure(const ast::Struct* str) {
|
||||||
|
auto struct_name = [&] { //
|
||||||
|
return builder_->Symbols().NameFor(str->name->symbol);
|
||||||
|
};
|
||||||
|
|
||||||
if (validator_.IsValidationEnabled(str->attributes,
|
if (validator_.IsValidationEnabled(str->attributes,
|
||||||
ast::DisabledValidation::kIgnoreStructMemberLimit)) {
|
ast::DisabledValidation::kIgnoreStructMemberLimit)) {
|
||||||
// Maximum number of members in a structure type
|
// Maximum number of members in a structure type
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#limits
|
// https://gpuweb.github.io/gpuweb/wgsl/#limits
|
||||||
const size_t kMaxNumStructMembers = 16383;
|
const size_t kMaxNumStructMembers = 16383;
|
||||||
if (str->members.Length() > kMaxNumStructMembers) {
|
if (str->members.Length() > kMaxNumStructMembers) {
|
||||||
AddError("struct '" + builder_->Symbols().NameFor(str->name->symbol) + "' has " +
|
AddError("struct '" + struct_name() + "' has " + std::to_string(str->members.Length()) +
|
||||||
std::to_string(str->members.Length()) + " members, maximum is " +
|
" members, maximum is " + std::to_string(kMaxNumStructMembers),
|
||||||
std::to_string(kMaxNumStructMembers),
|
|
||||||
str->source);
|
str->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -3608,6 +3639,7 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
|
|||||||
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;
|
||||||
|
|
||||||
|
size_t members_nest_depth = 0;
|
||||||
for (auto* member : str->members) {
|
for (auto* member : str->members) {
|
||||||
Mark(member);
|
Mark(member);
|
||||||
Mark(member->name);
|
Mark(member->name);
|
||||||
@ -3624,6 +3656,8 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
members_nest_depth = std::max(members_nest_depth, NestDepth(type));
|
||||||
|
|
||||||
// validator_.Validate member type
|
// validator_.Validate member type
|
||||||
if (!validator_.IsPlain(type)) {
|
if (!validator_.IsPlain(type)) {
|
||||||
AddError(sem_.TypeNameOf(type) + " cannot be used as the type of a structure member",
|
AddError(sem_.TypeNameOf(type) + " cannot be used as the type of a structure member",
|
||||||
@ -3821,6 +3855,18 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Maximum nesting depth of composite types
|
||||||
|
// https://gpuweb.github.io/gpuweb/wgsl/#limits
|
||||||
|
const size_t nest_depth = 1 + members_nest_depth;
|
||||||
|
if (nest_depth > kMaxNestDepthOfCompositeType) {
|
||||||
|
AddError("struct '" + struct_name() + "' has nesting depth of " +
|
||||||
|
std::to_string(nest_depth) + ", maximum is " +
|
||||||
|
std::to_string(kMaxNestDepthOfCompositeType),
|
||||||
|
str->source);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
nest_depth_.Add(out, nest_depth);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,6 +349,7 @@ class Resolver {
|
|||||||
|
|
||||||
/// Builds and returns the semantic information for an array.
|
/// Builds and returns the semantic information for an array.
|
||||||
/// @returns the semantic Array information, or nullptr if an error is raised.
|
/// @returns the semantic Array information, or nullptr if an error is raised.
|
||||||
|
/// @param array_source the source of the array
|
||||||
/// @param el_source the source of the array element, or the array if the array does not have a
|
/// @param el_source the source of the array element, or the array if the array does not have a
|
||||||
/// locally-declared element AST node.
|
/// locally-declared element AST node.
|
||||||
/// @param count_source the source of the array count, or the array if the array does not have a
|
/// @param count_source the source of the array count, or the array if the array does not have a
|
||||||
@ -356,7 +357,8 @@ class Resolver {
|
|||||||
/// @param el_ty the Array element type
|
/// @param el_ty the Array element type
|
||||||
/// @param el_count the number of elements in the array.
|
/// @param el_count the number of elements in the array.
|
||||||
/// @param explicit_stride the explicit byte stride of the array. Zero means implicit stride.
|
/// @param explicit_stride the explicit byte stride of the array. Zero means implicit stride.
|
||||||
type::Array* Array(const Source& el_source,
|
type::Array* Array(const Source& array_source,
|
||||||
|
const Source& el_source,
|
||||||
const Source& count_source,
|
const Source& count_source,
|
||||||
const type::Type* el_ty,
|
const type::Type* el_ty,
|
||||||
const type::ArrayCount* el_count,
|
const type::ArrayCount* el_count,
|
||||||
@ -496,6 +498,10 @@ class Resolver {
|
|||||||
/// @note: Will raise an ICE if @p symbol is not a builtin type.
|
/// @note: Will raise an ICE if @p symbol is not a builtin type.
|
||||||
type::Type* BuiltinType(builtin::Builtin builtin_ty, const ast::Identifier* ident);
|
type::Type* BuiltinType(builtin::Builtin builtin_ty, const ast::Identifier* ident);
|
||||||
|
|
||||||
|
/// @returns the nesting depth of @ty as defined in
|
||||||
|
/// https://gpuweb.github.io/gpuweb/wgsl/#composite-types
|
||||||
|
size_t NestDepth(const type::Type* ty) const;
|
||||||
|
|
||||||
// ArrayConstructorSig represents a unique array constructor signature.
|
// ArrayConstructorSig represents a unique array constructor signature.
|
||||||
// It is a tuple of the array type, number of arguments provided and earliest evaluation stage.
|
// It is a tuple of the array type, number of arguments provided and earliest evaluation stage.
|
||||||
using ArrayConstructorSig =
|
using ArrayConstructorSig =
|
||||||
@ -566,6 +572,7 @@ class Resolver {
|
|||||||
logical_binary_lhs_to_parent_;
|
logical_binary_lhs_to_parent_;
|
||||||
utils::Hashset<const ast::Expression*, 8> skip_const_eval_;
|
utils::Hashset<const ast::Expression*, 8> skip_const_eval_;
|
||||||
IdentifierResolveHint identifier_resolve_hint_;
|
IdentifierResolveHint identifier_resolve_hint_;
|
||||||
|
utils::Hashmap<const type::Type*, size_t, 8> nest_depth_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::resolver
|
} // namespace tint::resolver
|
||||||
|
@ -2434,5 +2434,195 @@ TEST_F(ResolverTest, MaxNumStructMembers_WithIgnoreStructMemberLimit_Valid) {
|
|||||||
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t kMaxNestDepthOfCompositeType = 255;
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNestDepthOfCompositeType_Structs_Valid) {
|
||||||
|
auto* s = Structure("S", utils::Vector{Member("m", ty.i32())});
|
||||||
|
size_t depth = 1; // Depth of struct
|
||||||
|
size_t iterations = kMaxNestDepthOfCompositeType - depth;
|
||||||
|
for (size_t i = 0; i < iterations; ++i) {
|
||||||
|
s = Structure("S" + std::to_string(i), utils::Vector{Member("m", ty.Of(s))});
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNestDepthOfCompositeType_Structs_Invalid) {
|
||||||
|
auto* s = Structure("S", utils::Vector{Member("m", ty.i32())});
|
||||||
|
size_t depth = 1; // Depth of struct
|
||||||
|
size_t iterations = kMaxNestDepthOfCompositeType - depth + 1;
|
||||||
|
for (size_t i = 0; i < iterations; ++i) {
|
||||||
|
auto source = i == iterations - 1 ? Source{{12, 34}} : Source{{0, i}};
|
||||||
|
s = Structure(source, "S" + std::to_string(i), utils::Vector{Member("m", ty.Of(s))});
|
||||||
|
}
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(), "12:34 error: struct 'S254' has nesting depth of 256, maximum is 255");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNestDepthOfCompositeType_StructsWithVector_Valid) {
|
||||||
|
auto* s = Structure("S", utils::Vector{Member("m", ty.vec3<i32>())});
|
||||||
|
size_t depth = 2; // Despth of struct + vector
|
||||||
|
size_t iterations = kMaxNestDepthOfCompositeType - depth;
|
||||||
|
for (size_t i = 0; i < iterations; ++i) {
|
||||||
|
s = Structure("S" + std::to_string(i), utils::Vector{Member("m", ty.Of(s))});
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNestDepthOfCompositeType_StructsWithVector_Invalid) {
|
||||||
|
auto* s = Structure("S", utils::Vector{Member("m", ty.vec3<i32>())});
|
||||||
|
size_t depth = 2; // Despth of struct + vector
|
||||||
|
size_t iterations = kMaxNestDepthOfCompositeType - depth + 1;
|
||||||
|
for (size_t i = 0; i < iterations; ++i) {
|
||||||
|
auto source = i == iterations - 1 ? Source{{12, 34}} : Source{{0, i}};
|
||||||
|
s = Structure(source, "S" + std::to_string(i), utils::Vector{Member("m", ty.Of(s))});
|
||||||
|
}
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(), "12:34 error: struct 'S253' has nesting depth of 256, maximum is 255");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNestDepthOfCompositeType_StructsWithMatrix_Valid) {
|
||||||
|
auto* s = Structure("S", utils::Vector{Member("m", ty.mat3x3<f32>())});
|
||||||
|
size_t depth = 3; // Depth of struct + matrix
|
||||||
|
size_t iterations = kMaxNestDepthOfCompositeType - depth;
|
||||||
|
for (size_t i = 0; i < iterations; ++i) {
|
||||||
|
s = Structure("S" + std::to_string(i), utils::Vector{Member("m", ty.Of(s))});
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNestDepthOfCompositeType_StructsWithMatrix_Invalid) {
|
||||||
|
auto* s = Structure("S", utils::Vector{Member("m", ty.mat3x3<f32>())});
|
||||||
|
size_t depth = 3; // Depth of struct + matrix
|
||||||
|
size_t iterations = kMaxNestDepthOfCompositeType - depth + 1;
|
||||||
|
for (size_t i = 0; i < iterations; ++i) {
|
||||||
|
auto source = i == iterations - 1 ? Source{{12, 34}} : Source{{0, i}};
|
||||||
|
s = Structure(source, "S" + std::to_string(i), utils::Vector{Member("m", ty.Of(s))});
|
||||||
|
}
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(), "12:34 error: struct 'S252' has nesting depth of 256, maximum is 255");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNestDepthOfCompositeType_Arrays_Valid) {
|
||||||
|
auto a = ty.array(ty.i32(), 10_u);
|
||||||
|
size_t depth = 1; // Depth of array
|
||||||
|
size_t iterations = kMaxNestDepthOfCompositeType - depth;
|
||||||
|
for (size_t i = 0; i < iterations; ++i) {
|
||||||
|
a = ty.array(a, 1_u);
|
||||||
|
}
|
||||||
|
Alias("a", a);
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNestDepthOfCompositeType_Arrays_Invalid) {
|
||||||
|
auto a = ty.array(Source{{99, 88}}, ty.i32(), 10_u);
|
||||||
|
size_t depth = 1; // Depth of array
|
||||||
|
size_t iterations = kMaxNestDepthOfCompositeType - depth + 1;
|
||||||
|
for (size_t i = 0; i < iterations; ++i) {
|
||||||
|
auto source = (i == iterations - 1) ? Source{{12, 34}} : Source{{0, i}};
|
||||||
|
a = ty.array(source, a, 1_u);
|
||||||
|
}
|
||||||
|
Alias("a", a);
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(), "12:34 error: array has nesting depth of 256, maximum is 255");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNestDepthOfCompositeType_ArraysOfVector_Valid) {
|
||||||
|
auto a = ty.array(ty.vec3<i32>(), 10_u);
|
||||||
|
size_t depth = 2; // Depth of array + vector
|
||||||
|
size_t iterations = kMaxNestDepthOfCompositeType - depth;
|
||||||
|
for (size_t i = 0; i < iterations; ++i) {
|
||||||
|
a = ty.array(a, 1_u);
|
||||||
|
}
|
||||||
|
Alias("a", a);
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNestDepthOfCompositeType_ArraysOfVector_Invalid) {
|
||||||
|
auto a = ty.array(Source{{99, 88}}, ty.vec3<i32>(), 10_u);
|
||||||
|
size_t depth = 2; // Depth of array + vector
|
||||||
|
size_t iterations = kMaxNestDepthOfCompositeType - depth + 1;
|
||||||
|
for (size_t i = 0; i < iterations; ++i) {
|
||||||
|
auto source = (i == iterations - 1) ? Source{{12, 34}} : Source{{0, i}};
|
||||||
|
a = ty.array(source, a, 1_u);
|
||||||
|
}
|
||||||
|
Alias("a", a);
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(), "12:34 error: array has nesting depth of 256, maximum is 255");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNestDepthOfCompositeType_ArraysOfMatrix_Valid) {
|
||||||
|
auto a = ty.array(ty.mat3x3<f32>(), 10_u);
|
||||||
|
size_t depth = 3; // Depth of array + matrix
|
||||||
|
size_t iterations = kMaxNestDepthOfCompositeType - depth;
|
||||||
|
for (size_t i = 0; i < iterations; ++i) {
|
||||||
|
a = ty.array(a, 1_u);
|
||||||
|
}
|
||||||
|
Alias("a", a);
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNestDepthOfCompositeType_ArraysOfMatrix_Invalid) {
|
||||||
|
auto a = ty.array(ty.mat3x3<f32>(), 10_u);
|
||||||
|
size_t depth = 3; // Depth of array + matrix
|
||||||
|
size_t iterations = kMaxNestDepthOfCompositeType - depth + 1;
|
||||||
|
for (size_t i = 0; i < iterations; ++i) {
|
||||||
|
auto source = (i == iterations - 1) ? Source{{12, 34}} : Source{{0, i}};
|
||||||
|
a = ty.array(source, a, 1_u);
|
||||||
|
}
|
||||||
|
Alias("a", a);
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(), "12:34 error: array has nesting depth of 256, maximum is 255");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNestDepthOfCompositeType_StructsOfArray_Valid) {
|
||||||
|
auto a = ty.array(ty.mat3x3<f32>(), 10_u);
|
||||||
|
auto* s = Structure("S", utils::Vector{Member("m", a)});
|
||||||
|
size_t depth = 4; // Depth of struct + array + matrix
|
||||||
|
size_t iterations = kMaxNestDepthOfCompositeType - depth;
|
||||||
|
for (size_t i = 0; i < iterations; ++i) {
|
||||||
|
s = Structure("S" + std::to_string(i), utils::Vector{Member("m", ty.Of(s))});
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNestDepthOfCompositeType_StructsOfArray_Invalid) {
|
||||||
|
auto a = ty.array(ty.mat3x3<f32>(), 10_u);
|
||||||
|
auto* s = Structure("S", utils::Vector{Member("m", a)});
|
||||||
|
size_t depth = 4; // Depth of struct + array + matrix
|
||||||
|
size_t iterations = kMaxNestDepthOfCompositeType - depth + 1;
|
||||||
|
for (size_t i = 0; i < iterations; ++i) {
|
||||||
|
auto source = i == iterations - 1 ? Source{{12, 34}} : Source{{0, i}};
|
||||||
|
s = Structure(source, "S" + std::to_string(i), utils::Vector{Member("m", ty.Of(s))});
|
||||||
|
}
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(), "12:34 error: struct 'S251' has nesting depth of 256, maximum is 255");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNestDepthOfCompositeType_ArraysOfStruct_Valid) {
|
||||||
|
auto* s = Structure("S", utils::Vector{Member("m", ty.mat3x3<f32>())});
|
||||||
|
auto a = ty.array(ty.Of(s), 10_u);
|
||||||
|
size_t depth = 4; // Depth of array + struct + matrix
|
||||||
|
size_t iterations = kMaxNestDepthOfCompositeType - depth;
|
||||||
|
for (size_t i = 0; i < iterations; ++i) {
|
||||||
|
a = ty.array(a, 1_u);
|
||||||
|
}
|
||||||
|
Alias("a", a);
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverTest, MaxNestDepthOfCompositeType_ArraysOfStruct_Invalid) {
|
||||||
|
auto* s = Structure("S", utils::Vector{Member("m", ty.mat3x3<f32>())});
|
||||||
|
auto a = ty.array(ty.Of(s), 10_u);
|
||||||
|
size_t depth = 4; // Depth of array + struct + matrix
|
||||||
|
size_t iterations = kMaxNestDepthOfCompositeType - depth + 1;
|
||||||
|
for (size_t i = 0; i < iterations; ++i) {
|
||||||
|
auto source = (i == iterations - 1) ? Source{{12, 34}} : Source{{0, i}};
|
||||||
|
a = ty.array(source, a, 1_u);
|
||||||
|
}
|
||||||
|
Alias("a", a);
|
||||||
|
EXPECT_FALSE(r()->Resolve());
|
||||||
|
EXPECT_EQ(r()->error(), "12:34 error: array has nesting depth of 256, maximum is 255");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace tint::resolver
|
} // namespace tint::resolver
|
||||||
|
Loading…
x
Reference in New Issue
Block a user