[tint] Add TINT_ASSERT_ALL_FIELDS_REFLECTED() macro
Performs a compile-time assertion that all the fields of the given class have been reflected with TINT_REFLECT().
Change-Id: I4813486037715801a8b011c23f38e31e367c894c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/172600
Auto-Submit: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/tint/api/common/binding_point.h b/src/tint/api/common/binding_point.h
index 64d61f6..b602c81 100644
--- a/src/tint/api/common/binding_point.h
+++ b/src/tint/api/common/binding_point.h
@@ -46,7 +46,7 @@
uint32_t binding = 0;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(group, binding);
+ TINT_REFLECT(BindingPoint, group, binding);
/// Equality operator
/// @param rhs the BindingPoint to compare against
@@ -74,6 +74,9 @@
}
};
+/// Ensure that all the fields of BindingPoint are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(BindingPoint);
+
/// Prints the BindingPoint @p bp to @p o
/// @param o the stream to write to
/// @param bp the BindingPoint
diff --git a/src/tint/api/common/override_id.h b/src/tint/api/common/override_id.h
index 70abc33..f7a6837 100644
--- a/src/tint/api/common/override_id.h
+++ b/src/tint/api/common/override_id.h
@@ -41,9 +41,12 @@
uint16_t value = 0;
/// Reflect the fields of this struct so that it can be used by tint::ForeachField()
- TINT_REFLECT(value);
+ TINT_REFLECT(OverrideId, value);
};
+/// Ensure that all the fields of OverrideId are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(OverrideId);
+
/// Equality operator for OverrideId
/// @param lhs the OverrideId on the left of the '=' operator
/// @param rhs the OverrideId on the right of the '=' operator
diff --git a/src/tint/api/options/array_length_from_uniform.h b/src/tint/api/options/array_length_from_uniform.h
index ba7094a..f46825f 100644
--- a/src/tint/api/options/array_length_from_uniform.h
+++ b/src/tint/api/options/array_length_from_uniform.h
@@ -45,9 +45,12 @@
std::unordered_map<BindingPoint, uint32_t> bindpoint_to_size_index;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(ubo_binding, bindpoint_to_size_index);
+ TINT_REFLECT(ArrayLengthFromUniformOptions, ubo_binding, bindpoint_to_size_index);
};
+/// Ensure that all the fields of ArrayLengthFromUniformOptions are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(ArrayLengthFromUniformOptions);
+
} // namespace tint
#endif // SRC_TINT_API_OPTIONS_ARRAY_LENGTH_FROM_UNIFORM_H_
diff --git a/src/tint/api/options/binding_remapper.h b/src/tint/api/options/binding_remapper.h
index 493c854..4e1e4f8 100644
--- a/src/tint/api/options/binding_remapper.h
+++ b/src/tint/api/options/binding_remapper.h
@@ -43,9 +43,12 @@
BindingPoints binding_points;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(binding_points);
+ TINT_REFLECT(BindingRemapperOptions, binding_points);
};
+/// Ensure that all the fields of BindingRemapperOptions are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(BindingRemapperOptions);
+
} // namespace tint
#endif // SRC_TINT_API_OPTIONS_BINDING_REMAPPER_H_
diff --git a/src/tint/api/options/external_texture.h b/src/tint/api/options/external_texture.h
index ff01aec..76e7898 100644
--- a/src/tint/api/options/external_texture.h
+++ b/src/tint/api/options/external_texture.h
@@ -47,7 +47,7 @@
BindingPoint params;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(plane_1, params);
+ TINT_REFLECT(BindingPoints, plane_1, params);
};
/// BindingsMap is a map where the key is the binding location of a
@@ -59,9 +59,15 @@
BindingsMap bindings_map;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(bindings_map);
+ TINT_REFLECT(ExternalTextureOptions, bindings_map);
};
+/// Ensure that all the fields of ExternalTextureOptions::BindingPoints are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(ExternalTextureOptions::BindingPoints);
+
+/// Ensure that all the fields of ExternalTextureOptions are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(ExternalTextureOptions);
+
} // namespace tint
#endif // SRC_TINT_API_OPTIONS_EXTERNAL_TEXTURE_H_
diff --git a/src/tint/api/options/pixel_local.h b/src/tint/api/options/pixel_local.h
index 1b4e200..64022c3 100644
--- a/src/tint/api/options/pixel_local.h
+++ b/src/tint/api/options/pixel_local.h
@@ -54,9 +54,12 @@
uint32_t pixel_local_group_index = 0;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(attachments, attachment_formats, pixel_local_group_index);
+ TINT_REFLECT(PixelLocalOptions, attachments, attachment_formats, pixel_local_group_index);
};
+/// Ensure that all the fields of PixelLocalOptions are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(PixelLocalOptions);
+
/// Reflect valid value ranges for the PixelLocalOptions::TexelFormat enum.
TINT_REFLECT_ENUM_RANGE(PixelLocalOptions::TexelFormat, kR32Sint, kR32Float);
diff --git a/src/tint/api/options/texture_builtins_from_uniform.h b/src/tint/api/options/texture_builtins_from_uniform.h
index ac107e5..b929c6b 100644
--- a/src/tint/api/options/texture_builtins_from_uniform.h
+++ b/src/tint/api/options/texture_builtins_from_uniform.h
@@ -47,9 +47,12 @@
std::vector<BindingPoint> ubo_bindingpoint_ordering = {};
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(ubo_binding, ubo_bindingpoint_ordering);
+ TINT_REFLECT(TextureBuiltinsFromUniformOptions, ubo_binding, ubo_bindingpoint_ordering);
};
+/// Ensure that all the fields of TextureBuiltinsFromUniformOptions are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(TextureBuiltinsFromUniformOptions);
+
} // namespace tint
#endif // SRC_TINT_API_OPTIONS_TEXTURE_BUILTINS_FROM_UNIFORM_H_
diff --git a/src/tint/lang/core/BUILD.bazel b/src/tint/lang/core/BUILD.bazel
index ade8daa..6515589 100644
--- a/src/tint/lang/core/BUILD.bazel
+++ b/src/tint/lang/core/BUILD.bazel
@@ -145,6 +145,7 @@
deps = [
"//src/tint/lang/core",
"//src/tint/utils/macros",
+ "//src/tint/utils/math",
"//src/tint/utils/reflection",
"//src/tint/utils/traits",
"@benchmark",
diff --git a/src/tint/lang/core/BUILD.cmake b/src/tint/lang/core/BUILD.cmake
index ea40bb5..d9786fe 100644
--- a/src/tint/lang/core/BUILD.cmake
+++ b/src/tint/lang/core/BUILD.cmake
@@ -152,6 +152,7 @@
tint_target_add_dependencies(tint_lang_core_bench bench
tint_lang_core
tint_utils_macros
+ tint_utils_math
tint_utils_reflection
tint_utils_traits
)
diff --git a/src/tint/lang/core/BUILD.gn b/src/tint/lang/core/BUILD.gn
index b1186f8..cd834ac 100644
--- a/src/tint/lang/core/BUILD.gn
+++ b/src/tint/lang/core/BUILD.gn
@@ -144,6 +144,7 @@
"${tint_src_dir}:google_benchmark",
"${tint_src_dir}/lang/core",
"${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
"${tint_src_dir}/utils/reflection",
"${tint_src_dir}/utils/traits",
]
diff --git a/src/tint/lang/glsl/writer/common/options.h b/src/tint/lang/glsl/writer/common/options.h
index 1f5298f..31e1244 100644
--- a/src/tint/lang/glsl/writer/common/options.h
+++ b/src/tint/lang/glsl/writer/common/options.h
@@ -88,7 +88,8 @@
TextureBuiltinsFromUniformOptions texture_builtins_from_uniform = {};
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(disable_robustness,
+ TINT_REFLECT(Options,
+ disable_robustness,
disable_workgroup_init,
disable_polyfill_integer_div_mod,
version,
@@ -96,9 +97,13 @@
placeholder_binding_point,
binding_remapper_options,
external_texture_options,
+ first_instance_offset,
texture_builtins_from_uniform);
};
+/// Ensure that all the fields of Options are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Options);
+
} // namespace tint::glsl::writer
#endif // SRC_TINT_LANG_GLSL_WRITER_COMMON_OPTIONS_H_
diff --git a/src/tint/lang/glsl/writer/common/version.h b/src/tint/lang/glsl/writer/common/version.h
index 9c3463a..7eb682e 100644
--- a/src/tint/lang/glsl/writer/common/version.h
+++ b/src/tint/lang/glsl/writer/common/version.h
@@ -68,9 +68,12 @@
uint32_t minor_version = 1;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(standard, major_version, minor_version);
+ TINT_REFLECT(Version, standard, major_version, minor_version);
};
+/// Ensure that all the fields of Version are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Version);
+
} // namespace tint::glsl::writer
namespace tint {
diff --git a/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.h b/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.h
index ff2830b..d8a284a 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.h
+++ b/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.h
@@ -124,9 +124,12 @@
std::bitset<30> interstage_locations;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(interstage_variables);
+ TINT_REFLECT(Config, interstage_locations);
};
+ /// Ensure that all the fields of Config are reflected.
+ TINT_ASSERT_ALL_FIELDS_REFLECTED(Config);
+
/// Constructor using a the configuration provided in the input Data
TruncateInterstageVariables();
diff --git a/src/tint/lang/hlsl/writer/common/options.h b/src/tint/lang/hlsl/writer/common/options.h
index 50cf766..b8d9a75 100644
--- a/src/tint/lang/hlsl/writer/common/options.h
+++ b/src/tint/lang/hlsl/writer/common/options.h
@@ -108,7 +108,8 @@
PixelLocalOptions pixel_local_options = {};
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(disable_robustness,
+ TINT_REFLECT(Options,
+ disable_robustness,
disable_workgroup_init,
truncate_interstage_variables,
polyfill_reflect_vec2_f32,
@@ -125,6 +126,9 @@
pixel_local_options);
};
+/// Ensure that all the fields of Options are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Options);
+
} // namespace tint::hlsl::writer
#endif // SRC_TINT_LANG_HLSL_WRITER_COMMON_OPTIONS_H_
diff --git a/src/tint/lang/msl/writer/common/options.h b/src/tint/lang/msl/writer/common/options.h
index 1004293..3b359ab 100644
--- a/src/tint/lang/msl/writer/common/options.h
+++ b/src/tint/lang/msl/writer/common/options.h
@@ -53,8 +53,12 @@
inline bool operator!=(const BindingInfo& rhs) const { return !(*this == rhs); }
/// Reflect the fields of this class so taht it can be used by tint::ForeachField()
- TINT_REFLECT(binding);
+ TINT_REFLECT(BindingInfo, binding);
};
+
+/// Ensure that all the fields of BindingInfo are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(BindingInfo);
+
using Uniform = BindingInfo;
using Storage = BindingInfo;
using Texture = BindingInfo;
@@ -71,9 +75,12 @@
BindingInfo plane1{};
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(metadata, plane0, plane1);
+ TINT_REFLECT(ExternalTexture, metadata, plane0, plane1);
};
+/// Ensure that all the fields of ExternalTexture are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(ExternalTexture);
+
} // namespace binding
/// Maps the WGSL binding point to the SPIR-V group,binding for uniforms
@@ -105,9 +112,12 @@
ExternalTextureBindings external_texture{};
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(uniform, storage, texture, storage_texture, sampler, external_texture);
+ TINT_REFLECT(Bindings, uniform, storage, texture, storage_texture, sampler, external_texture);
};
+/// Ensure that all the fields of Bindings are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Bindings);
+
/// Configuration options used for generating MSL.
struct Options {
/// Constructor
@@ -152,7 +162,8 @@
Bindings bindings;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(disable_robustness,
+ TINT_REFLECT(Options,
+ disable_robustness,
disable_workgroup_init,
emit_vertex_point_size,
disable_polyfill_integer_div_mod,
@@ -163,6 +174,9 @@
bindings);
};
+/// Ensure that all the fields of Options are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Options);
+
} // namespace tint::msl::writer
#endif // SRC_TINT_LANG_MSL_WRITER_COMMON_OPTIONS_H_
diff --git a/src/tint/lang/spirv/writer/common/options.h b/src/tint/lang/spirv/writer/common/options.h
index 494369c..4fcbafe 100644
--- a/src/tint/lang/spirv/writer/common/options.h
+++ b/src/tint/lang/spirv/writer/common/options.h
@@ -55,8 +55,12 @@
inline bool operator!=(const BindingInfo& rhs) const { return !(*this == rhs); }
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(group, binding);
+ TINT_REFLECT(BindingInfo, group, binding);
};
+
+/// Ensure that all the fields of BindingInfo are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(BindingInfo);
+
using Uniform = BindingInfo;
using Storage = BindingInfo;
using Texture = BindingInfo;
@@ -73,9 +77,12 @@
BindingInfo plane1{};
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(metadata, plane0, plane1);
+ TINT_REFLECT(ExternalTexture, metadata, plane0, plane1);
};
+/// Ensure that all the fields of ExternalTexture are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(ExternalTexture);
+
} // namespace binding
// Maps the WGSL binding point to the SPIR-V group,binding for uniforms
@@ -107,9 +114,12 @@
ExternalTextureBindings external_texture{};
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(uniform, storage, texture, storage_texture, sampler, external_texture);
+ TINT_REFLECT(Bindings, uniform, storage, texture, storage_texture, sampler, external_texture);
};
+/// Ensure that all the fields of Bindings are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Bindings);
+
/// Configuration options used for generating SPIR-V.
struct Options {
/// Set to `true` to disable software robustness that prevents out-of-bounds accesses.
@@ -153,7 +163,8 @@
Bindings bindings;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(disable_robustness,
+ TINT_REFLECT(Options,
+ disable_robustness,
disable_image_robustness,
disable_runtime_sized_array_index_clamping,
disable_workgroup_init,
@@ -167,6 +178,9 @@
bindings);
};
+/// Ensure that all the fields of Options are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Options);
+
} // namespace tint::spirv::writer
#endif // SRC_TINT_LANG_SPIRV_WRITER_COMMON_OPTIONS_H_
diff --git a/src/tint/lang/wgsl/ast/transform/substitute_override.h b/src/tint/lang/wgsl/ast/transform/substitute_override.h
index 2e18b11..c95426d 100644
--- a/src/tint/lang/wgsl/ast/transform/substitute_override.h
+++ b/src/tint/lang/wgsl/ast/transform/substitute_override.h
@@ -79,9 +79,12 @@
std::unordered_map<OverrideId, double> map;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(map);
+ TINT_REFLECT(Config, map);
};
+ /// Ensure that all the fields of Config are reflected.
+ TINT_ASSERT_ALL_FIELDS_REFLECTED(Config);
+
/// Constructor
SubstituteOverride();
diff --git a/src/tint/lang/wgsl/ast/transform/vertex_pulling.h b/src/tint/lang/wgsl/ast/transform/vertex_pulling.h
index 62ec75f..f238c0d 100644
--- a/src/tint/lang/wgsl/ast/transform/vertex_pulling.h
+++ b/src/tint/lang/wgsl/ast/transform/vertex_pulling.h
@@ -89,9 +89,12 @@
uint32_t shader_location;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(format, offset, shader_location);
+ TINT_REFLECT(VertexAttributeDescriptor, format, offset, shader_location);
};
+/// Ensure that all the fields of VertexAttributeDescriptor are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(VertexAttributeDescriptor);
+
/// Describes a buffer containing multiple vertex attributes
struct VertexBufferLayoutDescriptor {
/// Constructor
@@ -122,9 +125,12 @@
std::vector<VertexAttributeDescriptor> attributes;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(array_stride, step_mode, attributes);
+ TINT_REFLECT(VertexBufferLayoutDescriptor, array_stride, step_mode, attributes);
};
+/// Ensure that all the fields of VertexBufferLayoutDescriptor are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(VertexBufferLayoutDescriptor);
+
/// Describes vertex state, which consists of many buffers containing vertex
/// attributes
using VertexStateDescriptor = std::vector<VertexBufferLayoutDescriptor>;
@@ -176,9 +182,12 @@
uint32_t pulling_group = 4u;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(vertex_state, pulling_group);
+ TINT_REFLECT(Config, vertex_state, pulling_group);
};
+ /// Ensure that all the fields of Config are reflected.
+ TINT_ASSERT_ALL_FIELDS_REFLECTED(Config);
+
/// Constructor
VertexPulling();
diff --git a/src/tint/lang/wgsl/common/allowed_features.h b/src/tint/lang/wgsl/common/allowed_features.h
index 7549fc7..9673103 100644
--- a/src/tint/lang/wgsl/common/allowed_features.h
+++ b/src/tint/lang/wgsl/common/allowed_features.h
@@ -63,9 +63,12 @@
}
/// Reflect the fields of this class so that it can be used by tint::ForeachField().
- TINT_REFLECT(extensions, features);
+ TINT_REFLECT(AllowedFeatures, extensions, features);
};
+/// Ensure that all the fields of AllowedFeatures are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(AllowedFeatures);
+
} // namespace tint::wgsl
#endif // SRC_TINT_LANG_WGSL_COMMON_ALLOWED_FEATURES_H_
diff --git a/src/tint/lang/wgsl/reader/options.h b/src/tint/lang/wgsl/reader/options.h
index 3ac0e03..eb3400f 100644
--- a/src/tint/lang/wgsl/reader/options.h
+++ b/src/tint/lang/wgsl/reader/options.h
@@ -39,9 +39,12 @@
AllowedFeatures allowed_features{};
/// Reflect the fields of this class so that it can be used by tint::ForeachField().
- TINT_REFLECT(allowed_features);
+ TINT_REFLECT(Options, allowed_features);
};
+/// Ensure that all the fields of Options are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Options);
+
} // namespace tint::wgsl::reader
#endif // SRC_TINT_LANG_WGSL_READER_OPTIONS_H_
diff --git a/src/tint/lang/wgsl/sem/sampler_texture_pair.h b/src/tint/lang/wgsl/sem/sampler_texture_pair.h
index f5896b6..6d3d6ae 100644
--- a/src/tint/lang/wgsl/sem/sampler_texture_pair.h
+++ b/src/tint/lang/wgsl/sem/sampler_texture_pair.h
@@ -68,9 +68,12 @@
}
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
- TINT_REFLECT(sampler_binding_point, texture_binding_point);
+ TINT_REFLECT(SamplerTexturePair, sampler_binding_point, texture_binding_point);
};
+/// Ensure that all the fields of SamplerTexturePair are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(SamplerTexturePair);
+
/// Prints the SamplerTexturePair @p stp to @p o
/// @param o the stream to write to
/// @param stp the SamplerTexturePair
diff --git a/src/tint/lang/wgsl/writer/options.h b/src/tint/lang/wgsl/writer/options.h
index 6fab6bb..09279a9 100644
--- a/src/tint/lang/wgsl/writer/options.h
+++ b/src/tint/lang/wgsl/writer/options.h
@@ -48,10 +48,15 @@
/// Set to `true` to use the syntax tree writer
bool use_syntax_tree_writer = false;
- TINT_REFLECT(use_syntax_tree_writer);
+ TINT_REFLECT(Options, use_syntax_tree_writer);
#endif
};
+#ifdef TINT_BUILD_SYNTAX_TREE_WRITER
+/// Ensure that all the fields of SamplerTexturePair are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Options);
+#endif
+
} // namespace tint::wgsl::writer
#endif // SRC_TINT_LANG_WGSL_WRITER_OPTIONS_H_
diff --git a/src/tint/utils/bytes/decoder_test.cc b/src/tint/utils/bytes/decoder_test.cc
index 3535298..d33dc42 100644
--- a/src/tint/utils/bytes/decoder_test.cc
+++ b/src/tint/utils/bytes/decoder_test.cc
@@ -114,7 +114,7 @@
uint8_t a;
uint16_t b;
uint32_t c;
- TINT_REFLECT(a, b, c);
+ TINT_REFLECT(S, a, b, c);
};
TEST(BytesDecoderTest, ReflectedObject) {
diff --git a/src/tint/utils/reflection/BUILD.bazel b/src/tint/utils/reflection/BUILD.bazel
index e5a25ef..28efe09 100644
--- a/src/tint/utils/reflection/BUILD.bazel
+++ b/src/tint/utils/reflection/BUILD.bazel
@@ -46,6 +46,7 @@
],
deps = [
"//src/tint/utils/macros",
+ "//src/tint/utils/math",
],
copts = COPTS,
visibility = ["//visibility:public"],
@@ -58,7 +59,10 @@
],
deps = [
"//src/tint/utils/macros",
+ "//src/tint/utils/math",
"//src/tint/utils/reflection",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/traits",
"@gtest",
],
copts = COPTS,
diff --git a/src/tint/utils/reflection/BUILD.cmake b/src/tint/utils/reflection/BUILD.cmake
index c2af545..143b121 100644
--- a/src/tint/utils/reflection/BUILD.cmake
+++ b/src/tint/utils/reflection/BUILD.cmake
@@ -45,6 +45,7 @@
tint_target_add_dependencies(tint_utils_reflection lib
tint_utils_macros
+ tint_utils_math
)
################################################################################
@@ -57,7 +58,10 @@
tint_target_add_dependencies(tint_utils_reflection_test test
tint_utils_macros
+ tint_utils_math
tint_utils_reflection
+ tint_utils_rtti
+ tint_utils_traits
)
tint_target_add_external_dependencies(tint_utils_reflection_test test
diff --git a/src/tint/utils/reflection/BUILD.gn b/src/tint/utils/reflection/BUILD.gn
index 42d0ab9..721544b 100644
--- a/src/tint/utils/reflection/BUILD.gn
+++ b/src/tint/utils/reflection/BUILD.gn
@@ -47,7 +47,10 @@
"reflection.cc",
"reflection.h",
]
- deps = [ "${tint_src_dir}/utils/macros" ]
+ deps = [
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ ]
}
if (tint_build_unittests) {
tint_unittests_source_set("unittests") {
@@ -55,7 +58,10 @@
deps = [
"${tint_src_dir}:gmock_and_gtest",
"${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
"${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/traits",
]
}
}
diff --git a/src/tint/utils/reflection/reflection.h b/src/tint/utils/reflection/reflection.h
index d674db1..7d192d8 100644
--- a/src/tint/utils/reflection/reflection.h
+++ b/src/tint/utils/reflection/reflection.h
@@ -28,10 +28,18 @@
#ifndef SRC_TINT_UTILS_REFLECTION_REFLECTION_H_
#define SRC_TINT_UTILS_REFLECTION_REFLECTION_H_
+#include <cstddef>
+#include <tuple>
#include <type_traits>
#include "src/tint/utils/macros/concat.h"
#include "src/tint/utils/macros/foreach.h"
+#include "src/tint/utils/math/math.h"
+
+/// Forward declarations
+namespace tint {
+class CastableBase;
+}
namespace tint {
@@ -45,6 +53,60 @@
template <typename T>
struct HasReflection<T, std::void_t<typename T::Reflection>> : std::true_type {};
+/// Helper for inferring the base class size of T.
+template <typename T, typename ENABLE = void>
+struct BaseClassSize {
+ /// Zero as T::Base does not exist
+ static constexpr size_t value = 0;
+};
+
+/// Specialization for types that contain a 'Base' type alias.
+template <typename T>
+struct BaseClassSize<T, std::void_t<typename T::Base>> {
+ /// The size of T::Base, or zero if T::Base is not a base of T
+ static constexpr size_t value =
+ std::is_base_of_v<typename T::Base, T> ? sizeof(typename T::Base) : 0;
+};
+
+/// A helper to check at compile-time that all the fields of a class are passed to TINT_REFLECT().
+template <typename CLASS, size_t INDEX, size_t OFFSET, typename FIELDS, bool ASSERT = true>
+struct CheckAllFieldsReflected;
+
+/// CheckAllFieldsReflected specialization that the final computed offset matches the size of the
+/// class.
+template <typename CLASS, size_t INDEX, size_t OFFSET, bool ASSERT>
+struct CheckAllFieldsReflected<CLASS, INDEX, OFFSET, std::tuple<void>, ASSERT> {
+ /// True iff the calculated size of class from all the fields matches the actual class size.
+ static constexpr bool value =
+ tint::RoundUp(alignof(CLASS), BaseClassSize<CLASS>::value + OFFSET) == sizeof(CLASS);
+ static_assert(value || (ASSERT == false),
+ "TINT_REFLECT() was not passed all the fields of the class, or the fields were "
+ "not passed in the same order they're declared in the class");
+};
+
+/// CheckAllFieldsReflected specialization that the field with index INDEX is at the expected offset
+/// in the class.
+template <typename CLASS,
+ size_t INDEX,
+ size_t OFFSET,
+ typename FIELD,
+ bool ASSERT,
+ typename... OTHERS>
+struct CheckAllFieldsReflected<CLASS, INDEX, OFFSET, std::tuple<FIELD, OTHERS...>, ASSERT> {
+ /// True iff the calculated size of class from all the fields matches the actual class size.
+ static constexpr bool value =
+ CheckAllFieldsReflected<CLASS,
+ INDEX + 1,
+ tint::RoundUp(alignof(FIELD), OFFSET) + sizeof(FIELD),
+ std::tuple<OTHERS...>,
+ ASSERT>::value;
+};
+
+/// Evaluates to true if type `T` can be used with TINT_ASSERT_ALL_FIELDS_REFLECTED().
+template <typename T>
+static constexpr bool CanUseTintAssertAllFieldsReflected =
+ !std::has_virtual_destructor_v<T> || std::is_base_of_v<CastableBase, T>;
+
} // namespace detail
/// Is true if the class T has reflected its fields with TINT_REFLECT()
@@ -59,23 +121,39 @@
void ForeachField(OBJECT&& object, CB&& callback) {
using T = std::decay_t<OBJECT>;
static_assert(HasReflection<T>, "object type requires a tint::Reflect<> specialization");
- T::Reflection::Fields(object, callback);
+ T::Reflection::ForeachField(object, callback);
}
+/// Macro used by TINT_FOREACH() in TINT_REFLECT() to generate the T::Reflection::Fields tuple.
+#define TINT_REFLECT_FIELD_TYPE(FIELD) decltype(Class::FIELD),
+
/// Macro used by TINT_FOREACH() in TINT_REFLECT() to call the callback function with each field in
/// the variadic.
-#define TINT_REFLECT_CALLBACK_FIELD(field) callback(object.field);
+#define TINT_REFLECT_CALLBACK_FIELD(FIELD) callback(object.FIELD);
-// TINT_REFLECT(...) reflects each of the fields arguments so that the types can be used with
-// tint::ForeachField().
-#define TINT_REFLECT(...) \
- struct Reflection { \
- template <typename OBJECT, typename CB> \
- static void Fields(OBJECT&& object, CB&& callback) { \
- TINT_FOREACH(TINT_REFLECT_CALLBACK_FIELD, __VA_ARGS__) \
- } \
+// TINT_REFLECT(CLASS, ...) reflects each of the fields arguments of CLASS so that the types can be
+// used with tint::ForeachField().
+#define TINT_REFLECT(CLASS, ...) \
+ struct Reflection { \
+ using Class = CLASS; \
+ using Fields = std::tuple<TINT_FOREACH(TINT_REFLECT_FIELD_TYPE, __VA_ARGS__) void>; \
+ template <typename OBJECT, typename CB> \
+ [[maybe_unused]] static void ForeachField(OBJECT&& object, CB&& callback) { \
+ TINT_FOREACH(TINT_REFLECT_CALLBACK_FIELD, __VA_ARGS__) \
+ } \
}
+/// TINT_ASSERT_ALL_FIELDS_REFLECTED(...) performs a compile-time assertion that all the fields of
+/// CLASS have been reflected with TINT_REFLECT().
+/// @note The order in which the fields are passed to TINT_REFLECT must match the declaration order
+/// in the class.
+#define TINT_ASSERT_ALL_FIELDS_REFLECTED(CLASS) \
+ static_assert(::tint::detail::CanUseTintAssertAllFieldsReflected<CLASS>, \
+ "TINT_ASSERT_ALL_FIELDS_REFLECTED() cannot be used on virtual classes, except " \
+ "for types using the tint::Castable framework"); \
+ static_assert( \
+ ::tint::detail::CheckAllFieldsReflected<CLASS, 0, 0, CLASS::Reflection::Fields>::value)
+
/// A template that can be specialized to reflect the valid range of an enum
/// Use TINT_REFLECT_ENUM_RANGE to specialize this class
template <typename T>
diff --git a/src/tint/utils/reflection/reflection_test.cc b/src/tint/utils/reflection/reflection_test.cc
index d7335d5..558c1bf 100644
--- a/src/tint/utils/reflection/reflection_test.cc
+++ b/src/tint/utils/reflection/reflection_test.cc
@@ -27,6 +27,7 @@
#include "src/tint/utils/reflection/reflection.h"
#include "gtest/gtest.h"
+#include "src/tint/utils/rtti/castable.h"
namespace tint {
namespace {
@@ -35,7 +36,7 @@
int i;
unsigned u;
bool b;
- TINT_REFLECT(i, u, b);
+ TINT_REFLECT(S, i, u, b);
};
static_assert(!HasReflection<int>);
@@ -100,5 +101,57 @@
EXPECT_EQ(s.b, false);
}
+////////////////////////////////////////////////////////////////////////////////
+// TINT_ASSERT_ALL_FIELDS_REFLECTED tests
+////////////////////////////////////////////////////////////////////////////////
+static_assert(detail::CanUseTintAssertAllFieldsReflected<S> == true);
+
+struct VirtualNonCastable {
+ virtual ~VirtualNonCastable() = default;
+};
+static_assert(detail::CanUseTintAssertAllFieldsReflected<VirtualNonCastable> == false);
+
+struct VirtualCastable : Castable<VirtualCastable, CastableBase> {
+ ~VirtualCastable() override = default;
+ int a, b, c;
+ TINT_REFLECT(VirtualCastable, a, b, c);
+};
+static_assert(detail::CanUseTintAssertAllFieldsReflected<VirtualCastable> == true);
+static_assert(detail::CheckAllFieldsReflected<VirtualCastable,
+ 0,
+ 0,
+ VirtualCastable::Reflection::Fields,
+ /* assert */ false>::value == true);
+
+struct MissingFirst {
+ int a, b, c;
+ TINT_REFLECT(MissingFirst, b, c);
+};
+static_assert(detail::CheckAllFieldsReflected<MissingFirst,
+ 0,
+ 0,
+ MissingFirst::Reflection::Fields,
+ /* assert */ false>::value == false);
+
+struct MissingMid {
+ int a, b, c;
+ TINT_REFLECT(MissingMid, a, c);
+};
+static_assert(detail::CheckAllFieldsReflected<MissingMid,
+ 0,
+ 0,
+ MissingMid::Reflection::Fields,
+ /* assert */ false>::value == false);
+
+struct MissingLast {
+ int a, b, c;
+ TINT_REFLECT(MissingLast, a, b);
+};
+static_assert(detail::CheckAllFieldsReflected<MissingLast,
+ 0,
+ 0,
+ MissingLast::Reflection::Fields,
+ /* assert */ false>::value == false);
+
} // namespace
} // namespace tint