| ... | ... | @@ -614,25 +614,21 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { |
| 614 | 614 | return addTopLevelDecl(c, fn_name, &proto_node.base); |
| 615 | 615 | } |
| 616 | 616 | |
| 617 | | fn transQualTypeMaybeInitialized(rp: RestorePoint, qt: clang.QualType, decl_init: ?*const clang.Expr, loc: clang.SourceLocation) TransError!*ast.Node { |
| 617 | fn transQualTypeMaybeInitialized(c: *Context, qt: clang.QualType, decl_init: ?*const clang.Expr, loc: clang.SourceLocation) TransError!Node { |
| 618 | 618 | return if (decl_init) |init_expr| |
| 619 | | transQualTypeInitialized(rp, qt, init_expr, loc) |
| 619 | transQualTypeInitialized(c, qt, init_expr, loc) |
| 620 | 620 | else |
| 621 | | transQualType(rp, qt, loc); |
| 621 | transQualType(c, qt, loc); |
| 622 | 622 | } |
| 623 | |
| 623 | 624 | /// if mangled_name is not null, this var decl was declared in a block scope. |
| 624 | 625 | fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]const u8) Error!void { |
| 625 | 626 | const var_name = mangled_name orelse try c.str(@ptrCast(*const clang.NamedDecl, var_decl).getName_bytes_begin()); |
| 626 | 627 | if (c.global_scope.sym_table.contains(var_name)) |
| 627 | 628 | return; // Avoid processing this decl twice |
| 628 | | const rp = makeRestorePoint(c); |
| 629 | | const visib_tok = if (mangled_name) |_| null else try appendToken(c, .Keyword_pub, "pub"); |
| 630 | | |
| 631 | | const thread_local_token = if (var_decl.getTLSKind() == .None) |
| 632 | | null |
| 633 | | else |
| 634 | | try appendToken(c, .Keyword_threadlocal, "threadlocal"); |
| 635 | 629 | |
| 630 | const is_pub = mangled_name == null; |
| 631 | const is_thread_local = var_decl.getTLSKind() != .None; |
| 636 | 632 | const scope = &c.global_scope.base; |
| 637 | 633 | |
| 638 | 634 | // TODO https://github.com/ziglang/zig/issues/3756 |
| ... | ... | @@ -651,42 +647,27 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co |
| 651 | 647 | // does the same as: |
| 652 | 648 | // extern int foo; |
| 653 | 649 | // int foo = 2; |
| 654 | | const extern_tok = if (storage_class == .Extern and !has_init) |
| 655 | | try appendToken(c, .Keyword_extern, "extern") |
| 656 | | else if (storage_class != .Static) |
| 657 | | try appendToken(c, .Keyword_export, "export") |
| 658 | | else |
| 659 | | null; |
| 660 | | |
| 661 | | const mut_tok = if (is_const) |
| 662 | | try appendToken(c, .Keyword_const, "const") |
| 663 | | else |
| 664 | | try appendToken(c, .Keyword_var, "var"); |
| 650 | const is_extern = storage_class == .Extern and !has_init; |
| 651 | const is_export = !is_extern and storage_class != .Static; |
| 665 | 652 | |
| 666 | | const name_tok = try appendIdentifier(c, checked_name); |
| 667 | | |
| 668 | | _ = try appendToken(c, .Colon, ":"); |
| 669 | | |
| 670 | | const type_node = transQualTypeMaybeInitialized(rp, qual_type, decl_init, var_decl_loc) catch |err| switch (err) { |
| 653 | const type_node = transQualTypeMaybeInitialized(c, qual_type, decl_init, var_decl_loc) catch |err| switch (err) { |
| 671 | 654 | error.UnsupportedTranslation, error.UnsupportedType => { |
| 672 | 655 | return failDecl(c, var_decl_loc, checked_name, "unable to resolve variable type", .{}); |
| 673 | 656 | }, |
| 674 | 657 | error.OutOfMemory => |e| return e, |
| 675 | 658 | }; |
| 676 | 659 | |
| 677 | | var eq_tok: ast.TokenIndex = undefined; |
| 678 | | var init_node: ?*ast.Node = null; |
| 660 | var init_node: ?Node = null; |
| 679 | 661 | |
| 680 | 662 | // If the initialization expression is not present, initialize with undefined. |
| 681 | 663 | // If it is an integer literal, we can skip the @as since it will be redundant |
| 682 | 664 | // with the variable type. |
| 683 | 665 | if (has_init) { |
| 684 | | eq_tok = try appendToken(c, .Equal, "="); |
| 685 | 666 | if (decl_init) |expr| { |
| 686 | 667 | const node_or_error = if (expr.getStmtClass() == .StringLiteralClass) |
| 687 | | transStringLiteralAsArray(rp, &c.global_scope.base, @ptrCast(*const clang.StringLiteral, expr), zigArraySize(rp.c, type_node) catch 0) |
| 668 | transStringLiteralAsArray(c, scope, @ptrCast(*const clang.StringLiteral, expr), zigArraySize(c, type_node) catch 0) |
| 688 | 669 | else |
| 689 | | transExprCoercing(rp, scope, expr, .used, .r_value); |
| 670 | transExprCoercing(c, scope, expr, .used, .r_value); |
| 690 | 671 | init_node = node_or_error catch |err| switch (err) { |
| 691 | 672 | error.UnsupportedTranslation, |
| 692 | 673 | error.UnsupportedType, |
| ... | ... | @@ -695,118 +676,83 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co |
| 695 | 676 | }, |
| 696 | 677 | error.OutOfMemory => |e| return e, |
| 697 | 678 | }; |
| 679 | if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) { |
| 680 | init_node = try Node.bool_to_int.create(c.arena, init_node); |
| 681 | } |
| 698 | 682 | } else { |
| 699 | | init_node = try transCreateNodeUndefinedLiteral(c); |
| 683 | init_node = Node.undefined_literal.init(); |
| 700 | 684 | } |
| 701 | 685 | } else if (storage_class != .Extern) { |
| 702 | | eq_tok = try appendToken(c, .Equal, "="); |
| 703 | 686 | // The C language specification states that variables with static or threadlocal |
| 704 | 687 | // storage without an initializer are initialized to a zero value. |
| 705 | 688 | |
| 706 | 689 | // @import("std").mem.zeroes(T) |
| 707 | | const import_fn_call = try c.createBuiltinCall("@import", 1); |
| 708 | | const std_node = try transCreateNodeStringLiteral(c, "\"std\""); |
| 709 | | import_fn_call.params()[0] = std_node; |
| 710 | | import_fn_call.rparen_token = try appendToken(c, .RParen, ")"); |
| 711 | | const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "mem"); |
| 712 | | const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "zeroes"); |
| 713 | | |
| 714 | | const zero_init_call = try c.createCall(outer_field_access, 1); |
| 715 | | zero_init_call.params()[0] = type_node; |
| 716 | | zero_init_call.rtoken = try appendToken(c, .RParen, ")"); |
| 717 | | |
| 718 | | init_node = &zero_init_call.base; |
| 690 | init_node = try Node.std_mem_zeroes.create(c.arena, type_node); |
| 719 | 691 | } |
| 720 | 692 | |
| 721 | | const linksection_expr = blk: { |
| 693 | const linksection_string = blk: { |
| 722 | 694 | var str_len: usize = undefined; |
| 723 | 695 | if (var_decl.getSectionAttribute(&str_len)) |str_ptr| { |
| 724 | | _ = try appendToken(rp.c, .Keyword_linksection, "linksection"); |
| 725 | | _ = try appendToken(rp.c, .LParen, "("); |
| 726 | | const expr = try transCreateNodeStringLiteral( |
| 727 | | rp.c, |
| 728 | | try std.fmt.allocPrint(rp.c.arena, "\"{s}\"", .{str_ptr[0..str_len]}), |
| 729 | | ); |
| 730 | | _ = try appendToken(rp.c, .RParen, ")"); |
| 731 | | |
| 732 | | break :blk expr; |
| 696 | break :blk str_ptr[0..str_len]; |
| 733 | 697 | } |
| 734 | 698 | break :blk null; |
| 735 | 699 | }; |
| 736 | 700 | |
| 737 | | const align_expr = blk: { |
| 738 | | const alignment = var_decl.getAlignedAttribute(rp.c.clang_context); |
| 701 | const alignment = blk: { |
| 702 | const alignment = var_decl.getAlignedAttribute(c.clang_context); |
| 739 | 703 | if (alignment != 0) { |
| 740 | | _ = try appendToken(rp.c, .Keyword_align, "align"); |
| 741 | | _ = try appendToken(rp.c, .LParen, "("); |
| 742 | 704 | // Clang reports the alignment in bits |
| 743 | | const expr = try transCreateNodeInt(rp.c, alignment / 8); |
| 744 | | _ = try appendToken(rp.c, .RParen, ")"); |
| 745 | | |
| 746 | | break :blk expr; |
| 705 | break :blk alignment / 8; |
| 747 | 706 | } |
| 748 | 707 | break :blk null; |
| 749 | 708 | }; |
| 750 | 709 | |
| 751 | | const node = try ast.Node.VarDecl.create(c.arena, .{ |
| 752 | | .name_token = name_tok, |
| 753 | | .mut_token = mut_tok, |
| 754 | | .semicolon_token = try appendToken(c, .Semicolon, ";"), |
| 755 | | }, .{ |
| 756 | | .visib_token = visib_tok, |
| 757 | | .thread_local_token = thread_local_token, |
| 758 | | .eq_token = eq_tok, |
| 759 | | .extern_export_token = extern_tok, |
| 760 | | .type_node = type_node, |
| 761 | | .align_node = align_expr, |
| 762 | | .section_node = linksection_expr, |
| 763 | | .init_node = init_node, |
| 710 | const node = try Node.var_decl.create(c.arena, .{ |
| 711 | .is_pub = is_pub, |
| 712 | .is_const = is_const, |
| 713 | .is_extern = is_extern, |
| 714 | .is_export = is_export, |
| 715 | .linksection_string = linksection_string, |
| 716 | .alignment = alignment, |
| 717 | .name = checked_name, |
| 718 | .type = type_node, |
| 719 | .init = init_node, |
| 764 | 720 | }); |
| 765 | 721 | return addTopLevelDecl(c, checked_name, &node.base); |
| 766 | 722 | } |
| 767 | 723 | |
| 768 | | fn transTypeDefAsBuiltin(c: *Context, typedef_decl: *const clang.TypedefNameDecl, builtin_name: []const u8) !*ast.Node { |
| 724 | fn transTypeDefAsBuiltin(c: *Context, typedef_decl: *const clang.TypedefNameDecl, builtin_name: []const u8) !Node { |
| 769 | 725 | _ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin_name); |
| 770 | | return transCreateNodeIdentifier(c, builtin_name); |
| 771 | | } |
| 772 | | |
| 773 | | fn checkForBuiltinTypedef(checked_name: []const u8) ?[]const u8 { |
| 774 | | const table = [_][2][]const u8{ |
| 775 | | .{ "uint8_t", "u8" }, |
| 776 | | .{ "int8_t", "i8" }, |
| 777 | | .{ "uint16_t", "u16" }, |
| 778 | | .{ "int16_t", "i16" }, |
| 779 | | .{ "uint32_t", "u32" }, |
| 780 | | .{ "int32_t", "i32" }, |
| 781 | | .{ "uint64_t", "u64" }, |
| 782 | | .{ "int64_t", "i64" }, |
| 783 | | .{ "intptr_t", "isize" }, |
| 784 | | .{ "uintptr_t", "usize" }, |
| 785 | | .{ "ssize_t", "isize" }, |
| 786 | | .{ "size_t", "usize" }, |
| 787 | | }; |
| 788 | | |
| 789 | | for (table) |entry| { |
| 790 | | if (mem.eql(u8, checked_name, entry[0])) { |
| 791 | | return entry[1]; |
| 792 | | } |
| 793 | | } |
| 794 | | |
| 795 | | return null; |
| 796 | | } |
| 726 | return Node.identifier.create(c.arena, builtin_name); |
| 727 | } |
| 728 | |
| 729 | const builtin_typedef_map = std.ComptimeStringMap([]const u8, .{ |
| 730 | .{ "uint8_t", "u8" }, |
| 731 | .{ "int8_t", "i8" }, |
| 732 | .{ "uint16_t", "u16" }, |
| 733 | .{ "int16_t", "i16" }, |
| 734 | .{ "uint32_t", "u32" }, |
| 735 | .{ "int32_t", "i32" }, |
| 736 | .{ "uint64_t", "u64" }, |
| 737 | .{ "int64_t", "i64" }, |
| 738 | .{ "intptr_t", "isize" }, |
| 739 | .{ "uintptr_t", "usize" }, |
| 740 | .{ "ssize_t", "isize" }, |
| 741 | .{ "size_t", "usize" }, |
| 742 | }); |
| 797 | 743 | |
| 798 | | fn transTypeDef(c: *Context, typedef_decl: *const clang.TypedefNameDecl, top_level_visit: bool) Error!?*ast.Node { |
| 744 | fn transTypeDef(c: *Context, typedef_decl: *const clang.TypedefNameDecl, top_level_visit: bool) Error!?Node { |
| 799 | 745 | if (c.decl_table.get(@ptrToInt(typedef_decl.getCanonicalDecl()))) |name| |
| 800 | 746 | return transCreateNodeIdentifier(c, name); // Avoid processing this decl twice |
| 801 | | const rp = makeRestorePoint(c); |
| 802 | 747 | |
| 803 | 748 | const typedef_name = try c.str(@ptrCast(*const clang.NamedDecl, typedef_decl).getName_bytes_begin()); |
| 804 | 749 | |
| 805 | 750 | // TODO https://github.com/ziglang/zig/issues/3756 |
| 806 | 751 | // TODO https://github.com/ziglang/zig/issues/1802 |
| 807 | 752 | const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ typedef_name, c.getMangle() }) else typedef_name; |
| 808 | | if (checkForBuiltinTypedef(checked_name)) |builtin| { |
| 809 | | return transTypeDefAsBuiltin(c, typedef_decl, builtin); |
| 753 | if (builtin_typedef_map.get(checked_name)) |builtin| { |
| 754 | _ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin); |
| 755 | return Node.identifier.create(c.arena, builtin); |
| 810 | 756 | } |
| 811 | 757 | |
| 812 | 758 | if (!top_level_visit) { |
| ... | ... | @@ -814,42 +760,36 @@ fn transTypeDef(c: *Context, typedef_decl: *const clang.TypedefNameDecl, top_lev |
| 814 | 760 | } |
| 815 | 761 | |
| 816 | 762 | _ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), checked_name); |
| 817 | | const node = (try transCreateNodeTypedef(rp, typedef_decl, true, checked_name)) orelse return null; |
| 763 | const node = (try transCreateNodeTypedef(c, typedef_decl, true, checked_name)) orelse return null; |
| 818 | 764 | try addTopLevelDecl(c, checked_name, node); |
| 819 | 765 | return transCreateNodeIdentifier(c, checked_name); |
| 820 | 766 | } |
| 821 | 767 | |
| 822 | 768 | fn transCreateNodeTypedef( |
| 823 | | rp: RestorePoint, |
| 769 | c: *Context, |
| 824 | 770 | typedef_decl: *const clang.TypedefNameDecl, |
| 825 | 771 | toplevel: bool, |
| 826 | 772 | checked_name: []const u8, |
| 827 | | ) Error!?*ast.Node { |
| 828 | | const visib_tok = if (toplevel) try appendToken(rp.c, .Keyword_pub, "pub") else null; |
| 829 | | const mut_tok = try appendToken(rp.c, .Keyword_const, "const"); |
| 830 | | const name_tok = try appendIdentifier(rp.c, checked_name); |
| 831 | | const eq_token = try appendToken(rp.c, .Equal, "="); |
| 773 | ) Error!?Node { |
| 832 | 774 | const child_qt = typedef_decl.getUnderlyingType(); |
| 833 | 775 | const typedef_loc = typedef_decl.getLocation(); |
| 834 | | const init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) { |
| 776 | const init_node = transQualType(c, child_qt, typedef_loc) catch |err| switch (err) { |
| 835 | 777 | error.UnsupportedType => { |
| 836 | | try failDecl(rp.c, typedef_loc, checked_name, "unable to resolve typedef child type", .{}); |
| 778 | try failDecl(c, typedef_loc, checked_name, "unable to resolve typedef child type", .{}); |
| 837 | 779 | return null; |
| 838 | 780 | }, |
| 839 | 781 | error.OutOfMemory => |e| return e, |
| 840 | 782 | }; |
| 841 | | const semicolon_token = try appendToken(rp.c, .Semicolon, ";"); |
| 842 | 783 | |
| 843 | | const node = try ast.Node.VarDecl.create(rp.c.arena, .{ |
| 844 | | .name_token = name_tok, |
| 845 | | .mut_token = mut_tok, |
| 846 | | .semicolon_token = semicolon_token, |
| 847 | | }, .{ |
| 848 | | .visib_token = visib_tok, |
| 849 | | .eq_token = eq_token, |
| 850 | | .init_node = init_node, |
| 851 | | }); |
| 852 | | return &node.base; |
| 784 | const payload = try c.arena.create(ast.Payload.Typedef); |
| 785 | payload.* = .{ |
| 786 | .base = .{ .tag = ([2]ast.Node.Tag{ .typedef, .pub_typedef })[toplevel] }, |
| 787 | .data = .{ |
| 788 | .name = checked_name, |
| 789 | .init = init_node, |
| 790 | }, |
| 791 | }; |
| 792 | return Node.initPayload(&payload.base); |
| 853 | 793 | } |
| 854 | 794 | |
| 855 | 795 | fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*ast.Node { |
| ... | ... | @@ -1399,13 +1339,15 @@ fn transBinaryOperator( |
| 1399 | 1339 | const lhs_uncasted = try transExpr(c, scope, stmt.getLHS(), .used, .l_value); |
| 1400 | 1340 | const rhs_uncasted = try transExpr(c, scope, stmt.getRHS(), .used, .r_value); |
| 1401 | 1341 | |
| 1402 | | const lhs = if (isBoolRes(lhs_uncasted)) |
| 1342 | const lhs = if (isBoolRes(lhs_uncasted)) |
| 1403 | 1343 | try Node.bool_to_int.create(c.arena, lhs_uncasted) |
| 1404 | | else lhs_uncasted; |
| 1344 | else |
| 1345 | lhs_uncasted; |
| 1405 | 1346 | |
| 1406 | | const rhs = if (isBoolRes(rhs_uncasted)) |
| 1347 | const rhs = if (isBoolRes(rhs_uncasted)) |
| 1407 | 1348 | try Node.bool_to_int.create(c.arena, rhs_uncasted) |
| 1408 | | else rhs_uncasted; |
| 1349 | else |
| 1350 | rhs_uncasted; |
| 1409 | 1351 | |
| 1410 | 1352 | const payload = try c.arena.create(ast.Payload.BinOp); |
| 1411 | 1353 | payload.* = .{ |
| ... | ... | @@ -1415,7 +1357,7 @@ fn transBinaryOperator( |
| 1415 | 1357 | .rhs = rhs, |
| 1416 | 1358 | }, |
| 1417 | 1359 | }; |
| 1418 | | return maybeSuppressResult(c, scope, used, &payload.base); |
| 1360 | return maybeSuppressResult(c, scope, used, Node.initPayload(&payload.base)); |
| 1419 | 1361 | } |
| 1420 | 1362 | |
| 1421 | 1363 | fn transCompoundStmtInline( |
| ... | ... | @@ -1459,13 +1401,11 @@ fn transCStyleCastExprClass( |
| 1459 | 1401 | } |
| 1460 | 1402 | |
| 1461 | 1403 | fn transDeclStmtOne( |
| 1462 | | rp: RestorePoint, |
| 1404 | c: *Context, |
| 1463 | 1405 | scope: *Scope, |
| 1464 | 1406 | decl: *const clang.Decl, |
| 1465 | 1407 | block_scope: *Scope.Block, |
| 1466 | | ) TransError!*ast.Node { |
| 1467 | | const c = rp.c; |
| 1468 | | |
| 1408 | ) TransError!Node { |
| 1469 | 1409 | switch (decl.getKind()) { |
| 1470 | 1410 | .Var => { |
| 1471 | 1411 | const var_decl = @ptrCast(*const clang.VarDecl, decl); |
| ... | ... | @@ -1479,47 +1419,38 @@ fn transDeclStmtOne( |
| 1479 | 1419 | .Extern, .Static => { |
| 1480 | 1420 | // This is actually a global variable, put it in the global scope and reference it. |
| 1481 | 1421 | // `_ = mangled_name;` |
| 1482 | | try visitVarDecl(rp.c, var_decl, mangled_name); |
| 1483 | | return try maybeSuppressResult(rp, scope, .unused, try transCreateNodeIdentifier(rp.c, mangled_name)); |
| 1422 | try visitVarDecl(c, var_decl, mangled_name); |
| 1423 | return try maybeSuppressResult(c, scope, .unused, try Node.identifier.create(c.arena, mangled_name)); |
| 1484 | 1424 | }, |
| 1485 | 1425 | else => {}, |
| 1486 | 1426 | } |
| 1487 | 1427 | |
| 1488 | | const mut_tok = if (qual_type.isConstQualified()) |
| 1489 | | try appendToken(c, .Keyword_const, "const") |
| 1490 | | else |
| 1491 | | try appendToken(c, .Keyword_var, "var"); |
| 1492 | | const name_tok = try appendIdentifier(c, mangled_name); |
| 1428 | const is_const = qual_type.isConstQualified(); |
| 1493 | 1429 | |
| 1494 | | _ = try appendToken(c, .Colon, ":"); |
| 1495 | 1430 | const loc = decl.getLocation(); |
| 1496 | | const type_node = try transQualTypeMaybeInitialized(rp, qual_type, decl_init, loc); |
| 1431 | const type_node = try transQualTypeMaybeInitialized(c, qual_type, decl_init, loc); |
| 1497 | 1432 | |
| 1498 | | const eq_token = try appendToken(c, .Equal, "="); |
| 1499 | 1433 | var init_node = if (decl_init) |expr| |
| 1500 | 1434 | if (expr.getStmtClass() == .StringLiteralClass) |
| 1501 | | try transStringLiteralAsArray(rp, scope, @ptrCast(*const clang.StringLiteral, expr), try zigArraySize(rp.c, type_node)) |
| 1435 | try transStringLiteralAsArray(c, scope, @ptrCast(*const clang.StringLiteral, expr), try zigArraySize(c, type_node)) |
| 1502 | 1436 | else |
| 1503 | | try transExprCoercing(rp, scope, expr, .used, .r_value) |
| 1437 | try transExprCoercing(c, scope, expr, .used, .r_value) |
| 1504 | 1438 | else |
| 1505 | 1439 | try transCreateNodeUndefinedLiteral(c); |
| 1506 | 1440 | if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) { |
| 1507 | | const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1); |
| 1508 | | builtin_node.params()[0] = init_node; |
| 1509 | | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1510 | | init_node = &builtin_node.base; |
| 1441 | init_node = try Node.bool_to_int.create(c.arena, init_node); |
| 1511 | 1442 | } |
| 1512 | | const semicolon_token = try appendToken(c, .Semicolon, ";"); |
| 1513 | | const node = try ast.Node.VarDecl.create(c.arena, .{ |
| 1514 | | .name_token = name_tok, |
| 1515 | | .mut_token = mut_tok, |
| 1516 | | .semicolon_token = semicolon_token, |
| 1517 | | }, .{ |
| 1518 | | .eq_token = eq_token, |
| 1519 | | .type_node = type_node, |
| 1520 | | .init_node = init_node, |
| 1443 | return Node.var_decl.create(c.arena, .{ |
| 1444 | .is_pub = false, |
| 1445 | .is_const = is_const, |
| 1446 | .is_extern = false, |
| 1447 | .is_export = false, |
| 1448 | .linksection_string = null, |
| 1449 | .alignment = null, |
| 1450 | .name = mangled_name, |
| 1451 | .type = type_node, |
| 1452 | .init = init_node, |
| 1521 | 1453 | }); |
| 1522 | | return &node.base; |
| 1523 | 1454 | }, |
| 1524 | 1455 | .Typedef => { |
| 1525 | 1456 | const typedef_decl = @ptrCast(*const clang.TypedefNameDecl, decl); |
| ... | ... | @@ -1529,7 +1460,7 @@ fn transDeclStmtOne( |
| 1529 | 1460 | const underlying_type = underlying_qual.getTypePtr(); |
| 1530 | 1461 | |
| 1531 | 1462 | const mangled_name = try block_scope.makeMangledName(c, name); |
| 1532 | | const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse |
| 1463 | const node = (try transCreateNodeTypedef(c, typedef_decl, false, mangled_name)) orelse |
| 1533 | 1464 | return error.UnsupportedTranslation; |
| 1534 | 1465 | return node; |
| 1535 | 1466 | }, |
| ... | ... | @@ -1543,14 +1474,14 @@ fn transDeclStmtOne( |
| 1543 | 1474 | } |
| 1544 | 1475 | } |
| 1545 | 1476 | |
| 1546 | | fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const clang.DeclStmt) TransError!*ast.Node { |
| 1547 | | const block_scope = scope.findBlockScope(rp.c) catch unreachable; |
| 1477 | fn transDeclStmt(c: *Context, scope: *Scope, stmt: *const clang.DeclStmt) TransError!Node { |
| 1478 | const block_scope = scope.findBlockScope(c) catch unreachable; |
| 1548 | 1479 | |
| 1549 | 1480 | var it = stmt.decl_begin(); |
| 1550 | 1481 | const end_it = stmt.decl_end(); |
| 1551 | 1482 | assert(it != end_it); |
| 1552 | 1483 | while (true) : (it += 1) { |
| 1553 | | const node = try transDeclStmtOne(rp, scope, it[0], block_scope); |
| 1484 | const node = try transDeclStmtOne(c, scope, it[0], block_scope); |
| 1554 | 1485 | |
| 1555 | 1486 | if (it + 1 == end_it) { |
| 1556 | 1487 | return node; |
| ... | ... | @@ -1562,15 +1493,15 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const clang.DeclStmt) T |
| 1562 | 1493 | } |
| 1563 | 1494 | |
| 1564 | 1495 | fn transDeclRefExpr( |
| 1565 | | rp: RestorePoint, |
| 1496 | c: *Context, |
| 1566 | 1497 | scope: *Scope, |
| 1567 | 1498 | expr: *const clang.DeclRefExpr, |
| 1568 | 1499 | lrvalue: LRValue, |
| 1569 | | ) TransError!*ast.Node { |
| 1500 | ) TransError!Node { |
| 1570 | 1501 | const value_decl = expr.getDecl(); |
| 1571 | | const name = try rp.c.str(@ptrCast(*const clang.NamedDecl, value_decl).getName_bytes_begin()); |
| 1502 | const name = try c.str(@ptrCast(*const clang.NamedDecl, value_decl).getName_bytes_begin()); |
| 1572 | 1503 | const mangled_name = scope.getAlias(name); |
| 1573 | | return transCreateNodeIdentifier(rp.c, mangled_name); |
| 1504 | return Node.identifier.create(c.arena, mangled_name); |
| 1574 | 1505 | } |
| 1575 | 1506 | |
| 1576 | 1507 | fn transImplicitCastExpr( |
| ... | ... | @@ -1642,52 +1573,29 @@ fn transImplicitCastExpr( |
| 1642 | 1573 | } |
| 1643 | 1574 | |
| 1644 | 1575 | fn transBoolExpr( |
| 1645 | | rp: RestorePoint, |
| 1576 | c: *Context, |
| 1646 | 1577 | scope: *Scope, |
| 1647 | 1578 | expr: *const clang.Expr, |
| 1648 | 1579 | used: ResultUsed, |
| 1649 | 1580 | lrvalue: LRValue, |
| 1650 | | grouped: bool, |
| 1651 | | ) TransError!*ast.Node { |
| 1581 | ) TransError!Node { |
| 1652 | 1582 | if (@ptrCast(*const clang.Stmt, expr).getStmtClass() == .IntegerLiteralClass) { |
| 1653 | 1583 | var is_zero: bool = undefined; |
| 1654 | | if (!(@ptrCast(*const clang.IntegerLiteral, expr).isZero(&is_zero, rp.c.clang_context))) { |
| 1655 | | return revertAndWarn(rp, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{}); |
| 1584 | if (!(@ptrCast(*const clang.IntegerLiteral, expr).isZero(&is_zero, c.clang_context))) { |
| 1585 | return revertAndWarn(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{}); |
| 1656 | 1586 | } |
| 1657 | | return try transCreateNodeBoolLiteral(rp.c, !is_zero); |
| 1587 | return Node{ .tag = ([2]ast.Node.Tag{ .true_literal, .false_literal })[is_zero] }; |
| 1658 | 1588 | } |
| 1659 | 1589 | |
| 1660 | | const lparen = if (grouped) |
| 1661 | | try appendToken(rp.c, .LParen, "(") |
| 1662 | | else |
| 1663 | | undefined; |
| 1664 | | var res = try transExpr(rp, scope, expr, used, lrvalue); |
| 1665 | | |
| 1590 | var res = try transExpr(c, scope, expr, used, lrvalue); |
| 1666 | 1591 | if (isBoolRes(res)) { |
| 1667 | | if (!grouped and res.tag == .GroupedExpression) { |
| 1668 | | const group = @fieldParentPtr(ast.Node.GroupedExpression, "base", res); |
| 1669 | | res = group.expr; |
| 1670 | | // get zig fmt to work properly |
| 1671 | | tokenSlice(rp.c, group.lparen)[0] = ')'; |
| 1672 | | } |
| 1673 | 1592 | return res; |
| 1674 | 1593 | } |
| 1675 | 1594 | |
| 1676 | | const ty = getExprQualType(rp.c, expr).getTypePtr(); |
| 1677 | | const node = try finishBoolExpr(rp, scope, expr.getBeginLoc(), ty, res, used); |
| 1595 | const ty = getExprQualType(c, expr).getTypePtr(); |
| 1596 | const node = try finishBoolExpr(c, scope, expr.getBeginLoc(), ty, res, used); |
| 1678 | 1597 | |
| 1679 | | if (grouped) { |
| 1680 | | const rparen = try appendToken(rp.c, .RParen, ")"); |
| 1681 | | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); |
| 1682 | | grouped_expr.* = .{ |
| 1683 | | .lparen = lparen, |
| 1684 | | .expr = node, |
| 1685 | | .rparen = rparen, |
| 1686 | | }; |
| 1687 | | return maybeSuppressResult(rp, scope, used, &grouped_expr.base); |
| 1688 | | } else { |
| 1689 | | return maybeSuppressResult(rp, scope, used, node); |
| 1690 | | } |
| 1598 | return maybeSuppressResult(c, scope, used, node); |
| 1691 | 1599 | } |
| 1692 | 1600 | |
| 1693 | 1601 | fn exprIsBooleanType(expr: *const clang.Expr) bool { |
| ... | ... | @@ -1713,34 +1621,32 @@ fn exprIsNarrowStringLiteral(expr: *const clang.Expr) bool { |
| 1713 | 1621 | } |
| 1714 | 1622 | } |
| 1715 | 1623 | |
| 1716 | | fn isBoolRes(res: *ast.Node) bool { |
| 1717 | | switch (res.tag) { |
| 1718 | | .BoolOr, |
| 1719 | | .BoolAnd, |
| 1720 | | .EqualEqual, |
| 1721 | | .BangEqual, |
| 1722 | | .LessThan, |
| 1723 | | .GreaterThan, |
| 1724 | | .LessOrEqual, |
| 1725 | | .GreaterOrEqual, |
| 1726 | | .BoolNot, |
| 1727 | | .BoolLiteral, |
| 1624 | fn isBoolRes(res: Node) bool { |
| 1625 | switch (res.tag()) { |
| 1626 | .@"or", |
| 1627 | .@"and", |
| 1628 | .equal, |
| 1629 | .note_equal, |
| 1630 | .less_than, |
| 1631 | .less_than_equal, |
| 1632 | .greater_than, |
| 1633 | .greater_than_equal, |
| 1634 | .not, |
| 1635 | .false_literal, |
| 1636 | .true_literal, |
| 1728 | 1637 | => return true, |
| 1729 | | |
| 1730 | | .GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr), |
| 1731 | | |
| 1732 | 1638 | else => return false, |
| 1733 | 1639 | } |
| 1734 | 1640 | } |
| 1735 | 1641 | |
| 1736 | 1642 | fn finishBoolExpr( |
| 1737 | | rp: RestorePoint, |
| 1643 | c: *Context, |
| 1738 | 1644 | scope: *Scope, |
| 1739 | 1645 | loc: clang.SourceLocation, |
| 1740 | 1646 | ty: *const clang.Type, |
| 1741 | | node: *ast.Node, |
| 1647 | node: Node, |
| 1742 | 1648 | used: ResultUsed, |
| 1743 | | ) TransError!*ast.Node { |
| 1649 | ) TransError!Node { |
| 1744 | 1650 | switch (ty.getTypeClass()) { |
| 1745 | 1651 | .Builtin => { |
| 1746 | 1652 | const builtin_ty = @ptrCast(*const clang.BuiltinType, ty); |
| ... | ... | @@ -1772,42 +1678,39 @@ fn finishBoolExpr( |
| 1772 | 1678 | .WChar_S, |
| 1773 | 1679 | .Float16, |
| 1774 | 1680 | => { |
| 1775 | | const op_token = try appendToken(rp.c, .BangEqual, "!="); |
| 1776 | | const rhs_node = try transCreateNodeInt(rp.c, 0); |
| 1777 | | return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false); |
| 1681 | // node != 0 |
| 1682 | return Node.not_equal.create(c.arena, .{ .lhs = node, .rhs = Node.zero_literal.init()}); |
| 1778 | 1683 | }, |
| 1779 | 1684 | .NullPtr => { |
| 1780 | | const op_token = try appendToken(rp.c, .EqualEqual, "=="); |
| 1781 | | const rhs_node = try transCreateNodeNullLiteral(rp.c); |
| 1782 | | return transCreateNodeInfixOp(rp, scope, node, .EqualEqual, op_token, rhs_node, used, false); |
| 1685 | // node == null |
| 1686 | return Node.equal.create(c.arena, .{ .lhs = node, .rhs = Node.null_literal.init()}); |
| 1783 | 1687 | }, |
| 1784 | 1688 | else => {}, |
| 1785 | 1689 | } |
| 1786 | 1690 | }, |
| 1787 | 1691 | .Pointer => { |
| 1788 | | const op_token = try appendToken(rp.c, .BangEqual, "!="); |
| 1789 | | const rhs_node = try transCreateNodeNullLiteral(rp.c); |
| 1790 | | return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false); |
| 1692 | // node == null |
| 1693 | return Node.equal.create(c.arena, .{ .lhs = node, .rhs = Node.null_literal.init()}); |
| 1791 | 1694 | }, |
| 1792 | 1695 | .Typedef => { |
| 1793 | 1696 | const typedef_ty = @ptrCast(*const clang.TypedefType, ty); |
| 1794 | 1697 | const typedef_decl = typedef_ty.getDecl(); |
| 1795 | 1698 | const underlying_type = typedef_decl.getUnderlyingType(); |
| 1796 | | return finishBoolExpr(rp, scope, loc, underlying_type.getTypePtr(), node, used); |
| 1699 | return finishBoolExpr(c, scope, loc, underlying_type.getTypePtr(), node, used); |
| 1797 | 1700 | }, |
| 1798 | 1701 | .Enum => { |
| 1799 | | const op_token = try appendToken(rp.c, .BangEqual, "!="); |
| 1800 | | const rhs_node = try transCreateNodeInt(rp.c, 0); |
| 1801 | | return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false); |
| 1702 | // node != 0 |
| 1703 | return Node.not_equal.create(c.arena, .{ .lhs = node, .rhs = Node.zero_literal.init()}); |
| 1704 | const op_token = try appendToken(c, .BangEqual, "!="); |
| 1802 | 1705 | }, |
| 1803 | 1706 | .Elaborated => { |
| 1804 | 1707 | const elaborated_ty = @ptrCast(*const clang.ElaboratedType, ty); |
| 1805 | 1708 | const named_type = elaborated_ty.getNamedType(); |
| 1806 | | return finishBoolExpr(rp, scope, loc, named_type.getTypePtr(), node, used); |
| 1709 | return finishBoolExpr(c, scope, loc, named_type.getTypePtr(), node, used); |
| 1807 | 1710 | }, |
| 1808 | 1711 | else => {}, |
| 1809 | 1712 | } |
| 1810 | | return revertAndWarn(rp, error.UnsupportedType, loc, "unsupported bool expression type", .{}); |
| 1713 | return fail(c, error.UnsupportedType, loc, "unsupported bool expression type", .{}); |
| 1811 | 1714 | } |
| 1812 | 1715 | |
| 1813 | 1716 | const SuppressCast = enum { |
| ... | ... | @@ -4242,7 +4145,7 @@ fn transCreateNodeBoolInfixOp( |
| 4242 | 4145 | .rhs = rhs, |
| 4243 | 4146 | }, |
| 4244 | 4147 | }; |
| 4245 | | return maybeSuppressResult(c, scope, used, &payload.base); |
| 4148 | return maybeSuppressResult(c, scope, used, Node.initPayload(&payload.base)); |
| 4246 | 4149 | } |
| 4247 | 4150 | |
| 4248 | 4151 | fn transCreateNodePtrType( |
| ... | ... | @@ -4654,7 +4557,7 @@ fn transCreateNodeShiftOp( |
| 4654 | 4557 | const lhs = try transExpr(c, scope, lhs_expr, .used, .l_value); |
| 4655 | 4558 | |
| 4656 | 4559 | const rhs_type = try qualTypeToLog2IntRef(c, stmt.getType(), rhs_location); |
| 4657 | | const rhs = try transExpr(c, scope, rhs_expr, .used, .r_value); |
| 4560 | const rhs = try transExprCoercing(c, scope, rhs_expr, .used, .r_value); |
| 4658 | 4561 | const rhs_casted = try Node.int_cast.create(c.arena, .{ .lhs = rhs_type, .rhs = rhs_type }); |
| 4659 | 4562 | |
| 4660 | 4563 | const payload = try c.arena.create(ast.Payload.BinOp); |
| ... | ... | @@ -4663,9 +4566,9 @@ fn transCreateNodeShiftOp( |
| 4663 | 4566 | .data = .{ |
| 4664 | 4567 | .lhs = lhs, |
| 4665 | 4568 | .rhs = rhs_casted, |
| 4666 | | } |
| 4569 | }, |
| 4667 | 4570 | }; |
| 4668 | | return &payload.base; |
| 4571 | return Node.initPayload(&payload.base); |
| 4669 | 4572 | } |
| 4670 | 4573 | |
| 4671 | 4574 | fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node { |
| ... | ... | @@ -4961,7 +4864,7 @@ fn finishTransFnProto( |
| 4961 | 4864 | }; |
| 4962 | 4865 | } |
| 4963 | 4866 | |
| 4964 | | const link_section_string: ?[]const u8 = blk: { |
| 4867 | const linksection_string = blk: { |
| 4965 | 4868 | if (fn_decl) |decl| { |
| 4966 | 4869 | var str_len: usize = undefined; |
| 4967 | 4870 | if (decl.getSectionAttribute(&str_len)) |str_ptr| { |
| ... | ... | @@ -5004,24 +4907,19 @@ fn finishTransFnProto( |
| 5004 | 4907 | } |
| 5005 | 4908 | }; |
| 5006 | 4909 | |
| 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 | | }; |
| 5024 | | return fn_proto; |
| 4910 | return Node.func.create(c.arena, .{ |
| 4911 | .is_pub = is_pub, |
| 4912 | .is_extern = is_extern, |
| 4913 | .is_export = is_export, |
| 4914 | .is_var_args = is_var_args, |
| 4915 | .name = name, |
| 4916 | .linksection_string = linksection_string, |
| 4917 | .explicit_callconv = explicit_callconv, |
| 4918 | .params = try c.arena.dupe(ast.Payload.Func.Param, fn_params.items), |
| 4919 | .return_type = return_node, |
| 4920 | .body = null, |
| 4921 | .alignment = alignment, |
| 4922 | }); |
| 5025 | 4923 | } |
| 5026 | 4924 | |
| 5027 | 4925 | fn warn(c: *Context, scope: *Scope, loc: clang.SourceLocation, comptime format: []const u8, args: anytype) !void { |
| ... | ... | @@ -5054,6 +4952,19 @@ pub fn freeErrors(errors: []ClangErrMsg) void { |
| 5054 | 4952 | errors.ptr.delete(errors.len); |
| 5055 | 4953 | } |
| 5056 | 4954 | |
| 4955 | fn isZigPrimitiveType(name: []const u8) bool { |
| 4956 | if (name.len > 1 and (name[0] == 'u' or name[0] == 'i')) { |
| 4957 | for (name[1..]) |c| { |
| 4958 | switch (c) { |
| 4959 | '0'...'9' => {}, |
| 4960 | else => return false, |
| 4961 | } |
| 4962 | } |
| 4963 | return true; |
| 4964 | } |
| 4965 | return @import("astgen.zig").simple_types.has(name); |
| 4966 | } |
| 4967 | |
| 5057 | 4968 | const MacroCtx = struct { |
| 5058 | 4969 | source: []const u8, |
| 5059 | 4970 | list: []const CToken, |