Commit f54e7d6c99

Vexu <git@vexu.eu>
2019-12-18 11:47:35
translate-c-2 update @kavika13's work to removal of TransResult
1 parent 90eed41
Changed files (3)
src-self-hosted/clang.zig
@@ -741,6 +741,11 @@ pub const ZigClangPreprocessedEntity_EntityKind = extern enum {
     InclusionDirectiveKind,
 };
 
+pub const ZigClangExpr_ConstExprUsage = extern enum {
+    EvaluateForCodeGen,
+    EvaluateForMangling,
+};
+
 pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation;
 pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8;
 pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint;
src-self-hosted/translate_c.zig
@@ -184,9 +184,7 @@ const Scope = struct {
             .Ref => null,
             .FnDef => @fieldParentPtr(FnDef, "base", scope).getAlias(name),
             .Block => @fieldParentPtr(Block, "base", scope).getAlias(name),
-            .Switch,
-            .Loop,
-            .Condition => scope.parent.?.getAlias(name),
+            .Switch, .Loop, .Condition => scope.parent.?.getAlias(name),
         };
     }
 
@@ -196,9 +194,7 @@ const Scope = struct {
             .Root => @fieldParentPtr(Root, "base", scope).contains(name),
             .FnDef => @fieldParentPtr(FnDef, "base", scope).contains(name),
             .Block => @fieldParentPtr(Block, "base", scope).contains(name),
-            .Switch,
-            .Loop,
-            .Condition => scope.parent.?.contains(name),
+            .Switch, .Loop, .Condition => scope.parent.?.contains(name),
         };
     }
 
@@ -594,7 +590,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
     const node = try transCreateNodeVarDecl(c, true, true, name);
 
     node.eq_token = try appendToken(c, .Equal, "=");
-    
+
     var semicolon: ast.TokenIndex = undefined;
     node.init_node = blk: {
         const rp = makeRestorePoint(c);
@@ -634,12 +630,12 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
             const field_name = try appendIdentifier(c, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl))));
             _ = try appendToken(c, .Colon, ":");
             const field_type = transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc) catch |err| switch (err) {
-                    error.UnsupportedType => {
-                        try failDecl(c, record_loc, name, "unable to translate {} member type", .{container_kind_name});
-                        return null;
-                    },
-                    else => |e| return e,
-                };
+                error.UnsupportedType => {
+                    try failDecl(c, record_loc, name, "unable to translate {} member type", .{container_kind_name});
+                    return null;
+                },
+                else => |e| return e,
+            };
 
             const field_node = try c.a().create(ast.Node.ContainerField);
             field_node.* = .{
@@ -879,205 +875,166 @@ fn transBinaryOperator(
 ) TransError!*ast.Node {
     const op = ZigClangBinaryOperator_getOpcode(stmt);
     const qt = ZigClangBinaryOperator_getType(stmt);
+    var op_token: ast.TokenIndex = undefined;
+    var op_id: ast.Node.InfixOp.Op = undefined;
     switch (op) {
-        .PtrMemD, .PtrMemI, .Cmp => return revertAndWarn(
-            rp,
-            error.UnsupportedTranslation,
-            ZigClangBinaryOperator_getBeginLoc(stmt),
-            "TODO: handle more C binary operators: {}",
-            .{op},
-        ),
-        .Assign => return try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt)),
-        .Add => {
-            const node = if (cIsUnsignedInteger(qt))
-                try transCreateNodeInfixOp(rp, scope, stmt, .AddWrap, .PlusPercent, "+%", true)
-            else
-                try transCreateNodeInfixOp(rp, scope, stmt, .Add, .Plus, "+", true);
-            return maybeSuppressResult(rp, scope, result_used, node);
-        },
-        .Sub => {
-            const node = if (cIsUnsignedInteger(qt))
-                try transCreateNodeInfixOp(rp, scope, stmt, .SubWrap, .MinusPercent, "-%", true)
-            else
-                try transCreateNodeInfixOp(rp, scope, stmt, .Sub, .Minus, "-", true);
-            return maybeSuppressResult(rp, scope, result_used, node);
-        },
-        .Mul => {
-            const node = if (cIsUnsignedInteger(qt))
-                try transCreateNodeInfixOp(rp, scope, stmt, .MultWrap, .AsteriskPercent, "*%", true)
-            else
-                try transCreateNodeInfixOp(rp, scope, stmt, .Mult, .Asterisk, "*", true);
-            return maybeSuppressResult(rp, scope, result_used, node);
+        .Assign => return transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt)),
+        .Comma => {
+            const block_scope = try scope.findBlockScope(rp.c);
+            const expr = block_scope.base.parent == scope;
+            const lparen = if (expr) blk: {
+                const l = try appendToken(rp.c, .LParen, "(");
+                block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
+                break :blk l;
+            } else undefined;
+
+            const lhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getLHS(stmt), .unused, .r_value);
+            try block_scope.block_node.statements.push(lhs);
+
+            const rhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
+            if (expr) {
+                _ = try appendToken(rp.c, .Semicolon, ";");
+                const break_node = try transCreateNodeBreak(rp.c, block_scope.label);
+                break_node.rhs = rhs;
+                try block_scope.block_node.statements.push(&break_node.base);
+                block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
+                const rparen = try appendToken(rp.c, .RParen, ")");
+                const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
+                grouped_expr.* = .{
+                    .lparen = lparen,
+                    .expr = &block_scope.block_node.base,
+                    .rparen = rparen,
+                };
+                return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base);
+            } else {
+                return maybeSuppressResult(rp, scope, result_used, rhs);
+            }
         },
         .Div => {
             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);
