diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index 5a702b182a..b98fa785d1 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -804,6 +804,8 @@ pub extern fn ZigClangType_getPointeeType(self: ?*const struct_ZigClangType) str pub extern fn ZigClangType_isVoidType(self: ?*const struct_ZigClangType) bool; pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*:0]const u8; pub extern fn ZigClangType_getAsArrayTypeUnsafe(self: *const ZigClangType) *const ZigClangArrayType; +pub extern fn ZigClangType_getAsRecordType(self: *const ZigClangType) ?*const ZigClangRecordType; +pub extern fn ZigClangType_getAsUnionType(self: *const ZigClangType) ?*const ZigClangRecordType; pub extern fn ZigClangStmt_getBeginLoc(self: *const struct_ZigClangStmt) struct_ZigClangSourceLocation; pub extern fn ZigClangStmt_getStmtClass(self: ?*const struct_ZigClangStmt) ZigClangStmtClass; pub extern fn ZigClangStmt_classof_Expr(self: ?*const struct_ZigClangStmt) bool; @@ -813,6 +815,7 @@ pub extern fn ZigClangExpr_getBeginLoc(self: *const struct_ZigClangExpr) struct_ pub extern fn ZigClangInitListExpr_getInit(self: ?*const struct_ZigClangInitListExpr, i: c_uint) *const ZigClangExpr; pub extern fn ZigClangInitListExpr_getArrayFiller(self: ?*const struct_ZigClangInitListExpr) *const ZigClangExpr; pub extern fn ZigClangInitListExpr_getNumInits(self: ?*const struct_ZigClangInitListExpr) c_uint; +pub extern fn ZigClangInitListExpr_getInitializedFieldInUnion(self: ?*const struct_ZigClangInitListExpr) ?*ZigClangFieldDecl; pub extern fn ZigClangAPValue_getKind(self: ?*const struct_ZigClangAPValue) ZigClangAPValueKind; pub extern fn ZigClangAPValue_getInt(self: ?*const struct_ZigClangAPValue) *const struct_ZigClangAPSInt; pub extern fn ZigClangAPValue_getArrayInitializedElts(self: ?*const struct_ZigClangAPValue) c_uint; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 579367a3f2..1539417cb6 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -1781,6 +1781,70 @@ fn transExprCoercing( return transExpr(rp, scope, expr, .used, .r_value); } +fn transInitListExprRecord( + rp: RestorePoint, + scope: *Scope, + loc: ZigClangSourceLocation, + expr: *const ZigClangInitListExpr, + ty: *const ZigClangType, + used: ResultUsed, +) TransError!*ast.Node { + var is_union_type = false; + // Unions and Structs are both represented as RecordDecl + const record_ty = ZigClangType_getAsRecordType(ty) orelse + blk: { + is_union_type = true; + break :blk ZigClangType_getAsUnionType(ty); + } orelse unreachable; + const record_decl = ZigClangRecordType_getDecl(record_ty); + const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse + unreachable; + + const ty_node = try transType(rp, ty, loc); + const init_count = ZigClangInitListExpr_getNumInits(expr); + var init_node = try transCreateNodeStructInitializer(rp.c, ty_node); + + var init_i: c_uint = 0; + var it = ZigClangRecordDecl_field_begin(record_def); + const end_it = ZigClangRecordDecl_field_end(record_def); + while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) { + const field_decl = ZigClangRecordDecl_field_iterator_deref(it); + + // The initializer for a union type has a single entry only + if (is_union_type and field_decl != ZigClangInitListExpr_getInitializedFieldInUnion(expr)) { + continue; + } + + assert(init_i < init_count); + const elem_expr = ZigClangInitListExpr_getInit(expr, init_i); + init_i += 1; + + // Generate the field assignment expression: + // .field_name = expr + const period_tok = try appendToken(rp.c, .Period, "."); + + const raw_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))); + if (raw_name.len < 1) continue; + const field_name_tok = try appendIdentifier(rp.c, raw_name); + + _ = try appendToken(rp.c, .Equal, "="); + + const field_init_node = try rp.c.a().create(ast.Node.FieldInitializer); + field_init_node.* = .{ + .period_token = period_tok, + .name_token = field_name_tok, + .expr = try transExpr(rp, scope, elem_expr, .used, .r_value), + }; + + try init_node.op.StructInitializer.push(&field_init_node.base); + _ = try appendToken(rp.c, .Comma, ","); + } + + init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); + + return &init_node.base; +} + fn transInitListExpr( rp: RestorePoint, scope: *Scope, @@ -1793,7 +1857,7 @@ fn transInitListExpr( switch (ZigClangType_getTypeClass(qual_type)) { .ConstantArray => {}, .Record, .Elaborated => { - return revertAndWarn(rp, error.UnsupportedType, source_loc, "TODO initListExpr for structs", .{}); + return transInitListExprRecord(rp, scope, source_loc, expr, qual_type, used); }, else => { const type_name = rp.c.str(ZigClangType_getTypeClassName(qual_type)); @@ -1861,16 +1925,13 @@ fn transInitListExpr( return &cat_node.base; } -fn transImplicitValueInitExpr( +fn transZeroInitExpr( rp: RestorePoint, scope: *Scope, - expr: *const ZigClangExpr, - used: ResultUsed, + source_loc: ZigClangSourceLocation, + ty: *const ZigClangType, ) TransError!*ast.Node { - const source_loc = ZigClangExpr_getBeginLoc(expr); - const qt = getExprQualType(rp.c, expr); - const ty = ZigClangQualType_getTypePtr(qt); - const node = switch (ZigClangType_getTypeClass(ty)) { + switch (ZigClangType_getTypeClass(ty)) { .Builtin => blk: { const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); switch (ZigClangBuiltinType_getKind(builtin_ty)) { @@ -1900,8 +1961,34 @@ fn transImplicitValueInitExpr( } }, .Pointer => return transCreateNodeNullLiteral(rp.c), - else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{}), - }; + .Typedef => { + const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); + const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); + return transZeroInitExpr( + rp, + scope, + source_loc, + ZigClangQualType_getTypePtr( + ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl), + ), + ); + }, + else => {}, + } + + return revertAndWarn(rp, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{}); +} + +fn transImplicitValueInitExpr( + rp: RestorePoint, + scope: *Scope, + expr: *const ZigClangExpr, + used: ResultUsed, +) TransError!*ast.Node { + const source_loc = ZigClangExpr_getBeginLoc(expr); + const qt = getExprQualType(rp.c, expr); + const ty = ZigClangQualType_getTypePtr(qt); + return transZeroInitExpr(rp, scope, source_loc, ty); } fn transIfStmt( @@ -3484,6 +3571,19 @@ fn transCreateNodeContainerInitializer(c: *Context, dot_tok: ast.TokenIndex) !*a return node; } +fn transCreateNodeStructInitializer(c: *Context, ty: *ast.Node) !*ast.Node.SuffixOp { + _ = try appendToken(c, .LBrace, "{"); + const node = try c.a().create(ast.Node.SuffixOp); + node.* = ast.Node.SuffixOp{ + .lhs = .{ .node = ty }, + .op = .{ + .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(c.a()), + }, + .rtoken = undefined, // set after appending values + }; + return node; +} + fn transCreateNodeInt(c: *Context, int: var) !*ast.Node { const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int}); const node = try c.a().create(ast.Node.IntegerLiteral); diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index c8dec14bfe..6217e17800 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -1825,6 +1825,18 @@ const ZigClangArrayType *ZigClangType_getAsArrayTypeUnsafe(const ZigClangType *s return reinterpret_cast(result); } +const ZigClangRecordType *ZigClangType_getAsRecordType(const ZigClangType *self) { + auto casted = reinterpret_cast(self); + const clang::RecordType *result = casted->getAsStructureType(); + return reinterpret_cast(result); +} + +const ZigClangRecordType *ZigClangType_getAsUnionType(const ZigClangType *self) { + auto casted = reinterpret_cast(self); + const clang::RecordType *result = casted->getAsUnionType(); + return reinterpret_cast(result); +} + ZigClangSourceLocation ZigClangStmt_getBeginLoc(const ZigClangStmt *self) { auto casted = reinterpret_cast(self); return bitcast(casted->getBeginLoc()); @@ -1898,6 +1910,12 @@ const ZigClangExpr *ZigClangInitListExpr_getArrayFiller(const ZigClangInitListEx return reinterpret_cast(result); } +const ZigClangFieldDecl *ZigClangInitListExpr_getInitializedFieldInUnion(const ZigClangInitListExpr *self) { + auto casted = reinterpret_cast(self); + const clang::FieldDecl *result = casted->getInitializedFieldInUnion(); + return reinterpret_cast(result); +} + unsigned ZigClangInitListExpr_getNumInits(const ZigClangInitListExpr *self) { auto casted = reinterpret_cast(self); return casted->getNumInits(); diff --git a/src/zig_clang.h b/src/zig_clang.h index 8f00ff2155..0b248a8121 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -934,6 +934,8 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangType_getPointeeType(const struct Zi ZIG_EXTERN_C bool ZigClangType_isVoidType(const struct ZigClangType *self); ZIG_EXTERN_C const char *ZigClangType_getTypeClassName(const struct ZigClangType *self); ZIG_EXTERN_C const struct ZigClangArrayType *ZigClangType_getAsArrayTypeUnsafe(const struct ZigClangType *self); +ZIG_EXTERN_C const ZigClangRecordType *ZigClangType_getAsRecordType(const ZigClangType *self); +ZIG_EXTERN_C const ZigClangRecordType *ZigClangType_getAsUnionType(const ZigClangType *self); ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangStmt_getBeginLoc(const struct ZigClangStmt *self); ZIG_EXTERN_C enum ZigClangStmtClass ZigClangStmt_getStmtClass(const struct ZigClangStmt *self); @@ -952,6 +954,7 @@ ZIG_EXTERN_C bool ZigClangExpr_EvaluateAsConstantExpr(const struct ZigClangExpr ZIG_EXTERN_C const ZigClangExpr *ZigClangInitListExpr_getInit(const ZigClangInitListExpr *, unsigned); ZIG_EXTERN_C const ZigClangExpr *ZigClangInitListExpr_getArrayFiller(const ZigClangInitListExpr *); ZIG_EXTERN_C unsigned ZigClangInitListExpr_getNumInits(const ZigClangInitListExpr *); +ZIG_EXTERN_C const ZigClangFieldDecl *ZigClangInitListExpr_getInitializedFieldInUnion(const ZigClangInitListExpr *self); ZIG_EXTERN_C enum ZigClangAPValueKind ZigClangAPValue_getKind(const struct ZigClangAPValue *self); ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangAPValue_getInt(const struct ZigClangAPValue *self); diff --git a/test/translate_c.zig b/test/translate_c.zig index c38eb3ad78..63c477f354 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -2,6 +2,69 @@ const tests = @import("tests.zig"); const builtin = @import("builtin"); pub fn addCases(cases: *tests.TranslateCContext) void { + cases.add("union initializer", + \\union { int x; char c[4]; } + \\ ua = {1}, + \\ ub = {.c={'a','b','b','a'}}; + , &[_][]const u8{ + \\const union_unnamed_1 = extern union { + \\ x: c_int, + \\ c: [4]u8, + \\}; + \\pub export var ua: union_unnamed_1 = union_unnamed_1{ + \\ .x = @as(c_int, 1), + \\}; + \\pub export var ub: union_unnamed_1 = union_unnamed_1{ + \\ .c = .{ + \\ @bitCast(u8, @truncate(i8, @as(c_int, 'a'))), + \\ @bitCast(u8, @truncate(i8, @as(c_int, 'b'))), + \\ @bitCast(u8, @truncate(i8, @as(c_int, 'b'))), + \\ @bitCast(u8, @truncate(i8, @as(c_int, 'a'))), + \\ }, + \\}; + }); + + cases.add("struct initializer - simple", + \\struct {double x,y,z;} s0 = {1.2, 1.3}; + \\struct {int sec,min,hour,day,mon,year;} s1 = {.day=31,12,2014,.sec=30,15,17}; + \\struct {int x,y;} s2 = {.y = 2, .x=1}; + , &[_][]const u8{ + \\const struct_unnamed_1 = extern struct { + \\ x: f64, + \\ y: f64, + \\ z: f64, + \\}; + \\pub export var s0: struct_unnamed_1 = struct_unnamed_1{ + \\ .x = 1.2, + \\ .y = 1.3, + \\ .z = 0, + \\}; + \\const struct_unnamed_2 = extern struct { + \\ sec: c_int, + \\ min: c_int, + \\ hour: c_int, + \\ day: c_int, + \\ mon: c_int, + \\ year: c_int, + \\}; + \\pub export var s1: struct_unnamed_2 = struct_unnamed_2{ + \\ .sec = @as(c_int, 30), + \\ .min = @as(c_int, 15), + \\ .hour = @as(c_int, 17), + \\ .day = @as(c_int, 31), + \\ .mon = @as(c_int, 12), + \\ .year = @as(c_int, 2014), + \\}; + \\const struct_unnamed_3 = extern struct { + \\ x: c_int, + \\ y: c_int, + \\}; + \\pub export var s2: struct_unnamed_3 = struct_unnamed_3{ + \\ .x = @as(c_int, 1), + \\ .y = @as(c_int, 2), + \\}; + }); + cases.add("simple ptrCast for casts between opaque types", \\struct opaque; \\struct opaque_2;