diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index efb3eb611f..94d1928a4c 100644 --- a/src-self-hosted/clang.zig +++ b/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; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index e3b16c6f77..438feed7a1 100644 --- a/src-self-hosted/translate_c.zig +++ b/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,174 +875,10 @@ 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); - }, - .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 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 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, - }); - }, - .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, - }); - }, - .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, - }); - }, - .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, - }); - }, - .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, - }); - }, - .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, - }); - }, - .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, - }); - }, - .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, - }); - }, - .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, - }); - }, - .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, - }); - }, - .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, - }); - }, + .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; @@ -1078,6 +910,131 @@ fn transBinaryOperator( 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"); + 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); + } + }, + .Rem => { + if (!cIsUnsignedInteger(qt)) { + // signed integer division uses @rem + const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem"); + 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); + } + }, + .Shl => { + const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<"); + return maybeSuppressResult(rp, scope, result_used, node); + }, + .Shr => { + const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftRight, .AngleBracketAngleBracketRight, ">>"); + 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 => { + op_id = .LessThan; + op_token = try appendToken(rp.c, .AngleBracketLeft, "<"); + }, + .GT => { + op_id = .GreaterThan; + op_token = try appendToken(rp.c, .AngleBracketRight, ">"); + }, + .LE => { + op_id = .LessOrEqual; + op_token = try appendToken(rp.c, .AngleBracketLeftEqual, "<="); + }, + .GE => { + op_id = .GreaterOrEqual; + op_token = try appendToken(rp.c, .AngleBracketRightEqual, ">="); + }, + .EQ => { + op_id = .EqualEqual; + op_token = try appendToken(rp.c, .EqualEqual, "=="); + }, + .NE => { + op_id = .BangEqual; + op_token = try appendToken(rp.c, .BangEqual, "!="); + }, + .And => { + op_id = .BitAnd; + op_token = try appendToken(rp.c, .Ampersand, "&"); + }, + .Xor => { + op_id = .BitXor; + op_token = try appendToken(rp.c, .Caret, "^"); + }, + .Or => { + 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; -} - -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); + return maybeSuppressResult(rp, scope, used, &grouped_expr.base); } 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, + op: ast.Node.InfixOp.Op, + used: ResultUsed, + grouped: bool, ) !*ast.Node { - if (!(op == .BoolAnd or op == .BoolOr)) { - @compileError("op must be either .BoolAnd or .BoolOr"); - } + std.debug.assert(op == .BoolAnd or op == .BoolOr); - return transCreateNodeInfixOpImpl( + 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 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 { diff --git a/test/translate_c.zig b/test/translate_c.zig index 18e806c280..3da0660acc 100644 --- a/test/translate_c.zig +++ b/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;