-                try div_trunc_node.params.push(lhs);
+                try div_trunc_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
                 _ = try appendToken(rp.c, .Comma, ",");
                 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
                 try div_trunc_node.params.push(rhs);
                 div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");
                 return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base);
-            } else {
-                // unsigned/float division uses the operator
-                const node = try transCreateNodeInfixOp(rp, scope, stmt, .Div, .Slash, "/", true);
-                return maybeSuppressResult(rp, scope, result_used, node);
             }
         },
         .Rem => {
             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);
-                try rem_node.params.push(lhs);
+                try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value));
                 _ = try appendToken(rp.c, .Comma, ",");
                 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
                 try rem_node.params.push(rhs);
                 rem_node.rparen_token = try appendToken(rp.c, .RParen, ")");
                 return maybeSuppressResult(rp, scope, result_used, &rem_node.base);
-            } else {
-                // unsigned/float division uses the operator
-                const node = try transCreateNodeInfixOp(rp, scope, stmt, .Mod, .Percent, "%", true);
-                return maybeSuppressResult(rp, scope, result_used, node);
             }
         },
         .Shl => {
             const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<");
-            return maybeSuppressResult(rp, scope, result_used, TransResult{
-                .node = node,
-                .child_scope = scope,
-                .node_scope = scope,
-            });
+            return maybeSuppressResult(rp, scope, result_used, node);
         },
         .Shr => {
             const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftRight, .AngleBracketAngleBracketRight, ">>");
