authorgravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2021-02-25 16:43:39-08:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-28 21:56:57+02:00
log294ee1bbc93a00ead5182234f824b0a665c579d9
tree2938d0ebf9309bfbef8021bad0fbf9d6a7b5fd76
parent0423f0f7d8afc24e48926849515f60a8a3a1e470

translate-c: add limited OffsetOfExpr support

Add support for OffsetOfExpr that contain exactly 1 component, when that component is a field. For example, given: ```c struct S { float f; double d; }; struct T { long l; int i; struct S s[10]; }; ``` Then: ```c offsetof(struct T, i) // supported offsetof(struct T, s[2].d) // not supported currently ```

6 files changed, 194 insertions(+), 0 deletions(-)

src/clang.zig+38
...@@ -432,6 +432,9 @@ pub const FieldDecl = opaque {...@@ -432,6 +432,9 @@ pub const FieldDecl = opaque {
432432
433 pub const getLocation = ZigClangFieldDecl_getLocation;433 pub const getLocation = ZigClangFieldDecl_getLocation;
434 extern fn ZigClangFieldDecl_getLocation(*const FieldDecl) SourceLocation;434 extern fn ZigClangFieldDecl_getLocation(*const FieldDecl) SourceLocation;
435
436 pub const getParent = ZigClangFieldDecl_getParent;
437 extern fn ZigClangFieldDecl_getParent(*const FieldDecl) ?*const RecordDecl;
435};438};
436439
437pub const FileID = opaque {};440pub const FileID = opaque {};
...@@ -593,6 +596,34 @@ pub const TypeOfExprType = opaque {...@@ -593,6 +596,34 @@ pub const TypeOfExprType = opaque {
593 extern fn ZigClangTypeOfExprType_getUnderlyingExpr(*const TypeOfExprType) *const Expr;596 extern fn ZigClangTypeOfExprType_getUnderlyingExpr(*const TypeOfExprType) *const Expr;
594};597};
595598
599pub const OffsetOfNode = opaque {
600 pub const getKind = ZigClangOffsetOfNode_getKind;
601 extern fn ZigClangOffsetOfNode_getKind(*const OffsetOfNode) OffsetOfNode_Kind;
602
603 pub const getArrayExprIndex = ZigClangOffsetOfNode_getArrayExprIndex;
604 extern fn ZigClangOffsetOfNode_getArrayExprIndex(*const OffsetOfNode) c_uint;
605
606 pub const getField = ZigClangOffsetOfNode_getField;
607 extern fn ZigClangOffsetOfNode_getField(*const OffsetOfNode) *FieldDecl;
608};
609
610pub const OffsetOfExpr = opaque {
611 pub const getNumComponents = ZigClangOffsetOfExpr_getNumComponents;
612 extern fn ZigClangOffsetOfExpr_getNumComponents(*const OffsetOfExpr) c_uint;
613
614 pub const getNumExpressions = ZigClangOffsetOfExpr_getNumExpressions;
615 extern fn ZigClangOffsetOfExpr_getNumExpressions(*const OffsetOfExpr) c_uint;
616
617 pub const getIndexExpr = ZigClangOffsetOfExpr_getIndexExpr;
618 extern fn ZigClangOffsetOfExpr_getIndexExpr(*const OffsetOfExpr, idx: c_uint) *const Expr;
619
620 pub const getComponent = ZigClangOffsetOfExpr_getComponent;
621 extern fn ZigClangOffsetOfExpr_getComponent(*const OffsetOfExpr, idx: c_uint) *const OffsetOfNode;
622
623 pub const getBeginLoc = ZigClangOffsetOfExpr_getBeginLoc;
624 extern fn ZigClangOffsetOfExpr_getBeginLoc(*const OffsetOfExpr) SourceLocation;
625};
626
596pub const MemberExpr = opaque {627pub const MemberExpr = opaque {
597 pub const getBase = ZigClangMemberExpr_getBase;628 pub const getBase = ZigClangMemberExpr_getBase;
598 extern fn ZigClangMemberExpr_getBase(*const MemberExpr) *const Expr;629 extern fn ZigClangMemberExpr_getBase(*const MemberExpr) *const Expr;
...@@ -1655,6 +1686,13 @@ pub const UnaryExprOrTypeTrait_Kind = extern enum {...@@ -1655,6 +1686,13 @@ pub const UnaryExprOrTypeTrait_Kind = extern enum {
1655 PreferredAlignOf,1686 PreferredAlignOf,
1656};1687};
16571688
1689pub const OffsetOfNode_Kind = extern enum {
1690 Array,
1691 Field,
1692 Identifier,
1693 Base,
1694};
1695
1658pub const Stage2ErrorMsg = extern struct {1696pub const Stage2ErrorMsg = extern struct {
1659 filename_ptr: ?[*]const u8,1697 filename_ptr: ?[*]const u8,
1660 filename_len: usize,1698 filename_len: usize,
src/translate_c.zig+52
...@@ -1069,12 +1069,64 @@ fn transStmt(...@@ -1069,12 +1069,64 @@ fn transStmt(
1069 const expr = try transExpr(c, scope, source_expr, .used);1069 const expr = try transExpr(c, scope, source_expr, .used);
1070 return maybeSuppressResult(c, scope, result_used, expr);1070 return maybeSuppressResult(c, scope, result_used, expr);
1071 },1071 },
1072 .OffsetOfExprClass => return transOffsetOfExpr(c, scope, @ptrCast(*const clang.OffsetOfExpr, stmt), result_used),
1072 else => {1073 else => {
1073 return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)});1074 return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)});
1074 },1075 },
1075 }1076 }
1076}1077}
10771078
1079/// Translate a "simple" offsetof expression containing exactly one component,
1080/// when that component is of kind .Field - e.g. offsetof(mytype, myfield)
1081fn transSimpleOffsetOfExpr(
1082 c: *Context,
1083 scope: *Scope,
1084 expr: *const clang.OffsetOfExpr,
1085) TransError!Node {
1086 assert(expr.getNumComponents() == 1);
1087 const component = expr.getComponent(0);
1088 if (component.getKind() == .Field) {
1089 const field_decl = component.getField();
1090 if (field_decl.getParent()) |record_decl| {
1091 if (c.decl_table.get(@ptrToInt(record_decl.getCanonicalDecl()))) |type_name| {
1092 const type_node = try Tag.type.create(c.arena, type_name);
1093
1094 var raw_field_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
1095 const quoted_field_name = try std.fmt.allocPrint(c.arena, "\"{s}\"", .{raw_field_name});
1096 const field_name_node = try Tag.string_literal.create(c.arena, quoted_field_name);
1097
1098 return Tag.byte_offset_of.create(c.arena, .{
1099 .lhs = type_node,
1100 .rhs = field_name_node,
1101 });
1102 }
1103 }
1104 }
1105 return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "Failed to translate simple OffsetOfExpr", .{});
1106}
1107
1108fn transOffsetOfExpr(
1109 c: *Context,
1110 scope: *Scope,
1111 expr: *const clang.OffsetOfExpr,
1112 result_used: ResultUsed,
1113) TransError!Node {
1114 if (expr.getNumComponents() == 1) {
1115 const offsetof_expr = try transSimpleOffsetOfExpr(c, scope, expr);
1116 return maybeSuppressResult(c, scope, result_used, offsetof_expr);
1117 }
1118
1119 // TODO implement OffsetOfExpr with more than 1 component
1120 // OffsetOfExpr API:
1121 // call expr.getComponent(idx) while idx < expr.getNumComponents()
1122 // component.getKind() will be either .Array or .Field (other kinds are C++-only)
1123 // if .Field, use component.getField() to retrieve *clang.FieldDecl
1124 // if .Array, use component.getArrayExprIndex() to get a c_uint which
1125 // can be passed to expr.getIndexExpr(expr_index) to get the *clang.Expr for the array index
1126
1127 return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO: implement complex OffsetOfExpr translation", .{});
1128}
1129
1078fn transBinaryOperator(1130fn transBinaryOperator(
1079 c: *Context,1131 c: *Context,
1080 scope: *Scope,1132 scope: *Scope,
src/translate_c/ast.zig+8
...@@ -148,6 +148,8 @@ pub const Node = extern union {...@@ -148,6 +148,8 @@ pub const Node = extern union {
148 ptr_cast,148 ptr_cast,
149 /// @divExact(lhs, rhs)149 /// @divExact(lhs, rhs)
150 div_exact,150 div_exact,
151 /// @byteOffsetOf(lhs, rhs)
152 byte_offset_of,
151153
152 negate,154 negate,
153 negate_wrap,155 negate_wrap,
...@@ -303,6 +305,7 @@ pub const Node = extern union {...@@ -303,6 +305,7 @@ pub const Node = extern union {
303 .std_mem_zeroinit,305 .std_mem_zeroinit,
304 .ptr_cast,306 .ptr_cast,
305 .div_exact,307 .div_exact,
308 .byte_offset_of,
306 => Payload.BinOp,309 => Payload.BinOp,
307310
308 .integer_literal,311 .integer_literal,
...@@ -1135,6 +1138,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1135,6 +1138,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1135 const payload = node.castTag(.div_exact).?.data;1138 const payload = node.castTag(.div_exact).?.data;
1136 return renderBuiltinCall(c, "@divExact", &.{ payload.lhs, payload.rhs });1139 return renderBuiltinCall(c, "@divExact", &.{ payload.lhs, payload.rhs });
1137 },1140 },
1141 .byte_offset_of => {
1142 const payload = node.castTag(.byte_offset_of).?.data;
1143 return renderBuiltinCall(c, "@byteOffsetOf", &.{ payload.lhs, payload.rhs });
1144 },
1138 .sizeof => {1145 .sizeof => {
1139 const payload = node.castTag(.sizeof).?.data;1146 const payload = node.castTag(.sizeof).?.data;
1140 return renderBuiltinCall(c, "@sizeOf", &.{payload});1147 return renderBuiltinCall(c, "@sizeOf", &.{payload});
...@@ -2001,6 +2008,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {...@@ -2001,6 +2008,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
2001 .array_type,2008 .array_type,
2002 .bool_to_int,2009 .bool_to_int,
2003 .div_exact,2010 .div_exact,
2011 .byte_offset_of,
2004 => {2012 => {
2005 // no grouping needed2013 // no grouping needed
2006 return renderNode(c, node);2014 return renderNode(c, node);
src/zig_clang.cpp+45
...@@ -2609,6 +2609,46 @@ const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct...@@ -2609,6 +2609,46 @@ const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct
2609 return reinterpret_cast<const struct ZigClangExpr *>(casted->getUnderlyingExpr());2609 return reinterpret_cast<const struct ZigClangExpr *>(casted->getUnderlyingExpr());
2610}2610}
26112611
2612enum ZigClangOffsetOfNode_Kind ZigClangOffsetOfNode_getKind(const struct ZigClangOffsetOfNode *self) {
2613 auto casted = reinterpret_cast<const clang::OffsetOfNode *>(self);
2614 return (ZigClangOffsetOfNode_Kind)casted->getKind();
2615}
2616
2617unsigned ZigClangOffsetOfNode_getArrayExprIndex(const struct ZigClangOffsetOfNode *self) {
2618 auto casted = reinterpret_cast<const clang::OffsetOfNode *>(self);
2619 return casted->getArrayExprIndex();
2620}
2621
2622struct ZigClangFieldDecl *ZigClangOffsetOfNode_getField(const struct ZigClangOffsetOfNode *self) {
2623 auto casted = reinterpret_cast<const clang::OffsetOfNode *>(self);
2624 return reinterpret_cast<ZigClangFieldDecl *>(casted->getField());
2625}
2626
2627unsigned ZigClangOffsetOfExpr_getNumComponents(const struct ZigClangOffsetOfExpr *self) {
2628 auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
2629 return casted->getNumComponents();
2630}
2631
2632unsigned ZigClangOffsetOfExpr_getNumExpressions(const struct ZigClangOffsetOfExpr *self) {
2633 auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
2634 return casted->getNumExpressions();
2635}
2636
2637const struct ZigClangExpr *ZigClangOffsetOfExpr_getIndexExpr(const struct ZigClangOffsetOfExpr *self, unsigned idx) {
2638 auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
2639 return reinterpret_cast<const struct ZigClangExpr *>(casted->getIndexExpr(idx));
2640}
2641
2642const struct ZigClangOffsetOfNode *ZigClangOffsetOfExpr_getComponent(const struct ZigClangOffsetOfExpr *self, unsigned idx) {
2643 auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
2644 return reinterpret_cast<const struct ZigClangOffsetOfNode *>(&casted->getComponent(idx));
2645}
2646
2647ZigClangSourceLocation ZigClangOffsetOfExpr_getBeginLoc(const ZigClangOffsetOfExpr *self) {
2648 auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
2649 return bitcast(casted->getBeginLoc());
2650}
2651
2612struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *self) {2652struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *self) {
2613 auto casted = reinterpret_cast<const clang::ElaboratedType *>(self);2653 auto casted = reinterpret_cast<const clang::ElaboratedType *>(self);
2614 return bitcast(casted->getNamedType());2654 return bitcast(casted->getNamedType());
...@@ -3008,6 +3048,11 @@ ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldD...@@ -3008,6 +3048,11 @@ ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldD
3008 return bitcast(casted->getLocation());3048 return bitcast(casted->getLocation());
3009}3049}
30103050
3051const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const struct ZigClangFieldDecl *self) {
3052 auto casted = reinterpret_cast<const clang::FieldDecl *>(self);
3053 return reinterpret_cast<const ZigClangRecordDecl *>(casted->getParent());
3054}
3055
3011ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *self) {3056ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *self) {
3012 auto casted = reinterpret_cast<const clang::FieldDecl *>(self);3057 auto casted = reinterpret_cast<const clang::FieldDecl *>(self);
3013 return bitcast(casted->getType());3058 return bitcast(casted->getType());
src/zig_clang.h+18
...@@ -928,6 +928,13 @@ enum ZigClangUnaryExprOrTypeTrait_Kind {...@@ -928,6 +928,13 @@ enum ZigClangUnaryExprOrTypeTrait_Kind {
928 ZigClangUnaryExprOrTypeTrait_KindPreferredAlignOf,928 ZigClangUnaryExprOrTypeTrait_KindPreferredAlignOf,
929};929};
930930
931enum ZigClangOffsetOfNode_Kind {
932 ZigClangOffsetOfNode_KindArray,
933 ZigClangOffsetOfNode_KindField,
934 ZigClangOffsetOfNode_KindIdentifier,
935 ZigClangOffsetOfNode_KindBase,
936};
937
931ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const struct ZigClangSourceManager *,938ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const struct ZigClangSourceManager *,
932 struct ZigClangSourceLocation Loc);939 struct ZigClangSourceLocation Loc);
933ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const struct ZigClangSourceManager *,940ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const struct ZigClangSourceManager *,
...@@ -1161,6 +1168,16 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangTypeOfType_getUnderlyingType(const...@@ -1161,6 +1168,16 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangTypeOfType_getUnderlyingType(const
11611168
1162ZIG_EXTERN_C const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct ZigClangTypeOfExprType *);1169ZIG_EXTERN_C const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct ZigClangTypeOfExprType *);
11631170
1171ZIG_EXTERN_C enum ZigClangOffsetOfNode_Kind ZigClangOffsetOfNode_getKind(const struct ZigClangOffsetOfNode *);
1172ZIG_EXTERN_C unsigned ZigClangOffsetOfNode_getArrayExprIndex(const struct ZigClangOffsetOfNode *);
1173ZIG_EXTERN_C struct ZigClangFieldDecl * ZigClangOffsetOfNode_getField(const struct ZigClangOffsetOfNode *);
1174
1175ZIG_EXTERN_C unsigned ZigClangOffsetOfExpr_getNumComponents(const struct ZigClangOffsetOfExpr *);
1176ZIG_EXTERN_C unsigned ZigClangOffsetOfExpr_getNumExpressions(const struct ZigClangOffsetOfExpr *);
1177ZIG_EXTERN_C const struct ZigClangExpr *ZigClangOffsetOfExpr_getIndexExpr(const struct ZigClangOffsetOfExpr *, unsigned idx);
1178ZIG_EXTERN_C const struct ZigClangOffsetOfNode *ZigClangOffsetOfExpr_getComponent(const struct ZigClangOffsetOfExpr *, unsigned idx);
1179ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangOffsetOfExpr_getBeginLoc(const struct ZigClangOffsetOfExpr *);
1180
1164ZIG_EXTERN_C struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *);1181ZIG_EXTERN_C struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *);
1165ZIG_EXTERN_C enum ZigClangElaboratedTypeKeyword ZigClangElaboratedType_getKeyword(const struct ZigClangElaboratedType *);1182ZIG_EXTERN_C enum ZigClangElaboratedTypeKeyword ZigClangElaboratedType_getKeyword(const struct ZigClangElaboratedType *);
11661183
...@@ -1261,6 +1278,7 @@ ZIG_EXTERN_C bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *)...@@ -1261,6 +1278,7 @@ ZIG_EXTERN_C bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *)
1261ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *);1278ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *);
1262ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *);1279ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *);
1263ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *);1280ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *);
1281ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const struct ZigClangFieldDecl *);
12641282
1265ZIG_EXTERN_C const struct ZigClangExpr *ZigClangEnumConstantDecl_getInitExpr(const struct ZigClangEnumConstantDecl *);1283ZIG_EXTERN_C const struct ZigClangExpr *ZigClangEnumConstantDecl_getInitExpr(const struct ZigClangEnumConstantDecl *);
1266ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct ZigClangEnumConstantDecl *);1284ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct ZigClangEnumConstantDecl *);
test/run_translated_c.zig+33
...@@ -1073,4 +1073,37 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {...@@ -1073,4 +1073,37 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
1073 \\ return 0;1073 \\ return 0;
1074 \\}1074 \\}
1075 , "");1075 , "");
1076
1077 cases.add("offsetof",
1078 \\#include <stddef.h>
1079 \\#include <stdlib.h>
1080 \\#define container_of(ptr, type, member) ({ \
1081 \\ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
1082 \\ (type *)( (char *)__mptr - offsetof(type,member) );})
1083 \\typedef struct {
1084 \\ int i;
1085 \\ struct { int x; char y; int z; } s;
1086 \\ float f;
1087 \\} container;
1088 \\int main(void) {
1089 \\ if (offsetof(container, i) != 0) abort();
1090 \\ if (offsetof(container, s) <= offsetof(container, i)) abort();
1091 \\ if (offsetof(container, f) <= offsetof(container, s)) abort();
1092 \\
1093 \\ container my_container;
1094 \\ typeof(my_container.s) *inner_member_pointer = &my_container.s;
1095 \\ float *float_member_pointer = &my_container.f;
1096 \\ int *anon_member_pointer = &my_container.s.z;
1097 \\ container *my_container_p;
1098 \\
1099 \\ my_container_p = container_of(inner_member_pointer, container, s);
1100 \\ if (my_container_p != &my_container) abort();
1101 \\
1102 \\ my_container_p = container_of(float_member_pointer, container, f);
1103 \\ if (my_container_p != &my_container) abort();
1104 \\
1105 \\ if (container_of(anon_member_pointer, typeof(my_container.s), z) != inner_member_pointer) abort();
1106 \\ return 0;
1107 \\}
1108 , "");
1076}1109}