authorgravatar for kavika@gmail.comMerlyn Morgan-Graham <kavika@gmail.com> 2019-12-16 01:33:27-08:00
committergravatar for kavika@gmail.comMerlyn Morgan-Graham <kavika@gmail.com> 2019-12-16 01:34:05-08:00
log89ef635b354062bebbe126e2be2f6e4540dc0db7
treebde3f956efb826d0984f020f46185b7964ba19fb
parentacff2d407b45519cc6dc24639dfe1289c899addd

Add boolean and, boolean or binary ops in translate-c-2


3 files changed, 505 insertions(+), 33 deletions(-)

src-self-hosted/clang.zig+10
......@@ -967,6 +967,16 @@ pub extern fn ZigClangDeclRefExpr_getDecl(*const ZigClangDeclRefExpr) *const Zig
967967pub extern fn ZigClangParenType_getInnerType(*const ZigClangParenType) ZigClangQualType;
968968
969969pub extern fn ZigClangElaboratedType_getNamedType(*const ZigClangElaboratedType) ZigClangQualType;
970pub extern fn ZigClangElaboratedType_getKeyword(*const ZigClangElaboratedType) ZigClangElaboratedTypeKeyword;
971pub const ZigClangElaboratedTypeKeyword = extern enum {
972 Struct,
973 Interface,
974 Union,
975 Class,
976 Enum,
977 Typename,
978 None,
979};
970980
971981pub extern fn ZigClangAttributedType_getEquivalentType(*const ZigClangAttributedType) ZigClangQualType;
972982
src-self-hosted/translate_c.zig+403-14
......@@ -592,14 +592,14 @@ fn transCreateNodeShiftOp(
592592 const rhs_location = ZigClangExpr_getBeginLoc(rhs_expr);
593593 // lhs >> u5(rh)
594594
595 const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value);
595 const lhs = try transExpr(rp, scope, lhs_expr, .used, .r_value);
596596 const op_token = try appendToken(rp.c, op_tok_id, bytes);
597597
598598 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
599599 const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location);
600600 try as_node.params.push(rhs_type);
601601 _ = try appendToken(rp.c, .Comma, ",");
602 const rhs = try transExpr(rp, scope, rhs_expr, .used, .l_value);
602 const rhs = try transExpr(rp, scope, rhs_expr, .used, .r_value);
603603 try as_node.params.push(rhs.node);
604604 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
605605
......@@ -672,7 +672,7 @@ fn transBinaryOperator(
672672 if (!cIsUnsignedInteger(qt)) {
673673 // signed integer division uses @divTrunc
674674 const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc");
675 const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
675 const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .r_value);
676676 try div_trunc_node.params.push(lhs.node);
677677 _ = try appendToken(rp.c, .Comma, ",");
678678 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
......@@ -697,7 +697,7 @@ fn transBinaryOperator(
697697 if (!cIsUnsignedInteger(qt)) {
698698 // signed integer division uses @rem
699699 const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem");
700 const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
700 const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .r_value);
701701 try rem_node.params.push(lhs.node);
702702 _ = try appendToken(rp.c, .Comma, ",");
703703 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
......@@ -806,10 +806,23 @@ fn transBinaryOperator(
806806 .node_scope = scope,
807807 });
808808 },
809 .LAnd,
810 .LOr,
811 .Comma,
812 => return revertAndWarn(
809 .LAnd => {
810 const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolAnd, .Keyword_and, "and");
811 return maybeSuppressResult(rp, scope, result_used, TransResult{
812 .node = node,
813 .child_scope = scope,
814 .node_scope = scope,
815 });
816 },
817 .LOr => {
818 const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolOr, .Keyword_or, "or");
819 return maybeSuppressResult(rp, scope, result_used, TransResult{
820 .node = node,
821 .child_scope = scope,
822 .node_scope = scope,
823 });
824 },
825 .Comma => return revertAndWarn(
813826 rp,
814827 error.UnsupportedTranslation,
815828 ZigClangBinaryOperator_getBeginLoc(stmt),
......@@ -1040,6 +1053,321 @@ fn transImplicitCastExpr(
10401053 }
10411054}
10421055
1056fn toEnumZeroCmp(
1057 rp: RestorePoint,
1058 scope: *Scope,
1059 expr: *ast.Node,
1060 generate_enum_node: fn (RestorePoint, *const struct_ZigClangType, source_loc: ZigClangSourceLocation) TransError!*ast.Node,
1061 enum_ty: *const struct_ZigClangType,
1062 enum_source_loc: ZigClangSourceLocation,
1063) !*ast.Node {
1064 // expr != @bitCast(EnumType, @as(@TagType(EnumType), 0))
1065
1066 // @bitCast(Enum,
1067 const bitcast = try transCreateNodeBuiltinFnCall(rp.c, "@bitCast");
1068 const bitcast_enum_identifier = try generate_enum_node(rp, enum_ty, enum_source_loc);
1069 try bitcast.params.push(bitcast_enum_identifier);
1070 _ = try appendToken(rp.c, .Comma, ",");
1071
1072 // @as(
1073 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
1074
1075 // @TagType(Enum),
1076 const tag_type = try transCreateNodeBuiltinFnCall(rp.c, "@TagType");
1077 const tag_type_enum_identifier = try generate_enum_node(rp, enum_ty, enum_source_loc);
1078 try tag_type.params.push(tag_type_enum_identifier);
1079 tag_type.rparen_token = try appendToken(rp.c, .RParen, ")");
1080 try cast_node.params.push(&tag_type.base);
1081 _ = try appendToken(rp.c, .Comma, ",");
1082
1083 // 0)
1084 const zero = try transCreateNodeInt(rp.c, 0);
1085 try cast_node.params.push(zero);
1086 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1087
1088 try bitcast.params.push(&cast_node.base);
1089 bitcast.rparen_token = try appendToken(rp.c, .RParen, ")");
1090
1091 // expr != @bitCast(EnumType, @as(@TagType(EnumType), 0))
1092 return transCreateNodeNotEqual(rp, scope, expr, &bitcast.base);
1093}
1094
1095fn transBoolExpr(
1096 rp: RestorePoint,
1097 scope: *Scope,
1098 expr: *const ZigClangExpr,
1099 used: ResultUsed,
1100 lrvalue: LRValue,
1101) !*ast.Node {
1102 var res = try transExpr(rp, scope, expr, used, lrvalue);
1103
1104 switch (res.node.id) {
1105 .InfixOp => switch (@ptrCast(*const ast.Node.InfixOp, &res.node).op) {
1106 .BoolOr,
1107 .BoolAnd,
1108 .EqualEqual,
1109 .BangEqual,
1110 .LessThan,
1111 .GreaterThan,
1112 .LessOrEqual,
1113 .GreaterOrEqual,
1114 => return res.node,
1115
1116 else => {},
1117 },
1118
1119 .PrefixOp => switch (@ptrCast(*const ast.Node.PrefixOp, &res.node).op) {
1120 .BoolNot => return res.node,
1121
1122 else => {},
1123 },
1124
1125 .BoolLiteral => return res.node,
1126
1127 else => {},
1128 }
1129
1130 const ty = ZigClangQualType_getTypePtr(getExprQualTypeBeforeImplicitCast(rp.c, expr));
1131
1132 switch (ZigClangType_getTypeClass(ty)) {
1133 .Builtin => {
1134 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
1135
1136 switch (ZigClangBuiltinType_getKind(builtin_ty)) {
1137 .Bool,
1138 .Char_U,
1139 .UChar,
1140 .Char_S,
1141 .SChar,
1142 .UShort,
1143 .UInt,
1144 .ULong,
1145 .ULongLong,
1146 .Short,
1147 .Int,
1148 .Long,
1149 .LongLong,
1150 .UInt128,
1151 .Int128,
1152 .Float,
1153 .Double,
1154 .Float128,
1155 .LongDouble,
1156 .WChar_U,
1157 .Char8,
1158 .Char16,
1159 .Char32,
1160 .WChar_S,
1161 .Float16,
1162 => return transCreateNodeNotEqual(rp, scope, res.node, try transCreateNodeInt(rp.c, 0)),
1163
1164 .NullPtr => return transCreateNodeNotEqual(rp, scope, res.node, try transCreateNodeNullLiteral(rp.c)),
1165
1166 .Void,
1167 .Half,
1168 .ObjCId,
1169 .ObjCClass,
1170 .ObjCSel,
1171 .OMPArraySection,
1172 .Dependent,
1173 .Overload,
1174 .BoundMember,
1175 .PseudoObject,
1176 .UnknownAny,
1177 .BuiltinFn,
1178 .ARCUnbridgedCast,
1179 .OCLImage1dRO,
1180 .OCLImage1dArrayRO,
1181 .OCLImage1dBufferRO,
1182 .OCLImage2dRO,
1183 .OCLImage2dArrayRO,
1184 .OCLImage2dDepthRO,
1185 .OCLImage2dArrayDepthRO,
1186 .OCLImage2dMSAARO,
1187 .OCLImage2dArrayMSAARO,
1188 .OCLImage2dMSAADepthRO,
1189 .OCLImage2dArrayMSAADepthRO,
1190 .OCLImage3dRO,
1191 .OCLImage1dWO,
1192 .OCLImage1dArrayWO,
1193 .OCLImage1dBufferWO,
1194 .OCLImage2dWO,
1195 .OCLImage2dArrayWO,
1196 .OCLImage2dDepthWO,
1197 .OCLImage2dArrayDepthWO,
1198 .OCLImage2dMSAAWO,
1199 .OCLImage2dArrayMSAAWO,
1200 .OCLImage2dMSAADepthWO,
1201 .OCLImage2dArrayMSAADepthWO,
1202 .OCLImage3dWO,
1203 .OCLImage1dRW,
1204 .OCLImage1dArrayRW,
1205 .OCLImage1dBufferRW,
1206 .OCLImage2dRW,
1207 .OCLImage2dArrayRW,
1208 .OCLImage2dDepthRW,
1209 .OCLImage2dArrayDepthRW,
1210 .OCLImage2dMSAARW,
1211 .OCLImage2dArrayMSAARW,
1212 .OCLImage2dMSAADepthRW,
1213 .OCLImage2dArrayMSAADepthRW,
1214 .OCLImage3dRW,
1215 .OCLSampler,
1216 .OCLEvent,
1217 .OCLClkEvent,
1218 .OCLQueue,
1219 .OCLReserveID,
1220 .ShortAccum,
1221 .Accum,
1222 .LongAccum,
1223 .UShortAccum,
1224 .UAccum,
1225 .ULongAccum,
1226 .ShortFract,
1227 .Fract,
1228 .LongFract,
1229 .UShortFract,
1230 .UFract,
1231 .ULongFract,
1232 .SatShortAccum,
1233 .SatAccum,
1234 .SatLongAccum,
1235 .SatUShortAccum,
1236 .SatUAccum,
1237 .SatULongAccum,
1238 .SatShortFract,
1239 .SatFract,
1240 .SatLongFract,
1241 .SatUShortFract,
1242 .SatUFract,
1243 .SatULongFract,
1244 .OCLIntelSubgroupAVCMcePayload,
1245 .OCLIntelSubgroupAVCImePayload,
1246 .OCLIntelSubgroupAVCRefPayload,
1247 .OCLIntelSubgroupAVCSicPayload,
1248 .OCLIntelSubgroupAVCMceResult,
1249 .OCLIntelSubgroupAVCImeResult,
1250 .OCLIntelSubgroupAVCRefResult,
1251 .OCLIntelSubgroupAVCSicResult,
1252 .OCLIntelSubgroupAVCImeResultSingleRefStreamout,
1253 .OCLIntelSubgroupAVCImeResultDualRefStreamout,
1254 .OCLIntelSubgroupAVCImeSingleRefStreamin,
1255 .OCLIntelSubgroupAVCImeDualRefStreamin,
1256 => return res.node,
1257 }
1258 },
1259 .Pointer => return transCreateNodeNotEqual(rp, scope, res.node, try transCreateNodeNullLiteral(rp.c)),
1260
1261 .Typedef => {
1262 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?
1263
1264 // 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
1265 // const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);
1266 // const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
1267 // const typedef_name_decl = ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl);
1268
1269 // const typedef_name = if (rp.c.decl_table.get(@ptrToInt(typedef_name_decl))) |existing_entry|
1270 // existing_entry.value
1271 // else
1272 // try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_name_decl)));
1273
1274 // return transCreateNodeIdentifier(rp.c, typedef_name);
1275 },
1276
1277 .Enum => {
1278 const gen_enum_decl_node = struct {
1279 // Have to use a callback because node must be generated inline in order to avoid weird AST printing behavior,
1280 // and the code to generate the nodes is a little different for each case
1281 fn generate_node(inner_rp: RestorePoint, enum_ty: *const struct_ZigClangType, source_loc: ZigClangSourceLocation) TransError!*ast.Node {
1282 const actual_enum_ty = @ptrCast(*const ZigClangEnumType, enum_ty);
1283 const enum_decl = ZigClangEnumType_getDecl(actual_enum_ty);
1284 const enum_type = (try transEnumDecl(inner_rp.c, enum_decl)) orelse {
1285 return revertAndWarn(inner_rp, error.UnsupportedType, source_loc, "unable to translate enum declaration", .{});
1286 };
1287 return enum_type;
1288 }
1289 };
1290
1291 return toEnumZeroCmp(rp, scope, res.node, gen_enum_decl_node.generate_node, ty, ZigClangExpr_getBeginLoc(expr));
1292 },
1293
1294 .Elaborated => {
1295 const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty);
1296
1297 switch (ZigClangElaboratedType_getKeyword(elaborated_ty)) {
1298 .Enum => {
1299 // Have to use a callback because node must be generated inline in order to avoid weird AST printing behavior,
1300 // and the code to generate the nodes is a little different for each case
1301 const gen_enum_type_node = struct {
1302 fn generate_node(inner_rp: RestorePoint, enum_ty: *const struct_ZigClangType, source_loc: ZigClangSourceLocation) TransError!*ast.Node {
1303 const inner_elaborated_ty = @ptrCast(*const ZigClangElaboratedType, enum_ty);
1304 const enum_type = try transQualType(inner_rp, ZigClangElaboratedType_getNamedType(inner_elaborated_ty), source_loc);
1305 return enum_type;
1306 }
1307 };
1308
1309 return toEnumZeroCmp(rp, scope, res.node, gen_enum_type_node.generate_node, ty, ZigClangExpr_getBeginLoc(expr));
1310 },
1311
1312 .Struct,
1313 .Union,
1314 .Interface,
1315 .Class,
1316 .Typename,
1317 .None,
1318 => return res.node,
1319 }
1320 },
1321
1322 .FunctionProto,
1323 .Record,
1324 .ConstantArray,
1325 .Paren,
1326 .Decayed,
1327 .Attributed,
1328 .IncompleteArray,
1329 .BlockPointer,
1330 .LValueReference,
1331 .RValueReference,
1332 .MemberPointer,
1333 .VariableArray,
1334 .DependentSizedArray,
1335 .DependentSizedExtVector,
1336 .Vector,
1337 .ExtVector,
1338 .FunctionNoProto,
1339 .UnresolvedUsing,
1340 .Adjusted,
1341 .TypeOfExpr,
1342 .TypeOf,
1343 .Decltype,
1344 .UnaryTransform,
1345 .TemplateTypeParm,
1346 .SubstTemplateTypeParm,
1347 .SubstTemplateTypeParmPack,
1348 .TemplateSpecialization,
1349 .Auto,
1350 .InjectedClassName,
1351 .DependentName,
1352 .DependentTemplateSpecialization,
1353 .PackExpansion,
1354 .ObjCObject,
1355 .ObjCInterface,
1356 .Complex,
1357 .ObjCObjectPointer,
1358 .Atomic,
1359 .Pipe,
1360 .ObjCTypeParam,
1361 .DeducedTemplateSpecialization,
1362 .DependentAddressSpace,
1363 .DependentVector,
1364 .MacroQualified,
1365 => return res.node,
1366 }
1367
1368 unreachable;
1369}
1370
10431371fn transIntegerLiteral(
10441372 rp: RestorePoint,
10451373 scope: *Scope,
......@@ -1848,6 +2176,14 @@ fn getExprQualType(c: *Context, expr: *const ZigClangExpr) ZigClangQualType {
18482176 return ZigClangExpr_getType(expr);
18492177}
18502178
2179fn getExprQualTypeBeforeImplicitCast(c: *Context, expr: *const ZigClangExpr) ZigClangQualType {
2180 if (ZigClangExpr_getStmtClass(expr) == .ImplicitCastExprClass) {
2181 const cast_expr = @ptrCast(*const ZigClangImplicitCastExpr, expr);
2182 return getExprQualType(c, ZigClangImplicitCastExpr_getSubExpr(cast_expr));
2183 }
2184 return ZigClangExpr_getType(expr);
2185}
2186
18512187fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocation) bool {
18522188 switch (ZigClangType_getTypeClass(ty)) {
18532189 .Builtin => {
......@@ -2000,25 +2336,24 @@ fn transCreateNodePrefixOp(
20002336 return node;
20012337}
20022338
2003fn transCreateNodeInfixOp(
2339fn transCreateNodeInfixOpImpl(
20042340 rp: RestorePoint,
20052341 scope: *Scope,
2006 stmt: *const ZigClangBinaryOperator,
2342 lhs_node: *ast.Node,
2343 rhs_node: *ast.Node,
20072344 op: ast.Node.InfixOp.Op,
20082345 op_tok_id: std.zig.Token.Id,
20092346 bytes: []const u8,
20102347 grouped: bool,
20112348) !*ast.Node {
20122349 const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined;
2013 const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
20142350 const op_token = try appendToken(rp.c, op_tok_id, bytes);
2015 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
20162351 const node = try rp.c.a().create(ast.Node.InfixOp);
20172352 node.* = ast.Node.InfixOp{
20182353 .op_token = op_token,
2019 .lhs = lhs.node,
2354 .lhs = lhs_node,
20202355 .op = op,
2021 .rhs = rhs.node,
2356 .rhs = rhs_node,
20222357 };
20232358 if (!grouped) return &node.base;
20242359 const rparen = try appendToken(rp.c, .RParen, ")");
......@@ -2031,6 +2366,60 @@ fn transCreateNodeInfixOp(
20312366 return &grouped_expr.base;
20322367}
20332368
2369fn transCreateNodeInfixOp(
2370 rp: RestorePoint,
2371 scope: *Scope,
2372 stmt: *const ZigClangBinaryOperator,
2373 op: ast.Node.InfixOp.Op,
2374 op_tok_id: std.zig.Token.Id,
2375 bytes: []const u8,
2376 grouped: bool,
2377) !*ast.Node {
2378 return transCreateNodeInfixOpImpl(
2379 rp,
2380 scope,
2381 (try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .r_value)).node,
2382 (try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value)).node,
2383 op,
2384 op_tok_id,
2385 bytes,
2386 grouped,
2387 );
2388}
2389
2390fn transCreateNodeNotEqual(
2391 rp: RestorePoint,
2392 scope: *Scope,
2393 lhs_node: *ast.Node,
2394 rhs_node: *ast.Node,
2395) !*ast.Node {
2396 return transCreateNodeInfixOpImpl(rp, scope, lhs_node, rhs_node, .BangEqual, .BangEqual, "!=", true);
2397}
2398
2399fn transCreateNodeBoolInfixOp(
2400 rp: RestorePoint,
2401 scope: *Scope,
2402 stmt: *const ZigClangBinaryOperator,
2403 comptime op: ast.Node.InfixOp.Op,
2404 comptime op_tok_id: std.zig.Token.Id,
2405 comptime bytes: []const u8,
2406) !*ast.Node {
2407 if (!(op == .BoolAnd or op == .BoolOr)) {
2408 @compileError("op must be either .BoolAnd or .BoolOr");
2409 }
2410
2411 return transCreateNodeInfixOpImpl(
2412 rp,
2413 scope,
2414 try transBoolExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .r_value),
2415 try transBoolExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value),
2416 op,
2417 op_tok_id,
2418 bytes,
2419 true,
2420 );
2421}
2422
20342423fn transCreateNodePtrType(
20352424 c: *Context,
20362425 is_const: bool,
test/translate_c.zig+92-19
......@@ -949,26 +949,99 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
949949 \\}
950950 });
951951
952 cases.addC("logical and, logical or on none bool values",
953 \\int and_or_none_bool(int a, float b, void *c) {
954 \\ if (a && b) return 0;
955 \\ if (b && c) return 1;
956 \\ if (a && c) return 2;
957 \\ if (a || b) return 3;
958 \\ if (b || c) return 4;
959 \\ if (a || c) return 5;
960 \\ return 6;
961 \\}
962 , &[_][]const u8{
963 \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
964 \\ if ((a != 0) and (b != 0)) return 0;
965 \\ if ((b != 0) and (c != null)) return 1;
966 \\ if ((a != 0) and (c != null)) return 2;
967 \\ if ((a != 0) or (b != 0)) return 3;
968 \\ if ((b != 0) or (c != null)) return 4;
969 \\ if ((a != 0) or (c != null)) return 5;
970 \\ return 6;
952 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;`
953 \\enum Foo {
954 \\ FooA,
955 \\ FooB,
956 \\ FooC,
957 \\};
958 \\int and_or_non_bool(int a, float b, void *c) {
959 \\ enum Foo d = FooA;
960 \\ int e = (a && b);
961 \\ int f = (b && c);
962 \\ int g = (a && c);
963 \\ int h = (a || b);
964 \\ int i = (b || c);
965 \\ int j = (a || c);
966 \\ int k = (a || d);
967 \\ int l = (d && b);
968 \\ int m = (c || d);
969 \\ return (((((((e + f) + g) + h) + i) + j) + k) + l) + m;
971970 \\}
971 , &[_][]const u8{
972 \\pub const FooA = enum_Foo.A;
973 \\pub const FooB = enum_Foo.B;
974 \\pub const FooC = enum_Foo.C;
975 \\pub const enum_Foo = extern enum {
976 \\ A,
977 \\ B,
978 \\ C,
979 \\};
980 \\pub export fn and_or_non_bool(a: c_int, b: f32, c: ?*c_void) c_int {
981 \\ var d: enum_Foo = @as(enum_Foo, FooA);
982 \\ var e: c_int = (a != 0) and (b != 0);
983 \\ var f: c_int = (b != 0) and (c != null);
984 \\ var g: c_int = (a != 0) and (c != null);
985 \\ var h: c_int = (a != 0) or (b != 0);
986 \\ var i: c_int = (b != 0) or (c != null);
987 \\ var j: c_int = (a != 0) or (c != null);
988 \\ var k: c_int = (a != 0) or (@as(c_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0)));
989 \\ var l: c_int = (@as(c_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0))) and (b != 0);
990 \\ var m: c_int = (c != null) or (@as(c_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0)));
991 \\ return (((((((e + f) + g) + h) + i) + j) + k) + l) + m;
992 \\}
993 });
994
995 cases.add_2("logical and, logical or, on non-bool values, extra parens",
996 \\enum Foo {
997 \\ FooA,
998 \\ FooB,
999 \\ FooC,
1000 \\};
1001 \\typedef int SomeTypedef;
1002 \\int and_or_non_bool(int a, float b, void *c) {
1003 \\ enum Foo d = FooA;
1004 \\ int e = (a && b);
1005 \\ int f = (b && c);
1006 \\ int g = (a && c);
1007 \\ int h = (a || b);
1008 \\ int i = (b || c);
1009 \\ int j = (a || c);
1010 \\ int k = (a || d);
1011 \\ int l = (d && b);
1012 \\ int m = (c || d);
1013 \\ SomeTypedef td = 44;
1014 \\ int o = (td || b);
1015 \\ int p = (c && td);
1016 \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
1017 \\}
1018 , &[_][]const u8{
1019 \\pub const FooA = enum_Foo.A;
1020 \\pub const FooB = enum_Foo.B;
1021 \\pub const FooC = enum_Foo.C;
1022 \\pub const enum_Foo = extern enum {
1023 \\ A,
1024 \\ B,
1025 \\ C,
1026 \\};
1027 \\pub const SomeTypedef = c_int;
1028 \\pub export fn and_or_non_bool(a: c_int, b: f32, c: ?*c_void) c_int {
1029 \\ var d: enum_Foo = @as(enum_Foo, FooA);
1030 \\ var e: c_int = ((a != 0) and (b != 0));
1031 \\ var f: c_int = ((b != 0) and (c != null));
1032 \\ var g: c_int = ((a != 0) and (c != null));
1033 \\ var h: c_int = ((a != 0) or (b != 0));
1034 \\ var i: c_int = ((b != 0) or (c != null));
1035 \\ var j: c_int = ((a != 0) or (c != null));
1036 \\ var k: c_int = ((a != 0) or (@as(c_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0))));
1037 \\ var l: c_int = ((@as(c_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0))) and (b != 0));
1038 \\ var m: c_int = ((c != null) or (@as(c_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0))));
1039 \\ var td: SomeTypedef = 44;
1040 \\ var o: c_int = ((td != 0) or (b != 0));
1041 \\ var p: c_int = ((c != null) and (td != 0));
1042 \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
1043 \\}
1044 \\pub const Foo = enum_Foo;
9721045 });
9731046
9741047 cases.addC("assign",