-            return maybeSuppressResult(rp, scope, result_used, TransResult{
-                .node = node,
-                .child_scope = scope,
-                .node_scope = scope,
-            });
+            return maybeSuppressResult(rp, scope, result_used, node);
+        },
+        .LAnd => {
+            const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolAnd, result_used, true);
+            return maybeSuppressResult(rp, scope, result_used, node);
+        },
+        .LOr => {
+            const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolOr, result_used, true);
+            return maybeSuppressResult(rp, scope, result_used, node);
+        },
+        else => {},
+    }
+    const lhs_node = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
+    switch (op) {
+        .PtrMemD, .PtrMemI, .Cmp => return revertAndWarn(
+            rp,
+            error.UnsupportedTranslation,
+            ZigClangBinaryOperator_getBeginLoc(stmt),
+            "TODO: handle more C binary operators: {}",
+            .{op},
+        ),
+        .Add => {
+            if (cIsUnsignedInteger(qt)) {
+                op_token = try appendToken(rp.c, .PlusPercent, "+%");
+                op_id = .AddWrap;
+            } else {
+                op_token = try appendToken(rp.c, .Plus, "+");
+                op_id = .Add;
+            }
+        },
+        .Sub => {
+            if (cIsUnsignedInteger(qt)) {
+                op_token = try appendToken(rp.c, .MinusPercent, "-%");
+                op_id = .SubWrap;
+            } else {
+                op_token = try appendToken(rp.c, .Minus, "-");
+                op_id = .Sub;
+            }
+        },
+        .Mul => {
+            if (cIsUnsignedInteger(qt)) {
+                op_token = try appendToken(rp.c, .AsteriskPercent, "*%");
+                op_id = .MultWrap;
+            } else {
+                op_token = try appendToken(rp.c, .Asterisk, "*");
+                op_id = .Mult;
+            }
+        },
+        .Div => {
+            // unsigned/float division uses the operator
+            op_id = .Div;
+            op_token = try appendToken(rp.c, .Slash, "/");
+        },
+        .Rem => {
+            // unsigned/float division uses the operator
+            op_id = .Mod;
+            op_token = try appendToken(rp.c, .Percent, "%");
         },
         .LT => {
-            const node = try transCreateNodeInfixOp(rp, scope, stmt, .LessThan, .AngleBracketLeft, "<", true);
-            return maybeSuppressResult(rp, scope, result_used, TransResult{
-                .node = node,
-                .child_scope = scope,
-                .node_scope = scope,
-            });
+            op_id = .LessThan;
+            op_token = try appendToken(rp.c, .AngleBracketLeft, "<");
         },
         .GT => {
-            const node = try transCreateNodeInfixOp(rp, scope, stmt, .GreaterThan, .AngleBracketRight, ">", true);
-            return maybeSuppressResult(rp, scope, result_used, TransResult{
-                .node = node,
-                .child_scope = scope,
-                .node_scope = scope,
-            });
+            op_id = .GreaterThan;
+            op_token = try appendToken(rp.c, .AngleBracketRight, ">");
         },
         .LE => {
-            const node = try transCreateNodeInfixOp(rp, scope, stmt, .LessOrEqual, .AngleBracketLeftEqual, "<=", true);
-            return maybeSuppressResult(rp, scope, result_used, TransResult{
-                .node = node,
-                .child_scope = scope,
-                .node_scope = scope,
-            });
+            op_id = .LessOrEqual;
+            op_token = try appendToken(rp.c, .AngleBracketLeftEqual, "<=");
         },
         .GE => {
-            const node = try transCreateNodeInfixOp(rp, scope, stmt, .GreaterOrEqual, .AngleBracketRightEqual, ">=", true);
-            return maybeSuppressResult(rp, scope, result_used, TransResult{
-                .node = node,
-                .child_scope = scope,
-                .node_scope = scope,
-            });
+            op_id = .GreaterOrEqual;
+            op_token = try appendToken(rp.c, .AngleBracketRightEqual, ">=");
         },
         .EQ => {
-            const node = try transCreateNodeInfixOp(rp, scope, stmt, .EqualEqual, .EqualEqual, "==", true);
-            return maybeSuppressResult(rp, scope, result_used, TransResult{
-                .node = node,
-                .child_scope = scope,
-                .node_scope = scope,
-            });
+            op_id = .EqualEqual;
+            op_token = try appendToken(rp.c, .EqualEqual, "==");
         },
         .NE => {
-            const node = try transCreateNodeInfixOp(rp, scope, stmt, .BangEqual, .BangEqual, "!=", true);
-            return maybeSuppressResult(rp, scope, result_used, TransResult{
-                .node = node,
-                .child_scope = scope,
-                .node_scope = scope,
-            });
+            op_id = .BangEqual;
+            op_token = try appendToken(rp.c, .BangEqual, "!=");
         },
         .And => {
-            const node = try transCreateNodeInfixOp(rp, scope, stmt, .BitAnd, .Ampersand, "&", true);
-            return maybeSuppressResult(rp, scope, result_used, TransResult{
-                .node = node,
-                .child_scope = scope,
-                .node_scope = scope,
-            });
+            op_id = .BitAnd;
+            op_token = try appendToken(rp.c, .Ampersand, "&");
         },
         .Xor => {
-            const node = try transCreateNodeInfixOp(rp, scope, stmt, .BitXor, .Caret, "^", true);
-            return maybeSuppressResult(rp, scope, result_used, TransResult{
-                .node = node,
-                .child_scope = scope,
-                .node_scope = scope,
-            });
+            op_id = .BitXor;
+            op_token = try appendToken(rp.c, .Caret, "^");
         },
         .Or => {
-            const node = try transCreateNodeInfixOp(rp, scope, stmt, .BitOr, .Pipe, "|", true);
-            return maybeSuppressResult(rp, scope, result_used, TransResult{
-                .node = node,
-                .child_scope = scope,
-                .node_scope = scope,
-            });
-        },
-        .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 => {
-            const block_scope = try scope.findBlockScope(rp.c);
-            const expr = block_scope.base.parent == scope;
-            const lparen = if (expr) blk: {
-                const l = try appendToken(rp.c, .LParen, "(");
-                block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
-                break :blk l;
-            } else undefined;
-
-            const lhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getLHS(stmt), .unused, .r_value);
-            try block_scope.block_node.statements.push(lhs);
-
-            const rhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
-            if (expr) {
-                _ = try appendToken(rp.c, .Semicolon, ";");
-                const break_node = try transCreateNodeBreak(rp.c, block_scope.label);
-                break_node.rhs = rhs;
-                try block_scope.block_node.statements.push(&break_node.base);
-                block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
-                const rparen = try appendToken(rp.c, .RParen, ")");
-                const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
-                grouped_expr.* = .{
-                    .lparen = lparen,
-                    .expr = &block_scope.block_node.base,
-                    .rparen = rparen,
-                };
-                return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base);
-            } else {
-                return maybeSuppressResult(rp, scope, result_used, rhs);
-            }
+            op_id = .BitOr;
+            op_token = try appendToken(rp.c, .Pipe, "|");
         },
