[tint] Improve TINT_ASSERT_ALL_FIELDS_REFLECTED()
Field and class alignment could result in false positives.
Migrate the assertion from a compile-time static assertion, to a google-test ASSERT_EQ().
This allows the test to check the individual field offsets, which results in a more accurate detection of missing fields.
Note: There is still an unavoidable false-negative if the class has an alignment that hides a missing tail field.
Change-Id: Ia284cc1d1220b51e2805d42e22dda2dfeff93b6f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/173960
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/utils/reflection/reflection.cc b/src/tint/utils/reflection/reflection.cc
index 57a5260..e01d9e3 100644
--- a/src/tint/utils/reflection/reflection.cc
+++ b/src/tint/utils/reflection/reflection.cc
@@ -27,9 +27,56 @@
#include "src/tint/utils/reflection/reflection.h"
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
-#endif
+#include <memory>
+#include <string>
-// A placeholder symbol used to emit a symbol for this lib target.
-int tint_utils_reflection_symbol = 1;
+#include "src/tint/utils/math/math.h"
+#include "src/tint/utils/text/string_stream.h"
+
+namespace tint::reflection::detail {
+
+Result<SuccessType> CheckAllFieldsReflected(VectorRef<ReflectedFieldInfo> fields,
+ std::string_view class_name,
+ size_t class_size,
+ size_t class_align,
+ bool class_is_castable,
+ std::string_view reflect_file,
+ uint32_t reflect_line) {
+ size_t calculated_offset = class_is_castable ? sizeof(CastableBase) : 0;
+ for (auto& field : fields) {
+ calculated_offset = RoundUp(field.align, calculated_offset);
+ if (calculated_offset < field.offset) {
+ StringStream msg;
+ msg << "TINT_REFLECT(" << class_name << ", ...) field mismatch at '" << field.name
+ << "'.\n"
+ "Expected field offset of "
+ << calculated_offset << " bytes, but field was at " << field.offset << " bytes";
+ diag::Diagnostic err;
+ err.message = msg.str();
+ err.owned_file = std::make_shared<Source::File>(std::string(reflect_file), "");
+ err.source.file = err.owned_file.get();
+ err.source.range.begin.line = reflect_line;
+ err.source.range.end.line = reflect_line;
+ return Failure{std::move(err)};
+ }
+ calculated_offset += field.size;
+ }
+ calculated_offset = RoundUp(class_align, calculated_offset);
+ if (calculated_offset != class_size) {
+ StringStream msg;
+ msg << "TINT_REFLECT(" << class_name
+ << ", ...) missing fields at end of class\n"
+ "Expected class size of "
+ << calculated_offset << " bytes, but class is " << class_size << " bytes";
+ diag::Diagnostic err;
+ err.message = msg.str();
+ err.owned_file = std::make_shared<Source::File>(std::string(reflect_file), "");
+ err.source.file = err.owned_file.get();
+ err.source.range.begin.line = reflect_line;
+ err.source.range.end.line = reflect_line;
+ return Failure{std::move(err)};
+ }
+ return Success;
+}
+
+} // namespace tint::reflection::detail