Commit 89ef635b35
Changed files (3)
src-self-hosted
test
src-self-hosted/clang.zig
@@ -967,6 +967,16 @@ pub extern fn ZigClangDeclRefExpr_getDecl(*const ZigClangDeclRefExpr) *const Zig
pub extern fn ZigClangParenType_getInnerType(*const ZigClangParenType) ZigClangQualType;
pub extern fn ZigClangElaboratedType_getNamedType(*const ZigClangElaboratedType) ZigClangQualType;
+pub extern fn ZigClangElaboratedType_getKeyword(*const ZigClangElaboratedType) ZigClangElaboratedTypeKeyword;
+pub const ZigClangElaboratedTypeKeyword = extern enum {
+ Struct,
+ Interface,
+ Union,
+ Class,
+ Enum,
+ Typename,
+ None,
+};
pub extern fn ZigClangAttributedType_getEquivalentType(*const ZigClangAttributedType) ZigClangQualType;
src-self-hosted/translate_c.zig
@@ -592,14 +592,14 @@ fn transCreateNodeShiftOp(
const rhs_location = ZigClangExpr_getBeginLoc(rhs_expr);
// lhs >> u5(rh)
- const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value);
+ const lhs = try transExpr(rp, scope, lhs_expr, .used, .r_value);
const op_token = try appendToken(rp.c, op_tok_id, bytes);
const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location);
try as_node.params.push(rhs_type);
_ = try appendToken(rp.c, .Comma, ",");
- const rhs = try transExpr(rp, scope, rhs_expr, .used, .l_value);
+ const rhs = try transExpr(rp, scope, rhs_expr, .used, .r_value);
try as_node.params.push(rhs.node);
as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
@@ -672,7 +672,7 @@ fn transBinaryOperator(
if (!cIsUnsignedInteger(qt)) {
// signed integer division uses @divTrunc
const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc");
- const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
+ const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .r_value);
try div_trunc_node.params.push(lhs.node);
_ = try appendToken(rp.c, .Comma, ",");
const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
@@ -697,7 +697,7 @@ fn transBinaryOperator(
if (!cIsUnsignedInteger(qt)) {
// signed integer division uses @rem
const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem");
- const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
+ const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .r_value);
try rem_node.params.push(lhs.node);
_ = try appendToken(rp.c, .Comma, ",");
const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
@@ -806,10 +806,23 @@ fn transBinaryOperator(
.node_scope = scope,
});
},
- .LAnd,
- .LOr,
- .Comma,
- => return revertAndWarn(
+ .LAnd => {
+ const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolAnd, .Keyword_and, "and");
+ return maybeSuppressResult(rp, scope, result_used, TransResult{
+ .node = node,
+ .child_scope = scope,
+ .node_scope = scope,
+ });
+ },
+ .LOr => {
+ const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolOr, .Keyword_or, "or");
+ return maybeSuppressResult(rp, scope, result_used, TransResult{
+ .node = node,
+ .child_scope = scope,
+ .node_scope = scope,
+ });
+ },
+ .Comma => return revertAndWarn(
rp,
error.UnsupportedTranslation,
ZigClangBinaryOperator_getBeginLoc(stmt),
@@ -1040,6 +1053,321 @@ fn transImplicitCastExpr(
}
}
+fn toEnumZeroCmp(
+ rp: RestorePoint,
+ scope: *Scope,
+ expr: *ast.Node,
+ generate_enum_node: fn (RestorePoint, *const struct_ZigClangType, source_loc: ZigClangSourceLocation) TransError!*ast.Node,
+ enum_ty: *const struct_ZigClangType,
+ enum_source_loc: ZigClangSourceLocation,
+) !*ast.Node {
+ // expr != @bitCast(EnumType, @as(@TagType(EnumType), 0))
+
+ // @bitCast(Enum,
+ const bitcast = try transCreateNodeBuiltinFnCall(rp.c, "@bitCast");
+ const bitcast_enum_identifier = try generate_enum_node(rp, enum_ty, enum_source_loc);
+ try bitcast.params.push(bitcast_enum_identifier);
+ _ = try appendToken(rp.c, .Comma, ",");
+
+ // @as(
+ const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
+
+ // @TagType(Enum),
+ const tag_type = try transCreateNodeBuiltinFnCall(rp.c, "@TagType");
+ const tag_type_enum_identifier = try generate_enum_node(rp, enum_ty, enum_source_loc);
+ try tag_type.params.push(tag_type_enum_identifier);
+ tag_type.rparen_token = try appendToken(rp.c, .RParen, ")");
+ try cast_node.params.push(&tag_type.base);
+ _ = try appendToken(rp.c, .Comma, ",");
+
+ // 0)
+ const zero = try transCreateNodeInt(rp.c, 0);
+ try cast_node.params.push(zero);
+ cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
+
+ try bitcast.params.push(&cast_node.base);
+ bitcast.rparen_token = try appendToken(rp.c, .RParen, ")");
+
+ // expr != @bitCast(EnumType, @as(@TagType(EnumType), 0))
+ return transCreateNodeNotEqual(rp, scope, expr, &bitcast.base);
+}
+
+fn transBoolExpr(
+ rp: RestorePoint,
+ scope: *Scope,
+ expr: *const ZigClangExpr,
+ used: ResultUsed,
+ lrvalue: LRValue,
+) !*ast.Node {
+ var res = try transExpr(rp, scope, expr, used, lrvalue);
+
+ switch (res.node.id) {
+ .InfixOp => switch (@ptrCast(*const ast.Node.InfixOp, &res.node).op) {
+ .BoolOr,
+ .BoolAnd,
+ .EqualEqual,
+ .BangEqual,
+ .LessThan,
+ .GreaterThan,
+ .LessOrEqual,
+ .GreaterOrEqual,
+ => return res.node,
+
+ else => {},
+ },
+
+ .PrefixOp => switch (@ptrCast(*const ast.Node.PrefixOp, &res.node).op) {
+ .BoolNot => return res.node,
+
+ else => {},
+ },
+
+ .BoolLiteral => return res.node,
+
+ else => {},
+ }
+
+ const ty = ZigClangQualType_getTypePtr(getExprQualTypeBeforeImplicitCast(rp.c, expr));
+
+ switch (ZigClangType_getTypeClass(ty)) {
+ .Builtin => {
+ const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
+
+ switch (ZigClangBuiltinType_getKind(builtin_ty)) {
+ .Bool,
+ .Char_U,
+ .UChar,
+ .Char_S,
+ .SChar,
+ .UShort,
+ .UInt,
+ .ULong,
+ .ULongLong,
+ .Short,
+ .Int,
+ .Long,
+ .LongLong,
+ .UInt128,
+ .Int128,
+ .Float,
+ .Double,
+ .Float128,
+ .LongDouble,
+ .WChar_U,
+ .Char8,
+ .Char16,
+ .Char32,
+ .WChar_S,
+ .Float16,
+ => return transCreateNodeNotEqual(rp, scope, res.node, try transCreateNodeInt(rp.c, 0)),
+
+ .NullPtr => return transCreateNodeNotEqual(rp, scope, res.node, try transCreateNodeNullLiteral(rp.c)),
+
+ .Void,
+ .Half,
+ .ObjCId,
+ .ObjCClass,
+ .ObjCSel,
+ .OMPArraySection,
+ .Dependent,
+ .Overload,
+ .BoundMember,
+ .PseudoObject,
+ .UnknownAny,
+ .BuiltinFn,
+ .ARCUnbridgedCast,
+ .OCLImage1dRO,
+ .OCLImage1dArrayRO,
+ .OCLImage1dBufferRO,
+ .OCLImage2dRO,
+ .OCLImage2dArrayRO,
+ .OCLImage2dDepthRO,
+ .OCLImage2dArrayDepthRO,
+ .OCLImage2dMSAARO,
+ .OCLImage2dArrayMSAARO,
+ .OCLImage2dMSAADepthRO,
+ .OCLImage2dArrayMSAADepthRO,
+ .OCLImage3dRO,
+ .OCLImage1dWO,
+ .OCLImage1dArrayWO,
+ .OCLImage1dBufferWO,
+ .OCLImage2dWO,
+ .OCLImage2dArrayWO,
+ .OCLImage2dDepthWO,
+ .OCLImage2dArrayDepthWO,
+ .OCLImage2dMSAAWO,
+ .OCLImage2dArrayMSAAWO,
+ .OCLImage2dMSAADepthWO,
+ .OCLImage2dArrayMSAADepthWO,
+ .OCLImage3dWO,
+ .OCLImage1dRW,
+ .OCLImage1dArrayRW,
+ .OCLImage1dBufferRW,
+ .OCLImage2dRW,
+ .OCLImage2dArrayRW,
+ .OCLImage2dDepthRW,
+ .OCLImage2dArrayDepthRW,
+ .OCLImage2dMSAARW,
+ .OCLImage2dArrayMSAARW,
+ .OCLImage2dMSAADepthRW,
+ .OCLImage2dArrayMSAADepthRW,
+ .OCLImage3dRW,
+ .OCLSampler,
+ .OCLEvent,
+ .OCLClkEvent,
+ .OCLQueue,
+ .OCLReserveID,
+ .ShortAccum,
+ .Accum,
+ .LongAccum,
+ .UShortAccum,
+ .UAccum,
+ .ULongAccum,
+ .ShortFract,
+ .Fract,
+ .LongFract,
+ .UShortFract,
+ .UFract,
+ .ULongFract,
+ .SatShortAccum,
+ .SatAccum,
+ .SatLongAccum,
+ .SatUShortAccum,
+ .SatUAccum,
+ .SatULongAccum,
+ .SatShortFract,
+ .SatFract,
+ .SatLongFract,
+ .SatUShortFract,
+ .SatUFract,
+ .SatULongFract,
+ .OCLIntelSubgroupAVCMcePayload,
+ .OCLIntelSubgroupAVCImePayload,
+ .OCLIntelSubgroupAVCRefPayload,
+ .OCLIntelSubgroupAVCSicPayload,
+ .OCLIntelSubgroupAVCMceResult,
+ .OCLIntelSubgroupAVCImeResult,
+ .OCLIntelSubgroupAVCRefResult,
+ .OCLIntelSubgroupAVCSicResult,
+ .OCLIntelSubgroupAVCImeResultSingleRefStreamout,
+ .OCLIntelSubgroupAVCImeResultDualRefStreamout,
+ .OCLIntelSubgroupAVCImeSingleRefStreamin,
+ .OCLIntelSubgroupAVCImeDualRefStreamin,
+ => return res.node,
+ }
+ },
+ .Pointer => return transCreateNodeNotEqual(rp, scope, res.node, try transCreateNodeNullLiteral(rp.c)),
+
+ .Typedef => {
+ return transCreateNodeNotEqual(rp, scope, res.node, try transCreateNodeInt(rp.c, 0)); // TODO currently assuming it is like an int/char/bool builtin type. Coerce the type and recurse? Add a toTypedefZeroCmp function?
+
+ // TODO This is the code that was in translate-c, but it seems like it is giving wrong results! It just prints the typedef name instead of the value
+ // const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);
+ // const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
+ // const typedef_name_decl = ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl);
+
+ // const typedef_name = if (rp.c.decl_table.get(@ptrToInt(typedef_name_decl))) |existing_entry|
+ // existing_entry.value
+ // else
+ // try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_name_decl)));
+
+ // return transCreateNodeIdentifier(rp.c, typedef_name);
+ },
+
+ .Enum => {
+ const gen_enum_decl_node = struct {
+ // Have to use a callback because node must be generated inline in order to avoid weird AST printing behavior,
+ // and the code to generate the nodes is a little different for each case
+ fn generate_node(inner_rp: RestorePoint, enum_ty: *const struct_ZigClangType, source_loc: ZigClangSourceLocation) TransError!*ast.Node {
+ const actual_enum_ty = @ptrCast(*const ZigClangEnumType, enum_ty);
+ const enum_decl = ZigClangEnumType_getDecl(actual_enum_ty);
+ const enum_type = (try transEnumDecl(inner_rp.c, enum_decl)) orelse {
+ return revertAndWarn(inner_rp, error.UnsupportedType, source_loc, "unable to translate enum declaration", .{});
+ };
+ return enum_type;
+ }
+ };
+
+ return toEnumZeroCmp(rp, scope, res.node, gen_enum_decl_node.generate_node, ty, ZigClangExpr_getBeginLoc(expr));
+ },
+
+ .Elaborated => {
+ const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty);
+
+ switch (ZigClangElaboratedType_getKeyword(elaborated_ty)) {
+ .Enum => {
+ // Have to use a callback because node must be generated inline in order to avoid weird AST printing behavior,
+ // and the code to generate the nodes is a little different for each case
+ const gen_enum_type_node = struct {
+ fn generate_node(inner_rp: RestorePoint, enum_ty: *const struct_ZigClangType, source_loc: ZigClangSourceLocation) TransError!*ast.Node {
+ const inner_elaborated_ty = @ptrCast(*const ZigClangElaboratedType, enum_ty);
+ const enum_type = try transQualType(inner_rp, ZigClangElaboratedType_getNamedType(inner_elaborated_ty), source_loc);
+ return enum_type;
+ }
+ };
+
+ return toEnumZeroCmp(rp, scope, res.node, gen_enum_type_node.generate_node, ty, ZigClangExpr_getBeginLoc(expr));
+ },
+
+ .Struct,
+ .Union,
+ .Interface,
+ .Class,
+ .Typename,
+ .None,
+ => return res.node,
+ }
+ },
+
+ .FunctionProto,
+ .Record,
+ .ConstantArray,
+ .Paren,
+ .Decayed,
+ .Attributed,
+ .IncompleteArray,
+ .BlockPointer,
+ .LValueReference,
+ .RValueReference,
+ .MemberPointer,
+ .VariableArray,
+ .DependentSizedArray,
+ .DependentSizedExtVector,
+ .Vector,
+ .ExtVector,
+ .FunctionNoProto,
+ .UnresolvedUsing,
+ .Adjusted,
+ .TypeOfExpr,
+ .TypeOf,
+ .Decltype,
+ .UnaryTransform,
+ .TemplateTypeParm,
+ .SubstTemplateTypeParm,
+ .SubstTemplateTypeParmPack,
+ .TemplateSpecialization,
+ .Auto,
+ .InjectedClassName,
+ .DependentName,
+ .DependentTemplateSpecialization,
+ .PackExpansion,
+ .ObjCObject,
+ .ObjCInterface,
+ .Complex,
+ .ObjCObjectPointer,
+ .Atomic,
+ .Pipe,
+ .ObjCTypeParam,
+ .DeducedTemplateSpecialization,
+ .DependentAddressSpace,
+ .DependentVector,
+ .MacroQualified,
+ => return res.node,
+ }
+
+ unreachable;
+}
+
fn transIntegerLiteral(
rp: RestorePoint,
scope: *Scope,
@@ -1848,6 +2176,14 @@ fn getExprQualType(c: *Context, expr: *const ZigClangExpr) ZigClangQualType {
return ZigClangExpr_getType(expr);
}
+fn getExprQualTypeBeforeImplicitCast(c: *Context, expr: *const ZigClangExpr) ZigClangQualType {
+ if (ZigClangExpr_getStmtClass(expr) == .ImplicitCastExprClass) {
+ const cast_expr = @ptrCast(*const ZigClangImplicitCastExpr, expr);
+ return getExprQualType(c, ZigClangImplicitCastExpr_getSubExpr(cast_expr));
+ }
+ return ZigClangExpr_getType(expr);
+}
+
fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocation) bool {
switch (ZigClangType_getTypeClass(ty)) {
.Builtin => {
@@ -2000,25 +2336,24 @@ fn transCreateNodePrefixOp(
return node;
}
-fn transCreateNodeInfixOp(
+fn transCreateNodeInfixOpImpl(
rp: RestorePoint,
scope: *Scope,
- stmt: *const ZigClangBinaryOperator,
+ lhs_node: *ast.Node,
+ rhs_node: *ast.Node,
op: ast.Node.InfixOp.Op,
op_tok_id: std.zig.Token.Id,
bytes: []const u8,
grouped: bool,
) !*ast.Node {
const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined;
- const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
const op_token = try appendToken(rp.c, op_tok_id, bytes);
- const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
const node = try rp.c.a().create(ast.Node.InfixOp);
node.* = ast.Node.InfixOp{
.op_token = op_token,
- .lhs = lhs.node,
+ .lhs = lhs_node,
.op = op,
- .rhs = rhs.node,
+ .rhs = rhs_node,
};
if (!grouped) return &node.base;
const rparen = try appendToken(rp.c, .RParen, ")");
@@ -2031,6 +2366,60 @@ fn transCreateNodeInfixOp(
return &grouped_expr.base;
}
+fn transCreateNodeInfixOp(
+ rp: RestorePoint,
+ scope: *Scope,
+ stmt: *const ZigClangBinaryOperator,
+ op: ast.Node.InfixOp.Op,
+ op_tok_id: std.zig.Token.Id,
+ bytes: []const u8,
+ grouped: bool,
+) !*ast.Node {
+ return transCreateNodeInfixOpImpl(
+ rp,
+ scope,
+ (try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .r_value)).node,
+ (try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value)).node,
+ op,
+ op_tok_id,
+ bytes,
+ grouped,
+ );
+}
+
+fn transCreateNodeNotEqual(
+ rp: RestorePoint,
+ scope: *Scope,
+ lhs_node: *ast.Node,
+ rhs_node: *ast.Node,
+) !*ast.Node {
+ return transCreateNodeInfixOpImpl(rp, scope, lhs_node, rhs_node, .BangEqual, .BangEqual, "!=", true);
+}
+
+fn transCreateNodeBoolInfixOp(
+ rp: RestorePoint,
+ scope: *Scope,
+ stmt: *const ZigClangBinaryOperator,
+ comptime op: ast.Node.InfixOp.Op,
+ comptime op_tok_id: std.zig.Token.Id,
+ comptime bytes: []const u8,
+) !*ast.Node {
+ if (!(op == .BoolAnd or op == .BoolOr)) {
+ @compileError("op must be either .BoolAnd or .BoolOr");
+ }
+
+ return transCreateNodeInfixOpImpl(
+ rp,
+ scope,
+ try transBoolExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .r_value),
+ try transBoolExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value),
+ op,
+ op_tok_id,
+ bytes,
+ true,
+ );
+}
+
fn transCreateNodePtrType(
c: *Context,
is_const: bool,
test/translate_c.zig
@@ -949,26 +949,99 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
- cases.addC("logical and, logical or on none bool values",
- \\int and_or_none_bool(int a, float b, void *c) {
- \\ if (a && b) return 0;
- \\ if (b && c) return 1;
- \\ if (a && c) return 2;
- \\ if (a || b) return 3;
- \\ if (b || c) return 4;
- \\ if (a || c) return 5;
- \\ return 6;
- \\}
- , &[_][]const u8{
- \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
- \\ if ((a != 0) and (b != 0)) return 0;
- \\ if ((b != 0) and (c != null)) return 1;
- \\ if ((a != 0) and (c != null)) return 2;
- \\ if ((a != 0) or (b != 0)) return 3;
- \\ if ((b != 0) or (c != null)) return 4;
- \\ if ((a != 0) or (c != null)) return 5;
- \\ return 6;
+ 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_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0)));
+ \\ var l: c_int = (@as(c_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0))) and (b != 0);
+ \\ var m: c_int = (c != null) or (@as(c_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0)));
+ \\ return (((((((e + f) + g) + h) + i) + j) + k) + l) + m;
+ \\}
+ });
+
+ cases.add_2("logical and, logical or, on non-bool values, extra parens",
+ \\enum Foo {
+ \\ FooA,
+ \\ FooB,
+ \\ FooC,
+ \\};
+ \\typedef int SomeTypedef;
+ \\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);
+ \\ SomeTypedef td = 44;
+ \\ int o = (td || b);
+ \\ int p = (c && td);
+ \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
+ \\}
+ , &[_][]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 const SomeTypedef = c_int;
+ \\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_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0))));
+ \\ var l: c_int = ((@as(c_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0))) and (b != 0));
+ \\ var m: c_int = ((c != null) or (@as(c_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0))));
+ \\ var td: SomeTypedef = 44;
+ \\ var o: c_int = ((td != 0) or (b != 0));
+ \\ var p: c_int = ((c != null) and (td != 0));
+ \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
+ \\}
+ \\pub const Foo = enum_Foo;
});
cases.addC("assign",