+        .Assign,
         .MulAssign,
         .DivAssign,
         .RemAssign,
@@ -1091,6 +1048,9 @@ fn transBinaryOperator(
         => unreachable,
         else => unreachable,
     }
+
+    const rhs_node = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
+    return transCreateNodeInfixOp(rp, scope, lhs_node, op_id, op_token, rhs_node, result_used, true);
 }
 
 fn transCompoundStmtInline(
@@ -1231,56 +1191,22 @@ 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 {
+    grouped: bool,
+) TransError!*ast.Node {
+    const lparen = if (grouped)
+        try appendToken(rp.c, .LParen, "(")
+    else
+        undefined;
     var res = try transExpr(rp, scope, expr, used, lrvalue);
 
-    switch (res.node.id) {
-        .InfixOp => switch (@ptrCast(*const ast.Node.InfixOp, &res.node).op) {
+    switch (res.id) {
+        .InfixOp => switch (@fieldParentPtr(ast.Node.InfixOp, "base", res).op) {
             .BoolOr,
             .BoolAnd,
             .EqualEqual,
@@ -1289,24 +1215,34 @@ fn transBoolExpr(
             .GreaterThan,
             .LessOrEqual,
             .GreaterOrEqual,
-            => return res.node,
+            => return res,
 
             else => {},
         },
 
-        .PrefixOp => switch (@ptrCast(*const ast.Node.PrefixOp, &res.node).op) {
-            .BoolNot => return res.node,
+        .PrefixOp => switch (@fieldParentPtr(ast.Node.PrefixOp, "base", res).op) {
+            .BoolNot => return res,
 
             else => {},
         },
 
-        .BoolLiteral => return res.node,
+        .BoolLiteral => return res,
 
         else => {},
     }
-
     const ty = ZigClangQualType_getTypePtr(getExprQualTypeBeforeImplicitCast(rp.c, expr));
+    return finishBoolExpr(rp, scope, ZigClangExpr_getBeginLoc(expr), ty, res, used, grouped);
+}
 
+fn finishBoolExpr(
+    rp: RestorePoint,
+    scope: *Scope,
+    loc: ZigClangSourceLocation,
+    ty: *const ZigClangType,
+    node: *ast.Node,
+    used: ResultUsed,
+    grouped: bool,
+) TransError!*ast.Node {
     switch (ZigClangType_getTypeClass(ty)) {
         .Builtin => {
             const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
@@ -1337,219 +1273,48 @@ fn transBoolExpr(
                 .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,
-
+                => {
+                    const op_token = try appendToken(rp.c, .BangEqual, "!=");
+                    const rhs_node = try transCreateNodeInt(rp.c, 0);
+                    return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, grouped);
+                },
+                .NullPtr => {
+                    const op_token = try appendToken(rp.c, .EqualEqual, "==");
+                    const rhs_node = try transCreateNodeNullLiteral(rp.c);
+                    return transCreateNodeInfixOp(rp, scope, node, .EqualEqual, op_token, rhs_node, used, grouped);
+                },
                 else => {},
             }
         },
-        .Pointer => return transCreateNodeNotEqual(rp, scope, res.node, try transCreateNodeNullLiteral(rp.c)),
-
+        .Pointer => {
+            const op_token = try appendToken(rp.c, .BangEqual, "!=");
+            const rhs_node = try transCreateNodeNullLiteral(rp.c);
+            return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, grouped);
+        },
         .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);
+            const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);
+            const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
+            const underlying_type = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
+            return finishBoolExpr(rp, scope, loc, ZigClangQualType_getTypePtr(underlying_type), node, used, grouped);
         },
-
         .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;
-                }
-            };
+            const enum_ty = @ptrCast(*const ZigClangEnumType, ty);
+            const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@enumToInt");
+            try builtin_node.params.push(node);
+            builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
 
