diff --git a/src/clang.zig b/src/clang.zig index 5ae4f50711..854ee7dc7e 100644 --- a/src/clang.zig +++ b/src/clang.zig @@ -432,6 +432,9 @@ pub const FieldDecl = opaque { pub const getLocation = ZigClangFieldDecl_getLocation; extern fn ZigClangFieldDecl_getLocation(*const FieldDecl) SourceLocation; + + pub const getParent = ZigClangFieldDecl_getParent; + extern fn ZigClangFieldDecl_getParent(*const FieldDecl) ?*const RecordDecl; }; pub const FileID = opaque {}; @@ -593,6 +596,34 @@ pub const TypeOfExprType = opaque { extern fn ZigClangTypeOfExprType_getUnderlyingExpr(*const TypeOfExprType) *const Expr; }; +pub const OffsetOfNode = opaque { + pub const getKind = ZigClangOffsetOfNode_getKind; + extern fn ZigClangOffsetOfNode_getKind(*const OffsetOfNode) OffsetOfNode_Kind; + + pub const getArrayExprIndex = ZigClangOffsetOfNode_getArrayExprIndex; + extern fn ZigClangOffsetOfNode_getArrayExprIndex(*const OffsetOfNode) c_uint; + + pub const getField = ZigClangOffsetOfNode_getField; + extern fn ZigClangOffsetOfNode_getField(*const OffsetOfNode) *FieldDecl; +}; + +pub const OffsetOfExpr = opaque { + pub const getNumComponents = ZigClangOffsetOfExpr_getNumComponents; + extern fn ZigClangOffsetOfExpr_getNumComponents(*const OffsetOfExpr) c_uint; + + pub const getNumExpressions = ZigClangOffsetOfExpr_getNumExpressions; + extern fn ZigClangOffsetOfExpr_getNumExpressions(*const OffsetOfExpr) c_uint; + + pub const getIndexExpr = ZigClangOffsetOfExpr_getIndexExpr; + extern fn ZigClangOffsetOfExpr_getIndexExpr(*const OffsetOfExpr, idx: c_uint) *const Expr; + + pub const getComponent = ZigClangOffsetOfExpr_getComponent; + extern fn ZigClangOffsetOfExpr_getComponent(*const OffsetOfExpr, idx: c_uint) *const OffsetOfNode; + + pub const getBeginLoc = ZigClangOffsetOfExpr_getBeginLoc; + extern fn ZigClangOffsetOfExpr_getBeginLoc(*const OffsetOfExpr) SourceLocation; +}; + pub const MemberExpr = opaque { pub const getBase = ZigClangMemberExpr_getBase; extern fn ZigClangMemberExpr_getBase(*const MemberExpr) *const Expr; @@ -1655,6 +1686,13 @@ pub const UnaryExprOrTypeTrait_Kind = extern enum { PreferredAlignOf, }; +pub const OffsetOfNode_Kind = extern enum { + Array, + Field, + Identifier, + Base, +}; + pub const Stage2ErrorMsg = extern struct { filename_ptr: ?[*]const u8, filename_len: usize, diff --git a/src/translate_c.zig b/src/translate_c.zig index 170e6ef2e1..6dac4bf0ef 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -1069,12 +1069,64 @@ fn transStmt( const expr = try transExpr(c, scope, source_expr, .used); return maybeSuppressResult(c, scope, result_used, expr); }, + .OffsetOfExprClass => return transOffsetOfExpr(c, scope, @ptrCast(*const clang.OffsetOfExpr, stmt), result_used), else => { return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)}); }, } } +/// Translate a "simple" offsetof expression containing exactly one component, +/// when that component is of kind .Field - e.g. offsetof(mytype, myfield) +fn transSimpleOffsetOfExpr( + c: *Context, + scope: *Scope, + expr: *const clang.OffsetOfExpr, +) TransError!Node { + assert(expr.getNumComponents() == 1); + const component = expr.getComponent(0); + if (component.getKind() == .Field) { + const field_decl = component.getField(); + if (field_decl.getParent()) |record_decl| { + if (c.decl_table.get(@ptrToInt(record_decl.getCanonicalDecl()))) |type_name| { + const type_node = try Tag.type.create(c.arena, type_name); + + var raw_field_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin()); + const quoted_field_name = try std.fmt.allocPrint(c.arena, "\"{s}\"", .{raw_field_name}); + const field_name_node = try Tag.string_literal.create(c.arena, quoted_field_name); + + return Tag.byte_offset_of.create(c.arena, .{ + .lhs = type_node, + .rhs = field_name_node, + }); + } + } + } + return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "Failed to translate simple OffsetOfExpr", .{}); +} + +fn transOffsetOfExpr( + c: *Context, + scope: *Scope, + expr: *const clang.OffsetOfExpr, + result_used: ResultUsed, +) TransError!Node { + if (expr.getNumComponents() == 1) { + const offsetof_expr = try transSimpleOffsetOfExpr(c, scope, expr); + return maybeSuppressResult(c, scope, result_used, offsetof_expr); + } + + // TODO implement OffsetOfExpr with more than 1 component + // OffsetOfExpr API: + // call expr.getComponent(idx) while idx < expr.getNumComponents() + // component.getKind() will be either .Array or .Field (other kinds are C++-only) + // if .Field, use component.getField() to retrieve *clang.FieldDecl + // if .Array, use component.getArrayExprIndex() to get a c_uint which + // can be passed to expr.getIndexExpr(expr_index) to get the *clang.Expr for the array index + + return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO: implement complex OffsetOfExpr translation", .{}); +} + fn transBinaryOperator( c: *Context, scope: *Scope, diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index c02b4048f7..e984274c75 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -148,6 +148,8 @@ pub const Node = extern union { ptr_cast, /// @divExact(lhs, rhs) div_exact, + /// @byteOffsetOf(lhs, rhs) + byte_offset_of, negate, negate_wrap, @@ -303,6 +305,7 @@ pub const Node = extern union { .std_mem_zeroinit, .ptr_cast, .div_exact, + .byte_offset_of, => Payload.BinOp, .integer_literal, @@ -1135,6 +1138,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { const payload = node.castTag(.div_exact).?.data; return renderBuiltinCall(c, "@divExact", &.{ payload.lhs, payload.rhs }); }, + .byte_offset_of => { + const payload = node.castTag(.byte_offset_of).?.data; + return renderBuiltinCall(c, "@byteOffsetOf", &.{ payload.lhs, payload.rhs }); + }, .sizeof => { const payload = node.castTag(.sizeof).?.data; return renderBuiltinCall(c, "@sizeOf", &.{payload}); @@ -2001,6 +2008,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { .array_type, .bool_to_int, .div_exact, + .byte_offset_of, => { // no grouping needed return renderNode(c, node); diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index 8387f6fa80..0ddb597371 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -2609,6 +2609,46 @@ const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct return reinterpret_cast(casted->getUnderlyingExpr()); } +enum ZigClangOffsetOfNode_Kind ZigClangOffsetOfNode_getKind(const struct ZigClangOffsetOfNode *self) { + auto casted = reinterpret_cast(self); + return (ZigClangOffsetOfNode_Kind)casted->getKind(); +} + +unsigned ZigClangOffsetOfNode_getArrayExprIndex(const struct ZigClangOffsetOfNode *self) { + auto casted = reinterpret_cast(self); + return casted->getArrayExprIndex(); +} + +struct ZigClangFieldDecl *ZigClangOffsetOfNode_getField(const struct ZigClangOffsetOfNode *self) { + auto casted = reinterpret_cast(self); + return reinterpret_cast(casted->getField()); +} + +unsigned ZigClangOffsetOfExpr_getNumComponents(const struct ZigClangOffsetOfExpr *self) { + auto casted = reinterpret_cast(self); + return casted->getNumComponents(); +} + +unsigned ZigClangOffsetOfExpr_getNumExpressions(const struct ZigClangOffsetOfExpr *self) { + auto casted = reinterpret_cast(self); + return casted->getNumExpressions(); +} + +const struct ZigClangExpr *ZigClangOffsetOfExpr_getIndexExpr(const struct ZigClangOffsetOfExpr *self, unsigned idx) { + auto casted = reinterpret_cast(self); + return reinterpret_cast(casted->getIndexExpr(idx)); +} + +const struct ZigClangOffsetOfNode *ZigClangOffsetOfExpr_getComponent(const struct ZigClangOffsetOfExpr *self, unsigned idx) { + auto casted = reinterpret_cast(self); + return reinterpret_cast(&casted->getComponent(idx)); +} + +ZigClangSourceLocation ZigClangOffsetOfExpr_getBeginLoc(const ZigClangOffsetOfExpr *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->getBeginLoc()); +} + struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *self) { auto casted = reinterpret_cast(self); return bitcast(casted->getNamedType()); @@ -3008,6 +3048,11 @@ ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldD return bitcast(casted->getLocation()); } +const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const struct ZigClangFieldDecl *self) { + auto casted = reinterpret_cast(self); + return reinterpret_cast(casted->getParent()); +} + ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *self) { auto casted = reinterpret_cast(self); return bitcast(casted->getType()); diff --git a/src/zig_clang.h b/src/zig_clang.h index 3c3e97f4a3..b3717946ea 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -928,6 +928,13 @@ enum ZigClangUnaryExprOrTypeTrait_Kind { ZigClangUnaryExprOrTypeTrait_KindPreferredAlignOf, }; +enum ZigClangOffsetOfNode_Kind { + ZigClangOffsetOfNode_KindArray, + ZigClangOffsetOfNode_KindField, + ZigClangOffsetOfNode_KindIdentifier, + ZigClangOffsetOfNode_KindBase, +}; + ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const struct ZigClangSourceManager *, struct ZigClangSourceLocation Loc); ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const struct ZigClangSourceManager *, @@ -1161,6 +1168,16 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangTypeOfType_getUnderlyingType(const ZIG_EXTERN_C const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct ZigClangTypeOfExprType *); +ZIG_EXTERN_C enum ZigClangOffsetOfNode_Kind ZigClangOffsetOfNode_getKind(const struct ZigClangOffsetOfNode *); +ZIG_EXTERN_C unsigned ZigClangOffsetOfNode_getArrayExprIndex(const struct ZigClangOffsetOfNode *); +ZIG_EXTERN_C struct ZigClangFieldDecl * ZigClangOffsetOfNode_getField(const struct ZigClangOffsetOfNode *); + +ZIG_EXTERN_C unsigned ZigClangOffsetOfExpr_getNumComponents(const struct ZigClangOffsetOfExpr *); +ZIG_EXTERN_C unsigned ZigClangOffsetOfExpr_getNumExpressions(const struct ZigClangOffsetOfExpr *); +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangOffsetOfExpr_getIndexExpr(const struct ZigClangOffsetOfExpr *, unsigned idx); +ZIG_EXTERN_C const struct ZigClangOffsetOfNode *ZigClangOffsetOfExpr_getComponent(const struct ZigClangOffsetOfExpr *, unsigned idx); +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangOffsetOfExpr_getBeginLoc(const struct ZigClangOffsetOfExpr *); + ZIG_EXTERN_C struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *); ZIG_EXTERN_C enum ZigClangElaboratedTypeKeyword ZigClangElaboratedType_getKeyword(const struct ZigClangElaboratedType *); @@ -1261,6 +1278,7 @@ ZIG_EXTERN_C bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *) ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *); ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *); ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *); +ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const struct ZigClangFieldDecl *); ZIG_EXTERN_C const struct ZigClangExpr *ZigClangEnumConstantDecl_getInitExpr(const struct ZigClangEnumConstantDecl *); ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct ZigClangEnumConstantDecl *); diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig index 70dc1c835d..23b0a70395 100644 --- a/test/run_translated_c.zig +++ b/test/run_translated_c.zig @@ -1073,4 +1073,37 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { \\ return 0; \\} , ""); + + cases.add("offsetof", + \\#include + \\#include + \\#define container_of(ptr, type, member) ({ \ + \\ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + \\ (type *)( (char *)__mptr - offsetof(type,member) );}) + \\typedef struct { + \\ int i; + \\ struct { int x; char y; int z; } s; + \\ float f; + \\} container; + \\int main(void) { + \\ if (offsetof(container, i) != 0) abort(); + \\ if (offsetof(container, s) <= offsetof(container, i)) abort(); + \\ if (offsetof(container, f) <= offsetof(container, s)) abort(); + \\ + \\ container my_container; + \\ typeof(my_container.s) *inner_member_pointer = &my_container.s; + \\ float *float_member_pointer = &my_container.f; + \\ int *anon_member_pointer = &my_container.s.z; + \\ container *my_container_p; + \\ + \\ my_container_p = container_of(inner_member_pointer, container, s); + \\ if (my_container_p != &my_container) abort(); + \\ + \\ my_container_p = container_of(float_member_pointer, container, f); + \\ if (my_container_p != &my_container) abort(); + \\ + \\ if (container_of(anon_member_pointer, typeof(my_container.s), z) != inner_member_pointer) abort(); + \\ return 0; + \\} + , ""); }