authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2019-12-19 09:39:39+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2019-12-19 09:56:00+02:00
log809deb6ec0bf9ea5649d3ba4ca80485e2148a538
tree3e0fce5e13a70ac3757c39e4577b92608d87ef45
parente4c47e80b43eb3096093b38e8e984d9042e3742e
signature Commit is signed but in an unrecognized format.

translate-c-2 unary operators common case


3 files changed, 337 insertions(+), 163 deletions(-)

src-self-hosted/clang.zig+4
...@@ -1116,3 +1116,7 @@ pub extern fn ZigClangCallExpr_getArgs(*const ZigClangCallExpr) [*]const *const...@@ -1116,3 +1116,7 @@ pub extern fn ZigClangCallExpr_getArgs(*const ZigClangCallExpr) [*]const *const
1116pub extern fn ZigClangUnaryExprOrTypeTraitExpr_getTypeOfArgument(*const ZigClangUnaryExprOrTypeTraitExpr) ZigClangQualType;1116pub extern fn ZigClangUnaryExprOrTypeTraitExpr_getTypeOfArgument(*const ZigClangUnaryExprOrTypeTraitExpr) ZigClangQualType;
1117pub extern fn ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(*const ZigClangUnaryExprOrTypeTraitExpr) ZigClangSourceLocation;1117pub extern fn ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(*const ZigClangUnaryExprOrTypeTraitExpr) ZigClangSourceLocation;
11181118
1119pub extern fn ZigClangUnaryOperator_getOpcode(*const ZigClangUnaryOperator) ZigClangUO;
1120pub extern fn ZigClangUnaryOperator_getType(*const ZigClangUnaryOperator) ZigClangQualType;
1121pub extern fn ZigClangUnaryOperator_getSubExpr(*const ZigClangUnaryOperator) *const ZigClangExpr;
1122pub extern fn ZigClangUnaryOperator_getBeginLoc(*const ZigClangUnaryOperator) ZigClangSourceLocation;
src-self-hosted/translate_c.zig+151
...@@ -897,6 +897,7 @@ fn transStmt(...@@ -897,6 +897,7 @@ fn transStmt(
897 .ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const ZigClangArraySubscriptExpr, stmt), result_used),897 .ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const ZigClangArraySubscriptExpr, stmt), result_used),
898 .CallExprClass => return transCallExpr(rp, scope, @ptrCast(*const ZigClangCallExpr, stmt), result_used),898 .CallExprClass => return transCallExpr(rp, scope, @ptrCast(*const ZigClangCallExpr, stmt), result_used),
899 .UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(rp, scope, @ptrCast(*const ZigClangUnaryExprOrTypeTraitExpr, stmt), result_used),899 .UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(rp, scope, @ptrCast(*const ZigClangUnaryExprOrTypeTraitExpr, stmt), result_used),
900 .UnaryOperatorClass => return transUnaryOperator(rp, scope, @ptrCast(*const ZigClangUnaryOperator, stmt), result_used),
900 else => {901 else => {
901 return revertAndWarn(902 return revertAndWarn(
902 rp,903 rp,
...@@ -2163,6 +2164,139 @@ fn transUnaryExprOrTypeTraitExpr(...@@ -2163,6 +2164,139 @@ fn transUnaryExprOrTypeTraitExpr(
2163 return maybeSuppressResult(rp, scope, result_used, &builtin_node.base);2164 return maybeSuppressResult(rp, scope, result_used, &builtin_node.base);
2164}2165}
21652166
2167fn qualTypeHaswrappingOverflow(qt: ZigClangQualType) bool {
2168 if (cIsSignedInteger(qt) or cIsFloating(qt)) {
2169 // float and signed integer overflow is undefined behavior.
2170 return false;
2171 } else {
2172 // unsigned integer overflow wraps around.
2173 return true;
2174 }
2175}
2176
2177fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnaryOperator, used: ResultUsed) TransError!*ast.Node {
2178 const op_expr = ZigClangUnaryOperator_getSubExpr(stmt);
2179 switch (ZigClangUnaryOperator_getOpcode(stmt)) {
2180 .PostInc => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
2181 return transCreatePostCrement(rp, scope, stmt, .AssignPlusWrap, .PlusPercentEqual, "+%=", used)
2182 else
2183 return transCreatePostCrement(rp, scope, stmt, .AssignPlus, .PlusEqual, "+=", used),
2184 .PostDec => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
2185 return transCreatePostCrement(rp, scope, stmt, .AssignMinusWrap, .MinusPercentEqual, "-%=", used)
2186 else
2187 return transCreatePostCrement(rp, scope, stmt, .AssignMinus, .MinusEqual, "-=", used),
2188 .PreInc => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
2189 return transCreatePreCrement(rp, scope, stmt, .AssignPlusWrap, .PlusPercentEqual, "+%=", used)
2190 else
2191 return transCreatePreCrement(rp, scope, stmt, .AssignPlus, .PlusEqual, "+=", used),
2192 .PreDec => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
2193 return transCreatePreCrement(rp, scope, stmt, .AssignMinusWrap, .MinusPercentEqual, "-%=", used)
2194 else
2195 return transCreatePreCrement(rp, scope, stmt, .AssignMinus, .MinusEqual, "-=", used),
2196 .AddrOf => {
2197 const op_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
2198 op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value);
2199 return &op_node.base;
2200 },
2201 .Deref => {
2202 const value_node = try transExpr(rp, scope, op_expr, used, .r_value);
2203 var is_ptr = false;
2204 const fn_ty = qualTypeGetFnProto(ZigClangExpr_getType(op_expr), &is_ptr);
2205 if (fn_ty != null and is_ptr)
2206 return value_node;
2207 const unwrapped = try transCreateNodeUnwrapNull(rp.c, value_node);
2208 return transCreateNodePtrDeref(rp.c, unwrapped);
2209 },
2210 .Plus => return transExpr(rp, scope, op_expr, used, .r_value),
2211 .Minus => {
2212 if (!qualTypeHaswrappingOverflow(ZigClangExpr_getType(op_expr))) {
2213 const op_node = try transCreateNodePrefixOp(rp.c, .Negation, .Minus, "-");
2214 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
2215 return &op_node.base;
2216 } else if (cIsUnsignedInteger(ZigClangExpr_getType(op_expr))) {
2217 // we gotta emit 0 -% x
2218 const zero = try transCreateNodeInt(rp.c, 0);
2219 const token = try appendToken(rp.c, .MinusPercent, "-%");
2220 const expr = try transExpr(rp, scope, op_expr, .used, .r_value);
2221 return transCreateNodeInfixOp(rp, scope, zero, .SubWrap, token, expr, used, true);
2222 } else
2223 return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "C negation with non float non integer", .{});
2224 },
2225 .Not => {
2226 const op_node = try transCreateNodePrefixOp(rp.c, .BitNot, .Tilde, "~");
2227 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
2228 return &op_node.base;
2229 },
2230 .LNot => {
2231 const op_node = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
2232 op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true);
2233 return &op_node.base;
2234 },
2235 else => return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "TODO handle C translation UO_Real", .{}),
2236 }
2237}
2238
2239fn transCreatePreCrement(
2240 rp: RestorePoint,
2241 scope: *Scope,
2242 stmt: *const ZigClangUnaryOperator,
2243 op: ast.Node.InfixOp.Op,
2244 op_tok_id: std.zig.Token.Id,
2245 bytes: []const u8,
2246 used: ResultUsed,
2247) TransError!*ast.Node {
2248 const op_expr = ZigClangUnaryOperator_getSubExpr(stmt);
2249
2250 if (used == .unused) {
2251 // common case
2252 // c: ++expr
2253 // zig: expr += 1
2254 const expr = try transExpr(rp, scope, op_expr, .used, .r_value);
2255 const token = try appendToken(rp.c, op_tok_id, bytes);
2256 const one = try transCreateNodeInt(rp.c, 1);
2257 _ = try appendToken(rp.c, .Semicolon, ";");
2258 return transCreateNodeInfixOp(rp, scope, expr, op, token, one, .used, false);
2259 }
2260 // worst case
2261 // c: ++expr
2262 // zig: (blk: {
2263 // zig: const _ref = &expr;
2264 // zig: *_ref += 1;
2265 // zig: break :blk *_ref
2266 // zig: })
2267}
2268
2269fn transCreatePostCrement(
2270 rp: RestorePoint,
2271 scope: *Scope,
2272 stmt: *const ZigClangUnaryOperator,
2273 op: ast.Node.InfixOp.Op,
2274 op_tok_id: std.zig.Token.Id,
2275 bytes: []const u8,
2276 used: ResultUsed,
2277) TransError!*ast.Node {
2278 const op_expr = ZigClangUnaryOperator_getSubExpr(stmt);
2279
2280 if (used == .unused) {
2281 // common case
2282 // c: ++expr
2283 // zig: expr += 1
2284 const expr = try transExpr(rp, scope, op_expr, .used, .r_value);
2285 const token = try appendToken(rp.c, op_tok_id, bytes);
2286 const one = try transCreateNodeInt(rp.c, 1);
2287 _ = try appendToken(rp.c, .Semicolon, ";");
2288 return transCreateNodeInfixOp(rp, scope, expr, op, token, one, .used, false);
2289 }
2290 // worst case
2291 // c: expr++
2292 // zig: (blk: {
2293 // zig: const _ref = &expr;
2294 // zig: const _tmp = *_ref;
2295 // zig: *_ref += 1;
2296 // zig: break :blk _tmp
2297 // zig: })
2298}
2299
2166fn transCPtrCast(2300fn transCPtrCast(
2167 rp: RestorePoint,2301 rp: RestorePoint,
2168 loc: ZigClangSourceLocation,2302 loc: ZigClangSourceLocation,
...@@ -2507,6 +2641,23 @@ fn cIsUnsignedInteger(qt: ZigClangQualType) bool {...@@ -2507,6 +2641,23 @@ fn cIsUnsignedInteger(qt: ZigClangQualType) bool {
2507 };2641 };
2508}2642}
25092643
2644fn cIsSignedInteger(qt: ZigClangQualType) bool {
2645 const c_type = qualTypeCanon(qt);
2646 if (ZigClangType_getTypeClass(c_type) != .Builtin) return false;
2647 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, c_type);
2648 return switch (ZigClangBuiltinType_getKind(builtin_ty)) {
2649 .SChar,
2650 .Short,
2651 .Int,
2652 .Long,
2653 .LongLong,
2654 .Int128,
2655 .WChar_S,
2656 => true,
2657 else => false,
2658 };
2659}
2660
2510fn cIsFloating(qt: ZigClangQualType) bool {2661fn cIsFloating(qt: ZigClangQualType) bool {
2511 const c_type = qualTypeCanon(qt);2662 const c_type = qualTypeCanon(qt);
2512 if (ZigClangType_getTypeClass(c_type) != .Builtin) return false;2663 if (ZigClangType_getTypeClass(c_type) != .Builtin) return false;
test/translate_c.zig+182-163
...@@ -769,6 +769,56 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -769,6 +769,56 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
769 \\}769 \\}
770 });770 });
771771
772 cases.addC_both("normal deref",
773 \\void foo(int *x) {
774 \\ *x = 1;
775 \\}
776 , &[_][]const u8{
777 \\pub export fn foo(x: [*c]c_int) void {
778 \\ x.?.* = 1;
779 \\}
780 });
781
782 cases.addC_both("address of operator",
783 \\int foo(void) {
784 \\ int x = 1234;
785 \\ int *ptr = &x;
786 \\ return *ptr;
787 \\}
788 , &[_][]const u8{
789 \\pub export fn foo() c_int {
790 \\ var x: c_int = 1234;
791 \\ var ptr: [*c]c_int = &x;
792 \\ return ptr.?.*;
793 \\}
794 });
795
796 cases.addC_both("bin not",
797 \\int foo(int x) {
798 \\ return ~x;
799 \\}
800 , &[_][]const u8{
801 \\pub export fn foo(x: c_int) c_int {
802 \\ return ~x;
803 \\}
804 });
805
806 cases.addC_both("bool not",
807 \\int foo(int a, float b, void *c) {
808 \\ return !(a == 0);
809 \\ return !a;
810 \\ return !b;
811 \\ return !c;
812 \\}
813 , &[_][]const u8{
814 \\pub export fn foo(a: c_int, b: f32, c: ?*c_void) c_int {
815 \\ return !(a == 0);
816 \\ return !(a != 0);
817 \\ return !(b != 0);
818 \\ return !(c != null);
819 \\}
820 });
821
772 /////////////// Cases that pass for only stage2 ////////////////822 /////////////// Cases that pass for only stage2 ////////////////
773823
774 cases.add_2("Parameterless function prototypes",824 cases.add_2("Parameterless function prototypes",
...@@ -1664,9 +1714,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1664,9 +1714,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1664 \\}1714 \\}
1665 });1715 });
16661716
1667 /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////1717 cases.add_2("simple data types",
1668
1669 cases.addAllowWarnings("simple data types",
1670 \\#include <stdint.h>1718 \\#include <stdint.h>
1671 \\int foo(char a, unsigned char b, signed char c);1719 \\int foo(char a, unsigned char b, signed char c);
1672 \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype1720 \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype
...@@ -1674,22 +1722,72 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1674,22 +1722,72 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1674 \\void baz(int8_t a, int16_t b, int32_t c, int64_t d);1722 \\void baz(int8_t a, int16_t b, int32_t c, int64_t d);
1675 , &[_][]const u8{1723 , &[_][]const u8{
1676 \\pub extern fn foo(a: u8, b: u8, c: i8) c_int;1724 \\pub extern fn foo(a: u8, b: u8, c: i8) c_int;
1677 ,
1678 \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void;1725 \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void;
1679 ,
1680 \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void;1726 \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void;
1681 });1727 });
16821728
1683 cases.addC("simple function",1729 cases.add_2("simple function",
1684 \\int abs(int a) {1730 \\int abs(int a) {
1685 \\ return a < 0 ? -a : a;1731 \\ return a < 0 ? -a : a;
1686 \\}1732 \\}
1687 , &[_][]const u8{1733 , &[_][]const u8{
1688 \\export fn abs(a: c_int) c_int {1734 \\pub export fn abs(a: c_int) c_int {
1689 \\ return if (a < 0) -a else a;1735 \\ return if ((a < 0)) -a else a;
1736 \\}
1737 });
1738
1739 cases.add_2("post increment",
1740 \\unsigned foo1(unsigned a) {
1741 \\ a++;
1742 \\ return a;
1743 \\}
1744 \\int foo2(int a) {
1745 \\ a++;
1746 \\ return a;
1747 \\}
1748 , &[_][]const u8{
1749 \\pub export fn foo1(a: c_uint) c_uint {
1750 \\ a +%= 1;
1751 \\ return a;
1752 \\}
1753 \\pub export fn foo2(a: c_int) c_int {
1754 \\ a += 1;
1755 \\ return a;
1756 \\}
1757 });
1758
1759 cases.add_2("deref function pointer",
1760 \\void foo(void) {}
1761 \\int baz(void) { return 0; }
1762 \\void bar(void) {
1763 \\ void(*f)(void) = foo;
1764 \\ int(*b)(void) = baz;
1765 \\ f();
1766 \\ (*(f))();
1767 \\ foo();
1768 \\ b();
1769 \\ (*(b))();
1770 \\ baz();
1771 \\}
1772 , &[_][]const u8{
1773 \\pub export fn foo() void {}
1774 \\pub export fn baz() c_int {
1775 \\ return 0;
1776 \\}
1777 \\pub export fn bar() void {
1778 \\ var f: ?extern fn () void = foo;
1779 \\ var b: ?extern fn () c_int = baz;
1780 \\ f.?();
1781 \\ (f).?();
1782 \\ foo();
1783 \\ _ = b.?();
1784 \\ _ = (b).?();
1785 \\ _ = baz();
1690 \\}1786 \\}
1691 });1787 });
16921788
1789 /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
1790
1693 cases.add("macro defines string literal with hex",1791 cases.add("macro defines string literal with hex",
1694 \\#define FOO "aoeu\xab derp"1792 \\#define FOO "aoeu\xab derp"
1695 \\#define FOO2 "aoeu\x0007a derp"1793 \\#define FOO2 "aoeu\x0007a derp"
...@@ -1714,28 +1812,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1714,28 +1812,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1714 \\pub const FOO_CHAR = 63;1812 \\pub const FOO_CHAR = 63;
1715 });1813 });
17161814
1717 cases.addC("post increment",
1718 \\unsigned foo1(unsigned a) {
1719 \\ a++;
1720 \\ return a;
1721 \\}
1722 \\int foo2(int a) {
1723 \\ a++;
1724 \\ return a;
1725 \\}
1726 , &[_][]const u8{
1727 \\pub export fn foo1(_arg_a: c_uint) c_uint {
1728 \\ var a = _arg_a;
1729 \\ a +%= 1;
1730 \\ return a;
1731 \\}
1732 \\pub export fn foo2(_arg_a: c_int) c_int {
1733 \\ var a = _arg_a;
1734 \\ a += 1;
1735 \\ return a;
1736 \\}
1737 });
1738
1739 cases.addC("shift right assign",1815 cases.addC("shift right assign",
1740 \\int log2(unsigned a) {1816 \\int log2(unsigned a) {
1741 \\ int i = 0;1817 \\ int i = 0;
...@@ -1993,96 +2069,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1993,96 +2069,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1993 \\}2069 \\}
1994 });2070 });
19952071
1996 cases.addC("deref function pointer",
1997 \\void foo(void) {}
1998 \\int baz(void) { return 0; }
1999 \\void bar(void) {
2000 \\ void(*f)(void) = foo;
2001 \\ int(*b)(void) = baz;
2002 \\ f();
2003 \\ (*(f))();
2004 \\ foo();
2005 \\ b();
2006 \\ (*(b))();
2007 \\ baz();
2008 \\}
2009 , &[_][]const u8{
2010 \\pub export fn foo() void {}
2011 \\pub export fn baz() c_int {
2012 \\ return 0;
2013 \\}
2014 \\pub export fn bar() void {
2015 \\ var f: ?extern fn () void = foo;
2016 \\ var b: ?extern fn () c_int = baz;
2017 \\ f.?();
2018 \\ f.?();
2019 \\ foo();
2020 \\ _ = b.?();
2021 \\ _ = b.?();
2022 \\ _ = baz();
2023 \\}
2024 });
2025
2026 cases.addC("normal deref",
2027 \\void foo(int *x) {
2028 \\ *x = 1;
2029 \\}
2030 , &[_][]const u8{
2031 \\pub export fn foo(x: [*c]c_int) void {
2032 \\ x.?.* = 1;
2033 \\}
2034 });
2035
2036 cases.add("address of operator",
2037 \\int foo(void) {
2038 \\ int x = 1234;
2039 \\ int *ptr = &x;
2040 \\ return *ptr;
2041 \\}
2042 , &[_][]const u8{
2043 \\pub fn foo() c_int {
2044 \\ var x: c_int = 1234;
2045 \\ var ptr: [*c]c_int = &x;
2046 \\ return ptr.?.*;
2047 \\}
2048 });
2049
2050 cases.add("bin not",
2051 \\int foo(int x) {
2052 \\ return ~x;
2053 \\}
2054 , &[_][]const u8{
2055 \\pub fn foo(x: c_int) c_int {
2056 \\ return ~x;
2057 \\}
2058 });
2059
2060 cases.add("bool not",
2061 \\int foo(int a, float b, void *c) {
2062 \\ return !(a == 0);
2063 \\ return !a;
2064 \\ return !b;
2065 \\ return !c;
2066 \\}
2067 , &[_][]const u8{
2068 \\pub fn foo(a: c_int, b: f32, c: ?*c_void) c_int {
2069 \\ return !(a == 0);
2070 \\ return !(a != 0);
2071 \\ return !(b != 0);
2072 \\ return !(c != null);
2073 \\}
2074 });
2075
2076 cases.add("primitive types included in defined symbols",
2077 \\int foo(int u32) {
2078 \\ return u32;
2079 \\}
2080 , &[_][]const u8{
2081 \\pub fn foo(u32_0: c_int) c_int {
2082 \\ return u32_0;
2083 \\}
2084 });
2085
2086 cases.addC("implicit casts",2072 cases.addC("implicit casts",
2087 \\#include <stdbool.h>2073 \\#include <stdbool.h>
2088 \\2074 \\
...@@ -2637,49 +2623,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2637,49 +2623,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2637 \\}2623 \\}
2638 });2624 });
26392625
2640 cases.addC("logical and, logical or, on non-bool values", // Note this gets cut off by extra C symbols being injected in middle: `pub const Foo = enum_Foo;`
2641 \\enum Foo {
2642 \\ FooA,
2643 \\ FooB,
2644 \\ FooC,
2645 \\};
2646 \\int and_or_non_bool(int a, float b, void *c) {
2647 \\ enum Foo d = FooA;
2648 \\ int e = (a && b);
2649 \\ int f = (b && c);
2650 \\ int g = (a && c);
2651 \\ int h = (a || b);
2652 \\ int i = (b || c);
2653 \\ int j = (a || c);
2654 \\ int k = (a || d);
2655 \\ int l = (d && b);
2656 \\ int m = (c || d);
2657 \\ return (((((((e + f) + g) + h) + i) + j) + k) + l) + m;
2658 \\}
2659 , &[_][]const u8{
2660 \\pub const FooA = enum_Foo.A;
2661 \\pub const FooB = enum_Foo.B;
2662 \\pub const FooC = enum_Foo.C;
2663 \\pub const enum_Foo = extern enum {
2664 \\ A,
2665 \\ B,
2666 \\ C,
2667 \\};
2668 \\pub export fn and_or_non_bool(a: c_int, b: f32, c: ?*c_void) c_int {
2669 \\ var d: enum_Foo = @as(enum_Foo, FooA);
2670 \\ var e: c_int = (a != 0) and (b != 0);
2671 \\ var f: c_int = (b != 0) and (c != null);
2672 \\ var g: c_int = (a != 0) and (c != null);
2673 \\ var h: c_int = (a != 0) or (b != 0);
2674 \\ var i: c_int = (b != 0) or (c != null);
2675 \\ var j: c_int = (a != 0) or (c != null);
2676 \\ var k: c_int = (a != 0) or (@as(c_uint, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0)));
2677 \\ var l: c_int = (@as(c_uint, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0))) and (b != 0);
2678 \\ var m: c_int = (c != null) or (@as(c_uint, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0)));
2679 \\ return (((((((e + f) + g) + h) + i) + j) + k) + l) + m;
2680 \\}
2681 });
2682
2683 cases.add("variable name shadowing",2626 cases.add("variable name shadowing",
2684 \\int foo(void) {2627 \\int foo(void) {
2685 \\ int x = 1;2628 \\ int x = 1;
...@@ -2726,4 +2669,80 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2726,4 +2669,80 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2726 \\ return 4;2669 \\ return 4;
2727 \\}2670 \\}
2728 });2671 });
2672
2673 cases.addAllowWarnings("simple data types",
2674 \\#include <stdint.h>
2675 \\int foo(char a, unsigned char b, signed char c);
2676 \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype
2677 \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d);
2678 \\void baz(int8_t a, int16_t b, int32_t c, int64_t d);
2679 , &[_][]const u8{
2680 \\pub extern fn foo(a: u8, b: u8, c: i8) c_int;
2681 ,
2682 \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void;
2683 ,
2684 \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void;
2685 });
2686
2687 cases.addC("simple function",
2688 \\int abs(int a) {
2689 \\ return a < 0 ? -a : a;
2690 \\}
2691 , &[_][]const u8{
2692 \\pub export fn abs(a: c_int) c_int {
2693 \\ return if (a < 0) -a else a;
2694 \\}
2695 });
2696
2697 cases.addC("post increment",
2698 \\unsigned foo1(unsigned a) {
2699 \\ a++;
2700 \\ return a;
2701 \\}
2702 \\int foo2(int a) {
2703 \\ a++;
2704 \\ return a;
2705 \\}
2706 , &[_][]const u8{
2707 \\pub export fn foo1(_arg_a: c_uint) c_uint {
2708 \\ var a = _arg_a;
2709 \\ a +%= 1;
2710 \\ return a;
2711 \\}
2712 \\pub export fn foo2(_arg_a: c_int) c_int {
2713 \\ var a = _arg_a;
2714 \\ a += 1;
2715 \\ return a;
2716 \\}
2717 });
2718
2719 cases.addC("deref function pointer",
2720 \\void foo(void) {}
2721 \\int baz(void) { return 0; }
2722 \\void bar(void) {
2723 \\ void(*f)(void) = foo;
2724 \\ int(*b)(void) = baz;
2725 \\ f();
2726 \\ (*(f))();
2727 \\ foo();
2728 \\ b();
2729 \\ (*(b))();
2730 \\ baz();
2731 \\}
2732 , &[_][]const u8{
2733 \\pub export fn foo() void {}
2734 \\pub export fn baz() c_int {
2735 \\ return 0;
2736 \\}
2737 \\pub export fn bar() void {
2738 \\ var f: ?extern fn () void = foo;
2739 \\ var b: ?extern fn () c_int = baz;
2740 \\ f.?();
2741 \\ f.?();
2742 \\ foo();
2743 \\ _ = b.?();
2744 \\ _ = b.?();
2745 \\ _ = baz();
2746 \\}
2747 });
2729}2748}