-            return toEnumZeroCmp(rp, scope, res.node, gen_enum_decl_node.generate_node, ty, ZigClangExpr_getBeginLoc(expr));
+            const op_token = try appendToken(rp.c, .BangEqual, "!=");
+            const rhs_node = try transCreateNodeInt(rp.c, 0);
+            return transCreateNodeInfixOp(rp, scope, &builtin_node.base, .BangEqual, op_token, rhs_node, used, grouped);
         },
-
         .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,
-
-                else => {},
-            }
+            const named_type = ZigClangElaboratedType_getNamedType(elaborated_ty);
+            return finishBoolExpr(rp, scope, loc, ZigClangQualType_getTypePtr(named_type), node, used, grouped);
         },
-
-        .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,
-
-        else => unreachable,
+        else => {},
     }
-
-    unreachable;
+    return revertAndWarn(rp, error.UnsupportedType, loc, "unsupported bool expression type", .{});
 }
 
 fn transIntegerLiteral(
@@ -2036,7 +1801,6 @@ fn transSwitch(
     const switch_block = try transCreateNodeBlock(rp.c, null);
     try switch_block.statements.push(&switch_node.base);
     switch_scope.pending_block = switch_block;
-    
 
     const last = try transStmt(rp, &block_scope.base, ZigClangSwitchStmt_getBody(stmt), .unused, .r_value);
     _ = try appendToken(rp.c, .Semicolon, ";");
@@ -2085,7 +1849,6 @@ fn transCase(
     } else
         try transExpr(rp, scope, ZigClangCaseStmt_getLHS(stmt), .used, .r_value);
 
-
     const switch_prong = try transCreateNodeSwitchCase(rp.c, expr);
     switch_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base;
     _ = try appendToken(rp.c, .Comma, ",");
@@ -2271,7 +2034,7 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigCla
         const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
         grouped_expr.* = .{
             .lparen = lparen,
-            .expr =  &if_node.base,
+            .expr = &if_node.base,
             .rparen = rparen,
         };
         return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
@@ -2670,87 +2433,64 @@ fn transCreateNodePrefixOp(
     return node;
 }
 
-fn transCreateNodeInfixOpImpl(
+fn transCreateNodeInfixOp(
     rp: RestorePoint,
     scope: *Scope,
     lhs_node: *ast.Node,
-    rhs_node: *ast.Node,
     op: ast.Node.InfixOp.Op,
-    op_tok_id: std.zig.Token.Id,
-    bytes: []const u8,
+    op_token: ast.TokenIndex,
+    rhs_node: *ast.Node,
+    used: ResultUsed,
     grouped: bool,
 ) !*ast.Node {
-    const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined;
-    const op_token = try appendToken(rp.c, op_tok_id, bytes);
+    var lparen = if (grouped)
+        try appendToken(rp.c, .LParen, "(")
+    else
+        null;
     const node = try rp.c.a().create(ast.Node.InfixOp);
-    node.* = ast.Node.InfixOp{
+    node.* = .{
         .op_token = op_token,
         .lhs = lhs_node,
         .op = op,
         .rhs = rhs_node,
     };
-    if (!grouped) return &node.base;
+    if (!grouped) return maybeSuppressResult(rp, scope, used, &node.base);
     const rparen = try appendToken(rp.c, .RParen, ")");
     const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
     grouped_expr.* = .{
-        .lparen = lparen,
+        .lparen = lparen.?,
         .expr = &node.base,
         .rparen = rparen,
     };
-    return &grouped_expr.base;
+    return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
 }
 
-fn transCreateNodeInfixOp(
+fn transCreateNodeBoolInfixOp(
     rp: RestorePoint,
     scope: *Scope,
     stmt: *const ZigClangBinaryOperator,
     op: ast.Node.InfixOp.Op,
-    op_tok_id: std.zig.Token.Id,
-    bytes: []const u8,
+    used: ResultUsed,
     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);
-}
+    std.debug.assert(op == .BoolAnd or op == .BoolOr);
 
-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");
-    }
+    const lhs_hode = try transBoolExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value, true);
+    const op_token = if (op == .BoolAnd)
+        try appendToken(rp.c, .Keyword_and, "and")
+    else
+        try appendToken(rp.c, .Keyword_or, "or");
+    const rhs = try transBoolExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value, true);
 
-    return transCreateNodeInfixOpImpl(
+    return transCreateNodeInfixOp(
         rp,
         scope,
-        try transBoolExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .r_value),
-        try transBoolExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value),
+        lhs_hode,
         op,
-        op_tok_id,
-        bytes,
-        true,
+        op_token,
+        rhs,
+        used,
+        grouped,
     );
 }
 
