diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index 20a815cb75..db76185ab9 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -1,4 +1,5 @@ -pub const struct_ZigClangAPValue = @OpaqueType(); +const builtin = @import("builtin"); + pub const struct_ZigClangAPSInt = @OpaqueType(); pub const struct_ZigClangAPFloat = @OpaqueType(); pub const struct_ZigClangASTContext = @OpaqueType(); @@ -723,6 +724,7 @@ pub extern fn ZigClangSourceLocation_eq(a: struct_ZigClangSourceLocation, b: str pub extern fn ZigClangTypedefType_getDecl(self: ?*const struct_ZigClangTypedefType) ?*const struct_ZigClangTypedefNameDecl; pub extern fn ZigClangTypedefNameDecl_getUnderlyingType(self: ?*const struct_ZigClangTypedefNameDecl) struct_ZigClangQualType; pub extern fn ZigClangQualType_getCanonicalType(self: struct_ZigClangQualType) struct_ZigClangQualType; +pub extern fn ZigClangQualType_getTypeClass(self: struct_ZigClangQualType) ZigClangTypeClass; pub extern fn ZigClangQualType_getTypePtr(self: struct_ZigClangQualType) *const struct_ZigClangType; pub extern fn ZigClangQualType_addConst(self: [*c]struct_ZigClangQualType) void; pub extern fn ZigClangQualType_eq(self: struct_ZigClangQualType, arg1: struct_ZigClangQualType) bool; @@ -730,6 +732,7 @@ pub extern fn ZigClangQualType_isConstQualified(self: struct_ZigClangQualType) b pub extern fn ZigClangQualType_isVolatileQualified(self: struct_ZigClangQualType) bool; pub extern fn ZigClangQualType_isRestrictQualified(self: struct_ZigClangQualType) bool; pub extern fn ZigClangType_getTypeClass(self: ?*const struct_ZigClangType) ZigClangTypeClass; +pub extern fn ZigClangType_getPointeeType(self: ?*const struct_ZigClangType) struct_ZigClangQualType; pub extern fn ZigClangType_isVoidType(self: ?*const struct_ZigClangType) bool; pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*]const u8; pub extern fn ZigClangStmt_getBeginLoc(self: *const struct_ZigClangStmt) struct_ZigClangSourceLocation; @@ -894,3 +897,77 @@ pub const ZigClangCompoundStmt_const_body_iterator = [*c]const *struct_ZigClangS pub extern fn ZigClangCompoundStmt_body_begin(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator; pub extern fn ZigClangCompoundStmt_body_end(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator; + +pub const ZigClangDeclStmt_const_decl_iterator = [*c]const *struct_ZigClangDecl; + +pub extern fn ZigClangDeclStmt_decl_begin(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator; +pub extern fn ZigClangDeclStmt_decl_end(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator; + +pub extern fn ZigClangVarDecl_getType(self: ?*const struct_ZigClangVarDecl) struct_ZigClangQualType; +pub extern fn ZigClangVarDecl_getInit(*const ZigClangVarDecl) ?*const ZigClangExpr; +pub extern fn ZigClangVarDecl_getTLSKind(self: ?*const struct_ZigClangVarDecl) ZigClangVarDecl_TLSKind; +pub const ZigClangVarDecl_TLSKind = extern enum { + None, + Static, + Dynamic, +}; + +pub extern fn ZigClangImplicitCastExpr_getBeginLoc(*const ZigClangImplicitCastExpr) ZigClangSourceLocation; +pub extern fn ZigClangImplicitCastExpr_getCastKind(*const ZigClangImplicitCastExpr) ZigClangCK; +pub extern fn ZigClangImplicitCastExpr_getSubExpr(*const ZigClangImplicitCastExpr) *const ZigClangExpr; + +pub extern fn ZigClangArrayType_getElementType(*const ZigClangArrayType) ZigClangQualType; + +pub extern fn ZigClangDeclRefExpr_getDecl(*const ZigClangDeclRefExpr) *const ZigClangValueDecl; + +pub extern fn ZigClangParenType_getInnerType(*const ZigClangParenType) ZigClangQualType; + +pub extern fn ZigClangElaboratedType_getNamedType(*const ZigClangElaboratedType) ZigClangQualType; + +pub extern fn ZigClangAttributedType_getEquivalentType(*const ZigClangAttributedType) ZigClangQualType; + +pub extern fn ZigClangCStyleCastExpr_getBeginLoc(*const ZigClangCStyleCastExpr) ZigClangSourceLocation; +pub extern fn ZigClangCStyleCastExpr_getSubExpr(*const ZigClangCStyleCastExpr) *const ZigClangExpr; +pub extern fn ZigClangCStyleCastExpr_getType(*const ZigClangCStyleCastExpr) ZigClangQualType; + +pub const ZigClangExprEvalResult = struct_ZigClangExprEvalResult; +pub const struct_ZigClangExprEvalResult = extern struct { + HasSideEffects: bool, + HasUndefinedBehavior: bool, + SmallVectorImpl: ?*c_void, + Val: ZigClangAPValue, +}; + +pub const struct_ZigClangAPValue = extern struct { + Kind: ZigClangAPValue_ValueKind, + Data: if (builtin.os == .windows) [52]u8 else [68]u8, +}; + +pub const ZigClangAPValue_ValueKind = extern enum { + ZigClangAPValue_ValueKind_Uninitialized, + ZigClangAPValue_ValueKind_Int, + ZigClangAPValue_ValueKind_Float, + ZigClangAPValue_ValueKind_ComplexInt, + ZigClangAPValue_ValueKind_ComplexFloat, + ZigClangAPValue_ValueKind_LValue, + ZigClangAPValue_ValueKind_Vector, + ZigClangAPValue_ValueKind_Array, + ZigClangAPValue_ValueKind_Struct, + ZigClangAPValue_ValueKind_Union, + ZigClangAPValue_ValueKind_MemberPointer, + ZigClangAPValue_ValueKind_AddrLabelDiff, +}; + +pub extern fn ZigClangIntegerLiteral_EvaluateAsInt(*const ZigClangIntegerLiteral, *ZigClangExprEvalResult, *const ZigClangASTContext) bool; +pub extern fn ZigClangIntegerLiteral_getBeginLoc(*const ZigClangIntegerLiteral) ZigClangSourceLocation; + +pub extern fn ZigClangReturnStmt_getRetValue(*const ZigClangReturnStmt) ?*const ZigClangExpr; + +pub extern fn ZigClangBinaryOperator_getOpcode(*const ZigClangBinaryOperator) ZigClangBO; +pub extern fn ZigClangBinaryOperator_getBeginLoc(*const ZigClangBinaryOperator) ZigClangSourceLocation; +pub extern fn ZigClangBinaryOperator_getLHS(*const ZigClangBinaryOperator) *const ZigClangExpr; +pub extern fn ZigClangBinaryOperator_getRHS(*const ZigClangBinaryOperator) *const ZigClangExpr; +pub extern fn ZigClangBinaryOperator_getType(*const ZigClangBinaryOperator) ZigClangQualType; + +pub extern fn ZigClangStringLiteral_getKind(*const ZigClangStringLiteral) ZigClangStringLiteral_StringKind; +pub extern fn ZigClangStringLiteral_getString_bytes_begin_size(*const ZigClangStringLiteral, *usize) [*c]const u8; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index b7ced4a89f..b18397ede2 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -20,7 +20,7 @@ pub const ClangErrMsg = Stage2ErrorMsg; pub const Error = error{OutOfMemory}; const TypeError = Error || error{UnsupportedType}; -const TransError = Error || error{UnsupportedTranslation}; +const TransError = TypeError || error{UnsupportedTranslation}; const DeclTable = std.HashMap(usize, void, addrHash, addrEql); @@ -107,6 +107,8 @@ const Context = struct { decl_table: DeclTable, global_scope: *Scope.Root, mode: Mode, + ptr_params: std.BufSet, + clang_context: *ZigClangASTContext, fn a(c: *Context) *std.mem.Allocator { return &c.tree.arena_allocator.allocator; @@ -183,6 +185,8 @@ pub fn translate( .decl_table = DeclTable.init(arena), .global_scope = try arena.create(Scope.Root), .mode = mode, + .ptr_params = std.BufSet.init(arena), + .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?, }; context.global_scope.* = Scope.Root{ .base = Scope{ @@ -195,7 +199,7 @@ pub fn translate( return context.err; } - _ = try appendToken(&context, .Eof, ""); + tree.root_node.eof_token = try appendToken(&context, .Eof, ""); tree.source = source_buffer.toOwnedSlice(); if (false) { std.debug.warn("debug source:\n{}\n==EOF==\ntokens:\n", tree.source); @@ -257,7 +261,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { .storage_class = storage_class, .scope = &scope, .is_export = switch (storage_class) { - .None => has_body, + .None => has_body and c.mode != .import, .Extern, .Static => false, .PrivateExtern => return failDecl(c, fn_decl_loc, fn_name, "unsupported storage class: private extern"), .Auto => unreachable, // Not legal on functions @@ -267,7 +271,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { const proto_node = switch (ZigClangType_getTypeClass(fn_type)) { .FunctionProto => blk: { const fn_proto_type = @ptrCast(*const ZigClangFunctionProtoType, fn_type); - break :blk transFnProto(rp, fn_proto_type, fn_decl_loc, decl_ctx) catch |err| switch (err) { + break :blk transFnProto(rp, fn_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) { error.UnsupportedType => { return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function"); }, @@ -276,7 +280,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { }, .FunctionNoProto => blk: { const fn_no_proto_type = @ptrCast(*const ZigClangFunctionType, fn_type); - break :blk transFnNoProto(rp, fn_no_proto_type, fn_decl_loc, decl_ctx) catch |err| switch (err) { + break :blk transFnNoProto(rp, fn_no_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) { error.UnsupportedType => { return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function"); }, @@ -295,7 +299,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { const body_stmt = ZigClangFunctionDecl_getBody(fn_decl); const result = transStmt(rp, scope, body_stmt, .unused, .r_value) catch |err| switch (err) { error.OutOfMemory => |e| return e, - error.UnsupportedTranslation => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function"), + error.UnsupportedTranslation, + error.UnsupportedType, + => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function"), }; assert(result.node.id == ast.Node.Id.Block); proto_node.body_node = result.node; @@ -322,7 +328,15 @@ fn transStmt( ) !TransResult { const sc = ZigClangStmt_getStmtClass(stmt); switch (sc) { + .BinaryOperatorClass => return transBinaryOperator(rp, scope, @ptrCast(*const ZigClangBinaryOperator, stmt), result_used), .CompoundStmtClass => return transCompoundStmt(rp, scope, @ptrCast(*const ZigClangCompoundStmt, stmt)), + .CStyleCastExprClass => return transCStyleCastExprClass(rp, scope, @ptrCast(*const ZigClangCStyleCastExpr, stmt), result_used, lrvalue), + .DeclStmtClass => return transDeclStmt(rp, scope, @ptrCast(*const ZigClangDeclStmt, stmt)), + .DeclRefExprClass => return transDeclRefExpr(rp, scope, @ptrCast(*const ZigClangDeclRefExpr, stmt), lrvalue), + .ImplicitCastExprClass => return transImplicitCastExpr(rp, scope, @ptrCast(*const ZigClangImplicitCastExpr, stmt), result_used), + .IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const ZigClangIntegerLiteral, stmt), result_used), + .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const ZigClangReturnStmt, stmt)), + .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used), else => { return revertAndWarn( rp, @@ -335,6 +349,87 @@ fn transStmt( } } +fn transBinaryOperator( + rp: RestorePoint, + scope: *Scope, + stmt: *const ZigClangBinaryOperator, + result_used: ResultUsed, +) TransError!TransResult { + const op = ZigClangBinaryOperator_getOpcode(stmt); + const qt = ZigClangBinaryOperator_getType(stmt); + switch (op) { + .PtrMemD, .PtrMemI, .Cmp => return revertAndWarn( + rp, + error.UnsupportedTranslation, + ZigClangBinaryOperator_getBeginLoc(stmt), + "TODO: handle more C binary operators: {}", + op, + ), + .Assign => return TransResult{ + .node = &(try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt))).base, + .child_scope = scope, + .node_scope = scope, + }, + .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, TransResult{ + .node = node, + .child_scope = scope, + .node_scope = scope, + }); + }, + .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, TransResult{ + .node = node, + .child_scope = scope, + .node_scope = scope, + }); + }, + .Mul, + .Div, + .Rem, + .Shl, + .Shr, + .LT, + .GT, + .LE, + .GE, + .EQ, + .NE, + .And, + .Xor, + .Or, + .LAnd, + .LOr, + .Comma, + => return revertAndWarn( + rp, + error.UnsupportedTranslation, + ZigClangBinaryOperator_getBeginLoc(stmt), + "TODO: handle more C binary operators: {}", + op, + ), + .MulAssign, + .DivAssign, + .RemAssign, + .AddAssign, + .SubAssign, + .ShlAssign, + .ShrAssign, + .AndAssign, + .XorAssign, + .OrAssign, + => unreachable, + } +} + fn transCompoundStmtInline( rp: RestorePoint, parent_scope: *Scope, @@ -345,9 +440,10 @@ fn transCompoundStmtInline( const end_it = ZigClangCompoundStmt_body_end(stmt); var scope = parent_scope; while (it != end_it) : (it += 1) { - const result = try transStmt(rp, scope, it.*, .unused, .r_value); + const result = try transStmt(rp, parent_scope, it.*, .unused, .r_value); scope = result.child_scope; - try block_node.statements.push(result.node); + if (result.node != &block_node.base) + try block_node.statements.push(result.node); } return TransResult{ .node = &block_node.base, @@ -368,6 +464,427 @@ fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompo }; } +fn transCStyleCastExprClass( + rp: RestorePoint, + scope: *Scope, + stmt: *const ZigClangCStyleCastExpr, + result_used: ResultUsed, + lrvalue: LRValue, +) !TransResult { + const sub_expr = ZigClangCStyleCastExpr_getSubExpr(stmt); + const cast_node = (try transCCast( + rp, + scope, + ZigClangCStyleCastExpr_getBeginLoc(stmt), + ZigClangCStyleCastExpr_getType(stmt), + ZigClangExpr_getType(sub_expr), + (try transExpr(rp, scope, sub_expr, .used, lrvalue)).node, + )); + const cast_res = TransResult{ + .node = cast_node, + .child_scope = scope, + .node_scope = scope, + }; + return maybeSuppressResult(rp, scope, result_used, cast_res); +} + +fn transDeclStmt(rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangDeclStmt) !TransResult { + const c = rp.c; + const block_scope = findBlockScope(parent_scope); + var scope = parent_scope; + + var it = ZigClangDeclStmt_decl_begin(stmt); + const end_it = ZigClangDeclStmt_decl_end(stmt); + while (it != end_it) : (it += 1) { + switch (ZigClangDecl_getKind(it.*)) { + .Var => { + const var_decl = @ptrCast(*const ZigClangVarDecl, it.*); + + const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None) + null + else + try appendToken(c, .Keyword_threadlocal, "threadlocal"); + const qual_type = ZigClangVarDecl_getType(var_decl); + const mut_token = if (ZigClangQualType_isConstQualified(qual_type)) + try appendToken(c, .Keyword_const, "const") + else + try appendToken(c, .Keyword_var, "var"); + const c_name = try c.str(ZigClangDecl_getName_bytes_begin( + @ptrCast(*const ZigClangDecl, var_decl), + )); + const name_token = try appendToken(c, .Identifier, c_name); + + const var_scope = try c.a().create(Scope.Var); + var_scope.* = Scope.Var{ + .base = Scope{ .id = .Var, .parent = scope }, + .c_name = c_name, + .zig_name = c_name, // TODO: getWantedName + }; + scope = &var_scope.base; + + const colon_token = try appendToken(c, .Colon, ":"); + const loc = ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)); + const type_node = try transQualType(rp, qual_type, loc); + + const eq_token = try appendToken(c, .Equal, "="); + const init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| + (try transExpr(rp, scope, expr, .used, .r_value)).node + else blk: { + const undefined_token = try appendToken(c, .Keyword_undefined, "undefined"); + const undefined_node = try rp.c.a().create(ast.Node.UndefinedLiteral); + undefined_node.* = ast.Node.UndefinedLiteral{ + .base = ast.Node{ .id = .UndefinedLiteral }, + .token = undefined_token, + }; + break :blk &undefined_node.base; + }; + const semicolon_token = try appendToken(c, .Semicolon, ";"); + + const node = try c.a().create(ast.Node.VarDecl); + node.* = ast.Node.VarDecl{ + .base = ast.Node{ .id = .VarDecl }, + .doc_comments = null, + .visib_token = null, + .thread_local_token = thread_local_token, + .name_token = name_token, + .eq_token = eq_token, + .mut_token = mut_token, + .comptime_token = null, + .extern_export_token = null, + .lib_name = null, + .type_node = type_node, + .align_node = null, // TODO ?*Node, + .section_node = null, + .init_node = init_node, + .semicolon_token = semicolon_token, + }; + try block_scope.block_node.statements.push(&node.base); + }, + + else => |kind| return revertAndWarn( + rp, + error.UnsupportedTranslation, + ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)), + "TODO implement translation of DeclStmt kind {}", + @tagName(kind), + ), + } + } + + return TransResult{ + .node = &block_scope.block_node.base, + .node_scope = scope, + .child_scope = scope, + }; +} + +fn transDeclRefExpr( + rp: RestorePoint, + scope: *Scope, + expr: *const ZigClangDeclRefExpr, + lrvalue: LRValue, +) !TransResult { + const value_decl = ZigClangDeclRefExpr_getDecl(expr); + const c_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, value_decl))); + const zig_name = transLookupZigIdentifier(scope, c_name); + if (lrvalue == .l_value) try rp.c.ptr_params.put(zig_name); + const node = try appendIdentifier(rp.c, zig_name); + return TransResult{ + .node = node, + .node_scope = scope, + .child_scope = scope, + }; +} + +fn transImplicitCastExpr( + rp: RestorePoint, + scope: *Scope, + expr: *const ZigClangImplicitCastExpr, + result_used: ResultUsed, +) !TransResult { + const c = rp.c; + const sub_expr = ZigClangImplicitCastExpr_getSubExpr(expr); + const sub_expr_node = try transExpr(rp, scope, @ptrCast(*const ZigClangExpr, sub_expr), .used, .r_value); + switch (ZigClangImplicitCastExpr_getCastKind(expr)) { + .BitCast => { + const dest_type = getExprQualType(c, @ptrCast(*const ZigClangExpr, expr)); + const src_type = getExprQualType(c, sub_expr); + return TransResult{ + .node = try transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node.node), + .node_scope = scope, + .child_scope = scope, + }; + }, + .IntegralCast => { + const dest_type = ZigClangExpr_getType(@ptrCast(*const ZigClangExpr, expr)); + const src_type = ZigClangExpr_getType(sub_expr); + return TransResult{ + .node = try transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node.node), + .node_scope = scope, + .child_scope = scope, + }; + }, + .FunctionToPointerDecay, .ArrayToPointerDecay => { + return maybeSuppressResult(rp, scope, result_used, sub_expr_node); + }, + .LValueToRValue => { + return transExpr(rp, scope, sub_expr, .used, .r_value); + }, + else => |kind| return revertAndWarn( + rp, + error.UnsupportedTranslation, + ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, expr)), + "TODO implement translation of CastKind {}", + @tagName(kind), + ), + } +} + +fn transIntegerLiteral( + rp: RestorePoint, + scope: *Scope, + expr: *const ZigClangIntegerLiteral, + result_used: ResultUsed, +) !TransResult { + var eval_result: ZigClangExprEvalResult = undefined; + if (!ZigClangIntegerLiteral_EvaluateAsInt(expr, &eval_result, rp.c.clang_context)) { + const loc = ZigClangIntegerLiteral_getBeginLoc(expr); + return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal"); + } + const node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val)); + const res = TransResult{ + .node = node, + .child_scope = scope, + .node_scope = scope, + }; + return maybeSuppressResult(rp, scope, result_used, res); +} + +fn transReturnStmt( + rp: RestorePoint, + scope: *Scope, + expr: *const ZigClangReturnStmt, +) !TransResult { + const node = try transCreateNodeReturnExpr(rp.c); + if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| { + const ret_node = node.cast(ast.Node.ControlFlowExpression).?; + ret_node.rhs = (try transExpr(rp, scope, val_expr, .used, .r_value)).node; + } + _ = try appendToken(rp.c, .Semicolon, ";"); + return TransResult{ + .node = node, + .child_scope = scope, + .node_scope = scope, + }; +} + +fn transStringLiteral( + rp: RestorePoint, + scope: *Scope, + stmt: *const ZigClangStringLiteral, + result_used: ResultUsed, +) !TransResult { + const kind = ZigClangStringLiteral_getKind(stmt); + switch (kind) { + .Ascii, .UTF8 => { + var len: usize = undefined; + const bytes_ptr = ZigClangStringLiteral_getString_bytes_begin_size(stmt, &len); + const str = bytes_ptr[0..len]; + + var char_buf: [4]u8 = undefined; + len = 0; + for (str) |c| len += escapeChar(c, &char_buf).len; + + const buf = try rp.c.a().alloc(u8, len + "c\"\"".len); + buf[0] = 'c'; + buf[1] = '"'; + writeEscapedString(buf[2..], str); + buf[buf.len - 1] = '"'; + + const token = try appendToken(rp.c, .StringLiteral, buf); + const node = try rp.c.a().create(ast.Node.StringLiteral); + node.* = ast.Node.StringLiteral{ + .base = ast.Node{ .id = .StringLiteral }, + .token = token, + }; + const res = TransResult{ + .node = &node.base, + .child_scope = scope, + .node_scope = scope, + }; + return maybeSuppressResult(rp, scope, result_used, res); + }, + .UTF16, .UTF32, .Wide => return revertAndWarn( + rp, + error.UnsupportedTranslation, + ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)), + "TODO: support string literal kind {}", + kind, + ), + } +} + +fn escapedStringLen(s: []const u8) usize { + var len: usize = 0; + var char_buf: [4]u8 = undefined; + for (s) |c| len += escapeChar(c, &char_buf).len; + return len; +} + +fn writeEscapedString(buf: []u8, s: []const u8) void { + var char_buf: [4]u8 = undefined; + var i: usize = 0; + for (s) |c| { + const escaped = escapeChar(c, &char_buf); + std.mem.copy(u8, buf[i..], escaped); + i += escaped.len; + } +} + +// Returns either a string literal or a slice of `buf`. +fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 { + // TODO: https://github.com/ziglang/zig/issues/2749 + const escaped = switch (c) { + // Printable ASCII except for ' " \ + ' ', '!', '#'...'&', '('...'[', ']'...'~' => ([_]u8{c})[0..], + '\'', '\"', '\\' => ([_]u8{ '\\', c })[0..], + '\n' => return "\\n"[0..], + '\r' => return "\\r"[0..], + '\t' => return "\\t"[0..], + else => return std.fmt.bufPrint(char_buf[0..], "\\x{x:2}", c) catch unreachable, + }; + std.mem.copy(u8, char_buf, escaped); + return char_buf[0..escaped.len]; +} + +fn transCCast( + rp: RestorePoint, + scope: *Scope, + loc: ZigClangSourceLocation, + dst_type: ZigClangQualType, + src_type: ZigClangQualType, + expr: *ast.Node, +) !*ast.Node { + if (ZigClangType_isVoidType(qualTypeCanon(dst_type))) return expr; + if (ZigClangQualType_eq(dst_type, src_type)) return expr; + if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type)) + return transCPtrCast(rp, loc, dst_type, src_type, expr); + if (cIsUnsignedInteger(dst_type) and qualTypeIsPtr(src_type)) { + const cast_node = try transCreateNodeFnCall(rp.c, try transQualType(rp, dst_type, loc)); + const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt"); + try builtin_node.params.push(expr); + builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + try cast_node.op.Call.params.push(&builtin_node.base); + cast_node.rtoken = try appendToken(rp.c, .RParen, ")"); + return &cast_node.base; + } + if (cIsUnsignedInteger(src_type) and qualTypeIsPtr(dst_type)) { + const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr"); + try builtin_node.params.push(try transQualType(rp, dst_type, loc)); + _ = try appendToken(rp.c, .Comma, ","); + try builtin_node.params.push(expr); + builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + return &builtin_node.base; + } + // TODO: maybe widen to increase size + // TODO: maybe bitcast to change sign + // TODO: maybe truncate to reduce size + const cast_node = try transCreateNodeFnCall(rp.c, try transQualType(rp, dst_type, loc)); + try cast_node.op.Call.params.push(expr); + cast_node.rtoken = try appendToken(rp.c, .RParen, ")"); + return &cast_node.base; +} + +fn transExpr( + rp: RestorePoint, + scope: *Scope, + expr: *const ZigClangExpr, + used: ResultUsed, + lrvalue: LRValue, +) TransError!TransResult { + return transStmt(rp, scope, @ptrCast(*const ZigClangStmt, expr), used, lrvalue); +} + +fn findBlockScope(inner: *Scope) *Scope.Block { + var scope = inner; + while (true) : (scope = scope.parent orelse unreachable) { + if (scope.id == .Block) return @fieldParentPtr(Scope.Block, "base", scope); + } +} + +fn transLookupZigIdentifier(inner: *Scope, c_name: []const u8) []const u8 { + var scope = inner; + while (true) : (scope = scope.parent orelse return c_name) { + if (scope.id == .Var) { + const var_scope = @ptrCast(*const Scope.Var, scope); + if (std.mem.eql(u8, var_scope.c_name, c_name)) return var_scope.zig_name; + } + } +} + +fn transCPtrCast( + rp: RestorePoint, + loc: ZigClangSourceLocation, + dst_type: ZigClangQualType, + src_type: ZigClangQualType, + expr: *ast.Node, +) !*ast.Node { + const ty = ZigClangQualType_getTypePtr(dst_type); + const child_type = ZigClangType_getPointeeType(ty); + + // Implicit downcasting from higher to lower alignment values is forbidden, + // use @alignCast to side-step this problem + const ptrcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrCast"); + const dst_type_node = try transType(rp, ty, loc); + try ptrcast_node.params.push(dst_type_node); + _ = try appendToken(rp.c, .Comma, ","); + + if (ZigClangType_isVoidType(qualTypeCanon(child_type))) { + // void has 1-byte alignment, so @alignCast is not needed + try ptrcast_node.params.push(expr); + } else { + const aligncast_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignCast"); + const alignof_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignOf"); + const child_type_node = try transQualType(rp, child_type, loc); + try alignof_node.params.push(child_type_node); + alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + try aligncast_node.params.push(&alignof_node.base); + _ = try appendToken(rp.c, .Comma, ","); + try aligncast_node.params.push(expr); + aligncast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + try ptrcast_node.params.push(&aligncast_node.base); + } + ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); + + return &ptrcast_node.base; +} + +fn maybeSuppressResult( + rp: RestorePoint, + scope: *Scope, + used: ResultUsed, + result: TransResult, +) !TransResult { + if (used == .used) return result; + // NOTE: This is backwards, but the semicolon must immediately follow the node. + _ = try appendToken(rp.c, .Semicolon, ";"); + const lhs = try appendIdentifier(rp.c, "_"); + const op_token = try appendToken(rp.c, .Equal, "="); + const op_node = try rp.c.a().create(ast.Node.InfixOp); + op_node.* = ast.Node.InfixOp{ + .base = ast.Node{ .id = .InfixOp }, + .op_token = op_token, + .lhs = lhs, + .op = .Assign, + .rhs = result.node, + }; + return TransResult{ + .node = &op_node.base, + .child_scope = scope, + .node_scope = scope, + }; +} + fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void { try c.tree.root_node.decls.push(decl_node); } @@ -376,11 +893,263 @@ fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSou return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc); } +fn qualTypeIsPtr(qt: ZigClangQualType) bool { + return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer; +} + +fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool { + const ty = ZigClangQualType_getTypePtr(qt); + if (ZigClangType_getTypeClass(ty) == .Paren) { + const paren_type = @ptrCast(*const ZigClangParenType, ty); + const inner_type = ZigClangParenType_getInnerType(paren_type); + return ZigClangQualType_getTypeClass(inner_type) == .FunctionProto; + } + if (ZigClangType_getTypeClass(ty) == .Attributed) { + const attr_type = @ptrCast(*const ZigClangAttributedType, ty); + return qualTypeChildIsFnProto(ZigClangAttributedType_getEquivalentType(attr_type)); + } + return false; +} + fn qualTypeCanon(qt: ZigClangQualType) *const ZigClangType { const canon = ZigClangQualType_getCanonicalType(qt); return ZigClangQualType_getTypePtr(canon); } +fn getExprQualType(c: *Context, expr: *const ZigClangExpr) ZigClangQualType { + blk: { + // If this is a C `char *`, turn it into a `const char *` + if (ZigClangExpr_getStmtClass(expr) != .ImplicitCastExprClass) break :blk; + const cast_expr = @ptrCast(*const ZigClangImplicitCastExpr, expr); + if (ZigClangImplicitCastExpr_getCastKind(cast_expr) != .ArrayToPointerDecay) break :blk; + const sub_expr = ZigClangImplicitCastExpr_getSubExpr(cast_expr); + if (ZigClangExpr_getStmtClass(sub_expr) != .StringLiteralClass) break :blk; + const array_qt = ZigClangExpr_getType(sub_expr); + const array_type = @ptrCast(*const ZigClangArrayType, ZigClangQualType_getTypePtr(array_qt)); + var pointee_qt = ZigClangArrayType_getElementType(array_type); + ZigClangQualType_addConst(&pointee_qt); + return ZigClangASTContext_getPointerType(c.clang_context, pointee_qt); + } + return ZigClangExpr_getType(expr); +} + +fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocation) bool { + switch (ZigClangType_getTypeClass(ty)) { + .Builtin => { + const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); + return ZigClangBuiltinType_getKind(builtin_ty) == .Void; + }, + .Record => { + const record_ty = @ptrCast(*const ZigClangRecordType, ty); + const record_decl = ZigClangRecordType_getDecl(record_ty); + return (ZigClangRecordDecl_getDefinition(record_decl) == null); + }, + .Elaborated => { + const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty); + const qt = ZigClangElaboratedType_getNamedType(elaborated_ty); + return typeIsOpaque(c, ZigClangQualType_getTypePtr(qt), loc); + }, + .Typedef => { + const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); + const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); + const underlying_type = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); + return typeIsOpaque(c, ZigClangQualType_getTypePtr(underlying_type), loc); + }, + else => return false, + } +} + +fn cIsUnsignedInteger(qt: ZigClangQualType) bool { + const c_type = qualTypeCanon(qt); + if (ZigClangType_getTypeClass(c_type) != .Builtin) return false; + const builtin_ty = @ptrCast(*const ZigClangBuiltinType, c_type); + return switch (ZigClangBuiltinType_getKind(builtin_ty)) { + .Char_U, + .UChar, + .Char_S, + .UShort, + .UInt, + .ULong, + .ULongLong, + .UInt128, + .WChar_U, + => true, + else => false, + }; +} + +fn transCreateNodeAssign( + rp: RestorePoint, + scope: *Scope, + result_used: ResultUsed, + lhs: *const ZigClangExpr, + rhs: *const ZigClangExpr, +) !*ast.Node.InfixOp { + // common case + // c: lhs = rhs + // zig: lhs = rhs + if (result_used == .unused) { + const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); + const eq_token = try appendToken(rp.c, .Equal, "="); + const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); + _ = try appendToken(rp.c, .Semicolon, ";"); + + const node = try rp.c.a().create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ + .base = ast.Node{ .id = .InfixOp }, + .op_token = eq_token, + .lhs = lhs_node.node, + .op = .Assign, + .rhs = rhs_node.node, + }; + return node; + } + + // worst case + // c: lhs = rhs + // zig: (x: { + // zig: const _tmp = rhs; + // zig: lhs = _tmp; + // zig: break :x _tmp + // zig: }) + return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangExpr_getBeginLoc(lhs), "TODO: worst case assign op expr"); +} + +fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.BuiltinCall { + const builtin_token = try appendToken(c, .Builtin, name); + _ = try appendToken(c, .LParen, "("); + const node = try c.a().create(ast.Node.BuiltinCall); + node.* = ast.Node.BuiltinCall{ + .base = ast.Node{ .id = .BuiltinCall }, + .builtin_token = builtin_token, + .params = ast.Node.BuiltinCall.ParamList.init(c.a()), + .rparen_token = undefined, // set after appending args + }; + return node; +} + +fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp { + _ = try appendToken(c, .LParen, "("); + const node = try c.a().create(ast.Node.SuffixOp); + node.* = ast.Node.SuffixOp{ + .base = ast.Node{ .id = .SuffixOp }, + .lhs = fn_expr, + .op = ast.Node.SuffixOp.Op{ + .Call = ast.Node.SuffixOp.Op.Call{ + .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()), + .async_attr = null, + }, + }, + .rtoken = undefined, // set after appending args + }; + return node; +} + +fn transCreateNodePrefixOp( + c: *Context, + op: ast.Node.PrefixOp.Op, + op_tok_id: std.zig.Token.Id, + bytes: []const u8, +) !*ast.Node.PrefixOp { + const node = try c.a().create(ast.Node.PrefixOp); + node.* = ast.Node.PrefixOp{ + .base = ast.Node{ .id = .PrefixOp }, + .op_token = try appendToken(c, op_tok_id, bytes), + .op = op, + .rhs = undefined, // translate and set afterward + }; + return node; +} + +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 { + const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined; + const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value); + const op_token = try appendToken(rp.c, op_tok_id, bytes); + const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); + const node = try rp.c.a().create(ast.Node.InfixOp); + node.* = ast.Node.InfixOp{ + .base = ast.Node{ .id = .InfixOp }, + .op_token = op_token, + .lhs = lhs.node, + .op = op, + .rhs = rhs.node, + }; + if (!grouped) return &node.base; + const rparen = try appendToken(rp.c, .RParen, ")"); + const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); + grouped_expr.* = ast.Node.GroupedExpression{ + .base = ast.Node{ .id = .GroupedExpression }, + .lparen = lparen, + .expr = &node.base, + .rparen = rparen, + }; + return &grouped_expr.base; +} + +fn transCreateNodePtrType( + c: *Context, + is_const: bool, + is_volatile: bool, + op_tok_id: std.zig.Token.Id, + bytes: []const u8, +) !*ast.Node.PrefixOp { + const node = try c.a().create(ast.Node.PrefixOp); + node.* = ast.Node.PrefixOp{ + .base = ast.Node{ .id = .PrefixOp }, + .op_token = try appendToken(c, op_tok_id, bytes), + .op = ast.Node.PrefixOp.Op{ + .PtrType = ast.Node.PrefixOp.PtrInfo{ + .allowzero_token = null, + .align_info = null, + .const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null, + .volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null, + }, + }, + .rhs = undefined, // translate and set afterward + }; + return node; +} + +fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node { + const num_limbs = ZigClangAPSInt_getNumWords(int.?); + var big = try std.math.big.Int.initCapacity(c.a(), num_limbs); + defer big.deinit(); + const data = ZigClangAPSInt_getRawData(int.?); + var i: usize = 0; + while (i < num_limbs) : (i += 1) big.limbs[i] = data[i]; + const str = big.toString(c.a(), 10) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + else => unreachable, + }; + const token = try appendToken(c, .IntegerLiteral, str); + const node = try c.a().create(ast.Node.IntegerLiteral); + node.* = ast.Node.IntegerLiteral{ + .base = ast.Node{ .id = .IntegerLiteral }, + .token = token, + }; + return &node.base; +} + +fn transCreateNodeReturnExpr(c: *Context) !*ast.Node { + const ltoken = try appendToken(c, .Keyword_return, "return"); + const node = try c.a().create(ast.Node.ControlFlowExpression); + node.* = ast.Node.ControlFlowExpression{ + .base = ast.Node{ .id = .ControlFlowExpression }, + .ltoken = ltoken, + .kind = .Return, + .rhs = null, + }; + return &node.base; +} + const RestorePoint = struct { c: *Context, token_index: ast.TokenIndex, @@ -429,9 +1198,43 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour }, .FunctionProto => { const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); - const fn_proto = try transFnProto(rp, fn_proto_ty, source_loc, null); + const fn_proto = try transFnProto(rp, fn_proto_ty, source_loc, null, false); return &fn_proto.base; }, + .Paren => { + const paren_ty = @ptrCast(*const ZigClangParenType, ty); + return transQualType(rp, ZigClangParenType_getInnerType(paren_ty), source_loc); + }, + .Pointer => { + const child_qt = ZigClangType_getPointeeType(ty); + if (qualTypeChildIsFnProto(child_qt)) { + const optional_node = try transCreateNodePrefixOp(rp.c, .OptionalType, .QuestionMark, "?"); + optional_node.rhs = try transQualType(rp, child_qt, source_loc); + return &optional_node.base; + } + if (typeIsOpaque(rp.c, ZigClangQualType_getTypePtr(child_qt), source_loc)) { + const optional_node = try transCreateNodePrefixOp(rp.c, .OptionalType, .QuestionMark, "?"); + const pointer_node = try transCreateNodePtrType( + rp.c, + ZigClangQualType_isConstQualified(child_qt), + ZigClangQualType_isVolatileQualified(child_qt), + .Asterisk, + "*", + ); + optional_node.rhs = &pointer_node.base; + pointer_node.rhs = try transQualType(rp, child_qt, source_loc); + return &optional_node.base; + } + const pointer_node = try transCreateNodePtrType( + rp.c, + ZigClangQualType_isConstQualified(child_qt), + ZigClangQualType_isVolatileQualified(child_qt), + .BracketStarCBracket, + "[*c]", + ); + pointer_node.rhs = try transQualType(rp, child_qt, source_loc); + return &pointer_node.base; + }, else => { const type_name = rp.c.str(ZigClangType_getTypeClassName(ty)); return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", type_name); @@ -465,6 +1268,7 @@ fn transFnProto( fn_proto_ty: *const ZigClangFunctionProtoType, source_loc: ZigClangSourceLocation, fn_decl_context: ?FnDeclContext, + is_pub: bool, ) !*ast.Node.FnProto { const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_proto_ty); const cc = try transCC(rp, fn_ty, source_loc); @@ -475,7 +1279,7 @@ fn transFnProto( return revertAndWarn(rp, error.UnsupportedType, source_loc, "TODO: implement parameters for FunctionProto in transType"); } - return finishTransFnProto(rp, fn_ty, source_loc, fn_decl_context, is_var_args, cc); + return finishTransFnProto(rp, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub); } fn transFnNoProto( @@ -483,10 +1287,11 @@ fn transFnNoProto( fn_ty: *const ZigClangFunctionType, source_loc: ZigClangSourceLocation, fn_decl_context: ?FnDeclContext, + is_pub: bool, ) !*ast.Node.FnProto { const cc = try transCC(rp, fn_ty, source_loc); const is_var_args = if (fn_decl_context) |ctx| !ctx.is_export else true; - return finishTransFnProto(rp, fn_ty, source_loc, fn_decl_context, is_var_args, cc); + return finishTransFnProto(rp, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub); } fn finishTransFnProto( @@ -496,18 +1301,20 @@ fn finishTransFnProto( fn_decl_context: ?FnDeclContext, is_var_args: bool, cc: CallingConvention, + is_pub: bool, ) !*ast.Node.FnProto { const is_export = if (fn_decl_context) |ctx| ctx.is_export else false; + const is_extern = if (fn_decl_context) |ctx| !ctx.has_body else true; // TODO check for always_inline attribute // TODO check for align attribute // pub extern fn name(...) T - const pub_tok = try appendToken(rp.c, .Keyword_pub, "pub"); + const pub_tok = if (is_pub) try appendToken(rp.c, .Keyword_pub, "pub") else null; const cc_tok = if (cc == .Stdcall) try appendToken(rp.c, .Keyword_stdcallcc, "stdcallcc") else null; const extern_export_inline_tok = if (is_export) try appendToken(rp.c, .Keyword_export, "export") - else if (cc == .C) + else if (cc == .C and is_extern) try appendToken(rp.c, .Keyword_extern, "extern") else null; @@ -657,7 +1464,7 @@ fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, .start = start_index, .end = end_index, }; - try c.source_buffer.appendByte('\n'); + try c.source_buffer.appendByte(' '); return token_index; } diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 6ea6dc4eff..154803f884 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -444,9 +444,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { const char *extern_str = extern_string(node->data.fn_proto.is_extern); const char *export_str = export_string(node->data.fn_proto.is_export); const char *inline_str = inline_string(node->data.fn_proto.is_inline); - fprintf(ar->f, "%s%s%s%sfn", pub_str, inline_str, export_str, extern_str); + fprintf(ar->f, "%s%s%s%sfn ", pub_str, inline_str, export_str, extern_str); if (node->data.fn_proto.name != nullptr) { - fprintf(ar->f, " "); print_symbol(ar, node->data.fn_proto.name); } fprintf(ar->f, "("); diff --git a/src/codegen.cpp b/src/codegen.cpp index 94e2a98b2f..234b28219b 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3837,7 +3837,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr return result_loc; } else if (handle_is_ptr(src_return_type)) { LLVMValueRef store_instr = LLVMBuildStore(g->builder, result, result_loc); - LLVMSetAlignment(store_instr, LLVMGetAlignment(result_loc)); + LLVMSetAlignment(store_instr, get_ptr_align(g, instruction->result_loc->value.type)); return result_loc; } else { return result; diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index 28062ea69f..7c87f31125 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #if __GNUC__ >= 8 @@ -1287,6 +1288,20 @@ static_assert((clang::StringLiteral::StringKind)ZigClangStringLiteral_StringKind static_assert((clang::StringLiteral::StringKind)ZigClangStringLiteral_StringKind_UTF16 == clang::StringLiteral::UTF16, ""); static_assert((clang::StringLiteral::StringKind)ZigClangStringLiteral_StringKind_UTF32 == clang::StringLiteral::UTF32, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_Uninitialized == clang::APValue::ValueKind::Uninitialized, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_Int == clang::APValue::ValueKind::Int, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_Float == clang::APValue::ValueKind::Float, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_ComplexInt == clang::APValue::ValueKind::ComplexInt, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_ComplexFloat == clang::APValue::ValueKind::ComplexFloat, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_LValue == clang::APValue::ValueKind::LValue, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_Vector == clang::APValue::ValueKind::Vector, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_Array == clang::APValue::ValueKind::Array, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_Struct == clang::APValue::ValueKind::Struct, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_Union == clang::APValue::ValueKind::Union, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_MemberPointer == clang::APValue::ValueKind::MemberPointer, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_AddrLabelDiff == clang::APValue::ValueKind::AddrLabelDiff, ""); + +static_assert(sizeof(ZigClangAPValue) == sizeof(clang::APValue), ""); static_assert(sizeof(ZigClangSourceLocation) == sizeof(clang::SourceLocation), ""); static ZigClangSourceLocation bitcast(clang::SourceLocation src) { @@ -1312,6 +1327,13 @@ static clang::QualType bitcast(ZigClangQualType src) { return dest; } +static_assert(sizeof(ZigClangExprEvalResult) == sizeof(clang::Expr::EvalResult), ""); +static ZigClangExprEvalResult bitcast(clang::Expr::EvalResult src) { + ZigClangExprEvalResult dest; + memcpy(&dest, static_cast(&src), sizeof(ZigClangExprEvalResult)); + return dest; +} + static_assert(sizeof(ZigClangAPValueLValueBase) == sizeof(clang::APValue::LValueBase), ""); static ZigClangAPValueLValueBase bitcast(clang::APValue::LValueBase src) { ZigClangAPValueLValueBase dest; @@ -1331,6 +1353,12 @@ static ZigClangCompoundStmt_const_body_iterator bitcast(clang::CompoundStmt::con return dest; } +static_assert(sizeof(ZigClangDeclStmt_const_decl_iterator) == sizeof(clang::DeclStmt::const_decl_iterator), ""); +static ZigClangDeclStmt_const_decl_iterator bitcast(clang::DeclStmt::const_decl_iterator src) { + ZigClangDeclStmt_const_decl_iterator dest; + memcpy(&dest, static_cast(&src), sizeof(ZigClangDeclStmt_const_decl_iterator)); + return dest; +} ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const ZigClangSourceManager *self, ZigClangSourceLocation Loc) @@ -1381,7 +1409,7 @@ ZigClangSourceManager *ZigClangASTUnit_getSourceManager(ZigClangASTUnit *self) { return reinterpret_cast(result); } -bool ZigClangASTUnit_visitLocalTopLevelDecls(ZigClangASTUnit *self, void *context, +bool ZigClangASTUnit_visitLocalTopLevelDecls(ZigClangASTUnit *self, void *context, bool (*Fn)(void *context, const ZigClangDecl *decl)) { return reinterpret_cast(self)->visitLocalTopLevelDecls(context, @@ -1540,6 +1568,11 @@ const ZigClangType *ZigClangQualType_getTypePtr(ZigClangQualType self) { return reinterpret_cast(ty); } +ZigClangTypeClass ZigClangQualType_getTypeClass(ZigClangQualType self) { + clang::QualType ty = bitcast(self); + return (ZigClangTypeClass)(ty->getTypeClass()); +} + void ZigClangQualType_addConst(ZigClangQualType *self) { reinterpret_cast(self)->addConst(); } @@ -1815,6 +1848,21 @@ void ZigClangASTUnit_delete(struct ZigClangASTUnit *self) { delete reinterpret_cast(self); } +struct ZigClangQualType ZigClangVarDecl_getType(const struct ZigClangVarDecl *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->getType()); +} + +const struct ZigClangExpr *ZigClangVarDecl_getInit(const struct ZigClangVarDecl *self) { + auto casted = reinterpret_cast(self); + return reinterpret_cast(casted->getInit()); +} + +enum ZigClangVarDecl_TLSKind ZigClangVarDecl_getTLSKind(const ZigClangVarDecl *self) { + auto casted = reinterpret_cast(self); + return (ZigClangVarDecl_TLSKind)casted->getTLSKind(); +} + enum ZigClangBuiltinTypeKind ZigClangBuiltinType_getKind(const struct ZigClangBuiltinType *self) { auto casted = reinterpret_cast(self); return (ZigClangBuiltinTypeKind)casted->getKind(); @@ -1862,6 +1910,16 @@ ZigClangCompoundStmt_const_body_iterator ZigClangCompoundStmt_body_end(const str return bitcast(casted->body_end()); } +ZigClangDeclStmt_const_decl_iterator ZigClangDeclStmt_decl_begin(const struct ZigClangDeclStmt *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->decl_begin()); +} + +ZigClangDeclStmt_const_decl_iterator ZigClangDeclStmt_decl_end(const struct ZigClangDeclStmt *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->decl_end()); +} + unsigned ZigClangAPFloat_convertToHexString(const ZigClangAPFloat *self, char *DST, unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM) { @@ -1888,3 +1946,104 @@ const struct ZigClangStringLiteral *ZigClangPredefinedExpr_getFunctionName( const clang::StringLiteral *result = casted->getFunctionName(); return reinterpret_cast(result); } + +ZigClangSourceLocation ZigClangImplicitCastExpr_getBeginLoc(const struct ZigClangImplicitCastExpr *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->getBeginLoc()); +} + +enum ZigClangCK ZigClangImplicitCastExpr_getCastKind(const struct ZigClangImplicitCastExpr *self) { + auto casted = reinterpret_cast(self); + return (ZigClangCK)casted->getCastKind(); +} + +const struct ZigClangExpr *ZigClangImplicitCastExpr_getSubExpr(const struct ZigClangImplicitCastExpr *self) { + auto casted = reinterpret_cast(self); + return reinterpret_cast(casted->getSubExpr()); +} + +struct ZigClangQualType ZigClangArrayType_getElementType(const struct ZigClangArrayType *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->getElementType()); +} + +const struct ZigClangValueDecl *ZigClangDeclRefExpr_getDecl(const struct ZigClangDeclRefExpr *self) { + auto casted = reinterpret_cast(self); + return reinterpret_cast(casted->getDecl()); +} + +struct ZigClangQualType ZigClangParenType_getInnerType(const struct ZigClangParenType *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->getInnerType()); +} + +struct ZigClangQualType ZigClangAttributedType_getEquivalentType(const struct ZigClangAttributedType *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->getEquivalentType()); +} + +struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->getNamedType()); +} + +struct ZigClangSourceLocation ZigClangCStyleCastExpr_getBeginLoc(const struct ZigClangCStyleCastExpr *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->getBeginLoc()); +} + +const struct ZigClangExpr *ZigClangCStyleCastExpr_getSubExpr(const struct ZigClangCStyleCastExpr *self) { + auto casted = reinterpret_cast(self); + return reinterpret_cast(casted->getSubExpr()); +} + +struct ZigClangQualType ZigClangCStyleCastExpr_getType(const struct ZigClangCStyleCastExpr *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->getType()); +} + +bool ZigClangIntegerLiteral_EvaluateAsInt(const struct ZigClangIntegerLiteral *self, struct ZigClangExprEvalResult *result, const struct ZigClangASTContext *ctx) { + auto casted_self = reinterpret_cast(self); + auto casted_ctx = reinterpret_cast(ctx); + clang::Expr::EvalResult eval_result; + if (!casted_self->EvaluateAsInt(eval_result, *casted_ctx)) { + return false; + } + *result = bitcast(eval_result); + return true; +} + +struct ZigClangSourceLocation ZigClangIntegerLiteral_getBeginLoc(const struct ZigClangIntegerLiteral *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->getBeginLoc()); +} + +const struct ZigClangExpr *ZigClangReturnStmt_getRetValue(const struct ZigClangReturnStmt *self) { + auto casted = reinterpret_cast(self); + return reinterpret_cast(casted->getRetValue()); +} + +enum ZigClangBO ZigClangBinaryOperator_getOpcode(const struct ZigClangBinaryOperator *self) { + auto casted = reinterpret_cast(self); + return (ZigClangBO)casted->getOpcode(); +} + +struct ZigClangSourceLocation ZigClangBinaryOperator_getBeginLoc(const struct ZigClangBinaryOperator *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->getBeginLoc()); +} + +const struct ZigClangExpr *ZigClangBinaryOperator_getLHS(const struct ZigClangBinaryOperator *self) { + auto casted = reinterpret_cast(self); + return reinterpret_cast(casted->getLHS()); +} + +const struct ZigClangExpr *ZigClangBinaryOperator_getRHS(const struct ZigClangBinaryOperator *self) { + auto casted = reinterpret_cast(self); + return reinterpret_cast(casted->getRHS()); +} + +struct ZigClangQualType ZigClangBinaryOperator_getType(const struct ZigClangBinaryOperator *self) { + auto casted = reinterpret_cast(self); + return bitcast(casted->getType()); +} diff --git a/src/zig_clang.h b/src/zig_clang.h index 1bdf34fc2f..183aaef681 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -30,6 +30,38 @@ struct ZigClangAPValueLValueBase { unsigned Version; }; +enum ZigClangAPValue_ValueKind { + ZigClangAPValue_ValueKind_Uninitialized, + ZigClangAPValue_ValueKind_Int, + ZigClangAPValue_ValueKind_Float, + ZigClangAPValue_ValueKind_ComplexInt, + ZigClangAPValue_ValueKind_ComplexFloat, + ZigClangAPValue_ValueKind_LValue, + ZigClangAPValue_ValueKind_Vector, + ZigClangAPValue_ValueKind_Array, + ZigClangAPValue_ValueKind_Struct, + ZigClangAPValue_ValueKind_Union, + ZigClangAPValue_ValueKind_MemberPointer, + ZigClangAPValue_ValueKind_AddrLabelDiff +}; + +struct ZigClangAPValue { + enum ZigClangAPValue_ValueKind Kind; + // experimentally-derived size of clang::APValue::DataType +#ifdef _WIN32 + char Data[52]; +#else + char Data[68]; +#endif +}; + +struct ZigClangExprEvalResult { + bool HasSideEffects; + bool HasUndefinedBehavior; + void *SmallVectorImpl; + ZigClangAPValue Val; +}; + struct ZigClangAPValue; struct ZigClangAPSInt; struct ZigClangAPFloat; @@ -105,6 +137,7 @@ struct ZigClangFunctionType; struct ZigClangPredefinedExpr; typedef struct ZigClangStmt *const * ZigClangCompoundStmt_const_body_iterator; +typedef struct ZigClangDecl *const * ZigClangDeclStmt_const_decl_iterator; enum ZigClangBO { ZigClangBO_PtrMemD, @@ -732,6 +765,12 @@ enum ZigClangStringLiteral_StringKind { ZigClangStringLiteral_StringKind_UTF32, }; +enum ZigClangVarDecl_TLSKind { + ZigClangVarDecl_TLSKind_None, + ZigClangVarDecl_TLSKind_Static, + ZigClangVarDecl_TLSKind_Dynamic, +}; + ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const struct ZigClangSourceManager *, struct ZigClangSourceLocation Loc); ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const struct ZigClangSourceManager *, @@ -754,7 +793,7 @@ ZIG_EXTERN_C void ZigClangErrorMsg_delete(struct Stage2ErrorMsg *ptr, size_t len ZIG_EXTERN_C struct ZigClangASTContext *ZigClangASTUnit_getASTContext(struct ZigClangASTUnit *); ZIG_EXTERN_C struct ZigClangSourceManager *ZigClangASTUnit_getSourceManager(struct ZigClangASTUnit *); -ZIG_EXTERN_C bool ZigClangASTUnit_visitLocalTopLevelDecls(struct ZigClangASTUnit *, void *context, +ZIG_EXTERN_C bool ZigClangASTUnit_visitLocalTopLevelDecls(struct ZigClangASTUnit *, void *context, bool (*Fn)(void *context, const struct ZigClangDecl *decl)); ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangRecordType_getDecl(const struct ZigClangRecordType *record_ty); @@ -789,6 +828,10 @@ ZIG_EXTERN_C const char *ZigClangDecl_getName_bytes_begin(const struct ZigClangD ZIG_EXTERN_C enum ZigClangDeclKind ZigClangDecl_getKind(const struct ZigClangDecl *decl); ZIG_EXTERN_C const char *ZigClangDecl_getDeclKindName(const struct ZigClangDecl *decl); +ZIG_EXTERN_C struct ZigClangQualType ZigClangVarDecl_getType(const struct ZigClangVarDecl *); +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangVarDecl_getInit(const struct ZigClangVarDecl *var_decl); +ZIG_EXTERN_C enum ZigClangVarDecl_TLSKind ZigClangVarDecl_getTLSKind(const struct ZigClangVarDecl *var_decl); + ZIG_EXTERN_C bool ZigClangSourceLocation_eq(struct ZigClangSourceLocation a, struct ZigClangSourceLocation b); ZIG_EXTERN_C const struct ZigClangTypedefNameDecl *ZigClangTypedefType_getDecl(const struct ZigClangTypedefType *); @@ -796,6 +839,7 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangTypedefNameDecl_getUnderlyingType(c ZIG_EXTERN_C struct ZigClangQualType ZigClangQualType_getCanonicalType(struct ZigClangQualType); ZIG_EXTERN_C const struct ZigClangType *ZigClangQualType_getTypePtr(struct ZigClangQualType); +ZIG_EXTERN_C enum ZigClangTypeClass ZigClangQualType_getTypeClass(struct ZigClangQualType); ZIG_EXTERN_C void ZigClangQualType_addConst(struct ZigClangQualType *); ZIG_EXTERN_C bool ZigClangQualType_eq(struct ZigClangQualType, struct ZigClangQualType); ZIG_EXTERN_C bool ZigClangQualType_isConstQualified(struct ZigClangQualType); @@ -846,6 +890,9 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangFunctionProtoType_getParamType(cons ZIG_EXTERN_C ZigClangCompoundStmt_const_body_iterator ZigClangCompoundStmt_body_begin(const struct ZigClangCompoundStmt *self); ZIG_EXTERN_C ZigClangCompoundStmt_const_body_iterator ZigClangCompoundStmt_body_end(const struct ZigClangCompoundStmt *self); +ZIG_EXTERN_C ZigClangDeclStmt_const_decl_iterator ZigClangDeclStmt_decl_begin(const struct ZigClangDeclStmt *self); +ZIG_EXTERN_C ZigClangDeclStmt_const_decl_iterator ZigClangDeclStmt_decl_end(const struct ZigClangDeclStmt *self); + ZIG_EXTERN_C unsigned ZigClangAPFloat_convertToHexString(const struct ZigClangAPFloat *self, char *DST, unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM); @@ -855,4 +902,34 @@ ZIG_EXTERN_C const char *ZigClangStringLiteral_getString_bytes_begin_size(const ZIG_EXTERN_C const struct ZigClangStringLiteral *ZigClangPredefinedExpr_getFunctionName( const struct ZigClangPredefinedExpr *self); + +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangImplicitCastExpr_getBeginLoc(const struct ZigClangImplicitCastExpr *); +ZIG_EXTERN_C enum ZigClangCK ZigClangImplicitCastExpr_getCastKind(const struct ZigClangImplicitCastExpr *); +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangImplicitCastExpr_getSubExpr(const struct ZigClangImplicitCastExpr *); + +ZIG_EXTERN_C struct ZigClangQualType ZigClangArrayType_getElementType(const struct ZigClangArrayType *); + +ZIG_EXTERN_C const struct ZigClangValueDecl *ZigClangDeclRefExpr_getDecl(const struct ZigClangDeclRefExpr *); + +ZIG_EXTERN_C struct ZigClangQualType ZigClangParenType_getInnerType(const struct ZigClangParenType *); + +ZIG_EXTERN_C struct ZigClangQualType ZigClangAttributedType_getEquivalentType(const struct ZigClangAttributedType *); + +ZIG_EXTERN_C struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *); + +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangCStyleCastExpr_getBeginLoc(const struct ZigClangCStyleCastExpr *); +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangCStyleCastExpr_getSubExpr(const struct ZigClangCStyleCastExpr *); +ZIG_EXTERN_C struct ZigClangQualType ZigClangCStyleCastExpr_getType(const struct ZigClangCStyleCastExpr *); + +ZIG_EXTERN_C bool ZigClangIntegerLiteral_EvaluateAsInt(const struct ZigClangIntegerLiteral *, struct ZigClangExprEvalResult *, const struct ZigClangASTContext *); +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangIntegerLiteral_getBeginLoc(const struct ZigClangIntegerLiteral *); + +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangReturnStmt_getRetValue(const struct ZigClangReturnStmt *); + +ZIG_EXTERN_C enum ZigClangBO ZigClangBinaryOperator_getOpcode(const struct ZigClangBinaryOperator *); +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangBinaryOperator_getBeginLoc(const struct ZigClangBinaryOperator *); +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangBinaryOperator_getLHS(const struct ZigClangBinaryOperator *); +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangBinaryOperator_getRHS(const struct ZigClangBinaryOperator *); +ZIG_EXTERN_C struct ZigClangQualType ZigClangBinaryOperator_getType(const struct ZigClangBinaryOperator *); + #endif diff --git a/test/translate_c.zig b/test/translate_c.zig index f25d708f32..d2a5b72b2b 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -18,28 +18,80 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn bar() c_int; ); + cases.add_both("simple var decls", + \\void foo(void) { + \\ int a; + \\ char b = 123; + \\ const int c; + \\ const unsigned d = 440; + \\} + , + \\pub fn foo() void { + \\ var a: c_int = undefined; + \\ var b: u8 = u8(123); + \\ const c: c_int = undefined; + \\ const d: c_uint = c_uint(440); + \\} + ); + + cases.add_both("ignore result, explicit function arguments", + \\void foo(void) { + \\ int a; + \\ 1; + \\ "hey"; + \\ 1 + 1; + \\ 1 - 1; + \\ a = 1; + \\} + , + \\pub fn foo() void { + \\ var a: c_int = undefined; + \\ _ = 1; + \\ _ = c"hey"; + \\ _ = (1 + 1); + \\ _ = (1 - 1); + \\ a = 1; + \\} + ); + /////////////// Cases that pass for only stage2 //////////////// - cases.add_2("Parameterless function prototypes", + // TODO: restore these tests after removing "import mode" concept + // https://github.com/ziglang/zig/issues/2780 + + // cases.add_2("Parameterless function prototypes", + // \\void a() {} + // \\void b(void) {} + // \\void c(); + // \\void d(void); + // , + // \\pub export fn a() void {} + // \\pub export fn b() void {} + // \\pub extern fn c(...) void; + // \\pub extern fn d() void; + // ); + + // cases.add_2("simple function definition", + // \\void foo(void) {} + // \\static void bar(void) {} + // , + // \\pub export fn foo() void {} + // \\pub extern fn bar() void {} + // ); + + cases.add_2("parameterless function prototypes", \\void a() {} \\void b(void) {} \\void c(); \\void d(void); , - \\pub export fn a() void {} - \\pub export fn b() void {} + \\pub fn a(...) void {} + \\pub fn b() void {} \\pub extern fn c(...) void; \\pub extern fn d() void; ); - cases.add_2("simple function definition", - \\void foo(void) {} - \\static void bar(void) {} - , - \\pub export fn foo() void {} - \\pub extern fn bar() void {} - ); - /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// + cases.add("typedef of function in struct field", \\typedef void lws_callback_function(void); \\struct Foo { @@ -47,9 +99,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ lws_callback_function *callback_http; \\}; , - \\pub const lws_callback_function = extern fn() void; + \\pub const lws_callback_function = extern fn () void; \\pub const struct_Foo = extern struct { - \\ func: ?extern fn() void, + \\ func: ?extern fn () void, \\ callback_http: ?lws_callback_function, \\}; ); @@ -68,13 +120,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; ); + cases.add_both("simple function definition", + \\void foo(void) {} + \\static void bar(void) {} + , + \\pub fn foo() void {} + \\pub fn bar() void {} + ); + cases.add("macro with left shift", \\#define REDISMODULE_READ (1<<0) , \\pub const REDISMODULE_READ = 1 << 0; ); - cases.add("casting pointers to ints and ints to pointers", + cases.add_both("casting pointers to ints and ints to pointers", \\void foo(void); \\void bar(void) { \\ void *func_ptr = foo; @@ -84,7 +144,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn foo() void; \\pub fn bar() void { \\ var func_ptr: ?*c_void = @ptrCast(?*c_void, foo); - \\ var typed_func_ptr: ?extern fn() void = @intToPtr(?extern fn() void, c_ulong(@ptrToInt(func_ptr))); + \\ var typed_func_ptr: ?extern fn () void = @intToPtr(?extern fn () void, c_ulong(@ptrToInt(func_ptr))); \\} ); @@ -159,7 +219,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} ); - cases.add("ignore result", + cases.add("ignore result, no function arguments", \\void foo() { \\ int a; \\ 1; @@ -260,7 +320,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void; ); - cases.add("noreturn attribute", + cases.add_both("noreturn attribute", \\void foo(void) __attribute__((noreturn)); , \\pub extern fn foo() noreturn; @@ -384,7 +444,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; , \\pub const struct_Foo = extern struct { - \\ derp: ?extern fn([*c]struct_Foo) void, + \\ derp: ?extern fn ([*c]struct_Foo) void, \\}; , \\pub const Foo = struct_Foo; @@ -467,13 +527,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\extern char (*fn_ptr2)(int, float); \\#define bar fn_ptr2 , - \\pub extern var fn_ptr: ?extern fn() void; + \\pub extern var fn_ptr: ?extern fn () void; , \\pub inline fn foo() void { \\ return fn_ptr.?(); \\} , - \\pub extern var fn_ptr2: ?extern fn(c_int, f32) u8; + \\pub extern var fn_ptr2: ?extern fn (c_int, f32) u8; , \\pub inline fn bar(arg0: c_int, arg1: f32) u8 { \\ return fn_ptr2.?(arg0, arg1); @@ -489,7 +549,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("__cdecl doesn't mess up function pointers", \\void foo(void (__cdecl *fn_ptr)(void)); , - \\pub extern fn foo(fn_ptr: ?extern fn() void) void; + \\pub extern fn foo(fn_ptr: ?extern fn () void) void; ); cases.add("comment after integer literal", @@ -1236,8 +1296,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ return 0; \\} \\pub export fn bar() void { - \\ var f: ?extern fn() void = foo; - \\ var b: ?extern fn() c_int = baz; + \\ var f: ?extern fn () void = foo; + \\ var b: ?extern fn () c_int = baz; \\ f.?(); \\ f.?(); \\ foo(); @@ -1372,9 +1432,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { , \\pub const GLbitfield = c_uint; , - \\pub const PFNGLCLEARPROC = ?extern fn(GLbitfield) void; + \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void; , - \\pub const OpenGLProc = ?extern fn() void; + \\pub const OpenGLProc = ?extern fn () void; , \\pub const union_OpenGLProcs = extern union { \\ ptr: [1]OpenGLProc,