| ... | ... | @@ -363,7 +363,7 @@ fn prepopulateGlobalNameTable(ast_unit: *ZigClangASTUnit, c: *Context) !void { |
| 363 | 363 | } |
| 364 | 364 | } |
| 365 | 365 | |
| 366 | | extern fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const ZigClangDecl) bool { |
| 366 | fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const ZigClangDecl) callconv(.C) bool { |
| 367 | 367 | const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context)); |
| 368 | 368 | declVisitorNamesOnly(c, decl) catch |err| { |
| 369 | 369 | c.err = err; |
| ... | ... | @@ -372,7 +372,7 @@ extern fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const ZigClangDecl) bo |
| 372 | 372 | return true; |
| 373 | 373 | } |
| 374 | 374 | |
| 375 | | extern fn declVisitorC(context: ?*c_void, decl: *const ZigClangDecl) bool { |
| 375 | fn declVisitorC(context: ?*c_void, decl: *const ZigClangDecl) callconv(.C) bool { |
| 376 | 376 | const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context)); |
| 377 | 377 | declVisitor(c, decl) catch |err| { |
| 378 | 378 | c.err = err; |
| ... | ... | @@ -1010,7 +1010,12 @@ fn transStmt( |
| 1010 | 1010 | .BreakStmtClass => return transBreak(rp, scope), |
| 1011 | 1011 | .ForStmtClass => return transForLoop(rp, scope, @ptrCast(*const ZigClangForStmt, stmt)), |
| 1012 | 1012 | .FloatingLiteralClass => return transFloatingLiteral(rp, scope, @ptrCast(*const ZigClangFloatingLiteral, stmt), result_used), |
| 1013 | | .ConditionalOperatorClass => return transConditionalOperator(rp, scope, @ptrCast(*const ZigClangConditionalOperator, stmt), result_used), |
| 1013 | .ConditionalOperatorClass => { |
| 1014 | return transConditionalOperator(rp, scope, @ptrCast(*const ZigClangConditionalOperator, stmt), result_used); |
| 1015 | }, |
| 1016 | .BinaryConditionalOperatorClass => { |
| 1017 | return transBinaryConditionalOperator(rp, scope, @ptrCast(*const ZigClangBinaryConditionalOperator, stmt), result_used); |
| 1018 | }, |
| 1014 | 1019 | .SwitchStmtClass => return transSwitch(rp, scope, @ptrCast(*const ZigClangSwitchStmt, stmt)), |
| 1015 | 1020 | .CaseStmtClass => return transCase(rp, scope, @ptrCast(*const ZigClangCaseStmt, stmt)), |
| 1016 | 1021 | .DefaultStmtClass => return transDefault(rp, scope, @ptrCast(*const ZigClangDefaultStmt, stmt)), |
| ... | ... | @@ -1024,6 +1029,18 @@ fn transStmt( |
| 1024 | 1029 | .UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(rp, scope, @ptrCast(*const ZigClangUnaryExprOrTypeTraitExpr, stmt), result_used), |
| 1025 | 1030 | .UnaryOperatorClass => return transUnaryOperator(rp, scope, @ptrCast(*const ZigClangUnaryOperator, stmt), result_used), |
| 1026 | 1031 | .CompoundAssignOperatorClass => return transCompoundAssignOperator(rp, scope, @ptrCast(*const ZigClangCompoundAssignOperator, stmt), result_used), |
| 1032 | .OpaqueValueExprClass => { |
| 1033 | const source_expr = ZigClangOpaqueValueExpr_getSourceExpr(@ptrCast(*const ZigClangOpaqueValueExpr, stmt)).?; |
| 1034 | const expr = try transExpr(rp, scope, source_expr, .used, lrvalue); |
| 1035 | if (expr.id == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr); |
| 1036 | const node = try rp.c.a().create(ast.Node.GroupedExpression); |
| 1037 | node.* = .{ |
| 1038 | .lparen = try appendToken(rp.c, .LParen, "("), |
| 1039 | .expr = expr, |
| 1040 | .rparen = try appendToken(rp.c, .RParen, ")"), |
| 1041 | }; |
| 1042 | return maybeSuppressResult(rp, scope, result_used, &node.base); |
| 1043 | }, |
| 1027 | 1044 | else => { |
| 1028 | 1045 | return revertAndWarn( |
| 1029 | 1046 | rp, |
| ... | ... | @@ -1330,28 +1347,27 @@ fn transImplicitCastExpr( |
| 1330 | 1347 | ) TransError!*ast.Node { |
| 1331 | 1348 | const c = rp.c; |
| 1332 | 1349 | const sub_expr = ZigClangImplicitCastExpr_getSubExpr(expr); |
| 1333 | | const sub_expr_node = try transExpr(rp, scope, @ptrCast(*const ZigClangExpr, sub_expr), .used, .r_value); |
| 1334 | 1350 | const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr)); |
| 1335 | 1351 | const src_type = getExprQualType(c, sub_expr); |
| 1336 | 1352 | switch (ZigClangImplicitCastExpr_getCastKind(expr)) { |
| 1337 | 1353 | .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast, .PointerToIntegral, .IntegralToPointer => { |
| 1354 | const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value); |
| 1338 | 1355 | return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node); |
| 1339 | 1356 | }, |
| 1340 | 1357 | .LValueToRValue, .NoOp, .FunctionToPointerDecay => { |
| 1358 | const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value); |
| 1341 | 1359 | return maybeSuppressResult(rp, scope, result_used, sub_expr_node); |
| 1342 | 1360 | }, |
| 1343 | 1361 | .ArrayToPointerDecay => { |
| 1344 | | switch (ZigClangExpr_getStmtClass(sub_expr)) { |
| 1345 | | .StringLiteralClass, .PredefinedExprClass => { |
| 1346 | | return maybeSuppressResult(rp, scope, result_used, sub_expr_node); |
| 1347 | | }, |
| 1348 | | else => { |
| 1349 | | const prefix_op = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); |
| 1350 | | prefix_op.rhs = sub_expr_node; |
| 1351 | | |
| 1352 | | return maybeSuppressResult(rp, scope, result_used, &prefix_op.base); |
| 1353 | | }, |
| 1362 | if (exprIsStringLiteral(sub_expr)) { |
| 1363 | const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value); |
| 1364 | return maybeSuppressResult(rp, scope, result_used, sub_expr_node); |
| 1354 | 1365 | } |
| 1366 | |
| 1367 | const prefix_op = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); |
| 1368 | prefix_op.rhs = try transExpr(rp, scope, sub_expr, .used, .r_value); |
| 1369 | |
| 1370 | return maybeSuppressResult(rp, scope, result_used, &prefix_op.base); |
| 1355 | 1371 | }, |
| 1356 | 1372 | .NullToPointer => { |
| 1357 | 1373 | return try transCreateNodeNullLiteral(rp.c); |
| ... | ... | @@ -1367,16 +1383,16 @@ fn transImplicitCastExpr( |
| 1367 | 1383 | return transCreateNodeInfixOp(rp, scope, &ptr_to_int.base, .BangEqual, op_token, rhs_node, result_used, false); |
| 1368 | 1384 | }, |
| 1369 | 1385 | .IntegralToBoolean => { |
| 1370 | | const node = try transExpr(rp, scope, sub_expr, .used, .r_value); |
| 1386 | const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value); |
| 1371 | 1387 | |
| 1372 | 1388 | // The expression is already a boolean one, return it as-is |
| 1373 | | if (isBoolRes(node)) |
| 1374 | | return node; |
| 1389 | if (isBoolRes(sub_expr_node)) |
| 1390 | return sub_expr_node; |
| 1375 | 1391 | |
| 1376 | 1392 | // val != 0 |
| 1377 | 1393 | const op_token = try appendToken(rp.c, .BangEqual, "!="); |
| 1378 | 1394 | const rhs_node = try transCreateNodeInt(rp.c, 0); |
| 1379 | | return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, result_used, false); |
| 1395 | return transCreateNodeInfixOp(rp, scope, sub_expr_node, .BangEqual, op_token, rhs_node, result_used, false); |
| 1380 | 1396 | }, |
| 1381 | 1397 | else => |kind| return revertAndWarn( |
| 1382 | 1398 | rp, |
| ... | ... | @@ -1412,7 +1428,7 @@ fn transBoolExpr( |
| 1412 | 1428 | return res; |
| 1413 | 1429 | } |
| 1414 | 1430 | |
| 1415 | | const ty = ZigClangQualType_getTypePtr(getExprQualTypeBeforeImplicitCast(rp.c, expr)); |
| 1431 | const ty = ZigClangQualType_getTypePtr(getExprQualType(rp.c, expr)); |
| 1416 | 1432 | const node = try finishBoolExpr(rp, scope, ZigClangExpr_getBeginLoc(expr), ty, res, used); |
| 1417 | 1433 | |
| 1418 | 1434 | if (grouped) { |
| ... | ... | @@ -1433,6 +1449,18 @@ fn exprIsBooleanType(expr: *const ZigClangExpr) bool { |
| 1433 | 1449 | return qualTypeIsBoolean(ZigClangExpr_getType(expr)); |
| 1434 | 1450 | } |
| 1435 | 1451 | |
| 1452 | fn exprIsStringLiteral(expr: *const ZigClangExpr) bool { |
| 1453 | switch (ZigClangExpr_getStmtClass(expr)) { |
| 1454 | .StringLiteralClass => return true, |
| 1455 | .PredefinedExprClass => return true, |
| 1456 | .UnaryOperatorClass => { |
| 1457 | const op_expr = ZigClangUnaryOperator_getSubExpr(@ptrCast(*const ZigClangUnaryOperator, expr)); |
| 1458 | return exprIsStringLiteral(op_expr); |
| 1459 | }, |
| 1460 | else => return false, |
| 1461 | } |
| 1462 | } |
| 1463 | |
| 1436 | 1464 | fn isBoolRes(res: *ast.Node) bool { |
| 1437 | 1465 | switch (res.id) { |
| 1438 | 1466 | .InfixOp => switch (@fieldParentPtr(ast.Node.InfixOp, "base", res).op) { |
| ... | ... | @@ -1765,10 +1793,34 @@ fn transCCast( |
| 1765 | 1793 | if (ZigClangType_isBooleanType(qualTypeCanon(src_type)) and |
| 1766 | 1794 | !ZigClangType_isBooleanType(qualTypeCanon(dst_type))) |
| 1767 | 1795 | { |
| 1796 | // @boolToInt returns either a comptime_int or a u1 |
| 1768 | 1797 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); |
| 1769 | 1798 | try builtin_node.params.push(expr); |
| 1770 | 1799 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1771 | | return &builtin_node.base; |
| 1800 | |
| 1801 | const inner_cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); |
| 1802 | try inner_cast_node.params.push(try transCreateNodeIdentifier(rp.c, "u1")); |
| 1803 | _ = try appendToken(rp.c, .Comma, ","); |
| 1804 | try inner_cast_node.params.push(&builtin_node.base); |
| 1805 | inner_cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1806 | |
| 1807 | const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); |
| 1808 | try cast_node.params.push(try transQualType(rp, dst_type, loc)); |
| 1809 | _ = try appendToken(rp.c, .Comma, ","); |
| 1810 | |
| 1811 | if (cIsSignedInteger(dst_type)) { |
| 1812 | const bitcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@bitCast"); |
| 1813 | try bitcast_node.params.push(try transCreateNodeIdentifier(rp.c, "i1")); |
| 1814 | _ = try appendToken(rp.c, .Comma, ","); |
| 1815 | try bitcast_node.params.push(&inner_cast_node.base); |
| 1816 | bitcast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1817 | try cast_node.params.push(&bitcast_node.base); |
| 1818 | } else { |
| 1819 | try cast_node.params.push(&inner_cast_node.base); |
| 1820 | } |
| 1821 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1822 | |
| 1823 | return &cast_node.base; |
| 1772 | 1824 | } |
| 1773 | 1825 | if (ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(dst_type)) == .Enum) { |
| 1774 | 1826 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToEnum"); |
| ... | ... | @@ -3024,6 +3076,64 @@ fn transFloatingLiteral(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangFl |
| 3024 | 3076 | return maybeSuppressResult(rp, scope, used, &node.base); |
| 3025 | 3077 | } |
| 3026 | 3078 | |
| 3079 | fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangBinaryConditionalOperator, used: ResultUsed) TransError!*ast.Node { |
| 3080 | // GNU extension of the ternary operator where the middle expression is |
| 3081 | // omitted, the conditition itself is returned if it evaluates to true |
| 3082 | const casted_stmt = @ptrCast(*const ZigClangAbstractConditionalOperator, stmt); |
| 3083 | const cond_expr = ZigClangAbstractConditionalOperator_getCond(casted_stmt); |
| 3084 | const true_expr = ZigClangAbstractConditionalOperator_getTrueExpr(casted_stmt); |
| 3085 | const false_expr = ZigClangAbstractConditionalOperator_getFalseExpr(casted_stmt); |
| 3086 | |
| 3087 | // c: (cond_expr)?:(false_expr) |
| 3088 | // zig: (blk: { |
| 3089 | // const _cond_temp = (cond_expr); |
| 3090 | // break :blk if (_cond_temp) _cond_temp else (false_expr); |
| 3091 | // }) |
| 3092 | const lparen = try appendToken(rp.c, .LParen, "("); |
| 3093 | |
| 3094 | const block_scope = try Scope.Block.init(rp.c, scope, "blk"); |
| 3095 | block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); |
| 3096 | |
| 3097 | const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp"); |
| 3098 | const tmp_var = try transCreateNodeVarDecl(rp.c, false, true, mangled_name); |
| 3099 | tmp_var.eq_token = try appendToken(rp.c, .Equal, "="); |
| 3100 | tmp_var.init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value); |
| 3101 | tmp_var.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); |
| 3102 | try block_scope.block_node.statements.push(&tmp_var.base); |
| 3103 | |
| 3104 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); |
| 3105 | |
| 3106 | const if_node = try transCreateNodeIf(rp.c); |
| 3107 | var cond_scope = Scope{ |
| 3108 | .parent = &block_scope.base, |
| 3109 | .id = .Condition, |
| 3110 | }; |
| 3111 | const tmp_var_node = try transCreateNodeIdentifier(rp.c, mangled_name); |
| 3112 | |
| 3113 | const ty = ZigClangQualType_getTypePtr(getExprQualType(rp.c, cond_expr)); |
| 3114 | const cond_node = try finishBoolExpr(rp, &block_scope.base, ZigClangExpr_getBeginLoc(cond_expr), ty, tmp_var_node, used); |
| 3115 | if_node.condition = cond_node; |
| 3116 | _ = try appendToken(rp.c, .RParen, ")"); |
| 3117 | |
| 3118 | if_node.body = try transCreateNodeIdentifier(rp.c, mangled_name); |
| 3119 | if_node.@"else" = try transCreateNodeElse(rp.c); |
| 3120 | if_node.@"else".?.body = try transExpr(rp, &block_scope.base, false_expr, .used, .r_value); |
| 3121 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3122 | |
| 3123 | break_node.rhs = &if_node.base; |
| 3124 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3125 | try block_scope.block_node.statements.push(&break_node.base); |
| 3126 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); |
| 3127 | |
| 3128 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); |
| 3129 | grouped_expr.* = .{ |
| 3130 | .lparen = lparen, |
| 3131 | .expr = &block_scope.block_node.base, |
| 3132 | .rparen = try appendToken(rp.c, .RParen, ")"), |
| 3133 | }; |
| 3134 | return maybeSuppressResult(rp, scope, used, &grouped_expr.base); |
| 3135 | } |
| 3136 | |
| 3027 | 3137 | fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangConditionalOperator, used: ResultUsed) TransError!*ast.Node { |
| 3028 | 3138 | const grouped = scope.id == .Condition; |
| 3029 | 3139 | const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined; |
| ... | ... | @@ -3033,9 +3143,10 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigCla |
| 3033 | 3143 | .id = .Condition, |
| 3034 | 3144 | }; |
| 3035 | 3145 | |
| 3036 | | const cond_expr = ZigClangConditionalOperator_getCond(stmt); |
| 3037 | | const true_expr = ZigClangConditionalOperator_getTrueExpr(stmt); |
| 3038 | | const false_expr = ZigClangConditionalOperator_getFalseExpr(stmt); |
| 3146 | const casted_stmt = @ptrCast(*const ZigClangAbstractConditionalOperator, stmt); |
| 3147 | const cond_expr = ZigClangAbstractConditionalOperator_getCond(casted_stmt); |
| 3148 | const true_expr = ZigClangAbstractConditionalOperator_getTrueExpr(casted_stmt); |
| 3149 | const false_expr = ZigClangAbstractConditionalOperator_getFalseExpr(casted_stmt); |
| 3039 | 3150 | |
| 3040 | 3151 | if_node.condition = try transBoolExpr(rp, &cond_scope, cond_expr, .used, .r_value, false); |
| 3041 | 3152 | _ = try appendToken(rp.c, .RParen, ")"); |
| ... | ... | @@ -3278,14 +3389,6 @@ fn getExprQualType(c: *Context, expr: *const ZigClangExpr) ZigClangQualType { |
| 3278 | 3389 | return ZigClangExpr_getType(expr); |
| 3279 | 3390 | } |
| 3280 | 3391 | |
| 3281 | | fn getExprQualTypeBeforeImplicitCast(c: *Context, expr: *const ZigClangExpr) ZigClangQualType { |
| 3282 | | if (ZigClangExpr_getStmtClass(expr) == .ImplicitCastExprClass) { |
| 3283 | | const cast_expr = @ptrCast(*const ZigClangImplicitCastExpr, expr); |
| 3284 | | return getExprQualType(c, ZigClangImplicitCastExpr_getSubExpr(cast_expr)); |
| 3285 | | } |
| 3286 | | return ZigClangExpr_getType(expr); |
| 3287 | | } |
| 3288 | | |
| 3289 | 3392 | fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocation) bool { |
| 3290 | 3393 | switch (ZigClangType_getTypeClass(ty)) { |
| 3291 | 3394 | .Builtin => { |