@@ -3149,16 +2889,14 @@ fn transCreateNodeShiftOp(
     comptime op_tok_id: std.zig.Token.Id,
     comptime bytes: []const u8,
 ) !*ast.Node {
-    if (!(op == .BitShiftLeft or op == .BitShiftRight)) {
-        @compileError("op must be either .BitShiftLeft or .BitShiftRight");
-    }
+    std.debug.assert(op == .BitShiftLeft or op == .BitShiftRight);
 
     const lhs_expr = ZigClangBinaryOperator_getLHS(stmt);
     const rhs_expr = ZigClangBinaryOperator_getRHS(stmt);
     const rhs_location = ZigClangExpr_getBeginLoc(rhs_expr);
     // lhs >> u5(rh)
 
-    const lhs = try transExpr(rp, scope, lhs_expr, .used, .r_value);
+    const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value);
     const op_token = try appendToken(rp.c, op_tok_id, bytes);
 
     const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
@@ -3166,13 +2904,13 @@ fn transCreateNodeShiftOp(
     try as_node.params.push(rhs_type);
     _ = try appendToken(rp.c, .Comma, ",");
     const rhs = try transExpr(rp, scope, rhs_expr, .used, .r_value);
-    try as_node.params.push(rhs.node);
+    try as_node.params.push(rhs);
     as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
 
     const node = try rp.c.a().create(ast.Node.InfixOp);
     node.* = ast.Node.InfixOp{
         .op_token = op_token,
-        .lhs = lhs.node,
+        .lhs = lhs,
         .op = op,
         .rhs = &as_node.base,
     };
@@ -3648,26 +3386,26 @@ fn isZigPrimitiveType(name: []const u8) bool {
     }
     // void is invalid in c so it doesn't need to be checked.
     return std.mem.eql(u8, name, "comptime_float") or
-    std.mem.eql(u8, name, "comptime_int") or
-    std.mem.eql(u8, name, "bool") or
-    std.mem.eql(u8, name, "isize") or
-    std.mem.eql(u8, name, "usize") or
-    std.mem.eql(u8, name, "f16") or
-    std.mem.eql(u8, name, "f32") or
-    std.mem.eql(u8, name, "f64") or
-    std.mem.eql(u8, name, "f128") or
-    std.mem.eql(u8, name, "c_longdouble") or
-    std.mem.eql(u8, name, "noreturn") or
-    std.mem.eql(u8, name, "type") or
-    std.mem.eql(u8, name, "anyerror") or
-    std.mem.eql(u8, name, "c_short") or
-    std.mem.eql(u8, name, "c_ushort") or
-    std.mem.eql(u8, name, "c_int") or
-    std.mem.eql(u8, name, "c_uint") or
-    std.mem.eql(u8, name, "c_long") or
-    std.mem.eql(u8, name, "c_ulong") or
-    std.mem.eql(u8, name, "c_longlong") or
-    std.mem.eql(u8, name, "c_ulonglong");
+        std.mem.eql(u8, name, "comptime_int") or
+        std.mem.eql(u8, name, "bool") or
+        std.mem.eql(u8, name, "isize") or
+        std.mem.eql(u8, name, "usize") or
+        std.mem.eql(u8, name, "f16") or
+        std.mem.eql(u8, name, "f32") or
+        std.mem.eql(u8, name, "f64") or
+        std.mem.eql(u8, name, "f128") or
+        std.mem.eql(u8, name, "c_longdouble") or
+        std.mem.eql(u8, name, "noreturn") or
+        std.mem.eql(u8, name, "type") or
+        std.mem.eql(u8, name, "anyerror") or
+        std.mem.eql(u8, name, "c_short") or
+        std.mem.eql(u8, name, "c_ushort") or
+        std.mem.eql(u8, name, "c_int") or
+        std.mem.eql(u8, name, "c_uint") or
+        std.mem.eql(u8, name, "c_long") or
+        std.mem.eql(u8, name, "c_ulong") or
+        std.mem.eql(u8, name, "c_longlong") or
+        std.mem.eql(u8, name, "c_ulonglong");
 }
 
 fn isValidZigIdentifier(name: []const u8) bool {
test/translate_c.zig
@@ -531,33 +531,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add_2("qualified struct and enum",
-        \\struct Foo {
-        \\    int x;
-        \\    int y;
-        \\};
-        \\enum Bar {
-        \\    BarA,
-        \\    BarB,
-        \\};
-        \\void func(struct Foo *a, enum Bar **b);
-    , &[_][]const u8{
-        \\pub const struct_Foo = extern struct {
-        \\    x: c_int,
-        \\    y: c_int,
-        \\};
-        \\pub const BarA = enum_Bar.A;
-        \\pub const BarB = enum_Bar.B;
-        \\pub const enum_Bar = extern enum {
-        \\    A,
-        \\    B,
-        \\};
-        \\pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
-    ,
-        \\pub const Foo = struct_Foo;
-        \\pub const Bar = enum_Bar;
-    });
-
     cases.add_both("constant size array",
         \\void func(int array[20]);
     , &[_][]const u8{
@@ -1388,17 +1361,109 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    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 k: c_int = ((a != 0) or (@enumToInt(@as(c_uint, d)) != 0));
+        \\    var l: c_int = ((@enumToInt(@as(c_uint, d)) != 0) and (b != 0));
+        \\    var m: c_int = ((c != null) or (@enumToInt(@as(c_uint, d)) != 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.add_2("qualified struct and enum",
+        \\struct Foo {
+        \\    int x;
+        \\    int y;
+        \\};
+        \\enum Bar {
+        \\    BarA,
+        \\    BarB,
+        \\};
+        \\void func(struct Foo *a, enum Bar **b);
+    , &[_][]const u8{
+        \\pub const struct_Foo = extern struct {
+        \\    x: c_int,
+        \\    y: c_int,
+        \\};
+        \\pub const BarA = enum_Bar.A;
+        \\pub const BarB = enum_Bar.B;
+        \\pub const enum_Bar = extern enum {
+        \\    A,
+        \\    B,
+        \\};
+        \\pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
+    ,
+        \\pub const Foo = struct_Foo;
+        \\pub const Bar = enum_Bar;
+    });
+
+    cases.add_2("bitwise binary operators, simpler parens", // TODO can combine with "bitwise binary operators" when parens are correctly preserved/not added in translate-c-2
+        \\int max(int a, int b) {
+        \\    int c = (a & b);
+        \\    int d = (a | b);
+        \\    return (c ^ d);
+        \\}
+    , &[_][]const u8{
+        \\pub export fn max(a: c_int, b: c_int) c_int {
+        \\    var c: c_int = (a & b);
+        \\    var d: c_int = (a | b);
+        \\    return (c ^ d);
+        \\}
+    });
+
+    cases.add_2("comparison operators (no if)", // TODO Come up with less contrived tests? Make sure to cover all these comparisons. Can use `if` after it is added to translate-c-2
+        \\int test_comparisons(int a, int b) {
+        \\    int c = (a < b);
+        \\    int d = (a > b);
+        \\    int e = (a <= b);
+        \\    int f = (a >= b);
+        \\    int g = (c < d);
+        \\    int h = (e < f);
+        \\    int i = (g < h);
+        \\    return i;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn test_comparisons(a: c_int, b: c_int) c_int {
+        \\    var c: c_int = (a < b);
+        \\    var d: c_int = (a > b);
+        \\    var e: c_int = (a <= b);
+        \\    var f: c_int = (a >= b);
+        \\    var g: c_int = (c < d);
+        \\    var h: c_int = (e < f);
+        \\    var i: c_int = (g < h);
+        \\    return i;
+        \\}
+    });
+
+    cases.add_2("==, !=, no if", // TODO remove this test after `if` conversion supported, and switch "==, !=" to addC_both
+        \\int max(int a, int b) {
+        \\    int c = (a == b);
+        \\    int d = (a != b);
+        \\    return (c != d);
+        \\}
+    , &[_][]const u8{
+        \\pub export fn max(a: c_int, b: c_int) c_int {
+        \\    var c: c_int = (a == b);
+        \\    var d: c_int = (a != b);
+        \\    return (c != d);
+        \\}
+    });
+
+    cases.add_2("bitshift, no parens", // TODO can fold this into "bitshift" once parens are preserved correctly in translate-c-2
+        \\int foo(void) {
+        \\    int a = (1 << 2);
+        \\    return a >> 1;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() c_int {
+        \\    var a: c_int = 1 << @as(@import("std").math.Log2Int(c_int), 2);
+        \\    return a >> @as(@import("std").math.Log2Int(c_int), 1);
+        \\}
+    });
+
     /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
 
     cases.addAllowWarnings("simple data types",
@@ -1525,21 +1590,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    return a;
         \\}
     });
-
-    cases.add_2("==, !=, no if", // TODO remove this test after `if` conversion supported, and switch "==, !=" to addC_both
-        \\int max(int a, int b) {
-        \\    int c = (a == b);
-        \\    int d = (a != b);
-        \\    return (c != d);
-        \\}
-    , &[_][]const u8{
-        \\pub export fn max(a: c_int, b: c_int) c_int {
-        \\    var c: c_int = (a == b);
-        \\    var d: c_int = (a != b);
-        \\    return (c != d);
-        \\}
-    });
-
     cases.addC("bitwise binary operators",
         \\int max(int a, int b) {
         \\    return (a & b) ^ (a | b);
@@ -1550,20 +1600,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add_2("bitwise binary operators, simpler parens", // TODO can combine with "bitwise binary operators" when parens are correctly preserved/not added in translate-c-2
-        \\int max(int a, int b) {
-        \\    int c = (a & b);
-        \\    int d = (a | b);
-        \\    return (c ^ d);
-        \\}
-    , &[_][]const u8{
-        \\pub export fn max(a: c_int, b: c_int) c_int {
-        \\    var c: c_int = (a & b);
-        \\    var d: c_int = (a | b);
-        \\    return (c ^ d);
-        \\}
-    });
-
     cases.addC("logical and, logical or",
         \\int max(int a, int b) {
         \\    if (a < b || a == b)
@@ -1580,30 +1616,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add_2("comparison operators (no if)", // TODO Come up with less contrived tests? Make sure to cover all these comparisons. Can use `if` after it is added to translate-c-2
-        \\int test_comparisons(int a, int b) {
-        \\    int c = (a < b);
-        \\    int d = (a > b);
-        \\    int e = (a <= b);
-        \\    int f = (a >= b);
-        \\    int g = (c < d);
-        \\    int h = (e < f);
-        \\    int i = (g < h);
-        \\    return i;
-        \\}
-    , &[_][]const u8{
-        \\pub export fn test_comparisons(a: c_int, b: c_int) c_int {
-        \\    var c: c_int = (a < b);
-        \\    var d: c_int = (a > b);
-        \\    var e: c_int = (a <= b);
-        \\    var f: c_int = (a >= b);
-        \\    var g: c_int = (c < d);
-        \\    var h: c_int = (e < f);
-        \\    var i: c_int = (g < h);
-        \\    return i;
-        \\}
-    });
-
     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,
@@ -1640,9 +1652,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    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 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;
         \\}
     });
@@ -1760,18 +1772,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add_2("bitshift, no parens", // TODO can fold this into "bitshift" once parens are preserved correctly in translate-c-2
-        \\int foo(void) {
-        \\    int a = (1 << 2);
-        \\    return a >> 1;
-        \\}
-    , &[_][]const u8{
-        \\pub export fn foo() c_int {
-        \\    var a: c_int = 1 << @as(@import("std").math.Log2Int(c_int), 2);
-        \\    return a >> @as(@import("std").math.Log2Int(c_int), 1);
-        \\}
-    });
-
     cases.addC("compound assignment operators",
         \\void foo(void) {
         \\    int a = 0;