Add size/alignment/offset to C++ IR and populate.
These values are not being serialized to JSON yet, so no need to change Rust
code -- that will happen in a followup CL.
PiperOrigin-RevId: 397309514
diff --git a/rs_bindings_from_cc/ast_visitor.cc b/rs_bindings_from_cc/ast_visitor.cc
index 5c88eeb..42871e5 100644
--- a/rs_bindings_from_cc/ast_visitor.cc
+++ b/rs_bindings_from_cc/ast_visitor.cc
@@ -17,6 +17,7 @@
#include "third_party/llvm/llvm-project/clang/include/clang/AST/Decl.h"
#include "third_party/llvm/llvm-project/clang/include/clang/AST/DeclCXX.h"
#include "third_party/llvm/llvm-project/clang/include/clang/AST/Mangle.h"
+#include "third_party/llvm/llvm-project/clang/include/clang/AST/RecordLayout.h"
#include "third_party/llvm/llvm-project/clang/include/clang/AST/Type.h"
#include "third_party/llvm/llvm-project/clang/include/clang/Basic/Specifiers.h"
#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/Casting.h"
@@ -97,6 +98,8 @@
default_access = clang::AS_private;
}
}
+ const clang::ASTRecordLayout& layout =
+ record_decl->getASTContext().getASTRecordLayout(record_decl);
for (const clang::FieldDecl* field_decl : record_decl->fields()) {
auto type = ConvertType(field_decl->getType(), field_decl->getASTContext());
if (!type.ok()) {
@@ -107,11 +110,16 @@
if (access == clang::AS_none) {
access = default_access;
}
- fields.push_back({.identifier = GetTranslatedName(field_decl),
- .type = *type,
- .access = TranslateAccessSpecifier(access)});
+ fields.push_back(
+ {.identifier = GetTranslatedName(field_decl),
+ .type = *type,
+ .access = TranslateAccessSpecifier(access),
+ .offset = layout.getFieldOffset(field_decl->getFieldIndex())});
}
- ir_.records.push_back({GetTranslatedName(record_decl), std::move(fields)});
+ ir_.records.push_back({.identifier = GetTranslatedName(record_decl),
+ .fields = std::move(fields),
+ .size = layout.getSize().getQuantity(),
+ .alignment = layout.getAlignment().getQuantity()});
return true;
}
diff --git a/rs_bindings_from_cc/ast_visitor_test.cc b/rs_bindings_from_cc/ast_visitor_test.cc
index 23ace9d..8cc741a 100644
--- a/rs_bindings_from_cc/ast_visitor_test.cc
+++ b/rs_bindings_from_cc/ast_visitor_test.cc
@@ -107,9 +107,33 @@
return testing::Field(&Record::fields, ElementsAre(matchers...));
}
+// Matches a Record that has the given size.
+MATCHER_P(RecordSizeIs, size, "") {
+ if (arg.size == size) return true;
+
+ *result_listener << "actual size: " << arg.size;
+ return false;
+}
+
+// Matches a Record that has the given alignment.
+MATCHER_P(AlignmentIs, alignment, "") {
+ if (arg.alignment == alignment) return true;
+
+ *result_listener << "actual alignment: " << arg.alignment;
+ return false;
+}
+
// Matches a Field that has the given access specifier.
MATCHER_P(AccessIs, access, "") { return arg.access == access; }
+// Matches a Field that has the given offset.
+MATCHER_P(OffsetIs, offset, "") {
+ if (arg.offset == offset) return true;
+
+ *result_listener << "actual offset: " << arg.offset;
+ return false;
+}
+
// Matches a Field with a type that matches all given matchers.
template <typename... Args>
auto FieldType(const Args&... matchers) {
@@ -227,12 +251,13 @@
{"struct SomeStruct { int first_field; int second_field; };"}, {});
EXPECT_THAT(ir.functions, IsEmpty());
- EXPECT_THAT(
- ir.records,
- ElementsAre(AllOf(
- IdentifierIs("SomeStruct"),
- FieldsAre(AllOf(IdentifierIs("first_field"), FieldType(IsInt())),
- AllOf(IdentifierIs("second_field"), FieldType(IsInt()))))));
+ EXPECT_THAT(ir.records,
+ ElementsAre(AllOf(
+ IdentifierIs("SomeStruct"), RecordSizeIs(8), AlignmentIs(4),
+ FieldsAre(AllOf(IdentifierIs("first_field"),
+ FieldType(IsInt()), OffsetIs(0)),
+ AllOf(IdentifierIs("second_field"),
+ FieldType(IsInt()), OffsetIs(32))))));
}
TEST(AstVisitorTest, MemberVariableAccessSpecifiers) {
diff --git a/rs_bindings_from_cc/ir.h b/rs_bindings_from_cc/ir.h
index 6fc6f24..4351839 100644
--- a/rs_bindings_from_cc/ir.h
+++ b/rs_bindings_from_cc/ir.h
@@ -146,6 +146,8 @@
Identifier identifier;
Type type;
AccessSpecifier access;
+ // Field offset in bits.
+ uint64_t offset;
};
// A record (struct, class, union).
@@ -154,6 +156,9 @@
Identifier identifier;
std::vector<Field> fields;
+ // Size and alignment in bytes.
+ int64_t size;
+ int64_t alignment;
};
// A complete intermediate representation of bindings for publicly accessible