mirror of
https://github.com/ziglang/zig.git
synced 2026-01-21 14:55:25 +00:00
translate-c-2 unary operators common case
This commit is contained in:
parent
e4c47e80b4
commit
809deb6ec0
@ -1116,3 +1116,7 @@ pub extern fn ZigClangCallExpr_getArgs(*const ZigClangCallExpr) [*]const *const
|
||||
pub extern fn ZigClangUnaryExprOrTypeTraitExpr_getTypeOfArgument(*const ZigClangUnaryExprOrTypeTraitExpr) ZigClangQualType;
|
||||
pub extern fn ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(*const ZigClangUnaryExprOrTypeTraitExpr) ZigClangSourceLocation;
|
||||
|
||||
pub extern fn ZigClangUnaryOperator_getOpcode(*const ZigClangUnaryOperator) ZigClangUO;
|
||||
pub extern fn ZigClangUnaryOperator_getType(*const ZigClangUnaryOperator) ZigClangQualType;
|
||||
pub extern fn ZigClangUnaryOperator_getSubExpr(*const ZigClangUnaryOperator) *const ZigClangExpr;
|
||||
pub extern fn ZigClangUnaryOperator_getBeginLoc(*const ZigClangUnaryOperator) ZigClangSourceLocation;
|
||||
|
||||
@ -897,6 +897,7 @@ fn transStmt(
|
||||
.ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const ZigClangArraySubscriptExpr, stmt), result_used),
|
||||
.CallExprClass => return transCallExpr(rp, scope, @ptrCast(*const ZigClangCallExpr, stmt), result_used),
|
||||
.UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(rp, scope, @ptrCast(*const ZigClangUnaryExprOrTypeTraitExpr, stmt), result_used),
|
||||
.UnaryOperatorClass => return transUnaryOperator(rp, scope, @ptrCast(*const ZigClangUnaryOperator, stmt), result_used),
|
||||
else => {
|
||||
return revertAndWarn(
|
||||
rp,
|
||||
@ -2163,6 +2164,139 @@ fn transUnaryExprOrTypeTraitExpr(
|
||||
return maybeSuppressResult(rp, scope, result_used, &builtin_node.base);
|
||||
}
|
||||
|
||||
fn qualTypeHaswrappingOverflow(qt: ZigClangQualType) bool {
|
||||
if (cIsSignedInteger(qt) or cIsFloating(qt)) {
|
||||
// float and signed integer overflow is undefined behavior.
|
||||
return false;
|
||||
} else {
|
||||
// unsigned integer overflow wraps around.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnaryOperator, used: ResultUsed) TransError!*ast.Node {
|
||||
const op_expr = ZigClangUnaryOperator_getSubExpr(stmt);
|
||||
switch (ZigClangUnaryOperator_getOpcode(stmt)) {
|
||||
.PostInc => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
|
||||
return transCreatePostCrement(rp, scope, stmt, .AssignPlusWrap, .PlusPercentEqual, "+%=", used)
|
||||
else
|
||||
return transCreatePostCrement(rp, scope, stmt, .AssignPlus, .PlusEqual, "+=", used),
|
||||
.PostDec => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
|
||||
return transCreatePostCrement(rp, scope, stmt, .AssignMinusWrap, .MinusPercentEqual, "-%=", used)
|
||||
else
|
||||
return transCreatePostCrement(rp, scope, stmt, .AssignMinus, .MinusEqual, "-=", used),
|
||||
.PreInc => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
|
||||
return transCreatePreCrement(rp, scope, stmt, .AssignPlusWrap, .PlusPercentEqual, "+%=", used)
|
||||
else
|
||||
return transCreatePreCrement(rp, scope, stmt, .AssignPlus, .PlusEqual, "+=", used),
|
||||
.PreDec => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
|
||||
return transCreatePreCrement(rp, scope, stmt, .AssignMinusWrap, .MinusPercentEqual, "-%=", used)
|
||||
else
|
||||
return transCreatePreCrement(rp, scope, stmt, .AssignMinus, .MinusEqual, "-=", used),
|
||||
.AddrOf => {
|
||||
const op_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
|
||||
op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value);
|
||||
return &op_node.base;
|
||||
},
|
||||
.Deref => {
|
||||
const value_node = try transExpr(rp, scope, op_expr, used, .r_value);
|
||||
var is_ptr = false;
|
||||
const fn_ty = qualTypeGetFnProto(ZigClangExpr_getType(op_expr), &is_ptr);
|
||||
if (fn_ty != null and is_ptr)
|
||||
return value_node;
|
||||
const unwrapped = try transCreateNodeUnwrapNull(rp.c, value_node);
|
||||
return transCreateNodePtrDeref(rp.c, unwrapped);
|
||||
},
|
||||
.Plus => return transExpr(rp, scope, op_expr, used, .r_value),
|
||||
.Minus => {
|
||||
if (!qualTypeHaswrappingOverflow(ZigClangExpr_getType(op_expr))) {
|
||||
const op_node = try transCreateNodePrefixOp(rp.c, .Negation, .Minus, "-");
|
||||
op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
|
||||
return &op_node.base;
|
||||
} else if (cIsUnsignedInteger(ZigClangExpr_getType(op_expr))) {
|
||||
// we gotta emit 0 -% x
|
||||
const zero = try transCreateNodeInt(rp.c, 0);
|
||||
const token = try appendToken(rp.c, .MinusPercent, "-%");
|
||||
const expr = try transExpr(rp, scope, op_expr, .used, .r_value);
|
||||
return transCreateNodeInfixOp(rp, scope, zero, .SubWrap, token, expr, used, true);
|
||||
} else
|
||||
return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "C negation with non float non integer", .{});
|
||||
},
|
||||
.Not => {
|
||||
const op_node = try transCreateNodePrefixOp(rp.c, .BitNot, .Tilde, "~");
|
||||
op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
|
||||
return &op_node.base;
|
||||
},
|
||||
.LNot => {
|
||||
const op_node = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
|
||||
op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true);
|
||||
return &op_node.base;
|
||||
},
|
||||
else => return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "TODO handle C translation UO_Real", .{}),
|
||||
}
|
||||
}
|
||||
|
||||
fn transCreatePreCrement(
|
||||
rp: RestorePoint,
|
||||
scope: *Scope,
|
||||
stmt: *const ZigClangUnaryOperator,
|
||||
op: ast.Node.InfixOp.Op,
|
||||
op_tok_id: std.zig.Token.Id,
|
||||
bytes: []const u8,
|
||||
used: ResultUsed,
|
||||
) TransError!*ast.Node {
|
||||
const op_expr = ZigClangUnaryOperator_getSubExpr(stmt);
|
||||
|
||||
if (used == .unused) {
|
||||
// common case
|
||||
// c: ++expr
|
||||
// zig: expr += 1
|
||||
const expr = try transExpr(rp, scope, op_expr, .used, .r_value);
|
||||
const token = try appendToken(rp.c, op_tok_id, bytes);
|
||||
const one = try transCreateNodeInt(rp.c, 1);
|
||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||
return transCreateNodeInfixOp(rp, scope, expr, op, token, one, .used, false);
|
||||
}
|
||||
// worst case
|
||||
// c: ++expr
|
||||
// zig: (blk: {
|
||||
// zig: const _ref = &expr;
|
||||
// zig: *_ref += 1;
|
||||
// zig: break :blk *_ref
|
||||
// zig: })
|
||||
}
|
||||
|
||||
fn transCreatePostCrement(
|
||||
rp: RestorePoint,
|
||||
scope: *Scope,
|
||||
stmt: *const ZigClangUnaryOperator,
|
||||
op: ast.Node.InfixOp.Op,
|
||||
op_tok_id: std.zig.Token.Id,
|
||||
bytes: []const u8,
|
||||
used: ResultUsed,
|
||||
) TransError!*ast.Node {
|
||||
const op_expr = ZigClangUnaryOperator_getSubExpr(stmt);
|
||||
|
||||
if (used == .unused) {
|
||||
// common case
|
||||
// c: ++expr
|
||||
// zig: expr += 1
|
||||
const expr = try transExpr(rp, scope, op_expr, .used, .r_value);
|
||||
const token = try appendToken(rp.c, op_tok_id, bytes);
|
||||
const one = try transCreateNodeInt(rp.c, 1);
|
||||
_ = try appendToken(rp.c, .Semicolon, ";");
|
||||
return transCreateNodeInfixOp(rp, scope, expr, op, token, one, .used, false);
|
||||
}
|
||||
// worst case
|
||||
// c: expr++
|
||||
// zig: (blk: {
|
||||
// zig: const _ref = &expr;
|
||||
// zig: const _tmp = *_ref;
|
||||
// zig: *_ref += 1;
|
||||
// zig: break :blk _tmp
|
||||
// zig: })
|
||||
}
|
||||
|
||||
fn transCPtrCast(
|
||||
rp: RestorePoint,
|
||||
loc: ZigClangSourceLocation,
|
||||
@ -2507,6 +2641,23 @@ fn cIsUnsignedInteger(qt: ZigClangQualType) bool {
|
||||
};
|
||||
}
|
||||
|
||||
fn cIsSignedInteger(qt: ZigClangQualType) bool {
|
||||
const c_type = qualTypeCanon(qt);
|
||||
if (ZigClangType_getTypeClass(c_type) != .Builtin) return false;
|
||||
const builtin_ty = @ptrCast(*const ZigClangBuiltinType, c_type);
|
||||
return switch (ZigClangBuiltinType_getKind(builtin_ty)) {
|
||||
.SChar,
|
||||
.Short,
|
||||
.Int,
|
||||
.Long,
|
||||
.LongLong,
|
||||
.Int128,
|
||||
.WChar_S,
|
||||
=> true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
fn cIsFloating(qt: ZigClangQualType) bool {
|
||||
const c_type = qualTypeCanon(qt);
|
||||
if (ZigClangType_getTypeClass(c_type) != .Builtin) return false;
|
||||
|
||||
@ -769,6 +769,56 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.addC_both("normal deref",
|
||||
\\void foo(int *x) {
|
||||
\\ *x = 1;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo(x: [*c]c_int) void {
|
||||
\\ x.?.* = 1;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.addC_both("address of operator",
|
||||
\\int foo(void) {
|
||||
\\ int x = 1234;
|
||||
\\ int *ptr = &x;
|
||||
\\ return *ptr;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() c_int {
|
||||
\\ var x: c_int = 1234;
|
||||
\\ var ptr: [*c]c_int = &x;
|
||||
\\ return ptr.?.*;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.addC_both("bin not",
|
||||
\\int foo(int x) {
|
||||
\\ return ~x;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo(x: c_int) c_int {
|
||||
\\ return ~x;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.addC_both("bool not",
|
||||
\\int foo(int a, float b, void *c) {
|
||||
\\ return !(a == 0);
|
||||
\\ return !a;
|
||||
\\ return !b;
|
||||
\\ return !c;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo(a: c_int, b: f32, c: ?*c_void) c_int {
|
||||
\\ return !(a == 0);
|
||||
\\ return !(a != 0);
|
||||
\\ return !(b != 0);
|
||||
\\ return !(c != null);
|
||||
\\}
|
||||
});
|
||||
|
||||
/////////////// Cases that pass for only stage2 ////////////////
|
||||
|
||||
cases.add_2("Parameterless function prototypes",
|
||||
@ -1664,9 +1714,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
});
|
||||
|
||||
/////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
|
||||
|
||||
cases.addAllowWarnings("simple data types",
|
||||
cases.add_2("simple data types",
|
||||
\\#include <stdint.h>
|
||||
\\int foo(char a, unsigned char b, signed char c);
|
||||
\\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 {
|
||||
\\void baz(int8_t a, int16_t b, int32_t c, int64_t d);
|
||||
, &[_][]const u8{
|
||||
\\pub extern fn foo(a: u8, b: u8, c: i8) c_int;
|
||||
,
|
||||
\\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void;
|
||||
,
|
||||
\\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void;
|
||||
});
|
||||
|
||||
cases.addC("simple function",
|
||||
cases.add_2("simple function",
|
||||
\\int abs(int a) {
|
||||
\\ return a < 0 ? -a : a;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\export fn abs(a: c_int) c_int {
|
||||
\\ return if (a < 0) -a else a;
|
||||
\\pub export fn abs(a: c_int) c_int {
|
||||
\\ return if ((a < 0)) -a else a;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add_2("post increment",
|
||||
\\unsigned foo1(unsigned a) {
|
||||
\\ a++;
|
||||
\\ return a;
|
||||
\\}
|
||||
\\int foo2(int a) {
|
||||
\\ a++;
|
||||
\\ return a;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo1(a: c_uint) c_uint {
|
||||
\\ a +%= 1;
|
||||
\\ return a;
|
||||
\\}
|
||||
\\pub export fn foo2(a: c_int) c_int {
|
||||
\\ a += 1;
|
||||
\\ return a;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add_2("deref function pointer",
|
||||
\\void foo(void) {}
|
||||
\\int baz(void) { return 0; }
|
||||
\\void bar(void) {
|
||||
\\ void(*f)(void) = foo;
|
||||
\\ int(*b)(void) = baz;
|
||||
\\ f();
|
||||
\\ (*(f))();
|
||||
\\ foo();
|
||||
\\ b();
|
||||
\\ (*(b))();
|
||||
\\ baz();
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() void {}
|
||||
\\pub export fn baz() c_int {
|
||||
\\ return 0;
|
||||
\\}
|
||||
\\pub export fn bar() void {
|
||||
\\ var f: ?extern fn () void = foo;
|
||||
\\ var b: ?extern fn () c_int = baz;
|
||||
\\ f.?();
|
||||
\\ (f).?();
|
||||
\\ foo();
|
||||
\\ _ = b.?();
|
||||
\\ _ = (b).?();
|
||||
\\ _ = baz();
|
||||
\\}
|
||||
});
|
||||
|
||||
/////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
|
||||
|
||||
cases.add("macro defines string literal with hex",
|
||||
\\#define FOO "aoeu\xab derp"
|
||||
\\#define FOO2 "aoeu\x0007a derp"
|
||||
@ -1714,28 +1812,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\pub const FOO_CHAR = 63;
|
||||
});
|
||||
|
||||
cases.addC("post increment",
|
||||
\\unsigned foo1(unsigned a) {
|
||||
\\ a++;
|
||||
\\ return a;
|
||||
\\}
|
||||
\\int foo2(int a) {
|
||||
\\ a++;
|
||||
\\ return a;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo1(_arg_a: c_uint) c_uint {
|
||||
\\ var a = _arg_a;
|
||||
\\ a +%= 1;
|
||||
\\ return a;
|
||||
\\}
|
||||
\\pub export fn foo2(_arg_a: c_int) c_int {
|
||||
\\ var a = _arg_a;
|
||||
\\ a += 1;
|
||||
\\ return a;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.addC("shift right assign",
|
||||
\\int log2(unsigned a) {
|
||||
\\ int i = 0;
|
||||
@ -1993,96 +2069,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.addC("deref function pointer",
|
||||
\\void foo(void) {}
|
||||
\\int baz(void) { return 0; }
|
||||
\\void bar(void) {
|
||||
\\ void(*f)(void) = foo;
|
||||
\\ int(*b)(void) = baz;
|
||||
\\ f();
|
||||
\\ (*(f))();
|
||||
\\ foo();
|
||||
\\ b();
|
||||
\\ (*(b))();
|
||||
\\ baz();
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() void {}
|
||||
\\pub export fn baz() c_int {
|
||||
\\ return 0;
|
||||
\\}
|
||||
\\pub export fn bar() void {
|
||||
\\ var f: ?extern fn () void = foo;
|
||||
\\ var b: ?extern fn () c_int = baz;
|
||||
\\ f.?();
|
||||
\\ f.?();
|
||||
\\ foo();
|
||||
\\ _ = b.?();
|
||||
\\ _ = b.?();
|
||||
\\ _ = baz();
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.addC("normal deref",
|
||||
\\void foo(int *x) {
|
||||
\\ *x = 1;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo(x: [*c]c_int) void {
|
||||
\\ x.?.* = 1;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("address of operator",
|
||||
\\int foo(void) {
|
||||
\\ int x = 1234;
|
||||
\\ int *ptr = &x;
|
||||
\\ return *ptr;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub fn foo() c_int {
|
||||
\\ var x: c_int = 1234;
|
||||
\\ var ptr: [*c]c_int = &x;
|
||||
\\ return ptr.?.*;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("bin not",
|
||||
\\int foo(int x) {
|
||||
\\ return ~x;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub fn foo(x: c_int) c_int {
|
||||
\\ return ~x;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("bool not",
|
||||
\\int foo(int a, float b, void *c) {
|
||||
\\ return !(a == 0);
|
||||
\\ return !a;
|
||||
\\ return !b;
|
||||
\\ return !c;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub fn foo(a: c_int, b: f32, c: ?*c_void) c_int {
|
||||
\\ return !(a == 0);
|
||||
\\ return !(a != 0);
|
||||
\\ return !(b != 0);
|
||||
\\ return !(c != null);
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("primitive types included in defined symbols",
|
||||
\\int foo(int u32) {
|
||||
\\ return u32;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub fn foo(u32_0: c_int) c_int {
|
||||
\\ return u32_0;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.addC("implicit casts",
|
||||
\\#include <stdbool.h>
|
||||
\\
|
||||
@ -2637,49 +2623,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
});
|
||||
|
||||
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;`
|
||||
\\enum Foo {
|
||||
\\ FooA,
|
||||
\\ FooB,
|
||||
\\ FooC,
|
||||
\\};
|
||||
\\int and_or_non_bool(int a, float b, void *c) {
|
||||
\\ enum Foo d = FooA;
|
||||
\\ int e = (a && b);
|
||||
\\ int f = (b && c);
|
||||
\\ int g = (a && c);
|
||||
\\ int h = (a || b);
|
||||
\\ int i = (b || c);
|
||||
\\ int j = (a || c);
|
||||
\\ int k = (a || d);
|
||||
\\ int l = (d && b);
|
||||
\\ int m = (c || d);
|
||||
\\ return (((((((e + f) + g) + h) + i) + j) + k) + l) + m;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub const FooA = enum_Foo.A;
|
||||
\\pub const FooB = enum_Foo.B;
|
||||
\\pub const FooC = enum_Foo.C;
|
||||
\\pub const enum_Foo = extern enum {
|
||||
\\ A,
|
||||
\\ B,
|
||||
\\ C,
|
||||
\\};
|
||||
\\pub export fn and_or_non_bool(a: c_int, b: f32, c: ?*c_void) c_int {
|
||||
\\ var d: enum_Foo = @as(enum_Foo, FooA);
|
||||
\\ var e: c_int = (a != 0) and (b != 0);
|
||||
\\ var f: c_int = (b != 0) and (c != null);
|
||||
\\ var g: c_int = (a != 0) and (c != null);
|
||||
\\ var h: c_int = (a != 0) or (b != 0);
|
||||
\\ var i: c_int = (b != 0) or (c != null);
|
||||
\\ var j: c_int = (a != 0) or (c != null);
|
||||
\\ var k: c_int = (a != 0) or (@as(c_uint, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0)));
|
||||
\\ var l: c_int = (@as(c_uint, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0))) and (b != 0);
|
||||
\\ var m: c_int = (c != null) or (@as(c_uint, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0)));
|
||||
\\ return (((((((e + f) + g) + h) + i) + j) + k) + l) + m;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("variable name shadowing",
|
||||
\\int foo(void) {
|
||||
\\ int x = 1;
|
||||
@ -2726,4 +2669,80 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ return 4;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.addAllowWarnings("simple data types",
|
||||
\\#include <stdint.h>
|
||||
\\int foo(char a, unsigned char b, signed char c);
|
||||
\\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype
|
||||
\\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d);
|
||||
\\void baz(int8_t a, int16_t b, int32_t c, int64_t d);
|
||||
, &[_][]const u8{
|
||||
\\pub extern fn foo(a: u8, b: u8, c: i8) c_int;
|
||||
,
|
||||
\\pub extern fn bar(a: u8, b: u16, c: u32, d: u64) void;
|
||||
,
|
||||
\\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void;
|
||||
});
|
||||
|
||||
cases.addC("simple function",
|
||||
\\int abs(int a) {
|
||||
\\ return a < 0 ? -a : a;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn abs(a: c_int) c_int {
|
||||
\\ return if (a < 0) -a else a;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.addC("post increment",
|
||||
\\unsigned foo1(unsigned a) {
|
||||
\\ a++;
|
||||
\\ return a;
|
||||
\\}
|
||||
\\int foo2(int a) {
|
||||
\\ a++;
|
||||
\\ return a;
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo1(_arg_a: c_uint) c_uint {
|
||||
\\ var a = _arg_a;
|
||||
\\ a +%= 1;
|
||||
\\ return a;
|
||||
\\}
|
||||
\\pub export fn foo2(_arg_a: c_int) c_int {
|
||||
\\ var a = _arg_a;
|
||||
\\ a += 1;
|
||||
\\ return a;
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.addC("deref function pointer",
|
||||
\\void foo(void) {}
|
||||
\\int baz(void) { return 0; }
|
||||
\\void bar(void) {
|
||||
\\ void(*f)(void) = foo;
|
||||
\\ int(*b)(void) = baz;
|
||||
\\ f();
|
||||
\\ (*(f))();
|
||||
\\ foo();
|
||||
\\ b();
|
||||
\\ (*(b))();
|
||||
\\ baz();
|
||||
\\}
|
||||
, &[_][]const u8{
|
||||
\\pub export fn foo() void {}
|
||||
\\pub export fn baz() c_int {
|
||||
\\ return 0;
|
||||
\\}
|
||||
\\pub export fn bar() void {
|
||||
\\ var f: ?extern fn () void = foo;
|
||||
\\ var b: ?extern fn () c_int = baz;
|
||||
\\ f.?();
|
||||
\\ f.?();
|
||||
\\ foo();
|
||||
\\ _ = b.?();
|
||||
\\ _ = b.?();
|
||||
\\ _ = baz();
|
||||
\\}
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user