| ... | ... | @@ -469,7 +469,6 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { |
| 469 | 469 | return visitFnDecl(c, def); |
| 470 | 470 | } |
| 471 | 471 | |
| 472 | | const rp = makeRestorePoint(c); |
| 473 | 472 | const fn_decl_loc = fn_decl.getLocation(); |
| 474 | 473 | const has_body = fn_decl.hasBody(); |
| 475 | 474 | const storage_class = fn_decl.getStorageClass(); |
| ... | ... | @@ -513,9 +512,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { |
| 513 | 512 | decl_ctx.has_body = false; |
| 514 | 513 | decl_ctx.storage_class = .Extern; |
| 515 | 514 | decl_ctx.is_export = false; |
| 516 | | try emitWarning(c, fn_decl_loc, "TODO unable to translate variadic function, demoted to declaration", .{}); |
| 515 | try warn(c, fn_decl_loc, "TODO unable to translate variadic function, demoted to declaration", .{}); |
| 517 | 516 | } |
| 518 | | break :blk transFnProto(rp, fn_decl, fn_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) { |
| 517 | break :blk transFnProto(c, fn_decl, fn_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) { |
| 519 | 518 | error.UnsupportedType => { |
| 520 | 519 | return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{}); |
| 521 | 520 | }, |
| ... | ... | @@ -524,7 +523,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { |
| 524 | 523 | }, |
| 525 | 524 | .FunctionNoProto => blk: { |
| 526 | 525 | const fn_no_proto_type = @ptrCast(*const clang.FunctionType, fn_type); |
| 527 | | break :blk transFnNoProto(rp, fn_no_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) { |
| 526 | break :blk transFnNoProto(c, fn_no_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) { |
| 528 | 527 | error.UnsupportedType => { |
| 529 | 528 | return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{}); |
| 530 | 529 | }, |
| ... | ... | @@ -535,13 +534,12 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { |
| 535 | 534 | }; |
| 536 | 535 | |
| 537 | 536 | if (!decl_ctx.has_body) { |
| 538 | | const semi_tok = try appendToken(c, .Semicolon, ";"); |
| 539 | 537 | return addTopLevelDecl(c, fn_name, &proto_node.base); |
| 540 | 538 | } |
| 541 | 539 | |
| 542 | 540 | // actual function definition with body |
| 543 | 541 | const body_stmt = fn_decl.getBody(); |
| 544 | | var block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, false); |
| 542 | var block_scope = try Scope.Block.init(c, &c.global_scope.base, false); |
| 545 | 543 | block_scope.return_type = return_qt; |
| 546 | 544 | defer block_scope.deinit(); |
| 547 | 545 | |
| ... | ... | @@ -559,34 +557,22 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { |
| 559 | 557 | const is_const = qual_type.isConstQualified(); |
| 560 | 558 | |
| 561 | 559 | const mangled_param_name = try block_scope.makeMangledName(c, param_name); |
| 560 | param.name = mangled_param_name; |
| 562 | 561 | |
| 563 | 562 | if (!is_const) { |
| 564 | 563 | const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{s}", .{mangled_param_name}); |
| 565 | 564 | const arg_name = try block_scope.makeMangledName(c, bare_arg_name); |
| 565 | param.name = arg_name; |
| 566 | 566 | |
| 567 | | const mut_tok = try appendToken(c, .Keyword_var, "var"); |
| 568 | | const name_tok = try appendIdentifier(c, mangled_param_name); |
| 569 | | const eq_token = try appendToken(c, .Equal, "="); |
| 570 | | const init_node = try transCreateNodeIdentifier(c, arg_name); |
| 571 | | const semicolon_token = try appendToken(c, .Semicolon, ";"); |
| 572 | | const node = try ast.Node.VarDecl.create(c.arena, .{ |
| 573 | | .mut_token = mut_tok, |
| 574 | | .name_token = name_tok, |
| 575 | | .semicolon_token = semicolon_token, |
| 576 | | }, .{ |
| 577 | | .eq_token = eq_token, |
| 578 | | .init_node = init_node, |
| 579 | | }); |
| 580 | | try block_scope.statements.append(&node.base); |
| 581 | | param.name_token = try appendIdentifier(c, arg_name); |
| 582 | | _ = try appendToken(c, .Colon, ":"); |
| 567 | const redecl_node = try Node.arg_redecl.create(c.arena, .{ .actual = mangled_param_name, .mangled = arg_name }); |
| 568 | try block_scope.statements.append(redecl_node); |
| 583 | 569 | } |
| 584 | 570 | |
| 585 | 571 | param_id += 1; |
| 586 | 572 | } |
| 587 | 573 | |
| 588 | 574 | const casted_body = @ptrCast(*const clang.CompoundStmt, body_stmt); |
| 589 | | transCompoundStmtInline(rp, &block_scope.base, casted_body, &block_scope) catch |err| switch (err) { |
| 575 | transCompoundStmtInline(c, &block_scope.base, casted_body, &block_scope) catch |err| switch (err) { |
| 590 | 576 | error.OutOfMemory => |e| return e, |
| 591 | 577 | error.UnsupportedTranslation, |
| 592 | 578 | error.UnsupportedType, |
| ... | ... | @@ -600,37 +586,31 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { |
| 600 | 586 | if (block_scope.statements.items.len > 0) { |
| 601 | 587 | var last = block_scope.statements.items[block_scope.statements.items.len - 1]; |
| 602 | 588 | while (true) { |
| 603 | | switch (last.tag) { |
| 604 | | .Block, .LabeledBlock => { |
| 605 | | const stmts = last.blockStatements(); |
| 606 | | if (stmts.len == 0) break; |
| 589 | switch (last.tag()) { |
| 590 | .block => { |
| 591 | const block = last.castTag(.block).?; |
| 592 | if (block.data.stmts.len == 0) break; |
| 607 | 593 | |
| 608 | | last = stmts[stmts.len - 1]; |
| 594 | last = block.data.stmts[block.data.stmts.len - 1]; |
| 609 | 595 | }, |
| 610 | 596 | // no extra return needed |
| 611 | | .Return => break :blk, |
| 597 | .@"return", .return_void => break :blk, |
| 612 | 598 | else => break, |
| 613 | 599 | } |
| 614 | 600 | } |
| 615 | 601 | } |
| 616 | 602 | |
| 617 | | const return_expr = try ast.Node.ControlFlowExpression.create(rp.c.arena, .{ |
| 618 | | .ltoken = try appendToken(rp.c, .Keyword_return, "return"), |
| 619 | | .tag = .Return, |
| 620 | | }, .{ |
| 621 | | .rhs = transZeroInitExpr(rp, scope, fn_decl_loc, return_qt.getTypePtr()) catch |err| switch (err) { |
| 622 | | error.OutOfMemory => |e| return e, |
| 623 | | error.UnsupportedTranslation, |
| 624 | | error.UnsupportedType, |
| 625 | | => return failDecl(c, fn_decl_loc, fn_name, "unable to create a return value for function", .{}), |
| 626 | | }, |
| 627 | | }); |
| 628 | | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 629 | | try block_scope.statements.append(&return_expr.base); |
| 603 | const rhs = transZeroInitExpr(c, scope, fn_decl_loc, return_qt.getTypePtr()) catch |err| switch (err) { |
| 604 | error.OutOfMemory => |e| return e, |
| 605 | error.UnsupportedTranslation, |
| 606 | error.UnsupportedType, |
| 607 | => return failDecl(c, fn_decl_loc, fn_name, "unable to create a return value for function", .{}), |
| 608 | }; |
| 609 | const ret = try Node.@"return".create(c.arena, rhs); |
| 610 | try block_scope.statements.append(ret); |
| 630 | 611 | } |
| 631 | 612 | |
| 632 | | const body_node = try block_scope.complete(rp.c); |
| 633 | | proto_node.setBodyNode(body_node); |
| 613 | proto_node.body = try block_scope.complete(c); |
| 634 | 614 | return addTopLevelDecl(c, fn_name, &proto_node.base); |
| 635 | 615 | } |
| 636 | 616 | |
| ... | ... | @@ -2440,16 +2420,16 @@ fn transInitListExpr( |
| 2440 | 2420 | } |
| 2441 | 2421 | |
| 2442 | 2422 | fn transZeroInitExpr( |
| 2443 | | rp: RestorePoint, |
| 2423 | c: *Context, |
| 2444 | 2424 | scope: *Scope, |
| 2445 | 2425 | source_loc: clang.SourceLocation, |
| 2446 | 2426 | ty: *const clang.Type, |
| 2447 | | ) TransError!*ast.Node { |
| 2427 | ) TransError!Node { |
| 2448 | 2428 | switch (ty.getTypeClass()) { |
| 2449 | 2429 | .Builtin => { |
| 2450 | 2430 | const builtin_ty = @ptrCast(*const clang.BuiltinType, ty); |
| 2451 | 2431 | switch (builtin_ty.getKind()) { |
| 2452 | | .Bool => return try transCreateNodeBoolLiteral(rp.c, false), |
| 2432 | .Bool => return Node.false_literal.init(), |
| 2453 | 2433 | .Char_U, |
| 2454 | 2434 | .UChar, |
| 2455 | 2435 | .Char_S, |
| ... | ... | @@ -2470,16 +2450,16 @@ fn transZeroInitExpr( |
| 2470 | 2450 | .Float128, |
| 2471 | 2451 | .Float16, |
| 2472 | 2452 | .LongDouble, |
| 2473 | | => return transCreateNodeInt(rp.c, 0), |
| 2474 | | else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), |
| 2453 | => return Node.zero_literal.init(), |
| 2454 | else => return fail(c, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), |
| 2475 | 2455 | } |
| 2476 | 2456 | }, |
| 2477 | | .Pointer => return transCreateNodeNullLiteral(rp.c), |
| 2457 | .Pointer => return Node.null_literal.init(), |
| 2478 | 2458 | .Typedef => { |
| 2479 | 2459 | const typedef_ty = @ptrCast(*const clang.TypedefType, ty); |
| 2480 | 2460 | const typedef_decl = typedef_ty.getDecl(); |
| 2481 | 2461 | return transZeroInitExpr( |
| 2482 | | rp, |
| 2462 | c, |
| 2483 | 2463 | scope, |
| 2484 | 2464 | source_loc, |
| 2485 | 2465 | typedef_decl.getUnderlyingType().getTypePtr(), |
| ... | ... | @@ -2488,7 +2468,7 @@ fn transZeroInitExpr( |
| 2488 | 2468 | else => {}, |
| 2489 | 2469 | } |
| 2490 | 2470 | |
| 2491 | | return revertAndWarn(rp, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{}); |
| 2471 | return fail(c, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{}); |
| 2492 | 2472 | } |
| 2493 | 2473 | |
| 2494 | 2474 | fn transImplicitValueInitExpr( |
| ... | ... | @@ -3985,7 +3965,7 @@ fn qualTypeToLog2IntRef(c: *Context, qt: clang.QualType, source_loc: clang.Sourc |
| 3985 | 3965 | if (int_bit_width != 0) { |
| 3986 | 3966 | // we can perform the log2 now. |
| 3987 | 3967 | const cast_bit_width = math.log2_int(u64, int_bit_width); |
| 3988 | | return Node.uint_type.create(c.arena, cast_bit_width); |
| 3968 | return Node.log2_int_type.create(c.arena, cast_bit_width); |
| 3989 | 3969 | } |
| 3990 | 3970 | |
| 3991 | 3971 | const zig_type = try transQualType(c, qt, source_loc); |
| ... | ... | @@ -4886,7 +4866,7 @@ const FnDeclContext = struct { |
| 4886 | 4866 | }; |
| 4887 | 4867 | |
| 4888 | 4868 | fn transCC( |
| 4889 | | rp: RestorePoint, |
| 4869 | c: *Context, |
| 4890 | 4870 | fn_ty: *const clang.FunctionType, |
| 4891 | 4871 | source_loc: clang.SourceLocation, |
| 4892 | 4872 | ) !CallingConvention { |
| ... | ... | @@ -4899,7 +4879,7 @@ fn transCC( |
| 4899 | 4879 | .X86ThisCall => return CallingConvention.Thiscall, |
| 4900 | 4880 | .AAPCS => return CallingConvention.AAPCS, |
| 4901 | 4881 | .AAPCS_VFP => return CallingConvention.AAPCSVFP, |
| 4902 | | else => return revertAndWarn( |
| 4882 | else => return fail( |
| 4903 | 4883 | rp, |
| 4904 | 4884 | error.UnsupportedType, |
| 4905 | 4885 | source_loc, |
| ... | ... | @@ -4910,33 +4890,33 @@ fn transCC( |
| 4910 | 4890 | } |
| 4911 | 4891 | |
| 4912 | 4892 | fn transFnProto( |
| 4913 | | rp: RestorePoint, |
| 4893 | c: *Context, |
| 4914 | 4894 | fn_decl: ?*const clang.FunctionDecl, |
| 4915 | 4895 | fn_proto_ty: *const clang.FunctionProtoType, |
| 4916 | 4896 | source_loc: clang.SourceLocation, |
| 4917 | 4897 | fn_decl_context: ?FnDeclContext, |
| 4918 | 4898 | is_pub: bool, |
| 4919 | | ) !*ast.Node.FnProto { |
| 4899 | ) !Node.FnProto { |
| 4920 | 4900 | const fn_ty = @ptrCast(*const clang.FunctionType, fn_proto_ty); |
| 4921 | | const cc = try transCC(rp, fn_ty, source_loc); |
| 4901 | const cc = try transCC(c, fn_ty, source_loc); |
| 4922 | 4902 | const is_var_args = fn_proto_ty.isVariadic(); |
| 4923 | | return finishTransFnProto(rp, fn_decl, fn_proto_ty, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub); |
| 4903 | return finishTransFnProto(c, fn_decl, fn_proto_ty, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub); |
| 4924 | 4904 | } |
| 4925 | 4905 | |
| 4926 | 4906 | fn transFnNoProto( |
| 4927 | | rp: RestorePoint, |
| 4907 | c: *Context, |
| 4928 | 4908 | fn_ty: *const clang.FunctionType, |
| 4929 | 4909 | source_loc: clang.SourceLocation, |
| 4930 | 4910 | fn_decl_context: ?FnDeclContext, |
| 4931 | 4911 | is_pub: bool, |
| 4932 | | ) !*ast.Node.FnProto { |
| 4933 | | const cc = try transCC(rp, fn_ty, source_loc); |
| 4912 | ) !Node.FnProto { |
| 4913 | const cc = try transCC(c, fn_ty, source_loc); |
| 4934 | 4914 | const is_var_args = if (fn_decl_context) |ctx| (!ctx.is_export and ctx.storage_class != .Static) else true; |
| 4935 | | return finishTransFnProto(rp, null, null, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub); |
| 4915 | return finishTransFnProto(c, null, null, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub); |
| 4936 | 4916 | } |
| 4937 | 4917 | |
| 4938 | 4918 | fn finishTransFnProto( |
| 4939 | | rp: RestorePoint, |
| 4919 | c: *Context, |
| 4940 | 4920 | fn_decl: ?*const clang.FunctionDecl, |
| 4941 | 4921 | fn_proto_ty: ?*const clang.FunctionProtoType, |
| 4942 | 4922 | fn_ty: *const clang.FunctionType, |
| ... | ... | @@ -4945,128 +4925,77 @@ fn finishTransFnProto( |
| 4945 | 4925 | is_var_args: bool, |
| 4946 | 4926 | cc: CallingConvention, |
| 4947 | 4927 | is_pub: bool, |
| 4948 | | ) !*ast.Node.FnProto { |
| 4928 | ) !*ast.Payload.Func { |
| 4949 | 4929 | const is_export = if (fn_decl_context) |ctx| ctx.is_export else false; |
| 4950 | 4930 | const is_extern = if (fn_decl_context) |ctx| !ctx.has_body else false; |
| 4951 | 4931 | |
| 4952 | 4932 | // TODO check for always_inline attribute |
| 4953 | 4933 | // TODO check for align attribute |
| 4954 | 4934 | |
| 4955 | | // pub extern fn name(...) T |
| 4956 | | const pub_tok = if (is_pub) try appendToken(rp.c, .Keyword_pub, "pub") else null; |
| 4957 | | const extern_export_inline_tok = if (is_export) |
| 4958 | | try appendToken(rp.c, .Keyword_export, "export") |
| 4959 | | else if (is_extern) |
| 4960 | | try appendToken(rp.c, .Keyword_extern, "extern") |
| 4961 | | else |
| 4962 | | null; |
| 4963 | | const fn_tok = try appendToken(rp.c, .Keyword_fn, "fn"); |
| 4964 | | const name_tok = if (fn_decl_context) |ctx| try appendIdentifier(rp.c, ctx.fn_name) else null; |
| 4965 | | const lparen_tok = try appendToken(rp.c, .LParen, "("); |
| 4966 | | |
| 4967 | | var fn_params = std.ArrayList(ast.Node.FnProto.ParamDecl).init(rp.c.gpa); |
| 4935 | var fn_params = std.ArrayList(ast.Payload.Func.Param).init(c.gpa); |
| 4968 | 4936 | defer fn_params.deinit(); |
| 4969 | 4937 | const param_count: usize = if (fn_proto_ty != null) fn_proto_ty.?.getNumParams() else 0; |
| 4970 | | try fn_params.ensureCapacity(param_count + 1); // +1 for possible var args node |
| 4938 | try fn_params.ensureCapacity(param_count); |
| 4971 | 4939 | |
| 4972 | 4940 | var i: usize = 0; |
| 4973 | 4941 | while (i < param_count) : (i += 1) { |
| 4974 | 4942 | const param_qt = fn_proto_ty.?.getParamType(@intCast(c_uint, i)); |
| 4943 | const is_noalias = param_qt.isRestrictQualified(); |
| 4975 | 4944 | |
| 4976 | | const noalias_tok = if (param_qt.isRestrictQualified()) try appendToken(rp.c, .Keyword_noalias, "noalias") else null; |
| 4977 | | |
| 4978 | | const param_name_tok: ?ast.TokenIndex = blk: { |
| 4979 | | if (fn_decl) |decl| { |
| 4980 | | const param = decl.getParamDecl(@intCast(c_uint, i)); |
| 4981 | | const param_name: []const u8 = try rp.c.str(@ptrCast(*const clang.NamedDecl, param).getName_bytes_begin()); |
| 4982 | | if (param_name.len < 1) |
| 4983 | | break :blk null; |
| 4984 | | |
| 4985 | | const result = try appendIdentifier(rp.c, param_name); |
| 4986 | | _ = try appendToken(rp.c, .Colon, ":"); |
| 4987 | | break :blk result; |
| 4988 | | } |
| 4989 | | break :blk null; |
| 4990 | | }; |
| 4945 | const param_name: ?[]const u8 = |
| 4946 | if (fn_decl) |decl| |
| 4947 | blk: { |
| 4948 | const param = decl.getParamDecl(@intCast(c_uint, i)); |
| 4949 | const param_name: []const u8 = try c.str(@ptrCast(*const clang.NamedDecl, param).getName_bytes_begin()); |
| 4950 | if (param_name.len < 1) |
| 4951 | break :blk null; |
| 4991 | 4952 | |
| 4992 | | const type_node = try transQualType(rp, param_qt, source_loc); |
| 4953 | break :blk param_name; |
| 4954 | } else null; |
| 4955 | const type_node = try transQualType(c, param_qt, source_loc); |
| 4993 | 4956 | |
| 4994 | 4957 | fn_params.addOneAssumeCapacity().* = .{ |
| 4995 | | .doc_comments = null, |
| 4996 | | .comptime_token = null, |
| 4997 | | .noalias_token = noalias_tok, |
| 4998 | | .name_token = param_name_tok, |
| 4999 | | .param_type = .{ .type_expr = type_node }, |
| 4958 | .is_noalias = is_noalias, |
| 4959 | .name = param_name, |
| 4960 | .type = type_node, |
| 5000 | 4961 | }; |
| 5001 | | |
| 5002 | | if (i + 1 < param_count) { |
| 5003 | | _ = try appendToken(rp.c, .Comma, ","); |
| 5004 | | } |
| 5005 | 4962 | } |
| 5006 | 4963 | |
| 5007 | | const var_args_token: ?ast.TokenIndex = if (is_var_args) blk: { |
| 5008 | | if (param_count > 0) { |
| 5009 | | _ = try appendToken(rp.c, .Comma, ","); |
| 5010 | | } |
| 5011 | | break :blk try appendToken(rp.c, .Ellipsis3, "..."); |
| 5012 | | } else null; |
| 5013 | | |
| 5014 | | const rparen_tok = try appendToken(rp.c, .RParen, ")"); |
| 5015 | | |
| 5016 | | const linksection_expr = blk: { |
| 4964 | const link_section_string: ?[]const u8 = blk: { |
| 5017 | 4965 | if (fn_decl) |decl| { |
| 5018 | 4966 | var str_len: usize = undefined; |
| 5019 | 4967 | if (decl.getSectionAttribute(&str_len)) |str_ptr| { |
| 5020 | | _ = try appendToken(rp.c, .Keyword_linksection, "linksection"); |
| 5021 | | _ = try appendToken(rp.c, .LParen, "("); |
| 5022 | | const expr = try transCreateNodeStringLiteral( |
| 5023 | | rp.c, |
| 5024 | | try std.fmt.allocPrint(rp.c.arena, "\"{s}\"", .{str_ptr[0..str_len]}), |
| 5025 | | ); |
| 5026 | | _ = try appendToken(rp.c, .RParen, ")"); |
| 5027 | | |
| 5028 | | break :blk expr; |
| 4968 | break :blk str_ptr[0..str_len]; |
| 5029 | 4969 | } |
| 5030 | 4970 | } |
| 5031 | 4971 | break :blk null; |
| 5032 | 4972 | }; |
| 5033 | 4973 | |
| 5034 | | const align_expr = blk: { |
| 4974 | const alignment: c_uint = blk: { |
| 5035 | 4975 | if (fn_decl) |decl| { |
| 5036 | | const alignment = decl.getAlignedAttribute(rp.c.clang_context); |
| 4976 | const alignment = decl.getAlignedAttribute(c.clang_context); |
| 5037 | 4977 | if (alignment != 0) { |
| 5038 | | _ = try appendToken(rp.c, .Keyword_align, "align"); |
| 5039 | | _ = try appendToken(rp.c, .LParen, "("); |
| 5040 | 4978 | // Clang reports the alignment in bits |
| 5041 | | const expr = try transCreateNodeInt(rp.c, alignment / 8); |
| 5042 | | _ = try appendToken(rp.c, .RParen, ")"); |
| 5043 | | |
| 5044 | | break :blk expr; |
| 4979 | break :blk alignment / 8; |
| 5045 | 4980 | } |
| 5046 | 4981 | } |
| 5047 | 4982 | break :blk null; |
| 5048 | 4983 | }; |
| 5049 | 4984 | |
| 5050 | | const callconv_expr = if ((is_export or is_extern) and cc == .C) null else blk: { |
| 5051 | | _ = try appendToken(rp.c, .Keyword_callconv, "callconv"); |
| 5052 | | _ = try appendToken(rp.c, .LParen, "("); |
| 5053 | | const expr = try transCreateNodeEnumLiteral(rp.c, @tagName(cc)); |
| 5054 | | _ = try appendToken(rp.c, .RParen, ")"); |
| 5055 | | break :blk expr; |
| 5056 | | }; |
| 4985 | const explicit_callconv = if ((is_export or is_extern) and cc == .C) null else cc; |
| 5057 | 4986 | |
| 5058 | 4987 | const return_type_node = blk: { |
| 5059 | 4988 | if (fn_ty.getNoReturnAttr()) { |
| 5060 | | break :blk try transCreateNodeIdentifier(rp.c, "noreturn"); |
| 4989 | break :blk Node.noreturn_type.init(); |
| 5061 | 4990 | } else { |
| 5062 | 4991 | const return_qt = fn_ty.getReturnType(); |
| 5063 | 4992 | if (isCVoid(return_qt)) { |
| 5064 | 4993 | // convert primitive c_void to actual void (only for return type) |
| 5065 | | break :blk try transCreateNodeIdentifier(rp.c, "void"); |
| 4994 | break :blk Node.void_type.init(); |
| 5066 | 4995 | } else { |
| 5067 | | break :blk transQualType(rp, return_qt, source_loc) catch |err| switch (err) { |
| 4996 | break :blk transQualType(c, return_qt, source_loc) catch |err| switch (err) { |
| 5068 | 4997 | error.UnsupportedType => { |
| 5069 | | try emitWarning(rp.c, source_loc, "unsupported function proto return type", .{}); |
| 4998 | try warn(c, source_loc, "unsupported function proto return type", .{}); |
| 5070 | 4999 | return err; |
| 5071 | 5000 | }, |
| 5072 | 5001 | error.OutOfMemory => |e| return e, |
| ... | ... | @@ -5075,32 +5004,23 @@ fn finishTransFnProto( |
| 5075 | 5004 | } |
| 5076 | 5005 | }; |
| 5077 | 5006 | |
| 5078 | | // We need to reserve an undefined (but non-null) body node to set later. |
| 5079 | | var body_node: ?*ast.Node = null; |
| 5080 | | if (fn_decl_context) |ctx| { |
| 5081 | | if (ctx.has_body) { |
| 5082 | | // TODO: we should be able to use undefined here but |
| 5083 | | // it causes a bug. This is undefined without zig language |
| 5084 | | // being aware of it. |
| 5085 | | body_node = @intToPtr(*ast.Node, 0x08); |
| 5086 | | } |
| 5087 | | } |
| 5088 | | |
| 5089 | | const fn_proto = try ast.Node.FnProto.create(rp.c.arena, .{ |
| 5090 | | .params_len = fn_params.items.len, |
| 5091 | | .return_type = .{ .Explicit = return_type_node }, |
| 5092 | | .fn_token = fn_tok, |
| 5093 | | }, .{ |
| 5094 | | .visib_token = pub_tok, |
| 5095 | | .name_token = name_tok, |
| 5096 | | .extern_export_inline_token = extern_export_inline_tok, |
| 5097 | | .align_expr = align_expr, |
| 5098 | | .section_expr = linksection_expr, |
| 5099 | | .callconv_expr = callconv_expr, |
| 5100 | | .body_node = body_node, |
| 5101 | | .var_args_token = var_args_token, |
| 5102 | | }); |
| 5103 | | mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items); |
| 5007 | const fn_proto = try c.arena.create(ast.Payload.Func); |
| 5008 | fn_proto.* = .{ |
| 5009 | .base = .{ .tag = .func }, |
| 5010 | .data = .{ |
| 5011 | .is_pub = is_pub, |
| 5012 | .is_extern = is_extern, |
| 5013 | .is_export = is_export, |
| 5014 | .is_var_args = is_var_args, |
| 5015 | .name = name, |
| 5016 | .link_section_string = link_section_string, |
| 5017 | .explicit_callconv = explicit_callconv, |
| 5018 | .params = c.arena.dupe(ast.Payload.Func.Param, fn_params.items), |
| 5019 | .return_type = return_node, |
| 5020 | .body = null, |
| 5021 | .alignment = alignment, |
| 5022 | }, |
| 5023 | }; |
| 5104 | 5024 | return fn_proto; |
| 5105 | 5025 | } |
| 5106 | 5026 | |
| ... | ... | @@ -5122,124 +5042,12 @@ fn fail( |
| 5122 | 5042 | } |
| 5123 | 5043 | |
| 5124 | 5044 | pub fn failDecl(c: *Context, loc: clang.SourceLocation, name: []const u8, comptime format: []const u8, args: anytype) !void { |
| 5045 | // location |
| 5125 | 5046 | // pub const name = @compileError(msg); |
| 5126 | | const pub_tok = try appendToken(c, .Keyword_pub, "pub"); |
| 5127 | | const const_tok = try appendToken(c, .Keyword_const, "const"); |
| 5128 | | const name_tok = try appendIdentifier(c, name); |
| 5129 | | const eq_tok = try appendToken(c, .Equal, "="); |
| 5130 | | const builtin_tok = try appendToken(c, .Builtin, "@compileError"); |
| 5131 | | const lparen_tok = try appendToken(c, .LParen, "("); |
| 5132 | | const msg_tok = try appendTokenFmt(c, .StringLiteral, "\"" ++ format ++ "\"", args); |
| 5133 | | const rparen_tok = try appendToken(c, .RParen, ")"); |
| 5134 | | const semi_tok = try appendToken(c, .Semicolon, ";"); |
| 5135 | | _ = try appendTokenFmt(c, .LineComment, "// {s}", .{c.locStr(loc)}); |
| 5136 | | |
| 5137 | | const msg_node = try c.arena.create(ast.Node.OneToken); |
| 5138 | | msg_node.* = .{ |
| 5139 | | .base = .{ .tag = .StringLiteral }, |
| 5140 | | .token = msg_tok, |
| 5141 | | }; |
| 5142 | | |
| 5143 | | const call_node = try ast.Node.BuiltinCall.alloc(c.arena, 1); |
| 5144 | | call_node.* = .{ |
| 5145 | | .builtin_token = builtin_tok, |
| 5146 | | .params_len = 1, |
| 5147 | | .rparen_token = rparen_tok, |
| 5148 | | }; |
| 5149 | | call_node.params()[0] = &msg_node.base; |
| 5150 | | |
| 5151 | | const var_decl_node = try ast.Node.VarDecl.create(c.arena, .{ |
| 5152 | | .name_token = name_tok, |
| 5153 | | .mut_token = const_tok, |
| 5154 | | .semicolon_token = semi_tok, |
| 5155 | | }, .{ |
| 5156 | | .visib_token = pub_tok, |
| 5157 | | .eq_token = eq_tok, |
| 5158 | | .init_node = &call_node.base, |
| 5159 | | }); |
| 5160 | | try addTopLevelDecl(c, name, &var_decl_node.base); |
| 5161 | | } |
| 5162 | | |
| 5163 | | fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenIndex { |
| 5164 | | std.debug.assert(token_id != .Identifier); // use appendIdentifier |
| 5165 | | return appendTokenFmt(c, token_id, "{s}", .{bytes}); |
| 5166 | | } |
| 5167 | | |
| 5168 | | fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, args: anytype) !ast.TokenIndex { |
| 5169 | | assert(token_id != .Invalid); |
| 5170 | | |
| 5171 | | try c.token_ids.ensureCapacity(c.gpa, c.token_ids.items.len + 1); |
| 5172 | | try c.token_locs.ensureCapacity(c.gpa, c.token_locs.items.len + 1); |
| 5173 | | |
| 5174 | | const start_index = c.source_buffer.items.len; |
| 5175 | | try c.source_buffer.writer().print(format ++ " ", args); |
| 5176 | | |
| 5177 | | c.token_ids.appendAssumeCapacity(token_id); |
| 5178 | | c.token_locs.appendAssumeCapacity(.{ |
| 5179 | | .start = start_index, |
| 5180 | | .end = c.source_buffer.items.len - 1, // back up before the space |
| 5181 | | }); |
| 5182 | | |
| 5183 | | return c.token_ids.items.len - 1; |
| 5184 | | } |
| 5185 | | |
| 5186 | | // TODO hook up with codegen |
| 5187 | | fn isZigPrimitiveType(name: []const u8) bool { |
| 5188 | | if (name.len > 1 and (name[0] == 'u' or name[0] == 'i')) { |
| 5189 | | for (name[1..]) |c| { |
| 5190 | | switch (c) { |
| 5191 | | '0'...'9' => {}, |
| 5192 | | else => return false, |
| 5193 | | } |
| 5194 | | } |
| 5195 | | return true; |
| 5196 | | } |
| 5197 | | // void is invalid in c so it doesn't need to be checked. |
| 5198 | | return mem.eql(u8, name, "comptime_float") or |
| 5199 | | mem.eql(u8, name, "comptime_int") or |
| 5200 | | mem.eql(u8, name, "bool") or |
| 5201 | | mem.eql(u8, name, "isize") or |
| 5202 | | mem.eql(u8, name, "usize") or |
| 5203 | | mem.eql(u8, name, "f16") or |
| 5204 | | mem.eql(u8, name, "f32") or |
| 5205 | | mem.eql(u8, name, "f64") or |
| 5206 | | mem.eql(u8, name, "f128") or |
| 5207 | | mem.eql(u8, name, "c_longdouble") or |
| 5208 | | mem.eql(u8, name, "noreturn") or |
| 5209 | | mem.eql(u8, name, "type") or |
| 5210 | | mem.eql(u8, name, "anyerror") or |
| 5211 | | mem.eql(u8, name, "c_short") or |
| 5212 | | mem.eql(u8, name, "c_ushort") or |
| 5213 | | mem.eql(u8, name, "c_int") or |
| 5214 | | mem.eql(u8, name, "c_uint") or |
| 5215 | | mem.eql(u8, name, "c_long") or |
| 5216 | | mem.eql(u8, name, "c_ulong") or |
| 5217 | | mem.eql(u8, name, "c_longlong") or |
| 5218 | | mem.eql(u8, name, "c_ulonglong"); |
| 5219 | | } |
| 5220 | | |
| 5221 | | fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex { |
| 5222 | | return appendTokenFmt(c, .Identifier, "{}", .{std.zig.fmtId(name)}); |
| 5223 | | } |
| 5224 | | |
| 5225 | | fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node { |
| 5226 | | const token_index = try appendIdentifier(c, name); |
| 5227 | | const identifier = try c.arena.create(ast.Node.OneToken); |
| 5228 | | identifier.* = .{ |
| 5229 | | .base = .{ .tag = .Identifier }, |
| 5230 | | .token = token_index, |
| 5231 | | }; |
| 5232 | | return &identifier.base; |
| 5233 | | } |
| 5234 | | |
| 5235 | | fn transCreateNodeIdentifierUnchecked(c: *Context, name: []const u8) !*ast.Node { |
| 5236 | | const token_index = try appendTokenFmt(c, .Identifier, "{s}", .{name}); |
| 5237 | | const identifier = try c.arena.create(ast.Node.OneToken); |
| 5238 | | identifier.* = .{ |
| 5239 | | .base = .{ .tag = .Identifier }, |
| 5240 | | .token = token_index, |
| 5241 | | }; |
| 5242 | | return &identifier.base; |
| 5047 | const location_comment = std.fmt.allocPrint(c.arena, "// {s}", .{c.locStr(loc)}); |
| 5048 | try c.global_scope.nodes.append(try Node.warning.create(c.arena, location_comment)); |
| 5049 | const fail_msg = std.fmt.allocPrint(c.arena, format, args); |
| 5050 | try c.global_scope.nodes.append(try Node.fail_decl.create(c.arena, fail_msg)); |
| 5243 | 5051 | } |
| 5244 | 5052 | |
| 5245 | 5053 | pub fn freeErrors(errors: []ClangErrMsg) void { |