| author | |
| committer | |
| log | 294ee1bbc93a00ead5182234f824b0a665c579d9 |
| tree | 2938d0ebf9309bfbef8021bad0fbf9d6a7b5fd76 |
| parent | 0423f0f7d8afc24e48926849515f60a8a3a1e470 |
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 | 432 | |
| 433 | 433 | pub const getLocation = ZigClangFieldDecl_getLocation; |
| 434 | 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 | }; |
| 436 | 439 | |
| 437 | 440 | pub const FileID = opaque {}; |
| ... | ... | @@ -593,6 +596,34 @@ pub const TypeOfExprType = opaque { |
| 593 | 596 | extern fn ZigClangTypeOfExprType_getUnderlyingExpr(*const TypeOfExprType) *const Expr; |
| 594 | 597 | }; |
| 595 | 598 | |
| 599 | pub 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 | ||
| 610 | pub 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 | ||
| 596 | 627 | pub const MemberExpr = opaque { |
| 597 | 628 | pub const getBase = ZigClangMemberExpr_getBase; |
| 598 | 629 | extern fn ZigClangMemberExpr_getBase(*const MemberExpr) *const Expr; |
| ... | ... | @@ -1655,6 +1686,13 @@ pub const UnaryExprOrTypeTrait_Kind = extern enum { |
| 1655 | 1686 | PreferredAlignOf, |
| 1656 | 1687 | }; |
| 1657 | 1688 | |
| 1689 | pub const OffsetOfNode_Kind = extern enum { | |
| 1690 | Array, | |
| 1691 | Field, | |
| 1692 | Identifier, | |
| 1693 | Base, | |
| 1694 | }; | |
| 1695 | ||
| 1658 | 1696 | pub const Stage2ErrorMsg = extern struct { |
| 1659 | 1697 | filename_ptr: ?[*]const u8, |
| 1660 | 1698 | filename_len: usize, |
src/translate_c.zig+52| ... | ... | @@ -1069,12 +1069,64 @@ fn transStmt( |
| 1069 | 1069 | const expr = try transExpr(c, scope, source_expr, .used); |
| 1070 | 1070 | return maybeSuppressResult(c, scope, result_used, expr); |
| 1071 | 1071 | }, |
| 1072 | .OffsetOfExprClass => return transOffsetOfExpr(c, scope, @ptrCast(*const clang.OffsetOfExpr, stmt), result_used), | |
| 1072 | 1073 | else => { |
| 1073 | 1074 | return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)}); |
| 1074 | 1075 | }, |
| 1075 | 1076 | } |
| 1076 | 1077 | } |
| 1077 | 1078 | |
| 1079 | /// Translate a "simple" offsetof expression containing exactly one component, | |
| 1080 | /// when that component is of kind .Field - e.g. offsetof(mytype, myfield) | |
| 1081 | fn 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 | ||
| 1108 | fn 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 | ||
| 1078 | 1130 | fn transBinaryOperator( |
| 1079 | 1131 | c: *Context, |
| 1080 | 1132 | scope: *Scope, |
src/translate_c/ast.zig+8| ... | ... | @@ -148,6 +148,8 @@ pub const Node = extern union { |
| 148 | 148 | ptr_cast, |
| 149 | 149 | /// @divExact(lhs, rhs) |
| 150 | 150 | div_exact, |
| 151 | /// @byteOffsetOf(lhs, rhs) | |
| 152 | byte_offset_of, | |
| 151 | 153 | |
| 152 | 154 | negate, |
| 153 | 155 | negate_wrap, |
| ... | ... | @@ -303,6 +305,7 @@ pub const Node = extern union { |
| 303 | 305 | .std_mem_zeroinit, |
| 304 | 306 | .ptr_cast, |
| 305 | 307 | .div_exact, |
| 308 | .byte_offset_of, | |
| 306 | 309 | => Payload.BinOp, |
| 307 | 310 | |
| 308 | 311 | .integer_literal, |
| ... | ... | @@ -1135,6 +1138,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 1135 | 1138 | const payload = node.castTag(.div_exact).?.data; |
| 1136 | 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 | 1145 | .sizeof => { |
| 1139 | 1146 | const payload = node.castTag(.sizeof).?.data; |
| 1140 | 1147 | return renderBuiltinCall(c, "@sizeOf", &.{payload}); |
| ... | ... | @@ -2001,6 +2008,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { |
| 2001 | 2008 | .array_type, |
| 2002 | 2009 | .bool_to_int, |
| 2003 | 2010 | .div_exact, |
| 2011 | .byte_offset_of, | |
| 2004 | 2012 | => { |
| 2005 | 2013 | // no grouping needed |
| 2006 | 2014 | return renderNode(c, node); |
src/zig_clang.cpp+45| ... | ... | @@ -2609,6 +2609,46 @@ const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct |
| 2609 | 2609 | return reinterpret_cast<const struct ZigClangExpr *>(casted->getUnderlyingExpr()); |
| 2610 | 2610 | } |
| 2611 | 2611 | |
| 2612 | enum 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 | ||
| 2617 | unsigned ZigClangOffsetOfNode_getArrayExprIndex(const struct ZigClangOffsetOfNode *self) { | |
| 2618 | auto casted = reinterpret_cast<const clang::OffsetOfNode *>(self); | |
| 2619 | return casted->getArrayExprIndex(); | |
| 2620 | } | |
| 2621 | ||
| 2622 | struct 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 | ||
| 2627 | unsigned ZigClangOffsetOfExpr_getNumComponents(const struct ZigClangOffsetOfExpr *self) { | |
| 2628 | auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self); | |
| 2629 | return casted->getNumComponents(); | |
| 2630 | } | |
| 2631 | ||
| 2632 | unsigned ZigClangOffsetOfExpr_getNumExpressions(const struct ZigClangOffsetOfExpr *self) { | |
| 2633 | auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self); | |
| 2634 | return casted->getNumExpressions(); | |
| 2635 | } | |
| 2636 | ||
| 2637 | const 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 | ||
| 2642 | const 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 | ||
| 2647 | ZigClangSourceLocation ZigClangOffsetOfExpr_getBeginLoc(const ZigClangOffsetOfExpr *self) { | |
| 2648 | auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self); | |
| 2649 | return bitcast(casted->getBeginLoc()); | |
| 2650 | } | |
| 2651 | ||
| 2612 | 2652 | struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *self) { |
| 2613 | 2653 | auto casted = reinterpret_cast<const clang::ElaboratedType *>(self); |
| 2614 | 2654 | return bitcast(casted->getNamedType()); |
| ... | ... | @@ -3008,6 +3048,11 @@ ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldD |
| 3008 | 3048 | return bitcast(casted->getLocation()); |
| 3009 | 3049 | } |
| 3010 | 3050 | |
| 3051 | const 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 | ||
| 3011 | 3056 | ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *self) { |
| 3012 | 3057 | auto casted = reinterpret_cast<const clang::FieldDecl *>(self); |
| 3013 | 3058 | return bitcast(casted->getType()); |
src/zig_clang.h+18| ... | ... | @@ -928,6 +928,13 @@ enum ZigClangUnaryExprOrTypeTrait_Kind { |
| 928 | 928 | ZigClangUnaryExprOrTypeTrait_KindPreferredAlignOf, |
| 929 | 929 | }; |
| 930 | 930 | |
| 931 | enum ZigClangOffsetOfNode_Kind { | |
| 932 | ZigClangOffsetOfNode_KindArray, | |
| 933 | ZigClangOffsetOfNode_KindField, | |
| 934 | ZigClangOffsetOfNode_KindIdentifier, | |
| 935 | ZigClangOffsetOfNode_KindBase, | |
| 936 | }; | |
| 937 | ||
| 931 | 938 | ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const struct ZigClangSourceManager *, |
| 932 | 939 | struct ZigClangSourceLocation Loc); |
| 933 | 940 | ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const struct ZigClangSourceManager *, |
| ... | ... | @@ -1161,6 +1168,16 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangTypeOfType_getUnderlyingType(const |
| 1161 | 1168 | |
| 1162 | 1169 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct ZigClangTypeOfExprType *); |
| 1163 | 1170 | |
| 1171 | ZIG_EXTERN_C enum ZigClangOffsetOfNode_Kind ZigClangOffsetOfNode_getKind(const struct ZigClangOffsetOfNode *); | |
| 1172 | ZIG_EXTERN_C unsigned ZigClangOffsetOfNode_getArrayExprIndex(const struct ZigClangOffsetOfNode *); | |
| 1173 | ZIG_EXTERN_C struct ZigClangFieldDecl * ZigClangOffsetOfNode_getField(const struct ZigClangOffsetOfNode *); | |
| 1174 | ||
| 1175 | ZIG_EXTERN_C unsigned ZigClangOffsetOfExpr_getNumComponents(const struct ZigClangOffsetOfExpr *); | |
| 1176 | ZIG_EXTERN_C unsigned ZigClangOffsetOfExpr_getNumExpressions(const struct ZigClangOffsetOfExpr *); | |
| 1177 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangOffsetOfExpr_getIndexExpr(const struct ZigClangOffsetOfExpr *, unsigned idx); | |
| 1178 | ZIG_EXTERN_C const struct ZigClangOffsetOfNode *ZigClangOffsetOfExpr_getComponent(const struct ZigClangOffsetOfExpr *, unsigned idx); | |
| 1179 | ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangOffsetOfExpr_getBeginLoc(const struct ZigClangOffsetOfExpr *); | |
| 1180 | ||
| 1164 | 1181 | ZIG_EXTERN_C struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *); |
| 1165 | 1182 | ZIG_EXTERN_C enum ZigClangElaboratedTypeKeyword ZigClangElaboratedType_getKeyword(const struct ZigClangElaboratedType *); |
| 1166 | 1183 | |
| ... | ... | @@ -1261,6 +1278,7 @@ ZIG_EXTERN_C bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *) |
| 1261 | 1278 | ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *); |
| 1262 | 1279 | ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *); |
| 1263 | 1280 | ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *); |
| 1281 | ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const struct ZigClangFieldDecl *); | |
| 1264 | 1282 | |
| 1265 | 1283 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangEnumConstantDecl_getInitExpr(const struct ZigClangEnumConstantDecl *); |
| 1266 | 1284 | ZIG_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 | 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 | } |