authorgravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2022-02-21 13:18:18-08:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-02-23 14:11:46+02:00
log9716a1c3ab3f56dcef7a70aac597f186a69714fc
tree501f29b5a9adcd0f5e20179dfd70ea0dff02d767
parent4a0b037464ccdf7bc090286f229dfad500a8ad23

translate-c: Add support for cast-to-union

Fixes #10955

8 files changed, 95 insertions(+), 6 deletions(-)

lib/std/zig/c_translation.zig+6
...@@ -30,6 +30,12 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {...@@ -30,6 +30,12 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
30 else => {},30 else => {},
31 }31 }
32 },32 },
33 .Union => |info| {
34 inline for (info.fields) |field| {
35 if (field.field_type == SourceType) return @unionInit(DestType, field.name, target);
36 }
37 @compileError("cast to union type '" ++ @typeName(DestType) ++ "' from type '" ++ @typeName(SourceType) ++ "' which is not present in union");
38 },
33 else => {},39 else => {},
34 }40 }
35 return @as(DestType, target);41 return @as(DestType, target);
src/clang.zig+8
...@@ -258,6 +258,14 @@ pub const CaseStmt = opaque {...@@ -258,6 +258,14 @@ pub const CaseStmt = opaque {
258 extern fn ZigClangCaseStmt_getSubStmt(*const CaseStmt) *const Stmt;258 extern fn ZigClangCaseStmt_getSubStmt(*const CaseStmt) *const Stmt;
259};259};
260260
261pub const CastExpr = opaque {
262 pub const getCastKind = ZigClangCastExpr_getCastKind;
263 extern fn ZigClangCastExpr_getCastKind(*const CastExpr) CK;
264
265 pub const getTargetFieldForToUnionCast = ZigClangCastExpr_getTargetFieldForToUnionCast;
266 extern fn ZigClangCastExpr_getTargetFieldForToUnionCast(*const CastExpr, QualType, QualType) ?*const FieldDecl;
267};
268
261pub const CharacterLiteral = opaque {269pub const CharacterLiteral = opaque {
262 pub const getBeginLoc = ZigClangCharacterLiteral_getBeginLoc;270 pub const getBeginLoc = ZigClangCharacterLiteral_getBeginLoc;
263 extern fn ZigClangCharacterLiteral_getBeginLoc(*const CharacterLiteral) SourceLocation;271 extern fn ZigClangCharacterLiteral_getBeginLoc(*const CharacterLiteral) SourceLocation;
src/translate_c.zig+23-6
...@@ -1791,14 +1791,31 @@ fn transCStyleCastExprClass(...@@ -1791,14 +1791,31 @@ fn transCStyleCastExprClass(
1791 stmt: *const clang.CStyleCastExpr,1791 stmt: *const clang.CStyleCastExpr,
1792 result_used: ResultUsed,1792 result_used: ResultUsed,
1793) TransError!Node {1793) TransError!Node {
1794 const cast_expr = @ptrCast(*const clang.CastExpr, stmt);
1794 const sub_expr = stmt.getSubExpr();1795 const sub_expr = stmt.getSubExpr();
1795 const cast_node = (try transCCast(1796 const dst_type = stmt.getType();
1797 const src_type = sub_expr.getType();
1798 const sub_expr_node = try transExpr(c, scope, sub_expr, .used);
1799 const loc = stmt.getBeginLoc();
1800
1801 const cast_node = if (cast_expr.getCastKind() == .ToUnion) blk: {
1802 const field_decl = cast_expr.getTargetFieldForToUnionCast(dst_type, src_type).?; // C syntax error if target field is null
1803 const field_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
1804
1805 const union_ty = try transQualType(c, scope, dst_type, loc);
1806
1807 const inits = [1]ast.Payload.ContainerInit.Initializer{.{ .name = field_name, .value = sub_expr_node }};
1808 break :blk try Tag.container_init.create(c.arena, .{
1809 .lhs = union_ty,
1810 .inits = try c.arena.dupe(ast.Payload.ContainerInit.Initializer, &inits),
1811 });
1812 } else (try transCCast(
1796 c,1813 c,
1797 scope,1814 scope,
1798 stmt.getBeginLoc(),1815 loc,
1799 stmt.getType(),1816 dst_type,
1800 sub_expr.getType(),1817 src_type,
1801 try transExpr(c, scope, sub_expr, .used),1818 sub_expr_node,
1802 ));1819 ));
1803 return maybeSuppressResult(c, scope, result_used, cast_node);1820 return maybeSuppressResult(c, scope, result_used, cast_node);
1804}1821}
...@@ -2370,7 +2387,7 @@ fn cIntTypeForEnum(enum_qt: clang.QualType) clang.QualType {...@@ -2370,7 +2387,7 @@ fn cIntTypeForEnum(enum_qt: clang.QualType) clang.QualType {
2370 return enum_decl.getIntegerType();2387 return enum_decl.getIntegerType();
2371}2388}
23722389
2373// when modifying this function, make sure to also update std.meta.cast2390// when modifying this function, make sure to also update std.zig.c_translation.cast
2374fn transCCast(2391fn transCCast(
2375 c: *Context,2392 c: *Context,
2376 scope: *Scope,2393 scope: *Scope,
src/zig_clang.cpp+12
...@@ -2986,6 +2986,18 @@ const struct ZigClangCompoundStmt *ZigClangStmtExpr_getSubStmt(const struct ZigC...@@ -2986,6 +2986,18 @@ const struct ZigClangCompoundStmt *ZigClangStmtExpr_getSubStmt(const struct ZigC
2986 return reinterpret_cast<const ZigClangCompoundStmt *>(casted->getSubStmt());2986 return reinterpret_cast<const ZigClangCompoundStmt *>(casted->getSubStmt());
2987}2987}
29882988
2989enum ZigClangCK ZigClangCastExpr_getCastKind(const struct ZigClangCastExpr *self) {
2990 auto casted = reinterpret_cast<const clang::CastExpr *>(self);
2991 return (ZigClangCK)casted->getCastKind();
2992}
2993
2994const struct ZigClangFieldDecl *ZigClangCastExpr_getTargetFieldForToUnionCast(const struct ZigClangCastExpr *self, ZigClangQualType union_type, ZigClangQualType op_type) {
2995 clang::QualType union_qt = bitcast(union_type);
2996 clang::QualType op_qt = bitcast(op_type);
2997 auto casted = reinterpret_cast<const clang::CastExpr *>(self);
2998 return reinterpret_cast<const ZigClangFieldDecl *>(casted->getTargetFieldForToUnionCast(union_qt, op_qt));
2999}
3000
2989struct ZigClangSourceLocation ZigClangCharacterLiteral_getBeginLoc(const struct ZigClangCharacterLiteral *self) {3001struct ZigClangSourceLocation ZigClangCharacterLiteral_getBeginLoc(const struct ZigClangCharacterLiteral *self) {
2990 auto casted = reinterpret_cast<const clang::CharacterLiteral *>(self);3002 auto casted = reinterpret_cast<const clang::CharacterLiteral *>(self);
2991 return bitcast(casted->getBeginLoc());3003 return bitcast(casted->getBeginLoc());
src/zig_clang.h+4
...@@ -103,6 +103,7 @@ struct ZigClangBuiltinType;...@@ -103,6 +103,7 @@ struct ZigClangBuiltinType;
103struct ZigClangCStyleCastExpr;103struct ZigClangCStyleCastExpr;
104struct ZigClangCallExpr;104struct ZigClangCallExpr;
105struct ZigClangCaseStmt;105struct ZigClangCaseStmt;
106struct ZigClangCastExpr;
106struct ZigClangCharacterLiteral;107struct ZigClangCharacterLiteral;
107struct ZigClangChooseExpr;108struct ZigClangChooseExpr;
108struct ZigClangCompoundAssignOperator;109struct ZigClangCompoundAssignOperator;
...@@ -1317,6 +1318,9 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangDecayedType_getDecayedType(const st...@@ -1317,6 +1318,9 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangDecayedType_getDecayedType(const st
13171318
1318ZIG_EXTERN_C const struct ZigClangCompoundStmt *ZigClangStmtExpr_getSubStmt(const struct ZigClangStmtExpr *);1319ZIG_EXTERN_C const struct ZigClangCompoundStmt *ZigClangStmtExpr_getSubStmt(const struct ZigClangStmtExpr *);
13191320
1321ZIG_EXTERN_C enum ZigClangCK ZigClangCastExpr_getCastKind(const struct ZigClangCastExpr *);
1322ZIG_EXTERN_C const struct ZigClangFieldDecl *ZigClangCastExpr_getTargetFieldForToUnionCast(const struct ZigClangCastExpr *, struct ZigClangQualType, struct ZigClangQualType);
1323
1320ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangCharacterLiteral_getBeginLoc(const struct ZigClangCharacterLiteral *);1324ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangCharacterLiteral_getBeginLoc(const struct ZigClangCharacterLiteral *);
1321ZIG_EXTERN_C enum ZigClangCharacterLiteral_CharacterKind ZigClangCharacterLiteral_getKind(const struct ZigClangCharacterLiteral *);1325ZIG_EXTERN_C enum ZigClangCharacterLiteral_CharacterKind ZigClangCharacterLiteral_getKind(const struct ZigClangCharacterLiteral *);
1322ZIG_EXTERN_C unsigned ZigClangCharacterLiteral_getValue(const struct ZigClangCharacterLiteral *);1326ZIG_EXTERN_C unsigned ZigClangCharacterLiteral_getValue(const struct ZigClangCharacterLiteral *);
test/behavior/translate_c_macros.h+7
...@@ -15,6 +15,11 @@ struct Foo {...@@ -15,6 +15,11 @@ struct Foo {
15 int a;15 int a;
16};16};
1717
18union U {
19 long l;
20 double d;
21};
22
18#define SIZE_OF_FOO sizeof(struct Foo)23#define SIZE_OF_FOO sizeof(struct Foo)
1924
20#define MAP_FAILED ((void *) -1)25#define MAP_FAILED ((void *) -1)
...@@ -30,3 +35,5 @@ struct Foo {...@@ -30,3 +35,5 @@ struct Foo {
30#define IGNORE_ME_8(x) (volatile void)(x)35#define IGNORE_ME_8(x) (volatile void)(x)
31#define IGNORE_ME_9(x) (const volatile void)(x)36#define IGNORE_ME_9(x) (const volatile void)(x)
32#define IGNORE_ME_10(x) (volatile const void)(x)37#define IGNORE_ME_10(x) (volatile const void)(x)
38
39#define UNION_CAST(X) (union U)(X)
test/behavior/translate_c_macros.zig+13
...@@ -47,3 +47,16 @@ test "cast negative integer to pointer" {...@@ -47,3 +47,16 @@ test "cast negative integer to pointer" {
4747
48 try expectEqual(@intToPtr(?*anyopaque, @bitCast(usize, @as(isize, -1))), h.MAP_FAILED);48 try expectEqual(@intToPtr(?*anyopaque, @bitCast(usize, @as(isize, -1))), h.MAP_FAILED);
49}49}
50
51test "casting to union with a macro" {
52 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO Sema.zirUnionInitPtr
53
54 const l: c_long = 42;
55 const d: f64 = 2.0;
56
57 var casted = h.UNION_CAST(l);
58 try expectEqual(l, casted.l);
59
60 casted = h.UNION_CAST(d);
61 try expectEqual(d, casted.d);
62}
test/run_translated_c.zig+22
...@@ -1829,4 +1829,26 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {...@@ -1829,4 +1829,26 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
1829 \\ return 0;1829 \\ return 0;
1830 \\}1830 \\}
1831 , "");1831 , "");
1832
1833 cases.add("Cast-to-union. Issue #10955",
1834 \\#include <stdlib.h>
1835 \\struct S { int x; };
1836 \\union U {
1837 \\ long l;
1838 \\ double d;
1839 \\ struct S s;
1840 \\};
1841 \\union U bar(union U u) { return u; }
1842 \\int main(void) {
1843 \\ union U u = (union U) 42L;
1844 \\ if (u.l != 42L) abort();
1845 \\ u = (union U) 2.0;
1846 \\ if (u.d != 2.0) abort();
1847 \\ u = bar((union U)4.0);
1848 \\ if (u.d != 4.0) abort();
1849 \\ u = (union U)(struct S){ .x = 5 };
1850 \\ if (u.s.x != 5) abort();
1851 \\ return 0;
1852 \\}
1853 , "");
1832}1854}