| author | |
| committer | |
| log | 4003cd4747019d79ff50aaa22415d2d3dfc15cf4 |
| tree | 1f77690a5fb7ccbef75bcab9c8c1e008ef3c5068 |
| parent | bf1f91595d4d3b5911632c671ef16e44d70dc9a6 |
| parent | 815950996dcc92ac6ac285f2005dbac51b9cb6f8 |
| signature |
MacOS stack traces
closes #1365 16 files changed, 1389 insertions(+), 573 deletions(-)
example/shared_library/mathtest.zig+9| ... | @@ -1,3 +1,12 @@ | ... | @@ -1,3 +1,12 @@ |
| 1 | // TODO Remove this workaround | ||
| 2 | comptime { | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | if (builtin.os == builtin.Os.macosx) { | ||
| 5 | @export("__mh_execute_header", _mh_execute_header, builtin.GlobalLinkage.Weak); | ||
| 6 | } | ||
| 7 | } | ||
| 8 | var _mh_execute_header = extern struct {x: usize}{.x = 0}; | ||
| 9 | |||
| 1 | export fn add(a: i32, b: i32) i32 { | 10 | export fn add(a: i32, b: i32) i32 { |
| 2 | return a + b; | 11 | return a + b; |
| 3 | } | 12 | } |
src/analyze.cpp+129-85| ... | @@ -19,12 +19,12 @@ | ... | @@ -19,12 +19,12 @@ |
| 19 | 19 | ||
| 20 | static const size_t default_backward_branch_quota = 1000; | 20 | static const size_t default_backward_branch_quota = 1000; |
| 21 | 21 | ||
| 22 | static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type); | 22 | static Error resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type); |
| 23 | static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type); | 23 | static Error resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type); |
| 24 | 24 | ||
| 25 | static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type); | 25 | static Error ATTRIBUTE_MUST_USE resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type); |
| 26 | static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type); | 26 | static Error ATTRIBUTE_MUST_USE resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type); |
| 27 | static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type); | 27 | static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type); |
| 28 | static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry); | 28 | static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry); |
| 29 | 29 | ||
| 30 | ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { | 30 | ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { |
| ... | @@ -370,15 +370,20 @@ uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) { | ... | @@ -370,15 +370,20 @@ uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) { |
| 370 | return LLVMSizeOfTypeInBits(g->target_data_ref, type_entry->type_ref); | 370 | return LLVMSizeOfTypeInBits(g->target_data_ref, type_entry->type_ref); |
| 371 | } | 371 | } |
| 372 | 372 | ||
| 373 | bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry) { | 373 | Result<bool> type_is_copyable(CodeGen *g, TypeTableEntry *type_entry) { |
| 374 | type_ensure_zero_bits_known(g, type_entry); | 374 | Error err; |
| 375 | if ((err = type_ensure_zero_bits_known(g, type_entry))) | ||
| 376 | return err; | ||
| 377 | |||
| 375 | if (!type_has_bits(type_entry)) | 378 | if (!type_has_bits(type_entry)) |
| 376 | return true; | 379 | return true; |
| 377 | 380 | ||
| 378 | if (!handle_is_ptr(type_entry)) | 381 | if (!handle_is_ptr(type_entry)) |
| 379 | return true; | 382 | return true; |
| 380 | 383 | ||
| 381 | ensure_complete_type(g, type_entry); | 384 | if ((err = ensure_complete_type(g, type_entry))) |
| 385 | return err; | ||
| 386 | |||
| 382 | return type_entry->is_copyable; | 387 | return type_entry->is_copyable; |
| 383 | } | 388 | } |
| 384 | 389 | ||
| ... | @@ -447,7 +452,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type | ... | @@ -447,7 +452,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type |
| 447 | } | 452 | } |
| 448 | } | 453 | } |
| 449 | 454 | ||
| 450 | type_ensure_zero_bits_known(g, child_type); | 455 | assertNoError(type_ensure_zero_bits_known(g, child_type)); |
| 451 | 456 | ||
| 452 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer); | 457 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer); |
| 453 | entry->is_copyable = true; | 458 | entry->is_copyable = true; |
| ... | @@ -554,11 +559,11 @@ TypeTableEntry *get_optional_type(CodeGen *g, TypeTableEntry *child_type) { | ... | @@ -554,11 +559,11 @@ TypeTableEntry *get_optional_type(CodeGen *g, TypeTableEntry *child_type) { |
| 554 | TypeTableEntry *entry = child_type->optional_parent; | 559 | TypeTableEntry *entry = child_type->optional_parent; |
| 555 | return entry; | 560 | return entry; |
| 556 | } else { | 561 | } else { |
| 557 | ensure_complete_type(g, child_type); | 562 | assertNoError(ensure_complete_type(g, child_type)); |
| 558 | 563 | ||
| 559 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdOptional); | 564 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdOptional); |
| 560 | assert(child_type->type_ref || child_type->zero_bits); | 565 | assert(child_type->type_ref || child_type->zero_bits); |
| 561 | entry->is_copyable = type_is_copyable(g, child_type); | 566 | entry->is_copyable = type_is_copyable(g, child_type).unwrap(); |
| 562 | 567 | ||
| 563 | buf_resize(&entry->name, 0); | 568 | buf_resize(&entry->name, 0); |
| 564 | buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name)); | 569 | buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name)); |
| ... | @@ -650,7 +655,7 @@ TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, T | ... | @@ -650,7 +655,7 @@ TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, T |
| 650 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion); | 655 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion); |
| 651 | entry->is_copyable = true; | 656 | entry->is_copyable = true; |
| 652 | assert(payload_type->di_type); | 657 | assert(payload_type->di_type); |
| 653 | ensure_complete_type(g, payload_type); | 658 | assertNoError(ensure_complete_type(g, payload_type)); |
| 654 | 659 | ||
| 655 | buf_resize(&entry->name, 0); | 660 | buf_resize(&entry->name, 0); |
| 656 | buf_appendf(&entry->name, "%s!%s", buf_ptr(&err_set_type->name), buf_ptr(&payload_type->name)); | 661 | buf_appendf(&entry->name, "%s!%s", buf_ptr(&err_set_type->name), buf_ptr(&payload_type->name)); |
| ... | @@ -739,7 +744,7 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t | ... | @@ -739,7 +744,7 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t |
| 739 | return entry; | 744 | return entry; |
| 740 | } | 745 | } |
| 741 | 746 | ||
| 742 | ensure_complete_type(g, child_type); | 747 | assertNoError(ensure_complete_type(g, child_type)); |
| 743 | 748 | ||
| 744 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray); | 749 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray); |
| 745 | entry->zero_bits = (array_size == 0) || child_type->zero_bits; | 750 | entry->zero_bits = (array_size == 0) || child_type->zero_bits; |
| ... | @@ -1050,13 +1055,13 @@ TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g) { | ... | @@ -1050,13 +1055,13 @@ TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g) { |
| 1050 | } | 1055 | } |
| 1051 | 1056 | ||
| 1052 | TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { | 1057 | TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 1058 | Error err; | ||
| 1053 | auto table_entry = g->fn_type_table.maybe_get(fn_type_id); | 1059 | auto table_entry = g->fn_type_table.maybe_get(fn_type_id); |
| 1054 | if (table_entry) { | 1060 | if (table_entry) { |
| 1055 | return table_entry->value; | 1061 | return table_entry->value; |
| 1056 | } | 1062 | } |
| 1057 | if (fn_type_id->return_type != nullptr) { | 1063 | if (fn_type_id->return_type != nullptr) { |
| 1058 | ensure_complete_type(g, fn_type_id->return_type); | 1064 | if ((err = ensure_complete_type(g, fn_type_id->return_type))) |
| 1059 | if (type_is_invalid(fn_type_id->return_type)) | ||
| 1060 | return g->builtin_types.entry_invalid; | 1065 | return g->builtin_types.entry_invalid; |
| 1061 | assert(fn_type_id->return_type->id != TypeTableEntryIdOpaque); | 1066 | assert(fn_type_id->return_type->id != TypeTableEntryIdOpaque); |
| 1062 | } else { | 1067 | } else { |
| ... | @@ -1172,8 +1177,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { | ... | @@ -1172,8 +1177,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 1172 | gen_param_info->src_index = i; | 1177 | gen_param_info->src_index = i; |
| 1173 | gen_param_info->gen_index = SIZE_MAX; | 1178 | gen_param_info->gen_index = SIZE_MAX; |
| 1174 | 1179 | ||
| 1175 | ensure_complete_type(g, type_entry); | 1180 | if ((err = ensure_complete_type(g, type_entry))) |
| 1176 | if (type_is_invalid(type_entry)) | ||
| 1177 | return g->builtin_types.entry_invalid; | 1181 | return g->builtin_types.entry_invalid; |
| 1178 | 1182 | ||
| 1179 | if (type_has_bits(type_entry)) { | 1183 | if (type_has_bits(type_entry)) { |
| ... | @@ -1493,6 +1497,7 @@ TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry) { | ... | @@ -1493,6 +1497,7 @@ TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry) { |
| 1493 | static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope, FnTableEntry *fn_entry) { | 1497 | static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_scope, FnTableEntry *fn_entry) { |
| 1494 | assert(proto_node->type == NodeTypeFnProto); | 1498 | assert(proto_node->type == NodeTypeFnProto); |
| 1495 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; | 1499 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| 1500 | Error err; | ||
| 1496 | 1501 | ||
| 1497 | FnTypeId fn_type_id = {0}; | 1502 | FnTypeId fn_type_id = {0}; |
| 1498 | init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length); | 1503 | init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length); |
| ... | @@ -1550,7 +1555,8 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c | ... | @@ -1550,7 +1555,8 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 1550 | return g->builtin_types.entry_invalid; | 1555 | return g->builtin_types.entry_invalid; |
| 1551 | } | 1556 | } |
| 1552 | if (!calling_convention_allows_zig_types(fn_type_id.cc)) { | 1557 | if (!calling_convention_allows_zig_types(fn_type_id.cc)) { |
| 1553 | type_ensure_zero_bits_known(g, type_entry); | 1558 | if ((err = type_ensure_zero_bits_known(g, type_entry))) |
| 1559 | return g->builtin_types.entry_invalid; | ||
| 1554 | if (!type_has_bits(type_entry)) { | 1560 | if (!type_has_bits(type_entry)) { |
| 1555 | add_node_error(g, param_node->data.param_decl.type, | 1561 | add_node_error(g, param_node->data.param_decl.type, |
| 1556 | buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'", | 1562 | buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'", |
| ... | @@ -1598,7 +1604,8 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c | ... | @@ -1598,7 +1604,8 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 1598 | case TypeTableEntryIdUnion: | 1604 | case TypeTableEntryIdUnion: |
| 1599 | case TypeTableEntryIdFn: | 1605 | case TypeTableEntryIdFn: |
| 1600 | case TypeTableEntryIdPromise: | 1606 | case TypeTableEntryIdPromise: |
| 1601 | type_ensure_zero_bits_known(g, type_entry); | 1607 | if ((err = type_ensure_zero_bits_known(g, type_entry))) |
| 1608 | return g->builtin_types.entry_invalid; | ||
| 1602 | if (type_requires_comptime(type_entry)) { | 1609 | if (type_requires_comptime(type_entry)) { |
| 1603 | add_node_error(g, param_node->data.param_decl.type, | 1610 | add_node_error(g, param_node->data.param_decl.type, |
| 1604 | buf_sprintf("parameter of type '%s' must be declared comptime", | 1611 | buf_sprintf("parameter of type '%s' must be declared comptime", |
| ... | @@ -1729,24 +1736,28 @@ bool type_is_invalid(TypeTableEntry *type_entry) { | ... | @@ -1729,24 +1736,28 @@ bool type_is_invalid(TypeTableEntry *type_entry) { |
| 1729 | } | 1736 | } |
| 1730 | 1737 | ||
| 1731 | 1738 | ||
| 1732 | static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { | 1739 | static Error resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1733 | assert(enum_type->id == TypeTableEntryIdEnum); | 1740 | assert(enum_type->id == TypeTableEntryIdEnum); |
| 1734 | 1741 | ||
| 1742 | if (enum_type->data.enumeration.is_invalid) | ||
| 1743 | return ErrorSemanticAnalyzeFail; | ||
| 1744 | |||
| 1735 | if (enum_type->data.enumeration.complete) | 1745 | if (enum_type->data.enumeration.complete) |
| 1736 | return; | 1746 | return ErrorNone; |
| 1737 | 1747 | ||
| 1738 | resolve_enum_zero_bits(g, enum_type); | 1748 | Error err; |
| 1739 | if (type_is_invalid(enum_type)) | 1749 | if ((err = resolve_enum_zero_bits(g, enum_type))) |
| 1740 | return; | 1750 | return err; |
| 1741 | 1751 | ||
| 1742 | AstNode *decl_node = enum_type->data.enumeration.decl_node; | 1752 | AstNode *decl_node = enum_type->data.enumeration.decl_node; |
| 1743 | 1753 | ||
| 1744 | if (enum_type->data.enumeration.embedded_in_current) { | 1754 | if (enum_type->data.enumeration.embedded_in_current) { |
| 1745 | if (!enum_type->data.enumeration.reported_infinite_err) { | 1755 | if (!enum_type->data.enumeration.reported_infinite_err) { |
| 1756 | enum_type->data.enumeration.is_invalid = true; | ||
| 1746 | enum_type->data.enumeration.reported_infinite_err = true; | 1757 | enum_type->data.enumeration.reported_infinite_err = true; |
| 1747 | add_node_error(g, decl_node, buf_sprintf("enum '%s' contains itself", buf_ptr(&enum_type->name))); | 1758 | add_node_error(g, decl_node, buf_sprintf("enum '%s' contains itself", buf_ptr(&enum_type->name))); |
| 1748 | } | 1759 | } |
| 1749 | return; | 1760 | return ErrorSemanticAnalyzeFail; |
| 1750 | } | 1761 | } |
| 1751 | 1762 | ||
| 1752 | assert(!enum_type->data.enumeration.zero_bits_loop_flag); | 1763 | assert(!enum_type->data.enumeration.zero_bits_loop_flag); |
| ... | @@ -1778,7 +1789,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { | ... | @@ -1778,7 +1789,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1778 | enum_type->data.enumeration.complete = true; | 1789 | enum_type->data.enumeration.complete = true; |
| 1779 | 1790 | ||
| 1780 | if (enum_type->data.enumeration.is_invalid) | 1791 | if (enum_type->data.enumeration.is_invalid) |
| 1781 | return; | 1792 | return ErrorSemanticAnalyzeFail; |
| 1782 | 1793 | ||
| 1783 | if (enum_type->zero_bits) { | 1794 | if (enum_type->zero_bits) { |
| 1784 | enum_type->type_ref = LLVMVoidType(); | 1795 | enum_type->type_ref = LLVMVoidType(); |
| ... | @@ -1797,7 +1808,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { | ... | @@ -1797,7 +1808,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1797 | 1808 | ||
| 1798 | ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type); | 1809 | ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type); |
| 1799 | enum_type->di_type = replacement_di_type; | 1810 | enum_type->di_type = replacement_di_type; |
| 1800 | return; | 1811 | return ErrorNone; |
| 1801 | } | 1812 | } |
| 1802 | 1813 | ||
| 1803 | TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type; | 1814 | TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type; |
| ... | @@ -1815,6 +1826,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { | ... | @@ -1815,6 +1826,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1815 | 1826 | ||
| 1816 | ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type); | 1827 | ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type); |
| 1817 | enum_type->di_type = tag_di_type; | 1828 | enum_type->di_type = tag_di_type; |
| 1829 | return ErrorNone; | ||
| 1818 | } | 1830 | } |
| 1819 | 1831 | ||
| 1820 | 1832 | ||
| ... | @@ -1897,15 +1909,15 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f | ... | @@ -1897,15 +1909,15 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f |
| 1897 | return struct_type; | 1909 | return struct_type; |
| 1898 | } | 1910 | } |
| 1899 | 1911 | ||
| 1900 | static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { | 1912 | static Error resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 1901 | assert(struct_type->id == TypeTableEntryIdStruct); | 1913 | assert(struct_type->id == TypeTableEntryIdStruct); |
| 1902 | 1914 | ||
| 1903 | if (struct_type->data.structure.complete) | 1915 | if (struct_type->data.structure.complete) |
| 1904 | return; | 1916 | return ErrorNone; |
| 1905 | 1917 | ||
| 1906 | resolve_struct_zero_bits(g, struct_type); | 1918 | Error err; |
| 1907 | if (struct_type->data.structure.is_invalid) | 1919 | if ((err = resolve_struct_zero_bits(g, struct_type))) |
| 1908 | return; | 1920 | return err; |
| 1909 | 1921 | ||
| 1910 | AstNode *decl_node = struct_type->data.structure.decl_node; | 1922 | AstNode *decl_node = struct_type->data.structure.decl_node; |
| 1911 | 1923 | ||
| ... | @@ -1916,7 +1928,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { | ... | @@ -1916,7 +1928,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 1916 | add_node_error(g, decl_node, | 1928 | add_node_error(g, decl_node, |
| 1917 | buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name))); | 1929 | buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name))); |
| 1918 | } | 1930 | } |
| 1919 | return; | 1931 | return ErrorSemanticAnalyzeFail; |
| 1920 | } | 1932 | } |
| 1921 | 1933 | ||
| 1922 | assert(!struct_type->data.structure.zero_bits_loop_flag); | 1934 | assert(!struct_type->data.structure.zero_bits_loop_flag); |
| ... | @@ -1943,8 +1955,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { | ... | @@ -1943,8 +1955,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 1943 | TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; | 1955 | TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; |
| 1944 | TypeTableEntry *field_type = type_struct_field->type_entry; | 1956 | TypeTableEntry *field_type = type_struct_field->type_entry; |
| 1945 | 1957 | ||
| 1946 | ensure_complete_type(g, field_type); | 1958 | if ((err = ensure_complete_type(g, field_type))) { |
| 1947 | if (type_is_invalid(field_type)) { | ||
| 1948 | struct_type->data.structure.is_invalid = true; | 1959 | struct_type->data.structure.is_invalid = true; |
| 1949 | break; | 1960 | break; |
| 1950 | } | 1961 | } |
| ... | @@ -2026,7 +2037,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { | ... | @@ -2026,7 +2037,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 2026 | struct_type->data.structure.complete = true; | 2037 | struct_type->data.structure.complete = true; |
| 2027 | 2038 | ||
| 2028 | if (struct_type->data.structure.is_invalid) | 2039 | if (struct_type->data.structure.is_invalid) |
| 2029 | return; | 2040 | return ErrorSemanticAnalyzeFail; |
| 2030 | 2041 | ||
| 2031 | if (struct_type->zero_bits) { | 2042 | if (struct_type->zero_bits) { |
| 2032 | struct_type->type_ref = LLVMVoidType(); | 2043 | struct_type->type_ref = LLVMVoidType(); |
| ... | @@ -2045,7 +2056,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { | ... | @@ -2045,7 +2056,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 2045 | 0, nullptr, di_element_types, (int)debug_field_count, 0, nullptr, ""); | 2056 | 0, nullptr, di_element_types, (int)debug_field_count, 0, nullptr, ""); |
| 2046 | ZigLLVMReplaceTemporary(g->dbuilder, struct_type->di_type, replacement_di_type); | 2057 | ZigLLVMReplaceTemporary(g->dbuilder, struct_type->di_type, replacement_di_type); |
| 2047 | struct_type->di_type = replacement_di_type; | 2058 | struct_type->di_type = replacement_di_type; |
| 2048 | return; | 2059 | return ErrorNone; |
| 2049 | } | 2060 | } |
| 2050 | assert(struct_type->di_type); | 2061 | assert(struct_type->di_type); |
| 2051 | 2062 | ||
| ... | @@ -2128,17 +2139,19 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { | ... | @@ -2128,17 +2139,19 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 2128 | 2139 | ||
| 2129 | ZigLLVMReplaceTemporary(g->dbuilder, struct_type->di_type, replacement_di_type); | 2140 | ZigLLVMReplaceTemporary(g->dbuilder, struct_type->di_type, replacement_di_type); |
| 2130 | struct_type->di_type = replacement_di_type; | 2141 | struct_type->di_type = replacement_di_type; |
| 2142 | |||
| 2143 | return ErrorNone; | ||
| 2131 | } | 2144 | } |
| 2132 | 2145 | ||
| 2133 | static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { | 2146 | static Error resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 2134 | assert(union_type->id == TypeTableEntryIdUnion); | 2147 | assert(union_type->id == TypeTableEntryIdUnion); |
| 2135 | 2148 | ||
| 2136 | if (union_type->data.unionation.complete) | 2149 | if (union_type->data.unionation.complete) |
| 2137 | return; | 2150 | return ErrorNone; |
| 2138 | 2151 | ||
| 2139 | resolve_union_zero_bits(g, union_type); | 2152 | Error err; |
| 2140 | if (type_is_invalid(union_type)) | 2153 | if ((err = resolve_union_zero_bits(g, union_type))) |
| 2141 | return; | 2154 | return err; |
| 2142 | 2155 | ||
| 2143 | AstNode *decl_node = union_type->data.unionation.decl_node; | 2156 | AstNode *decl_node = union_type->data.unionation.decl_node; |
| 2144 | 2157 | ||
| ... | @@ -2148,7 +2161,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2148,7 +2161,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 2148 | union_type->data.unionation.is_invalid = true; | 2161 | union_type->data.unionation.is_invalid = true; |
| 2149 | add_node_error(g, decl_node, buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name))); | 2162 | add_node_error(g, decl_node, buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name))); |
| 2150 | } | 2163 | } |
| 2151 | return; | 2164 | return ErrorSemanticAnalyzeFail; |
| 2152 | } | 2165 | } |
| 2153 | 2166 | ||
| 2154 | assert(!union_type->data.unionation.zero_bits_loop_flag); | 2167 | assert(!union_type->data.unionation.zero_bits_loop_flag); |
| ... | @@ -2179,8 +2192,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2179,8 +2192,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 2179 | TypeUnionField *union_field = &union_type->data.unionation.fields[i]; | 2192 | TypeUnionField *union_field = &union_type->data.unionation.fields[i]; |
| 2180 | TypeTableEntry *field_type = union_field->type_entry; | 2193 | TypeTableEntry *field_type = union_field->type_entry; |
| 2181 | 2194 | ||
| 2182 | ensure_complete_type(g, field_type); | 2195 | if ((err = ensure_complete_type(g, field_type))) { |
| 2183 | if (type_is_invalid(field_type)) { | ||
| 2184 | union_type->data.unionation.is_invalid = true; | 2196 | union_type->data.unionation.is_invalid = true; |
| 2185 | continue; | 2197 | continue; |
| 2186 | } | 2198 | } |
| ... | @@ -2219,7 +2231,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2219,7 +2231,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 2219 | union_type->data.unionation.most_aligned_union_member = most_aligned_union_member; | 2231 | union_type->data.unionation.most_aligned_union_member = most_aligned_union_member; |
| 2220 | 2232 | ||
| 2221 | if (union_type->data.unionation.is_invalid) | 2233 | if (union_type->data.unionation.is_invalid) |
| 2222 | return; | 2234 | return ErrorSemanticAnalyzeFail; |
| 2223 | 2235 | ||
| 2224 | if (union_type->zero_bits) { | 2236 | if (union_type->zero_bits) { |
| 2225 | union_type->type_ref = LLVMVoidType(); | 2237 | union_type->type_ref = LLVMVoidType(); |
| ... | @@ -2238,7 +2250,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2238,7 +2250,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 2238 | 2250 | ||
| 2239 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type); | 2251 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type); |
| 2240 | union_type->di_type = replacement_di_type; | 2252 | union_type->di_type = replacement_di_type; |
| 2241 | return; | 2253 | return ErrorNone; |
| 2242 | } | 2254 | } |
| 2243 | 2255 | ||
| 2244 | uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits; | 2256 | uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits; |
| ... | @@ -2274,7 +2286,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2274,7 +2286,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 2274 | 2286 | ||
| 2275 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type); | 2287 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type); |
| 2276 | union_type->di_type = replacement_di_type; | 2288 | union_type->di_type = replacement_di_type; |
| 2277 | return; | 2289 | return ErrorNone; |
| 2278 | } | 2290 | } |
| 2279 | 2291 | ||
| 2280 | LLVMTypeRef union_type_ref; | 2292 | LLVMTypeRef union_type_ref; |
| ... | @@ -2293,7 +2305,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2293,7 +2305,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 2293 | 2305 | ||
| 2294 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, tag_type->di_type); | 2306 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, tag_type->di_type); |
| 2295 | union_type->di_type = tag_type->di_type; | 2307 | union_type->di_type = tag_type->di_type; |
| 2296 | return; | 2308 | return ErrorNone; |
| 2297 | } else { | 2309 | } else { |
| 2298 | union_type_ref = most_aligned_union_member->type_ref; | 2310 | union_type_ref = most_aligned_union_member->type_ref; |
| 2299 | } | 2311 | } |
| ... | @@ -2367,19 +2379,21 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2367,19 +2379,21 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 2367 | 2379 | ||
| 2368 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type); | 2380 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type); |
| 2369 | union_type->di_type = replacement_di_type; | 2381 | union_type->di_type = replacement_di_type; |
| 2382 | |||
| 2383 | return ErrorNone; | ||
| 2370 | } | 2384 | } |
| 2371 | 2385 | ||
| 2372 | static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { | 2386 | static Error resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { |
| 2373 | assert(enum_type->id == TypeTableEntryIdEnum); | 2387 | assert(enum_type->id == TypeTableEntryIdEnum); |
| 2374 | 2388 | ||
| 2375 | if (enum_type->data.enumeration.zero_bits_known) | 2389 | if (enum_type->data.enumeration.zero_bits_known) |
| 2376 | return; | 2390 | return ErrorNone; |
| 2377 | 2391 | ||
| 2378 | if (enum_type->data.enumeration.zero_bits_loop_flag) { | 2392 | if (enum_type->data.enumeration.zero_bits_loop_flag) { |
| 2379 | add_node_error(g, enum_type->data.enumeration.decl_node, | 2393 | add_node_error(g, enum_type->data.enumeration.decl_node, |
| 2380 | buf_sprintf("'%s' depends on itself", buf_ptr(&enum_type->name))); | 2394 | buf_sprintf("'%s' depends on itself", buf_ptr(&enum_type->name))); |
| 2381 | enum_type->data.enumeration.is_invalid = true; | 2395 | enum_type->data.enumeration.is_invalid = true; |
| 2382 | return; | 2396 | return ErrorSemanticAnalyzeFail; |
| 2383 | } | 2397 | } |
| 2384 | 2398 | ||
| 2385 | enum_type->data.enumeration.zero_bits_loop_flag = true; | 2399 | enum_type->data.enumeration.zero_bits_loop_flag = true; |
| ... | @@ -2398,7 +2412,7 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { | ... | @@ -2398,7 +2412,7 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { |
| 2398 | enum_type->data.enumeration.is_invalid = true; | 2412 | enum_type->data.enumeration.is_invalid = true; |
| 2399 | enum_type->data.enumeration.zero_bits_loop_flag = false; | 2413 | enum_type->data.enumeration.zero_bits_loop_flag = false; |
| 2400 | enum_type->data.enumeration.zero_bits_known = true; | 2414 | enum_type->data.enumeration.zero_bits_known = true; |
| 2401 | return; | 2415 | return ErrorSemanticAnalyzeFail; |
| 2402 | } | 2416 | } |
| 2403 | 2417 | ||
| 2404 | enum_type->data.enumeration.src_field_count = field_count; | 2418 | enum_type->data.enumeration.src_field_count = field_count; |
| ... | @@ -2525,13 +2539,23 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { | ... | @@ -2525,13 +2539,23 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { |
| 2525 | enum_type->data.enumeration.zero_bits_loop_flag = false; | 2539 | enum_type->data.enumeration.zero_bits_loop_flag = false; |
| 2526 | enum_type->zero_bits = !type_has_bits(tag_int_type); | 2540 | enum_type->zero_bits = !type_has_bits(tag_int_type); |
| 2527 | enum_type->data.enumeration.zero_bits_known = true; | 2541 | enum_type->data.enumeration.zero_bits_known = true; |
| 2542 | |||
| 2543 | if (enum_type->data.enumeration.is_invalid) | ||
| 2544 | return ErrorSemanticAnalyzeFail; | ||
| 2545 | |||
| 2546 | return ErrorNone; | ||
| 2528 | } | 2547 | } |
| 2529 | 2548 | ||
| 2530 | static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { | 2549 | static Error resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { |
| 2531 | assert(struct_type->id == TypeTableEntryIdStruct); | 2550 | assert(struct_type->id == TypeTableEntryIdStruct); |
| 2532 | 2551 | ||
| 2552 | Error err; | ||
| 2553 | |||
| 2554 | if (struct_type->data.structure.is_invalid) | ||
| 2555 | return ErrorSemanticAnalyzeFail; | ||
| 2556 | |||
| 2533 | if (struct_type->data.structure.zero_bits_known) | 2557 | if (struct_type->data.structure.zero_bits_known) |
| 2534 | return; | 2558 | return ErrorNone; |
| 2535 | 2559 | ||
| 2536 | if (struct_type->data.structure.zero_bits_loop_flag) { | 2560 | if (struct_type->data.structure.zero_bits_loop_flag) { |
| 2537 | // If we get here it's due to recursion. This is a design flaw in the compiler, | 2561 | // If we get here it's due to recursion. This is a design flaw in the compiler, |
| ... | @@ -2547,7 +2571,7 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { | ... | @@ -2547,7 +2571,7 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { |
| 2547 | struct_type->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref, LLVMPointerType(LLVMInt8Type(), 0)); | 2571 | struct_type->data.structure.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref, LLVMPointerType(LLVMInt8Type(), 0)); |
| 2548 | } | 2572 | } |
| 2549 | } | 2573 | } |
| 2550 | return; | 2574 | return ErrorNone; |
| 2551 | } | 2575 | } |
| 2552 | 2576 | ||
| 2553 | struct_type->data.structure.zero_bits_loop_flag = true; | 2577 | struct_type->data.structure.zero_bits_loop_flag = true; |
| ... | @@ -2596,8 +2620,7 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { | ... | @@ -2596,8 +2620,7 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { |
| 2596 | buf_sprintf("enums, not structs, support field assignment")); | 2620 | buf_sprintf("enums, not structs, support field assignment")); |
| 2597 | } | 2621 | } |
| 2598 | 2622 | ||
| 2599 | type_ensure_zero_bits_known(g, field_type); | 2623 | if ((err = type_ensure_zero_bits_known(g, field_type))) { |
| 2600 | if (type_is_invalid(field_type)) { | ||
| 2601 | struct_type->data.structure.is_invalid = true; | 2624 | struct_type->data.structure.is_invalid = true; |
| 2602 | continue; | 2625 | continue; |
| 2603 | } | 2626 | } |
| ... | @@ -2634,16 +2657,27 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { | ... | @@ -2634,16 +2657,27 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { |
| 2634 | struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index; | 2657 | struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index; |
| 2635 | struct_type->zero_bits = (gen_field_index == 0); | 2658 | struct_type->zero_bits = (gen_field_index == 0); |
| 2636 | struct_type->data.structure.zero_bits_known = true; | 2659 | struct_type->data.structure.zero_bits_known = true; |
| 2660 | |||
| 2661 | if (struct_type->data.structure.is_invalid) { | ||
| 2662 | return ErrorSemanticAnalyzeFail; | ||
| 2663 | } | ||
| 2664 | |||
| 2665 | return ErrorNone; | ||
| 2637 | } | 2666 | } |
| 2638 | 2667 | ||
| 2639 | static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { | 2668 | static Error resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 2640 | assert(union_type->id == TypeTableEntryIdUnion); | 2669 | assert(union_type->id == TypeTableEntryIdUnion); |
| 2641 | 2670 | ||
| 2671 | Error err; | ||
| 2672 | |||
| 2673 | if (union_type->data.unionation.is_invalid) | ||
| 2674 | return ErrorSemanticAnalyzeFail; | ||
| 2675 | |||
| 2642 | if (union_type->data.unionation.zero_bits_known) | 2676 | if (union_type->data.unionation.zero_bits_known) |
| 2643 | return; | 2677 | return ErrorNone; |
| 2644 | 2678 | ||
| 2645 | if (type_is_invalid(union_type)) | 2679 | if (type_is_invalid(union_type)) |
| 2646 | return; | 2680 | return ErrorSemanticAnalyzeFail; |
| 2647 | 2681 | ||
| 2648 | if (union_type->data.unionation.zero_bits_loop_flag) { | 2682 | if (union_type->data.unionation.zero_bits_loop_flag) { |
| 2649 | // If we get here it's due to recursion. From this we conclude that the struct is | 2683 | // If we get here it's due to recursion. From this we conclude that the struct is |
| ... | @@ -2660,7 +2694,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2660,7 +2694,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 2660 | LLVMPointerType(LLVMInt8Type(), 0)); | 2694 | LLVMPointerType(LLVMInt8Type(), 0)); |
| 2661 | } | 2695 | } |
| 2662 | } | 2696 | } |
| 2663 | return; | 2697 | return ErrorNone; |
| 2664 | } | 2698 | } |
| 2665 | 2699 | ||
| 2666 | union_type->data.unionation.zero_bits_loop_flag = true; | 2700 | union_type->data.unionation.zero_bits_loop_flag = true; |
| ... | @@ -2679,7 +2713,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2679,7 +2713,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 2679 | union_type->data.unionation.is_invalid = true; | 2713 | union_type->data.unionation.is_invalid = true; |
| 2680 | union_type->data.unionation.zero_bits_loop_flag = false; | 2714 | union_type->data.unionation.zero_bits_loop_flag = false; |
| 2681 | union_type->data.unionation.zero_bits_known = true; | 2715 | union_type->data.unionation.zero_bits_known = true; |
| 2682 | return; | 2716 | return ErrorSemanticAnalyzeFail; |
| 2683 | } | 2717 | } |
| 2684 | union_type->data.unionation.src_field_count = field_count; | 2718 | union_type->data.unionation.src_field_count = field_count; |
| 2685 | union_type->data.unionation.fields = allocate<TypeUnionField>(field_count); | 2719 | union_type->data.unionation.fields = allocate<TypeUnionField>(field_count); |
| ... | @@ -2711,13 +2745,13 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2711,13 +2745,13 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 2711 | tag_int_type = analyze_type_expr(g, scope, enum_type_node); | 2745 | tag_int_type = analyze_type_expr(g, scope, enum_type_node); |
| 2712 | if (type_is_invalid(tag_int_type)) { | 2746 | if (type_is_invalid(tag_int_type)) { |
| 2713 | union_type->data.unionation.is_invalid = true; | 2747 | union_type->data.unionation.is_invalid = true; |
| 2714 | return; | 2748 | return ErrorSemanticAnalyzeFail; |
| 2715 | } | 2749 | } |
| 2716 | if (tag_int_type->id != TypeTableEntryIdInt) { | 2750 | if (tag_int_type->id != TypeTableEntryIdInt) { |
| 2717 | add_node_error(g, enum_type_node, | 2751 | add_node_error(g, enum_type_node, |
| 2718 | buf_sprintf("expected integer tag type, found '%s'", buf_ptr(&tag_int_type->name))); | 2752 | buf_sprintf("expected integer tag type, found '%s'", buf_ptr(&tag_int_type->name))); |
| 2719 | union_type->data.unionation.is_invalid = true; | 2753 | union_type->data.unionation.is_invalid = true; |
| 2720 | return; | 2754 | return ErrorSemanticAnalyzeFail; |
| 2721 | } | 2755 | } |
| 2722 | } else { | 2756 | } else { |
| 2723 | tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1); | 2757 | tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1); |
| ... | @@ -2744,13 +2778,13 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2744,13 +2778,13 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 2744 | TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node); | 2778 | TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node); |
| 2745 | if (type_is_invalid(enum_type)) { | 2779 | if (type_is_invalid(enum_type)) { |
| 2746 | union_type->data.unionation.is_invalid = true; | 2780 | union_type->data.unionation.is_invalid = true; |
| 2747 | return; | 2781 | return ErrorSemanticAnalyzeFail; |
| 2748 | } | 2782 | } |
| 2749 | if (enum_type->id != TypeTableEntryIdEnum) { | 2783 | if (enum_type->id != TypeTableEntryIdEnum) { |
| 2750 | union_type->data.unionation.is_invalid = true; | 2784 | union_type->data.unionation.is_invalid = true; |
| 2751 | add_node_error(g, enum_type_node, | 2785 | add_node_error(g, enum_type_node, |
| 2752 | buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name))); | 2786 | buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name))); |
| 2753 | return; | 2787 | return ErrorSemanticAnalyzeFail; |
| 2754 | } | 2788 | } |
| 2755 | tag_type = enum_type; | 2789 | tag_type = enum_type; |
| 2756 | abi_alignment_so_far = get_abi_alignment(g, enum_type); // this populates src_field_count | 2790 | abi_alignment_so_far = get_abi_alignment(g, enum_type); // this populates src_field_count |
| ... | @@ -2789,8 +2823,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2789,8 +2823,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 2789 | } | 2823 | } |
| 2790 | } else { | 2824 | } else { |
| 2791 | field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); | 2825 | field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); |
| 2792 | type_ensure_zero_bits_known(g, field_type); | 2826 | if ((err = type_ensure_zero_bits_known(g, field_type))) { |
| 2793 | if (type_is_invalid(field_type)) { | ||
| 2794 | union_type->data.unionation.is_invalid = true; | 2827 | union_type->data.unionation.is_invalid = true; |
| 2795 | continue; | 2828 | continue; |
| 2796 | } | 2829 | } |
| ... | @@ -2883,7 +2916,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2883,7 +2916,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 2883 | union_type->data.unionation.abi_alignment = abi_alignment_so_far; | 2916 | union_type->data.unionation.abi_alignment = abi_alignment_so_far; |
| 2884 | 2917 | ||
| 2885 | if (union_type->data.unionation.is_invalid) | 2918 | if (union_type->data.unionation.is_invalid) |
| 2886 | return; | 2919 | return ErrorSemanticAnalyzeFail; |
| 2887 | 2920 | ||
| 2888 | bool src_have_tag = decl_node->data.container_decl.auto_enum || | 2921 | bool src_have_tag = decl_node->data.container_decl.auto_enum || |
| 2889 | decl_node->data.container_decl.init_arg_expr != nullptr; | 2922 | decl_node->data.container_decl.init_arg_expr != nullptr; |
| ... | @@ -2905,7 +2938,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2905,7 +2938,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 2905 | add_node_error(g, source_node, | 2938 | add_node_error(g, source_node, |
| 2906 | buf_sprintf("%s union does not support enum tag type", qual_str)); | 2939 | buf_sprintf("%s union does not support enum tag type", qual_str)); |
| 2907 | union_type->data.unionation.is_invalid = true; | 2940 | union_type->data.unionation.is_invalid = true; |
| 2908 | return; | 2941 | return ErrorSemanticAnalyzeFail; |
| 2909 | } | 2942 | } |
| 2910 | 2943 | ||
| 2911 | if (create_enum_type) { | 2944 | if (create_enum_type) { |
| ... | @@ -2970,6 +3003,11 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { | ... | @@ -2970,6 +3003,11 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 2970 | union_type->data.unionation.gen_field_count = gen_field_index; | 3003 | union_type->data.unionation.gen_field_count = gen_field_index; |
| 2971 | union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !src_have_tag)); | 3004 | union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !src_have_tag)); |
| 2972 | union_type->data.unionation.zero_bits_known = true; | 3005 | union_type->data.unionation.zero_bits_known = true; |
| 3006 | |||
| 3007 | if (union_type->data.unionation.is_invalid) | ||
| 3008 | return ErrorSemanticAnalyzeFail; | ||
| 3009 | |||
| 3010 | return ErrorNone; | ||
| 2973 | } | 3011 | } |
| 2974 | 3012 | ||
| 2975 | static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) { | 3013 | static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) { |
| ... | @@ -3463,13 +3501,13 @@ VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent | ... | @@ -3463,13 +3501,13 @@ VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent |
| 3463 | variable_entry->shadowable = false; | 3501 | variable_entry->shadowable = false; |
| 3464 | variable_entry->mem_slot_index = SIZE_MAX; | 3502 | variable_entry->mem_slot_index = SIZE_MAX; |
| 3465 | variable_entry->src_arg_index = SIZE_MAX; | 3503 | variable_entry->src_arg_index = SIZE_MAX; |
| 3466 | variable_entry->align_bytes = get_abi_alignment(g, value->type); | ||
| 3467 | 3504 | ||
| 3468 | assert(name); | 3505 | assert(name); |
| 3469 | |||
| 3470 | buf_init_from_buf(&variable_entry->name, name); | 3506 | buf_init_from_buf(&variable_entry->name, name); |
| 3471 | 3507 | ||
| 3472 | if (value->type->id != TypeTableEntryIdInvalid) { | 3508 | if (!type_is_invalid(value->type)) { |
| 3509 | variable_entry->align_bytes = get_abi_alignment(g, value->type); | ||
| 3510 | |||
| 3473 | VariableTableEntry *existing_var = find_variable(g, parent_scope, name); | 3511 | VariableTableEntry *existing_var = find_variable(g, parent_scope, name); |
| 3474 | if (existing_var && !existing_var->shadowable) { | 3512 | if (existing_var && !existing_var->shadowable) { |
| 3475 | ErrorMsg *msg = add_node_error(g, source_node, | 3513 | ErrorMsg *msg = add_node_error(g, source_node, |
| ... | @@ -5311,13 +5349,13 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_ | ... | @@ -5311,13 +5349,13 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_ |
| 5311 | 5349 | ||
| 5312 | 5350 | ||
| 5313 | void init_const_undefined(CodeGen *g, ConstExprValue *const_val) { | 5351 | void init_const_undefined(CodeGen *g, ConstExprValue *const_val) { |
| 5352 | Error err; | ||
| 5314 | TypeTableEntry *wanted_type = const_val->type; | 5353 | TypeTableEntry *wanted_type = const_val->type; |
| 5315 | if (wanted_type->id == TypeTableEntryIdArray) { | 5354 | if (wanted_type->id == TypeTableEntryIdArray) { |
| 5316 | const_val->special = ConstValSpecialStatic; | 5355 | const_val->special = ConstValSpecialStatic; |
| 5317 | const_val->data.x_array.special = ConstArraySpecialUndef; | 5356 | const_val->data.x_array.special = ConstArraySpecialUndef; |
| 5318 | } else if (wanted_type->id == TypeTableEntryIdStruct) { | 5357 | } else if (wanted_type->id == TypeTableEntryIdStruct) { |
| 5319 | ensure_complete_type(g, wanted_type); | 5358 | if ((err = ensure_complete_type(g, wanted_type))) { |
| 5320 | if (type_is_invalid(wanted_type)) { | ||
| 5321 | return; | 5359 | return; |
| 5322 | } | 5360 | } |
| 5323 | 5361 | ||
| ... | @@ -5350,27 +5388,33 @@ ConstExprValue *create_const_vals(size_t count) { | ... | @@ -5350,27 +5388,33 @@ ConstExprValue *create_const_vals(size_t count) { |
| 5350 | return vals; | 5388 | return vals; |
| 5351 | } | 5389 | } |
| 5352 | 5390 | ||
| 5353 | void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry) { | 5391 | Error ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry) { |
| 5392 | if (type_is_invalid(type_entry)) | ||
| 5393 | return ErrorSemanticAnalyzeFail; | ||
| 5354 | if (type_entry->id == TypeTableEntryIdStruct) { | 5394 | if (type_entry->id == TypeTableEntryIdStruct) { |
| 5355 | if (!type_entry->data.structure.complete) | 5395 | if (!type_entry->data.structure.complete) |
| 5356 | resolve_struct_type(g, type_entry); | 5396 | return resolve_struct_type(g, type_entry); |
| 5357 | } else if (type_entry->id == TypeTableEntryIdEnum) { | 5397 | } else if (type_entry->id == TypeTableEntryIdEnum) { |
| 5358 | if (!type_entry->data.enumeration.complete) | 5398 | if (!type_entry->data.enumeration.complete) |
| 5359 | resolve_enum_type(g, type_entry); | 5399 | return resolve_enum_type(g, type_entry); |
| 5360 | } else if (type_entry->id == TypeTableEntryIdUnion) { | 5400 | } else if (type_entry->id == TypeTableEntryIdUnion) { |
| 5361 | if (!type_entry->data.unionation.complete) | 5401 | if (!type_entry->data.unionation.complete) |
| 5362 | resolve_union_type(g, type_entry); | 5402 | return resolve_union_type(g, type_entry); |
| 5363 | } | 5403 | } |
| 5404 | return ErrorNone; | ||
| 5364 | } | 5405 | } |
| 5365 | 5406 | ||
| 5366 | void type_ensure_zero_bits_known(CodeGen *g, TypeTableEntry *type_entry) { | 5407 | Error type_ensure_zero_bits_known(CodeGen *g, TypeTableEntry *type_entry) { |
| 5408 | if (type_is_invalid(type_entry)) | ||
| 5409 | return ErrorSemanticAnalyzeFail; | ||
| 5367 | if (type_entry->id == TypeTableEntryIdStruct) { | 5410 | if (type_entry->id == TypeTableEntryIdStruct) { |
| 5368 | resolve_struct_zero_bits(g, type_entry); | 5411 | return resolve_struct_zero_bits(g, type_entry); |
| 5369 | } else if (type_entry->id == TypeTableEntryIdEnum) { | 5412 | } else if (type_entry->id == TypeTableEntryIdEnum) { |
| 5370 | resolve_enum_zero_bits(g, type_entry); | 5413 | return resolve_enum_zero_bits(g, type_entry); |
| 5371 | } else if (type_entry->id == TypeTableEntryIdUnion) { | 5414 | } else if (type_entry->id == TypeTableEntryIdUnion) { |
| 5372 | resolve_union_zero_bits(g, type_entry); | 5415 | return resolve_union_zero_bits(g, type_entry); |
| 5373 | } | 5416 | } |
| 5417 | return ErrorNone; | ||
| 5374 | } | 5418 | } |
| 5375 | 5419 | ||
| 5376 | bool ir_get_var_is_comptime(VariableTableEntry *var) { | 5420 | bool ir_get_var_is_comptime(VariableTableEntry *var) { |
| ... | @@ -6213,7 +6257,7 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) { | ... | @@ -6213,7 +6257,7 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) { |
| 6213 | } | 6257 | } |
| 6214 | 6258 | ||
| 6215 | uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) { | 6259 | uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) { |
| 6216 | type_ensure_zero_bits_known(g, type_entry); | 6260 | assertNoError(type_ensure_zero_bits_known(g, type_entry)); |
| 6217 | if (type_entry->zero_bits) return 0; | 6261 | if (type_entry->zero_bits) return 0; |
| 6218 | 6262 | ||
| 6219 | // We need to make this function work without requiring ensure_complete_type | 6263 | // We need to make this function work without requiring ensure_complete_type |
src/analyze.hpp+4-3| ... | @@ -9,6 +9,7 @@ | ... | @@ -9,6 +9,7 @@ |
| 9 | #define ZIG_ANALYZE_HPP | 9 | #define ZIG_ANALYZE_HPP |
| 10 | 10 | ||
| 11 | #include "all_types.hpp" | 11 | #include "all_types.hpp" |
| 12 | #include "result.hpp" | ||
| 12 | 13 | ||
| 13 | void semantic_analyze(CodeGen *g); | 14 | void semantic_analyze(CodeGen *g); |
| 14 | ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg); | 15 | ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg); |
| ... | @@ -88,8 +89,8 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou | ... | @@ -88,8 +89,8 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou |
| 88 | AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index); | 89 | AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index); |
| 89 | FnTableEntry *scope_get_fn_if_root(Scope *scope); | 90 | FnTableEntry *scope_get_fn_if_root(Scope *scope); |
| 90 | bool type_requires_comptime(TypeTableEntry *type_entry); | 91 | bool type_requires_comptime(TypeTableEntry *type_entry); |
| 91 | void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry); | 92 | Error ATTRIBUTE_MUST_USE ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry); |
| 92 | void type_ensure_zero_bits_known(CodeGen *g, TypeTableEntry *type_entry); | 93 | Error ATTRIBUTE_MUST_USE type_ensure_zero_bits_known(CodeGen *g, TypeTableEntry *type_entry); |
| 93 | void complete_enum(CodeGen *g, TypeTableEntry *enum_type); | 94 | void complete_enum(CodeGen *g, TypeTableEntry *enum_type); |
| 94 | bool ir_get_var_is_comptime(VariableTableEntry *var); | 95 | bool ir_get_var_is_comptime(VariableTableEntry *var); |
| 95 | bool const_values_equal(ConstExprValue *a, ConstExprValue *b); | 96 | bool const_values_equal(ConstExprValue *a, ConstExprValue *b); |
| ... | @@ -178,7 +179,7 @@ TypeTableEntryId type_id_at_index(size_t index); | ... | @@ -178,7 +179,7 @@ TypeTableEntryId type_id_at_index(size_t index); |
| 178 | size_t type_id_len(); | 179 | size_t type_id_len(); |
| 179 | size_t type_id_index(TypeTableEntry *entry); | 180 | size_t type_id_index(TypeTableEntry *entry); |
| 180 | TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id); | 181 | TypeTableEntry *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id); |
| 181 | bool type_is_copyable(CodeGen *g, TypeTableEntry *type_entry); | 182 | Result<bool> type_is_copyable(CodeGen *g, TypeTableEntry *type_entry); |
| 182 | LinkLib *create_link_lib(Buf *name); | 183 | LinkLib *create_link_lib(Buf *name); |
| 183 | bool calling_convention_does_first_arg_return(CallingConvention cc); | 184 | bool calling_convention_does_first_arg_return(CallingConvention cc); |
| 184 | LinkLib *add_link_lib(CodeGen *codegen, Buf *lib); | 185 | LinkLib *add_link_lib(CodeGen *codegen, Buf *lib); |
src/codegen.cpp+9-5| ... | @@ -5812,12 +5812,16 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -5812,12 +5812,16 @@ static void do_code_gen(CodeGen *g) { |
| 5812 | 5812 | ||
| 5813 | LLVMValueRef global_value; | 5813 | LLVMValueRef global_value; |
| 5814 | if (var->linkage == VarLinkageExternal) { | 5814 | if (var->linkage == VarLinkageExternal) { |
| 5815 | global_value = LLVMAddGlobal(g->module, var->value->type->type_ref, buf_ptr(&var->name)); | 5815 | LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, buf_ptr(&var->name)); |
| 5816 | 5816 | if (existing_llvm_var) { | |
| 5817 | // TODO debug info for the extern variable | 5817 | global_value = LLVMConstBitCast(existing_llvm_var, LLVMPointerType(var->value->type->type_ref, 0)); |
| 5818 | } else { | ||
| 5819 | global_value = LLVMAddGlobal(g->module, var->value->type->type_ref, buf_ptr(&var->name)); | ||
| 5820 | // TODO debug info for the extern variable | ||
| 5818 | 5821 | ||
| 5819 | LLVMSetLinkage(global_value, LLVMExternalLinkage); | 5822 | LLVMSetLinkage(global_value, LLVMExternalLinkage); |
| 5820 | LLVMSetAlignment(global_value, var->align_bytes); | 5823 | LLVMSetAlignment(global_value, var->align_bytes); |
| 5824 | } | ||
| 5821 | } else { | 5825 | } else { |
| 5822 | bool exported = (var->linkage == VarLinkageExport); | 5826 | bool exported = (var->linkage == VarLinkageExport); |
| 5823 | const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported)); | 5827 | const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported)); |
src/ir.cpp+177-184| ... | @@ -8711,6 +8711,7 @@ static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t * | ... | @@ -8711,6 +8711,7 @@ static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t * |
| 8711 | } | 8711 | } |
| 8712 | 8712 | ||
| 8713 | static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, TypeTableEntry *expected_type, IrInstruction **instructions, size_t instruction_count) { | 8713 | static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, TypeTableEntry *expected_type, IrInstruction **instructions, size_t instruction_count) { |
| 8714 | Error err; | ||
| 8714 | assert(instruction_count >= 1); | 8715 | assert(instruction_count >= 1); |
| 8715 | IrInstruction *prev_inst = instructions[0]; | 8716 | IrInstruction *prev_inst = instructions[0]; |
| 8716 | if (type_is_invalid(prev_inst->value.type)) { | 8717 | if (type_is_invalid(prev_inst->value.type)) { |
| ... | @@ -9172,8 +9173,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -9172,8 +9173,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 9172 | if (prev_type->id == TypeTableEntryIdEnum && cur_type->id == TypeTableEntryIdUnion && | 9173 | if (prev_type->id == TypeTableEntryIdEnum && cur_type->id == TypeTableEntryIdUnion && |
| 9173 | (cur_type->data.unionation.decl_node->data.container_decl.auto_enum || cur_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) | 9174 | (cur_type->data.unionation.decl_node->data.container_decl.auto_enum || cur_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) |
| 9174 | { | 9175 | { |
| 9175 | type_ensure_zero_bits_known(ira->codegen, cur_type); | 9176 | if ((err = type_ensure_zero_bits_known(ira->codegen, cur_type))) |
| 9176 | if (type_is_invalid(cur_type)) | ||
| 9177 | return ira->codegen->builtin_types.entry_invalid; | 9177 | return ira->codegen->builtin_types.entry_invalid; |
| 9178 | if (cur_type->data.unionation.tag_type == prev_type) { | 9178 | if (cur_type->data.unionation.tag_type == prev_type) { |
| 9179 | continue; | 9179 | continue; |
| ... | @@ -9183,8 +9183,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod | ... | @@ -9183,8 +9183,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod |
| 9183 | if (cur_type->id == TypeTableEntryIdEnum && prev_type->id == TypeTableEntryIdUnion && | 9183 | if (cur_type->id == TypeTableEntryIdEnum && prev_type->id == TypeTableEntryIdUnion && |
| 9184 | (prev_type->data.unionation.decl_node->data.container_decl.auto_enum || prev_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) | 9184 | (prev_type->data.unionation.decl_node->data.container_decl.auto_enum || prev_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) |
| 9185 | { | 9185 | { |
| 9186 | type_ensure_zero_bits_known(ira->codegen, prev_type); | 9186 | if ((err = type_ensure_zero_bits_known(ira->codegen, prev_type))) |
| 9187 | if (type_is_invalid(prev_type)) | ||
| 9188 | return ira->codegen->builtin_types.entry_invalid; | 9187 | return ira->codegen->builtin_types.entry_invalid; |
| 9189 | if (prev_type->data.unionation.tag_type == cur_type) { | 9188 | if (prev_type->data.unionation.tag_type == cur_type) { |
| 9190 | prev_inst = cur_inst; | 9189 | prev_inst = cur_inst; |
| ... | @@ -9999,11 +9998,11 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s | ... | @@ -9999,11 +9998,11 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s |
| 9999 | static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr, | 9998 | static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr, |
| 10000 | IrInstruction *target, TypeTableEntry *wanted_type) | 9999 | IrInstruction *target, TypeTableEntry *wanted_type) |
| 10001 | { | 10000 | { |
| 10001 | Error err; | ||
| 10002 | assert(wanted_type->id == TypeTableEntryIdInt); | 10002 | assert(wanted_type->id == TypeTableEntryIdInt); |
| 10003 | 10003 | ||
| 10004 | TypeTableEntry *actual_type = target->value.type; | 10004 | TypeTableEntry *actual_type = target->value.type; |
| 10005 | ensure_complete_type(ira->codegen, actual_type); | 10005 | if ((err = ensure_complete_type(ira->codegen, actual_type))) |
| 10006 | if (type_is_invalid(actual_type)) | ||
| 10007 | return ira->codegen->invalid_instruction; | 10006 | return ira->codegen->invalid_instruction; |
| 10008 | 10007 | ||
| 10009 | if (wanted_type != actual_type->data.enumeration.tag_int_type) { | 10008 | if (wanted_type != actual_type->data.enumeration.tag_int_type) { |
| ... | @@ -10069,6 +10068,7 @@ static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruc | ... | @@ -10069,6 +10068,7 @@ static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruc |
| 10069 | static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *source_instr, | 10068 | static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *source_instr, |
| 10070 | IrInstruction *target, TypeTableEntry *wanted_type) | 10069 | IrInstruction *target, TypeTableEntry *wanted_type) |
| 10071 | { | 10070 | { |
| 10071 | Error err; | ||
| 10072 | assert(wanted_type->id == TypeTableEntryIdUnion); | 10072 | assert(wanted_type->id == TypeTableEntryIdUnion); |
| 10073 | assert(target->value.type->id == TypeTableEntryIdEnum); | 10073 | assert(target->value.type->id == TypeTableEntryIdEnum); |
| 10074 | 10074 | ||
| ... | @@ -10078,8 +10078,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so | ... | @@ -10078,8 +10078,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so |
| 10078 | return ira->codegen->invalid_instruction; | 10078 | return ira->codegen->invalid_instruction; |
| 10079 | TypeUnionField *union_field = find_union_field_by_tag(wanted_type, &val->data.x_enum_tag); | 10079 | TypeUnionField *union_field = find_union_field_by_tag(wanted_type, &val->data.x_enum_tag); |
| 10080 | assert(union_field != nullptr); | 10080 | assert(union_field != nullptr); |
| 10081 | type_ensure_zero_bits_known(ira->codegen, union_field->type_entry); | 10081 | if ((err = type_ensure_zero_bits_known(ira->codegen, union_field->type_entry))) |
| 10082 | if (type_is_invalid(union_field->type_entry)) | ||
| 10083 | return ira->codegen->invalid_instruction; | 10082 | return ira->codegen->invalid_instruction; |
| 10084 | if (!union_field->type_entry->zero_bits) { | 10083 | if (!union_field->type_entry->zero_bits) { |
| 10085 | AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at( | 10084 | AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at( |
| ... | @@ -10169,12 +10168,12 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction | ... | @@ -10169,12 +10168,12 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction |
| 10169 | static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *source_instr, | 10168 | static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *source_instr, |
| 10170 | IrInstruction *target, TypeTableEntry *wanted_type) | 10169 | IrInstruction *target, TypeTableEntry *wanted_type) |
| 10171 | { | 10170 | { |
| 10171 | Error err; | ||
| 10172 | assert(wanted_type->id == TypeTableEntryIdEnum); | 10172 | assert(wanted_type->id == TypeTableEntryIdEnum); |
| 10173 | 10173 | ||
| 10174 | TypeTableEntry *actual_type = target->value.type; | 10174 | TypeTableEntry *actual_type = target->value.type; |
| 10175 | 10175 | ||
| 10176 | ensure_complete_type(ira->codegen, wanted_type); | 10176 | if ((err = ensure_complete_type(ira->codegen, wanted_type))) |
| 10177 | if (type_is_invalid(wanted_type)) | ||
| 10178 | return ira->codegen->invalid_instruction; | 10177 | return ira->codegen->invalid_instruction; |
| 10179 | 10178 | ||
| 10180 | if (actual_type != wanted_type->data.enumeration.tag_int_type) { | 10179 | if (actual_type != wanted_type->data.enumeration.tag_int_type) { |
| ... | @@ -10517,6 +10516,7 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa | ... | @@ -10517,6 +10516,7 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa |
| 10517 | static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, | 10516 | static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, |
| 10518 | TypeTableEntry *wanted_type, IrInstruction *value) | 10517 | TypeTableEntry *wanted_type, IrInstruction *value) |
| 10519 | { | 10518 | { |
| 10519 | Error err; | ||
| 10520 | TypeTableEntry *actual_type = value->value.type; | 10520 | TypeTableEntry *actual_type = value->value.type; |
| 10521 | AstNode *source_node = source_instr->source_node; | 10521 | AstNode *source_node = source_instr->source_node; |
| 10522 | 10522 | ||
| ... | @@ -10796,8 +10796,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -10796,8 +10796,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 10796 | if (actual_type->id == TypeTableEntryIdComptimeFloat || | 10796 | if (actual_type->id == TypeTableEntryIdComptimeFloat || |
| 10797 | actual_type->id == TypeTableEntryIdComptimeInt) | 10797 | actual_type->id == TypeTableEntryIdComptimeInt) |
| 10798 | { | 10798 | { |
| 10799 | ensure_complete_type(ira->codegen, wanted_type); | 10799 | if ((err = ensure_complete_type(ira->codegen, wanted_type))) |
| 10800 | if (type_is_invalid(wanted_type)) | ||
| 10801 | return ira->codegen->invalid_instruction; | 10800 | return ira->codegen->invalid_instruction; |
| 10802 | if (wanted_type->id == TypeTableEntryIdEnum) { | 10801 | if (wanted_type->id == TypeTableEntryIdEnum) { |
| 10803 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.enumeration.tag_int_type, value); | 10802 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.enumeration.tag_int_type, value); |
| ... | @@ -10853,8 +10852,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -10853,8 +10852,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 10853 | 10852 | ||
| 10854 | // cast from union to the enum type of the union | 10853 | // cast from union to the enum type of the union |
| 10855 | if (actual_type->id == TypeTableEntryIdUnion && wanted_type->id == TypeTableEntryIdEnum) { | 10854 | if (actual_type->id == TypeTableEntryIdUnion && wanted_type->id == TypeTableEntryIdEnum) { |
| 10856 | type_ensure_zero_bits_known(ira->codegen, actual_type); | 10855 | if ((err = type_ensure_zero_bits_known(ira->codegen, actual_type))) |
| 10857 | if (type_is_invalid(actual_type)) | ||
| 10858 | return ira->codegen->invalid_instruction; | 10856 | return ira->codegen->invalid_instruction; |
| 10859 | 10857 | ||
| 10860 | if (actual_type->data.unionation.tag_type == wanted_type) { | 10858 | if (actual_type->data.unionation.tag_type == wanted_type) { |
| ... | @@ -10867,7 +10865,9 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -10867,7 +10865,9 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 10867 | (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum || | 10865 | (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum || |
| 10868 | wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) | 10866 | wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)) |
| 10869 | { | 10867 | { |
| 10870 | type_ensure_zero_bits_known(ira->codegen, wanted_type); | 10868 | if ((err = type_ensure_zero_bits_known(ira->codegen, wanted_type))) |
| 10869 | return ira->codegen->invalid_instruction; | ||
| 10870 | |||
| 10871 | if (wanted_type->data.unionation.tag_type == actual_type) { | 10871 | if (wanted_type->data.unionation.tag_type == actual_type) { |
| 10872 | return ir_analyze_enum_to_union(ira, source_instr, value, wanted_type); | 10872 | return ir_analyze_enum_to_union(ira, source_instr, value, wanted_type); |
| 10873 | } | 10873 | } |
| ... | @@ -10879,7 +10879,9 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -10879,7 +10879,9 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 10879 | if (union_type->data.unionation.decl_node->data.container_decl.auto_enum || | 10879 | if (union_type->data.unionation.decl_node->data.container_decl.auto_enum || |
| 10880 | union_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr) | 10880 | union_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr) |
| 10881 | { | 10881 | { |
| 10882 | type_ensure_zero_bits_known(ira->codegen, union_type); | 10882 | if ((err = type_ensure_zero_bits_known(ira->codegen, union_type))) |
| 10883 | return ira->codegen->invalid_instruction; | ||
| 10884 | |||
| 10883 | if (union_type->data.unionation.tag_type == actual_type) { | 10885 | if (union_type->data.unionation.tag_type == actual_type) { |
| 10884 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, union_type, value); | 10886 | IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, union_type, value); |
| 10885 | if (type_is_invalid(cast1->value.type)) | 10887 | if (type_is_invalid(cast1->value.type)) |
| ... | @@ -10923,8 +10925,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -10923,8 +10925,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 10923 | types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, | 10925 | types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, |
| 10924 | actual_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) | 10926 | actual_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) |
| 10925 | { | 10927 | { |
| 10926 | type_ensure_zero_bits_known(ira->codegen, actual_type); | 10928 | if ((err = type_ensure_zero_bits_known(ira->codegen, actual_type))) { |
| 10927 | if (type_is_invalid(actual_type)) { | ||
| 10928 | return ira->codegen->invalid_instruction; | 10929 | return ira->codegen->invalid_instruction; |
| 10929 | } | 10930 | } |
| 10930 | if (!type_has_bits(actual_type)) { | 10931 | if (!type_has_bits(actual_type)) { |
| ... | @@ -11323,6 +11324,7 @@ static bool optional_value_is_null(ConstExprValue *val) { | ... | @@ -11323,6 +11324,7 @@ static bool optional_value_is_null(ConstExprValue *val) { |
| 11323 | } | 11324 | } |
| 11324 | 11325 | ||
| 11325 | static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { | 11326 | static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { |
| 11327 | Error err; | ||
| 11326 | IrInstruction *op1 = bin_op_instruction->op1->other; | 11328 | IrInstruction *op1 = bin_op_instruction->op1->other; |
| 11327 | IrInstruction *op2 = bin_op_instruction->op2->other; | 11329 | IrInstruction *op2 = bin_op_instruction->op2->other; |
| 11328 | AstNode *source_node = bin_op_instruction->base.source_node; | 11330 | AstNode *source_node = bin_op_instruction->base.source_node; |
| ... | @@ -11458,8 +11460,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp | ... | @@ -11458,8 +11460,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 11458 | TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, source_node, nullptr, instructions, 2); | 11460 | TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, source_node, nullptr, instructions, 2); |
| 11459 | if (type_is_invalid(resolved_type)) | 11461 | if (type_is_invalid(resolved_type)) |
| 11460 | return resolved_type; | 11462 | return resolved_type; |
| 11461 | type_ensure_zero_bits_known(ira->codegen, resolved_type); | 11463 | if ((err = type_ensure_zero_bits_known(ira->codegen, resolved_type))) |
| 11462 | if (type_is_invalid(resolved_type)) | ||
| 11463 | return resolved_type; | 11464 | return resolved_type; |
| 11464 | 11465 | ||
| 11465 | bool operator_allowed; | 11466 | bool operator_allowed; |
| ... | @@ -12406,6 +12407,7 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi | ... | @@ -12406,6 +12407,7 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi |
| 12406 | } | 12407 | } |
| 12407 | 12408 | ||
| 12408 | static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) { | 12409 | static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) { |
| 12410 | Error err; | ||
| 12409 | VariableTableEntry *var = decl_var_instruction->var; | 12411 | VariableTableEntry *var = decl_var_instruction->var; |
| 12410 | 12412 | ||
| 12411 | IrInstruction *init_value = decl_var_instruction->init_value->other; | 12413 | IrInstruction *init_value = decl_var_instruction->init_value->other; |
| ... | @@ -12439,8 +12441,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc | ... | @@ -12439,8 +12441,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc |
| 12439 | if (type_is_invalid(result_type)) { | 12441 | if (type_is_invalid(result_type)) { |
| 12440 | result_type = ira->codegen->builtin_types.entry_invalid; | 12442 | result_type = ira->codegen->builtin_types.entry_invalid; |
| 12441 | } else { | 12443 | } else { |
| 12442 | type_ensure_zero_bits_known(ira->codegen, result_type); | 12444 | if ((err = type_ensure_zero_bits_known(ira->codegen, result_type))) { |
| 12443 | if (type_is_invalid(result_type)) { | ||
| 12444 | result_type = ira->codegen->builtin_types.entry_invalid; | 12445 | result_type = ira->codegen->builtin_types.entry_invalid; |
| 12445 | } | 12446 | } |
| 12446 | } | 12447 | } |
| ... | @@ -12958,6 +12959,7 @@ static VariableTableEntry *get_fn_var_by_index(FnTableEntry *fn_entry, size_t in | ... | @@ -12958,6 +12959,7 @@ static VariableTableEntry *get_fn_var_by_index(FnTableEntry *fn_entry, size_t in |
| 12958 | static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, | 12959 | static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 12959 | VariableTableEntry *var) | 12960 | VariableTableEntry *var) |
| 12960 | { | 12961 | { |
| 12962 | Error err; | ||
| 12961 | if (var->mem_slot_index != SIZE_MAX && var->owner_exec->analysis == nullptr) { | 12963 | if (var->mem_slot_index != SIZE_MAX && var->owner_exec->analysis == nullptr) { |
| 12962 | assert(ira->codegen->errors.length != 0); | 12964 | assert(ira->codegen->errors.length != 0); |
| 12963 | return ira->codegen->invalid_instruction; | 12965 | return ira->codegen->invalid_instruction; |
| ... | @@ -13012,7 +13014,8 @@ no_mem_slot: | ... | @@ -13012,7 +13014,8 @@ no_mem_slot: |
| 13012 | instruction->scope, instruction->source_node, var); | 13014 | instruction->scope, instruction->source_node, var); |
| 13013 | var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type, | 13015 | var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type, |
| 13014 | var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0); | 13016 | var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0); |
| 13015 | type_ensure_zero_bits_known(ira->codegen, var->value->type); | 13017 | if ((err = type_ensure_zero_bits_known(ira->codegen, var->value->type))) |
| 13018 | return ira->codegen->invalid_instruction; | ||
| 13016 | 13019 | ||
| 13017 | bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); | 13020 | bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); |
| 13018 | var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack; | 13021 | var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack; |
| ... | @@ -13024,6 +13027,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -13024,6 +13027,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 13024 | FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref, | 13027 | FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref, |
| 13025 | IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline) | 13028 | IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline) |
| 13026 | { | 13029 | { |
| 13030 | Error err; | ||
| 13027 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; | 13031 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; |
| 13028 | size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0; | 13032 | size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0; |
| 13029 | 13033 | ||
| ... | @@ -13388,8 +13392,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal | ... | @@ -13388,8 +13392,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 13388 | inst_fn_type_id.return_type = specified_return_type; | 13392 | inst_fn_type_id.return_type = specified_return_type; |
| 13389 | } | 13393 | } |
| 13390 | 13394 | ||
| 13391 | type_ensure_zero_bits_known(ira->codegen, specified_return_type); | 13395 | if ((err = type_ensure_zero_bits_known(ira->codegen, specified_return_type))) |
| 13392 | if (type_is_invalid(specified_return_type)) | ||
| 13393 | return ira->codegen->builtin_types.entry_invalid; | 13396 | return ira->codegen->builtin_types.entry_invalid; |
| 13394 | 13397 | ||
| 13395 | if (type_requires_comptime(specified_return_type)) { | 13398 | if (type_requires_comptime(specified_return_type)) { |
| ... | @@ -13664,12 +13667,12 @@ static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp | ... | @@ -13664,12 +13667,12 @@ static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp |
| 13664 | } | 13667 | } |
| 13665 | 13668 | ||
| 13666 | static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { | 13669 | static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { |
| 13670 | Error err; | ||
| 13667 | IrInstruction *value = un_op_instruction->value->other; | 13671 | IrInstruction *value = un_op_instruction->value->other; |
| 13668 | TypeTableEntry *type_entry = ir_resolve_type(ira, value); | 13672 | TypeTableEntry *type_entry = ir_resolve_type(ira, value); |
| 13669 | if (type_is_invalid(type_entry)) | 13673 | if (type_is_invalid(type_entry)) |
| 13670 | return ira->codegen->builtin_types.entry_invalid; | 13674 | return ira->codegen->builtin_types.entry_invalid; |
| 13671 | ensure_complete_type(ira->codegen, type_entry); | 13675 | if ((err = ensure_complete_type(ira->codegen, type_entry))) |
| 13672 | if (type_is_invalid(type_entry)) | ||
| 13673 | return ira->codegen->builtin_types.entry_invalid; | 13676 | return ira->codegen->builtin_types.entry_invalid; |
| 13674 | 13677 | ||
| 13675 | switch (type_entry->id) { | 13678 | switch (type_entry->id) { |
| ... | @@ -14023,6 +14026,7 @@ static TypeTableEntry *adjust_ptr_len(CodeGen *g, TypeTableEntry *ptr_type, PtrL | ... | @@ -14023,6 +14026,7 @@ static TypeTableEntry *adjust_ptr_len(CodeGen *g, TypeTableEntry *ptr_type, PtrL |
| 14023 | } | 14026 | } |
| 14024 | 14027 | ||
| 14025 | static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionElemPtr *elem_ptr_instruction) { | 14028 | static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionElemPtr *elem_ptr_instruction) { |
| 14029 | Error err; | ||
| 14026 | IrInstruction *array_ptr = elem_ptr_instruction->array_ptr->other; | 14030 | IrInstruction *array_ptr = elem_ptr_instruction->array_ptr->other; |
| 14027 | if (type_is_invalid(array_ptr->value.type)) | 14031 | if (type_is_invalid(array_ptr->value.type)) |
| 14028 | return ira->codegen->builtin_types.entry_invalid; | 14032 | return ira->codegen->builtin_types.entry_invalid; |
| ... | @@ -14131,8 +14135,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc | ... | @@ -14131,8 +14135,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc |
| 14131 | return ira->codegen->builtin_types.entry_invalid; | 14135 | return ira->codegen->builtin_types.entry_invalid; |
| 14132 | 14136 | ||
| 14133 | bool safety_check_on = elem_ptr_instruction->safety_check_on; | 14137 | bool safety_check_on = elem_ptr_instruction->safety_check_on; |
| 14134 | ensure_complete_type(ira->codegen, return_type->data.pointer.child_type); | 14138 | if ((err = ensure_complete_type(ira->codegen, return_type->data.pointer.child_type))) |
| 14135 | if (type_is_invalid(return_type->data.pointer.child_type)) | ||
| 14136 | return ira->codegen->builtin_types.entry_invalid; | 14139 | return ira->codegen->builtin_types.entry_invalid; |
| 14137 | 14140 | ||
| 14138 | uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type); | 14141 | uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type); |
| ... | @@ -14352,9 +14355,10 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, | ... | @@ -14352,9 +14355,10 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, |
| 14352 | static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, | 14355 | static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, |
| 14353 | IrInstruction *source_instr, IrInstruction *container_ptr, TypeTableEntry *container_type) | 14356 | IrInstruction *source_instr, IrInstruction *container_ptr, TypeTableEntry *container_type) |
| 14354 | { | 14357 | { |
| 14358 | Error err; | ||
| 14359 | |||
| 14355 | TypeTableEntry *bare_type = container_ref_type(container_type); | 14360 | TypeTableEntry *bare_type = container_ref_type(container_type); |
| 14356 | ensure_complete_type(ira->codegen, bare_type); | 14361 | if ((err = ensure_complete_type(ira->codegen, bare_type))) |
| 14357 | if (type_is_invalid(bare_type)) | ||
| 14358 | return ira->codegen->invalid_instruction; | 14362 | return ira->codegen->invalid_instruction; |
| 14359 | 14363 | ||
| 14360 | assert(container_ptr->value.type->id == TypeTableEntryIdPointer); | 14364 | assert(container_ptr->value.type->id == TypeTableEntryIdPointer); |
| ... | @@ -14553,6 +14557,7 @@ static ErrorTableEntry *find_err_table_entry(TypeTableEntry *err_set_type, Buf * | ... | @@ -14553,6 +14557,7 @@ static ErrorTableEntry *find_err_table_entry(TypeTableEntry *err_set_type, Buf * |
| 14553 | } | 14557 | } |
| 14554 | 14558 | ||
| 14555 | static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstructionFieldPtr *field_ptr_instruction) { | 14559 | static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstructionFieldPtr *field_ptr_instruction) { |
| 14560 | Error err; | ||
| 14556 | IrInstruction *container_ptr = field_ptr_instruction->container_ptr->other; | 14561 | IrInstruction *container_ptr = field_ptr_instruction->container_ptr->other; |
| 14557 | if (type_is_invalid(container_ptr->value.type)) | 14562 | if (type_is_invalid(container_ptr->value.type)) |
| 14558 | return ira->codegen->builtin_types.entry_invalid; | 14563 | return ira->codegen->builtin_types.entry_invalid; |
| ... | @@ -14654,8 +14659,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru | ... | @@ -14654,8 +14659,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru |
| 14654 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); | 14659 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); |
| 14655 | } | 14660 | } |
| 14656 | if (child_type->id == TypeTableEntryIdEnum) { | 14661 | if (child_type->id == TypeTableEntryIdEnum) { |
| 14657 | ensure_complete_type(ira->codegen, child_type); | 14662 | if ((err = ensure_complete_type(ira->codegen, child_type))) |
| 14658 | if (type_is_invalid(child_type)) | ||
| 14659 | return ira->codegen->builtin_types.entry_invalid; | 14663 | return ira->codegen->builtin_types.entry_invalid; |
| 14660 | 14664 | ||
| 14661 | TypeEnumField *field = find_enum_type_field(child_type, field_name); | 14665 | TypeEnumField *field = find_enum_type_field(child_type, field_name); |
| ... | @@ -14679,8 +14683,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru | ... | @@ -14679,8 +14683,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru |
| 14679 | (child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr || | 14683 | (child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr || |
| 14680 | child_type->data.unionation.decl_node->data.container_decl.auto_enum)) | 14684 | child_type->data.unionation.decl_node->data.container_decl.auto_enum)) |
| 14681 | { | 14685 | { |
| 14682 | ensure_complete_type(ira->codegen, child_type); | 14686 | if ((err = ensure_complete_type(ira->codegen, child_type))) |
| 14683 | if (type_is_invalid(child_type)) | ||
| 14684 | return ira->codegen->builtin_types.entry_invalid; | 14687 | return ira->codegen->builtin_types.entry_invalid; |
| 14685 | TypeUnionField *field = find_union_type_field(child_type, field_name); | 14688 | TypeUnionField *field = find_union_type_field(child_type, field_name); |
| 14686 | if (field) { | 14689 | if (field) { |
| ... | @@ -15257,6 +15260,7 @@ static TypeTableEntry *ir_analyze_instruction_set_float_mode(IrAnalyze *ira, | ... | @@ -15257,6 +15260,7 @@ static TypeTableEntry *ir_analyze_instruction_set_float_mode(IrAnalyze *ira, |
| 15257 | static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, | 15260 | static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, |
| 15258 | IrInstructionSliceType *slice_type_instruction) | 15261 | IrInstructionSliceType *slice_type_instruction) |
| 15259 | { | 15262 | { |
| 15263 | Error err; | ||
| 15260 | uint32_t align_bytes; | 15264 | uint32_t align_bytes; |
| 15261 | if (slice_type_instruction->align_value != nullptr) { | 15265 | if (slice_type_instruction->align_value != nullptr) { |
| 15262 | if (!ir_resolve_align(ira, slice_type_instruction->align_value->other, &align_bytes)) | 15266 | if (!ir_resolve_align(ira, slice_type_instruction->align_value->other, &align_bytes)) |
| ... | @@ -15268,6 +15272,8 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, | ... | @@ -15268,6 +15272,8 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, |
| 15268 | return ira->codegen->builtin_types.entry_invalid; | 15272 | return ira->codegen->builtin_types.entry_invalid; |
| 15269 | 15273 | ||
| 15270 | if (slice_type_instruction->align_value == nullptr) { | 15274 | if (slice_type_instruction->align_value == nullptr) { |
| 15275 | if ((err = type_ensure_zero_bits_known(ira->codegen, child_type))) | ||
| 15276 | return ira->codegen->builtin_types.entry_invalid; | ||
| 15271 | align_bytes = get_abi_alignment(ira->codegen, child_type); | 15277 | align_bytes = get_abi_alignment(ira->codegen, child_type); |
| 15272 | } | 15278 | } |
| 15273 | 15279 | ||
| ... | @@ -15306,7 +15312,8 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, | ... | @@ -15306,7 +15312,8 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, |
| 15306 | case TypeTableEntryIdBoundFn: | 15312 | case TypeTableEntryIdBoundFn: |
| 15307 | case TypeTableEntryIdPromise: | 15313 | case TypeTableEntryIdPromise: |
| 15308 | { | 15314 | { |
| 15309 | type_ensure_zero_bits_known(ira->codegen, child_type); | 15315 | if ((err = type_ensure_zero_bits_known(ira->codegen, child_type))) |
| 15316 | return ira->codegen->builtin_types.entry_invalid; | ||
| 15310 | TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type, | 15317 | TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type, |
| 15311 | is_const, is_volatile, PtrLenUnknown, align_bytes, 0, 0); | 15318 | is_const, is_volatile, PtrLenUnknown, align_bytes, 0, 0); |
| 15312 | TypeTableEntry *result_type = get_slice_type(ira->codegen, slice_ptr_type); | 15319 | TypeTableEntry *result_type = get_slice_type(ira->codegen, slice_ptr_type); |
| ... | @@ -15444,11 +15451,11 @@ static TypeTableEntry *ir_analyze_instruction_promise_type(IrAnalyze *ira, IrIns | ... | @@ -15444,11 +15451,11 @@ static TypeTableEntry *ir_analyze_instruction_promise_type(IrAnalyze *ira, IrIns |
| 15444 | static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, | 15451 | static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 15445 | IrInstructionSizeOf *size_of_instruction) | 15452 | IrInstructionSizeOf *size_of_instruction) |
| 15446 | { | 15453 | { |
| 15454 | Error err; | ||
| 15447 | IrInstruction *type_value = size_of_instruction->type_value->other; | 15455 | IrInstruction *type_value = size_of_instruction->type_value->other; |
| 15448 | TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); | 15456 | TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); |
| 15449 | 15457 | ||
| 15450 | ensure_complete_type(ira->codegen, type_entry); | 15458 | if ((err = ensure_complete_type(ira->codegen, type_entry))) |
| 15451 | if (type_is_invalid(type_entry)) | ||
| 15452 | return ira->codegen->builtin_types.entry_invalid; | 15459 | return ira->codegen->builtin_types.entry_invalid; |
| 15453 | 15460 | ||
| 15454 | switch (type_entry->id) { | 15461 | switch (type_entry->id) { |
| ... | @@ -15819,6 +15826,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira, | ... | @@ -15819,6 +15826,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira, |
| 15819 | static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, | 15826 | static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 15820 | IrInstructionSwitchTarget *switch_target_instruction) | 15827 | IrInstructionSwitchTarget *switch_target_instruction) |
| 15821 | { | 15828 | { |
| 15829 | Error err; | ||
| 15822 | IrInstruction *target_value_ptr = switch_target_instruction->target_value_ptr->other; | 15830 | IrInstruction *target_value_ptr = switch_target_instruction->target_value_ptr->other; |
| 15823 | if (type_is_invalid(target_value_ptr->value.type)) | 15831 | if (type_is_invalid(target_value_ptr->value.type)) |
| 15824 | return ira->codegen->builtin_types.entry_invalid; | 15832 | return ira->codegen->builtin_types.entry_invalid; |
| ... | @@ -15845,8 +15853,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, | ... | @@ -15845,8 +15853,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 15845 | if (pointee_val->special == ConstValSpecialRuntime) | 15853 | if (pointee_val->special == ConstValSpecialRuntime) |
| 15846 | pointee_val = nullptr; | 15854 | pointee_val = nullptr; |
| 15847 | } | 15855 | } |
| 15848 | ensure_complete_type(ira->codegen, target_type); | 15856 | if ((err = ensure_complete_type(ira->codegen, target_type))) |
| 15849 | if (type_is_invalid(target_type)) | ||
| 15850 | return ira->codegen->builtin_types.entry_invalid; | 15857 | return ira->codegen->builtin_types.entry_invalid; |
| 15851 | 15858 | ||
| 15852 | switch (target_type->id) { | 15859 | switch (target_type->id) { |
| ... | @@ -15910,8 +15917,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, | ... | @@ -15910,8 +15917,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 15910 | return tag_type; | 15917 | return tag_type; |
| 15911 | } | 15918 | } |
| 15912 | case TypeTableEntryIdEnum: { | 15919 | case TypeTableEntryIdEnum: { |
| 15913 | type_ensure_zero_bits_known(ira->codegen, target_type); | 15920 | if ((err = type_ensure_zero_bits_known(ira->codegen, target_type))) |
| 15914 | if (type_is_invalid(target_type)) | ||
| 15915 | return ira->codegen->builtin_types.entry_invalid; | 15921 | return ira->codegen->builtin_types.entry_invalid; |
| 15916 | if (target_type->data.enumeration.src_field_count < 2) { | 15922 | if (target_type->data.enumeration.src_field_count < 2) { |
| 15917 | TypeEnumField *only_field = &target_type->data.enumeration.fields[0]; | 15923 | TypeEnumField *only_field = &target_type->data.enumeration.fields[0]; |
| ... | @@ -16113,10 +16119,10 @@ static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionR | ... | @@ -16113,10 +16119,10 @@ static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionR |
| 16113 | static TypeTableEntry *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruction *instruction, | 16119 | static TypeTableEntry *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruction *instruction, |
| 16114 | TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields) | 16120 | TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields) |
| 16115 | { | 16121 | { |
| 16122 | Error err; | ||
| 16116 | assert(container_type->id == TypeTableEntryIdUnion); | 16123 | assert(container_type->id == TypeTableEntryIdUnion); |
| 16117 | 16124 | ||
| 16118 | ensure_complete_type(ira->codegen, container_type); | 16125 | if ((err = ensure_complete_type(ira->codegen, container_type))) |
| 16119 | if (type_is_invalid(container_type)) | ||
| 16120 | return ira->codegen->builtin_types.entry_invalid; | 16126 | return ira->codegen->builtin_types.entry_invalid; |
| 16121 | 16127 | ||
| 16122 | if (instr_field_count != 1) { | 16128 | if (instr_field_count != 1) { |
| ... | @@ -16145,8 +16151,7 @@ static TypeTableEntry *ir_analyze_container_init_fields_union(IrAnalyze *ira, Ir | ... | @@ -16145,8 +16151,7 @@ static TypeTableEntry *ir_analyze_container_init_fields_union(IrAnalyze *ira, Ir |
| 16145 | if (casted_field_value == ira->codegen->invalid_instruction) | 16151 | if (casted_field_value == ira->codegen->invalid_instruction) |
| 16146 | return ira->codegen->builtin_types.entry_invalid; | 16152 | return ira->codegen->builtin_types.entry_invalid; |
| 16147 | 16153 | ||
| 16148 | type_ensure_zero_bits_known(ira->codegen, casted_field_value->value.type); | 16154 | if ((err = type_ensure_zero_bits_known(ira->codegen, casted_field_value->value.type))) |
| 16149 | if (type_is_invalid(casted_field_value->value.type)) | ||
| 16150 | return ira->codegen->builtin_types.entry_invalid; | 16155 | return ira->codegen->builtin_types.entry_invalid; |
| 16151 | 16156 | ||
| 16152 | bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope); | 16157 | bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope); |
| ... | @@ -16180,6 +16185,7 @@ static TypeTableEntry *ir_analyze_container_init_fields_union(IrAnalyze *ira, Ir | ... | @@ -16180,6 +16185,7 @@ static TypeTableEntry *ir_analyze_container_init_fields_union(IrAnalyze *ira, Ir |
| 16180 | static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction, | 16185 | static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction, |
| 16181 | TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields) | 16186 | TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields) |
| 16182 | { | 16187 | { |
| 16188 | Error err; | ||
| 16183 | if (container_type->id == TypeTableEntryIdUnion) { | 16189 | if (container_type->id == TypeTableEntryIdUnion) { |
| 16184 | return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count, fields); | 16190 | return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count, fields); |
| 16185 | } | 16191 | } |
| ... | @@ -16190,8 +16196,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru | ... | @@ -16190,8 +16196,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru |
| 16190 | return ira->codegen->builtin_types.entry_invalid; | 16196 | return ira->codegen->builtin_types.entry_invalid; |
| 16191 | } | 16197 | } |
| 16192 | 16198 | ||
| 16193 | ensure_complete_type(ira->codegen, container_type); | 16199 | if ((err = ensure_complete_type(ira->codegen, container_type))) |
| 16194 | if (type_is_invalid(container_type)) | ||
| 16195 | return ira->codegen->builtin_types.entry_invalid; | 16200 | return ira->codegen->builtin_types.entry_invalid; |
| 16196 | 16201 | ||
| 16197 | size_t actual_field_count = container_type->data.structure.src_field_count; | 16202 | size_t actual_field_count = container_type->data.structure.src_field_count; |
| ... | @@ -16572,6 +16577,7 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc | ... | @@ -16572,6 +16577,7 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc |
| 16572 | } | 16577 | } |
| 16573 | 16578 | ||
| 16574 | static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstructionTagName *instruction) { | 16579 | static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstructionTagName *instruction) { |
| 16580 | Error err; | ||
| 16575 | IrInstruction *target = instruction->target->other; | 16581 | IrInstruction *target = instruction->target->other; |
| 16576 | if (type_is_invalid(target->value.type)) | 16582 | if (type_is_invalid(target->value.type)) |
| 16577 | return ira->codegen->builtin_types.entry_invalid; | 16583 | return ira->codegen->builtin_types.entry_invalid; |
| ... | @@ -16579,8 +16585,7 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn | ... | @@ -16579,8 +16585,7 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn |
| 16579 | assert(target->value.type->id == TypeTableEntryIdEnum); | 16585 | assert(target->value.type->id == TypeTableEntryIdEnum); |
| 16580 | 16586 | ||
| 16581 | if (instr_is_comptime(target)) { | 16587 | if (instr_is_comptime(target)) { |
| 16582 | type_ensure_zero_bits_known(ira->codegen, target->value.type); | 16588 | if ((err = type_ensure_zero_bits_known(ira->codegen, target->value.type))) |
| 16583 | if (type_is_invalid(target->value.type)) | ||
| 16584 | return ira->codegen->builtin_types.entry_invalid; | 16589 | return ira->codegen->builtin_types.entry_invalid; |
| 16585 | TypeEnumField *field = find_enum_field_by_tag(target->value.type, &target->value.data.x_bigint); | 16590 | TypeEnumField *field = find_enum_field_by_tag(target->value.type, &target->value.data.x_bigint); |
| 16586 | ConstExprValue *array_val = create_const_str_lit(ira->codegen, field->name); | 16591 | ConstExprValue *array_val = create_const_str_lit(ira->codegen, field->name); |
| ... | @@ -16604,6 +16609,7 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn | ... | @@ -16604,6 +16609,7 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn |
| 16604 | static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, | 16609 | static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, |
| 16605 | IrInstructionFieldParentPtr *instruction) | 16610 | IrInstructionFieldParentPtr *instruction) |
| 16606 | { | 16611 | { |
| 16612 | Error err; | ||
| 16607 | IrInstruction *type_value = instruction->type_value->other; | 16613 | IrInstruction *type_value = instruction->type_value->other; |
| 16608 | TypeTableEntry *container_type = ir_resolve_type(ira, type_value); | 16614 | TypeTableEntry *container_type = ir_resolve_type(ira, type_value); |
| 16609 | if (type_is_invalid(container_type)) | 16615 | if (type_is_invalid(container_type)) |
| ... | @@ -16624,8 +16630,7 @@ static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, | ... | @@ -16624,8 +16630,7 @@ static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, |
| 16624 | return ira->codegen->builtin_types.entry_invalid; | 16630 | return ira->codegen->builtin_types.entry_invalid; |
| 16625 | } | 16631 | } |
| 16626 | 16632 | ||
| 16627 | ensure_complete_type(ira->codegen, container_type); | 16633 | if ((err = ensure_complete_type(ira->codegen, container_type))) |
| 16628 | if (type_is_invalid(container_type)) | ||
| 16629 | return ira->codegen->builtin_types.entry_invalid; | 16634 | return ira->codegen->builtin_types.entry_invalid; |
| 16630 | 16635 | ||
| 16631 | TypeStructField *field = find_struct_type_field(container_type, field_name); | 16636 | TypeStructField *field = find_struct_type_field(container_type, field_name); |
| ... | @@ -16697,13 +16702,13 @@ static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, | ... | @@ -16697,13 +16702,13 @@ static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, |
| 16697 | static TypeTableEntry *ir_analyze_instruction_offset_of(IrAnalyze *ira, | 16702 | static TypeTableEntry *ir_analyze_instruction_offset_of(IrAnalyze *ira, |
| 16698 | IrInstructionOffsetOf *instruction) | 16703 | IrInstructionOffsetOf *instruction) |
| 16699 | { | 16704 | { |
| 16705 | Error err; | ||
| 16700 | IrInstruction *type_value = instruction->type_value->other; | 16706 | IrInstruction *type_value = instruction->type_value->other; |
| 16701 | TypeTableEntry *container_type = ir_resolve_type(ira, type_value); | 16707 | TypeTableEntry *container_type = ir_resolve_type(ira, type_value); |
| 16702 | if (type_is_invalid(container_type)) | 16708 | if (type_is_invalid(container_type)) |
| 16703 | return ira->codegen->builtin_types.entry_invalid; | 16709 | return ira->codegen->builtin_types.entry_invalid; |
| 16704 | 16710 | ||
| 16705 | ensure_complete_type(ira->codegen, container_type); | 16711 | if ((err = ensure_complete_type(ira->codegen, container_type))) |
| 16706 | if (type_is_invalid(container_type)) | ||
| 16707 | return ira->codegen->builtin_types.entry_invalid; | 16712 | return ira->codegen->builtin_types.entry_invalid; |
| 16708 | 16713 | ||
| 16709 | IrInstruction *field_name_value = instruction->field_name->other; | 16714 | IrInstruction *field_name_value = instruction->field_name->other; |
| ... | @@ -16748,19 +16753,15 @@ static void ensure_field_index(TypeTableEntry *type, const char *field_name, siz | ... | @@ -16748,19 +16753,15 @@ static void ensure_field_index(TypeTableEntry *type, const char *field_name, siz |
| 16748 | (buf_deinit(field_name_buf), true)); | 16753 | (buf_deinit(field_name_buf), true)); |
| 16749 | } | 16754 | } |
| 16750 | 16755 | ||
| 16751 | static TypeTableEntry *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, TypeTableEntry *root = nullptr) | 16756 | static TypeTableEntry *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, TypeTableEntry *root) { |
| 16752 | { | 16757 | Error err; |
| 16753 | static ConstExprValue *type_info_var = nullptr; | 16758 | static ConstExprValue *type_info_var = nullptr; |
| 16754 | static TypeTableEntry *type_info_type = nullptr; | 16759 | static TypeTableEntry *type_info_type = nullptr; |
| 16755 | if (type_info_var == nullptr) | 16760 | if (type_info_var == nullptr) { |
| 16756 | { | ||
| 16757 | type_info_var = get_builtin_value(ira->codegen, "TypeInfo"); | 16761 | type_info_var = get_builtin_value(ira->codegen, "TypeInfo"); |
| 16758 | assert(type_info_var->type->id == TypeTableEntryIdMetaType); | 16762 | assert(type_info_var->type->id == TypeTableEntryIdMetaType); |
| 16759 | 16763 | ||
| 16760 | ensure_complete_type(ira->codegen, type_info_var->data.x_type); | 16764 | assertNoError(ensure_complete_type(ira->codegen, type_info_var->data.x_type)); |
| 16761 | if (type_is_invalid(type_info_var->data.x_type)) | ||
| 16762 | return ira->codegen->builtin_types.entry_invalid; | ||
| 16763 | |||
| 16764 | type_info_type = type_info_var->data.x_type; | 16765 | type_info_type = type_info_var->data.x_type; |
| 16765 | assert(type_info_type->id == TypeTableEntryIdUnion); | 16766 | assert(type_info_type->id == TypeTableEntryIdUnion); |
| 16766 | } | 16767 | } |
| ... | @@ -16785,8 +16786,7 @@ static TypeTableEntry *ir_type_info_get_type(IrAnalyze *ira, const char *type_na | ... | @@ -16785,8 +16786,7 @@ static TypeTableEntry *ir_type_info_get_type(IrAnalyze *ira, const char *type_na |
| 16785 | 16786 | ||
| 16786 | VariableTableEntry *var = tld->var; | 16787 | VariableTableEntry *var = tld->var; |
| 16787 | 16788 | ||
| 16788 | ensure_complete_type(ira->codegen, var->value->type); | 16789 | if ((err = ensure_complete_type(ira->codegen, var->value->type))) |
| 16789 | if (type_is_invalid(var->value->type)) | ||
| 16790 | return ira->codegen->builtin_types.entry_invalid; | 16790 | return ira->codegen->builtin_types.entry_invalid; |
| 16791 | assert(var->value->type->id == TypeTableEntryIdMetaType); | 16791 | assert(var->value->type->id == TypeTableEntryIdMetaType); |
| 16792 | return var->value->data.x_type; | 16792 | return var->value->data.x_type; |
| ... | @@ -16794,9 +16794,9 @@ static TypeTableEntry *ir_type_info_get_type(IrAnalyze *ira, const char *type_na | ... | @@ -16794,9 +16794,9 @@ static TypeTableEntry *ir_type_info_get_type(IrAnalyze *ira, const char *type_na |
| 16794 | 16794 | ||
| 16795 | static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope) | 16795 | static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope) |
| 16796 | { | 16796 | { |
| 16797 | TypeTableEntry *type_info_definition_type = ir_type_info_get_type(ira, "Definition"); | 16797 | Error err; |
| 16798 | ensure_complete_type(ira->codegen, type_info_definition_type); | 16798 | TypeTableEntry *type_info_definition_type = ir_type_info_get_type(ira, "Definition", nullptr); |
| 16799 | if (type_is_invalid(type_info_definition_type)) | 16799 | if ((err = ensure_complete_type(ira->codegen, type_info_definition_type))) |
| 16800 | return false; | 16800 | return false; |
| 16801 | 16801 | ||
| 16802 | ensure_field_index(type_info_definition_type, "name", 0); | 16802 | ensure_field_index(type_info_definition_type, "name", 0); |
| ... | @@ -16804,18 +16804,15 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop | ... | @@ -16804,18 +16804,15 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop |
| 16804 | ensure_field_index(type_info_definition_type, "data", 2); | 16804 | ensure_field_index(type_info_definition_type, "data", 2); |
| 16805 | 16805 | ||
| 16806 | TypeTableEntry *type_info_definition_data_type = ir_type_info_get_type(ira, "Data", type_info_definition_type); | 16806 | TypeTableEntry *type_info_definition_data_type = ir_type_info_get_type(ira, "Data", type_info_definition_type); |
| 16807 | ensure_complete_type(ira->codegen, type_info_definition_data_type); | 16807 | if ((err = ensure_complete_type(ira->codegen, type_info_definition_data_type))) |
| 16808 | if (type_is_invalid(type_info_definition_data_type)) | ||
| 16809 | return false; | 16808 | return false; |
| 16810 | 16809 | ||
| 16811 | TypeTableEntry *type_info_fn_def_type = ir_type_info_get_type(ira, "FnDef", type_info_definition_data_type); | 16810 | TypeTableEntry *type_info_fn_def_type = ir_type_info_get_type(ira, "FnDef", type_info_definition_data_type); |
| 16812 | ensure_complete_type(ira->codegen, type_info_fn_def_type); | 16811 | if ((err = ensure_complete_type(ira->codegen, type_info_fn_def_type))) |
| 16813 | if (type_is_invalid(type_info_fn_def_type)) | ||
| 16814 | return false; | 16812 | return false; |
| 16815 | 16813 | ||
| 16816 | TypeTableEntry *type_info_fn_def_inline_type = ir_type_info_get_type(ira, "Inline", type_info_fn_def_type); | 16814 | TypeTableEntry *type_info_fn_def_inline_type = ir_type_info_get_type(ira, "Inline", type_info_fn_def_type); |
| 16817 | ensure_complete_type(ira->codegen, type_info_fn_def_inline_type); | 16815 | if ((err = ensure_complete_type(ira->codegen, type_info_fn_def_inline_type))) |
| 16818 | if (type_is_invalid(type_info_fn_def_inline_type)) | ||
| 16819 | return false; | 16816 | return false; |
| 16820 | 16817 | ||
| 16821 | // Loop through our definitions once to figure out how many definitions we will generate info for. | 16818 | // Loop through our definitions once to figure out how many definitions we will generate info for. |
| ... | @@ -16895,8 +16892,7 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop | ... | @@ -16895,8 +16892,7 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop |
| 16895 | case TldIdVar: | 16892 | case TldIdVar: |
| 16896 | { | 16893 | { |
| 16897 | VariableTableEntry *var = ((TldVar *)curr_entry->value)->var; | 16894 | VariableTableEntry *var = ((TldVar *)curr_entry->value)->var; |
| 16898 | ensure_complete_type(ira->codegen, var->value->type); | 16895 | if ((err = ensure_complete_type(ira->codegen, var->value->type))) |
| 16899 | if (type_is_invalid(var->value->type)) | ||
| 16900 | return false; | 16896 | return false; |
| 16901 | 16897 | ||
| 16902 | if (var->value->type->id == TypeTableEntryIdMetaType) | 16898 | if (var->value->type->id == TypeTableEntryIdMetaType) |
| ... | @@ -16953,7 +16949,7 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop | ... | @@ -16953,7 +16949,7 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop |
| 16953 | // calling_convention: TypeInfo.CallingConvention | 16949 | // calling_convention: TypeInfo.CallingConvention |
| 16954 | ensure_field_index(fn_def_val->type, "calling_convention", 2); | 16950 | ensure_field_index(fn_def_val->type, "calling_convention", 2); |
| 16955 | fn_def_fields[2].special = ConstValSpecialStatic; | 16951 | fn_def_fields[2].special = ConstValSpecialStatic; |
| 16956 | fn_def_fields[2].type = ir_type_info_get_type(ira, "CallingConvention"); | 16952 | fn_def_fields[2].type = ir_type_info_get_type(ira, "CallingConvention", nullptr); |
| 16957 | bigint_init_unsigned(&fn_def_fields[2].data.x_enum_tag, fn_node->cc); | 16953 | bigint_init_unsigned(&fn_def_fields[2].data.x_enum_tag, fn_node->cc); |
| 16958 | // is_var_args: bool | 16954 | // is_var_args: bool |
| 16959 | ensure_field_index(fn_def_val->type, "is_var_args", 3); | 16955 | ensure_field_index(fn_def_val->type, "is_var_args", 3); |
| ... | @@ -17027,8 +17023,7 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop | ... | @@ -17027,8 +17023,7 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop |
| 17027 | case TldIdContainer: | 17023 | case TldIdContainer: |
| 17028 | { | 17024 | { |
| 17029 | TypeTableEntry *type_entry = ((TldContainer *)curr_entry->value)->type_entry; | 17025 | TypeTableEntry *type_entry = ((TldContainer *)curr_entry->value)->type_entry; |
| 17030 | ensure_complete_type(ira->codegen, type_entry); | 17026 | if ((err = ensure_complete_type(ira->codegen, type_entry))) |
| 17031 | if (type_is_invalid(type_entry)) | ||
| 17032 | return false; | 17027 | return false; |
| 17033 | 17028 | ||
| 17034 | // This is a type. | 17029 | // This is a type. |
| ... | @@ -17054,12 +17049,67 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop | ... | @@ -17054,12 +17049,67 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop |
| 17054 | return true; | 17049 | return true; |
| 17055 | } | 17050 | } |
| 17056 | 17051 | ||
| 17052 | static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, TypeTableEntry *ptr_type_entry) { | ||
| 17053 | TypeTableEntry *attrs_type; | ||
| 17054 | uint32_t size_enum_index; | ||
| 17055 | if (is_slice(ptr_type_entry)) { | ||
| 17056 | attrs_type = ptr_type_entry->data.structure.fields[slice_ptr_index].type_entry; | ||
| 17057 | size_enum_index = 2; | ||
| 17058 | } else if (ptr_type_entry->id == TypeTableEntryIdPointer) { | ||
| 17059 | attrs_type = ptr_type_entry; | ||
| 17060 | size_enum_index = (ptr_type_entry->data.pointer.ptr_len == PtrLenSingle) ? 0 : 1; | ||
| 17061 | } else { | ||
| 17062 | zig_unreachable(); | ||
| 17063 | } | ||
| 17064 | |||
| 17065 | TypeTableEntry *type_info_pointer_type = ir_type_info_get_type(ira, "Pointer", nullptr); | ||
| 17066 | assertNoError(ensure_complete_type(ira->codegen, type_info_pointer_type)); | ||
| 17067 | |||
| 17068 | ConstExprValue *result = create_const_vals(1); | ||
| 17069 | result->special = ConstValSpecialStatic; | ||
| 17070 | result->type = type_info_pointer_type; | ||
| 17071 | |||
| 17072 | ConstExprValue *fields = create_const_vals(5); | ||
| 17073 | result->data.x_struct.fields = fields; | ||
| 17074 | |||
| 17075 | // size: Size | ||
| 17076 | ensure_field_index(result->type, "size", 0); | ||
| 17077 | TypeTableEntry *type_info_pointer_size_type = ir_type_info_get_type(ira, "Size", type_info_pointer_type); | ||
| 17078 | assertNoError(ensure_complete_type(ira->codegen, type_info_pointer_size_type)); | ||
| 17079 | fields[0].special = ConstValSpecialStatic; | ||
| 17080 | fields[0].type = type_info_pointer_size_type; | ||
| 17081 | bigint_init_unsigned(&fields[0].data.x_enum_tag, size_enum_index); | ||
| 17082 | |||
| 17083 | // is_const: bool | ||
| 17084 | ensure_field_index(result->type, "is_const", 1); | ||
| 17085 | fields[1].special = ConstValSpecialStatic; | ||
| 17086 | fields[1].type = ira->codegen->builtin_types.entry_bool; | ||
| 17087 | fields[1].data.x_bool = attrs_type->data.pointer.is_const; | ||
| 17088 | // is_volatile: bool | ||
| 17089 | ensure_field_index(result->type, "is_volatile", 2); | ||
| 17090 | fields[2].special = ConstValSpecialStatic; | ||
| 17091 | fields[2].type = ira->codegen->builtin_types.entry_bool; | ||
| 17092 | fields[2].data.x_bool = attrs_type->data.pointer.is_volatile; | ||
| 17093 | // alignment: u32 | ||
| 17094 | ensure_field_index(result->type, "alignment", 3); | ||
| 17095 | fields[3].special = ConstValSpecialStatic; | ||
| 17096 | fields[3].type = get_int_type(ira->codegen, false, 29); | ||
| 17097 | bigint_init_unsigned(&fields[3].data.x_bigint, attrs_type->data.pointer.alignment); | ||
| 17098 | // child: type | ||
| 17099 | ensure_field_index(result->type, "child", 4); | ||
| 17100 | fields[4].special = ConstValSpecialStatic; | ||
| 17101 | fields[4].type = ira->codegen->builtin_types.entry_type; | ||
| 17102 | fields[4].data.x_type = attrs_type->data.pointer.child_type; | ||
| 17103 | |||
| 17104 | return result; | ||
| 17105 | }; | ||
| 17106 | |||
| 17057 | static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *type_entry) { | 17107 | static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *type_entry) { |
| 17108 | Error err; | ||
| 17058 | assert(type_entry != nullptr); | 17109 | assert(type_entry != nullptr); |
| 17059 | assert(!type_is_invalid(type_entry)); | 17110 | assert(!type_is_invalid(type_entry)); |
| 17060 | 17111 | ||
| 17061 | ensure_complete_type(ira->codegen, type_entry); | 17112 | if ((err = ensure_complete_type(ira->codegen, type_entry))) |
| 17062 | if (type_is_invalid(type_entry)) | ||
| 17063 | return nullptr; | 17113 | return nullptr; |
| 17064 | 17114 | ||
| 17065 | const auto make_enum_field_val = [ira](ConstExprValue *enum_field_val, TypeEnumField *enum_field, | 17115 | const auto make_enum_field_val = [ira](ConstExprValue *enum_field_val, TypeEnumField *enum_field, |
| ... | @@ -17079,63 +17129,6 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17079,63 +17129,6 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17079 | enum_field_val->data.x_struct.fields = inner_fields; | 17129 | enum_field_val->data.x_struct.fields = inner_fields; |
| 17080 | }; | 17130 | }; |
| 17081 | 17131 | ||
| 17082 | const auto create_ptr_like_type_info = [ira](TypeTableEntry *ptr_type_entry) { | ||
| 17083 | TypeTableEntry *attrs_type; | ||
| 17084 | uint32_t size_enum_index; | ||
| 17085 | if (is_slice(ptr_type_entry)) { | ||
| 17086 | attrs_type = ptr_type_entry->data.structure.fields[slice_ptr_index].type_entry; | ||
| 17087 | size_enum_index = 2; | ||
| 17088 | } else if (ptr_type_entry->id == TypeTableEntryIdPointer) { | ||
| 17089 | attrs_type = ptr_type_entry; | ||
| 17090 | size_enum_index = (ptr_type_entry->data.pointer.ptr_len == PtrLenSingle) ? 0 : 1; | ||
| 17091 | } else { | ||
| 17092 | zig_unreachable(); | ||
| 17093 | } | ||
| 17094 | |||
| 17095 | TypeTableEntry *type_info_pointer_type = ir_type_info_get_type(ira, "Pointer"); | ||
| 17096 | ensure_complete_type(ira->codegen, type_info_pointer_type); | ||
| 17097 | assert(!type_is_invalid(type_info_pointer_type)); | ||
| 17098 | |||
| 17099 | ConstExprValue *result = create_const_vals(1); | ||
| 17100 | result->special = ConstValSpecialStatic; | ||
| 17101 | result->type = type_info_pointer_type; | ||
| 17102 | |||
| 17103 | ConstExprValue *fields = create_const_vals(5); | ||
| 17104 | result->data.x_struct.fields = fields; | ||
| 17105 | |||
| 17106 | // size: Size | ||
| 17107 | ensure_field_index(result->type, "size", 0); | ||
| 17108 | TypeTableEntry *type_info_pointer_size_type = ir_type_info_get_type(ira, "Size", type_info_pointer_type); | ||
| 17109 | ensure_complete_type(ira->codegen, type_info_pointer_size_type); | ||
| 17110 | assert(!type_is_invalid(type_info_pointer_size_type)); | ||
| 17111 | fields[0].special = ConstValSpecialStatic; | ||
| 17112 | fields[0].type = type_info_pointer_size_type; | ||
| 17113 | bigint_init_unsigned(&fields[0].data.x_enum_tag, size_enum_index); | ||
| 17114 | |||
| 17115 | // is_const: bool | ||
| 17116 | ensure_field_index(result->type, "is_const", 1); | ||
| 17117 | fields[1].special = ConstValSpecialStatic; | ||
| 17118 | fields[1].type = ira->codegen->builtin_types.entry_bool; | ||
| 17119 | fields[1].data.x_bool = attrs_type->data.pointer.is_const; | ||
| 17120 | // is_volatile: bool | ||
| 17121 | ensure_field_index(result->type, "is_volatile", 2); | ||
| 17122 | fields[2].special = ConstValSpecialStatic; | ||
| 17123 | fields[2].type = ira->codegen->builtin_types.entry_bool; | ||
| 17124 | fields[2].data.x_bool = attrs_type->data.pointer.is_volatile; | ||
| 17125 | // alignment: u32 | ||
| 17126 | ensure_field_index(result->type, "alignment", 3); | ||
| 17127 | fields[3].special = ConstValSpecialStatic; | ||
| 17128 | fields[3].type = get_int_type(ira->codegen, false, 29); | ||
| 17129 | bigint_init_unsigned(&fields[3].data.x_bigint, attrs_type->data.pointer.alignment); | ||
| 17130 | // child: type | ||
| 17131 | ensure_field_index(result->type, "child", 4); | ||
| 17132 | fields[4].special = ConstValSpecialStatic; | ||
| 17133 | fields[4].type = ira->codegen->builtin_types.entry_type; | ||
| 17134 | fields[4].data.x_type = attrs_type->data.pointer.child_type; | ||
| 17135 | |||
| 17136 | return result; | ||
| 17137 | }; | ||
| 17138 | |||
| 17139 | if (type_entry == ira->codegen->builtin_types.entry_global_error_set) { | 17132 | if (type_entry == ira->codegen->builtin_types.entry_global_error_set) { |
| 17140 | zig_panic("TODO implement @typeInfo for global error set"); | 17133 | zig_panic("TODO implement @typeInfo for global error set"); |
| 17141 | } | 17134 | } |
| ... | @@ -17171,7 +17164,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17171,7 +17164,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17171 | { | 17164 | { |
| 17172 | result = create_const_vals(1); | 17165 | result = create_const_vals(1); |
| 17173 | result->special = ConstValSpecialStatic; | 17166 | result->special = ConstValSpecialStatic; |
| 17174 | result->type = ir_type_info_get_type(ira, "Int"); | 17167 | result->type = ir_type_info_get_type(ira, "Int", nullptr); |
| 17175 | 17168 | ||
| 17176 | ConstExprValue *fields = create_const_vals(2); | 17169 | ConstExprValue *fields = create_const_vals(2); |
| 17177 | result->data.x_struct.fields = fields; | 17170 | result->data.x_struct.fields = fields; |
| ... | @@ -17193,7 +17186,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17193,7 +17186,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17193 | { | 17186 | { |
| 17194 | result = create_const_vals(1); | 17187 | result = create_const_vals(1); |
| 17195 | result->special = ConstValSpecialStatic; | 17188 | result->special = ConstValSpecialStatic; |
| 17196 | result->type = ir_type_info_get_type(ira, "Float"); | 17189 | result->type = ir_type_info_get_type(ira, "Float", nullptr); |
| 17197 | 17190 | ||
| 17198 | ConstExprValue *fields = create_const_vals(1); | 17191 | ConstExprValue *fields = create_const_vals(1); |
| 17199 | result->data.x_struct.fields = fields; | 17192 | result->data.x_struct.fields = fields; |
| ... | @@ -17208,14 +17201,14 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17208,14 +17201,14 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17208 | } | 17201 | } |
| 17209 | case TypeTableEntryIdPointer: | 17202 | case TypeTableEntryIdPointer: |
| 17210 | { | 17203 | { |
| 17211 | result = create_ptr_like_type_info(type_entry); | 17204 | result = create_ptr_like_type_info(ira, type_entry); |
| 17212 | break; | 17205 | break; |
| 17213 | } | 17206 | } |
| 17214 | case TypeTableEntryIdArray: | 17207 | case TypeTableEntryIdArray: |
| 17215 | { | 17208 | { |
| 17216 | result = create_const_vals(1); | 17209 | result = create_const_vals(1); |
| 17217 | result->special = ConstValSpecialStatic; | 17210 | result->special = ConstValSpecialStatic; |
| 17218 | result->type = ir_type_info_get_type(ira, "Array"); | 17211 | result->type = ir_type_info_get_type(ira, "Array", nullptr); |
| 17219 | 17212 | ||
| 17220 | ConstExprValue *fields = create_const_vals(2); | 17213 | ConstExprValue *fields = create_const_vals(2); |
| 17221 | result->data.x_struct.fields = fields; | 17214 | result->data.x_struct.fields = fields; |
| ... | @@ -17237,7 +17230,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17237,7 +17230,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17237 | { | 17230 | { |
| 17238 | result = create_const_vals(1); | 17231 | result = create_const_vals(1); |
| 17239 | result->special = ConstValSpecialStatic; | 17232 | result->special = ConstValSpecialStatic; |
| 17240 | result->type = ir_type_info_get_type(ira, "Optional"); | 17233 | result->type = ir_type_info_get_type(ira, "Optional", nullptr); |
| 17241 | 17234 | ||
| 17242 | ConstExprValue *fields = create_const_vals(1); | 17235 | ConstExprValue *fields = create_const_vals(1); |
| 17243 | result->data.x_struct.fields = fields; | 17236 | result->data.x_struct.fields = fields; |
| ... | @@ -17254,7 +17247,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17254,7 +17247,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17254 | { | 17247 | { |
| 17255 | result = create_const_vals(1); | 17248 | result = create_const_vals(1); |
| 17256 | result->special = ConstValSpecialStatic; | 17249 | result->special = ConstValSpecialStatic; |
| 17257 | result->type = ir_type_info_get_type(ira, "Promise"); | 17250 | result->type = ir_type_info_get_type(ira, "Promise", nullptr); |
| 17258 | 17251 | ||
| 17259 | ConstExprValue *fields = create_const_vals(1); | 17252 | ConstExprValue *fields = create_const_vals(1); |
| 17260 | result->data.x_struct.fields = fields; | 17253 | result->data.x_struct.fields = fields; |
| ... | @@ -17280,7 +17273,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17280,7 +17273,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17280 | { | 17273 | { |
| 17281 | result = create_const_vals(1); | 17274 | result = create_const_vals(1); |
| 17282 | result->special = ConstValSpecialStatic; | 17275 | result->special = ConstValSpecialStatic; |
| 17283 | result->type = ir_type_info_get_type(ira, "Enum"); | 17276 | result->type = ir_type_info_get_type(ira, "Enum", nullptr); |
| 17284 | 17277 | ||
| 17285 | ConstExprValue *fields = create_const_vals(4); | 17278 | ConstExprValue *fields = create_const_vals(4); |
| 17286 | result->data.x_struct.fields = fields; | 17279 | result->data.x_struct.fields = fields; |
| ... | @@ -17288,7 +17281,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17288,7 +17281,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17288 | // layout: ContainerLayout | 17281 | // layout: ContainerLayout |
| 17289 | ensure_field_index(result->type, "layout", 0); | 17282 | ensure_field_index(result->type, "layout", 0); |
| 17290 | fields[0].special = ConstValSpecialStatic; | 17283 | fields[0].special = ConstValSpecialStatic; |
| 17291 | fields[0].type = ir_type_info_get_type(ira, "ContainerLayout"); | 17284 | fields[0].type = ir_type_info_get_type(ira, "ContainerLayout", nullptr); |
| 17292 | bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.enumeration.layout); | 17285 | bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.enumeration.layout); |
| 17293 | // tag_type: type | 17286 | // tag_type: type |
| 17294 | ensure_field_index(result->type, "tag_type", 1); | 17287 | ensure_field_index(result->type, "tag_type", 1); |
| ... | @@ -17298,7 +17291,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17298,7 +17291,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17298 | // fields: []TypeInfo.EnumField | 17291 | // fields: []TypeInfo.EnumField |
| 17299 | ensure_field_index(result->type, "fields", 2); | 17292 | ensure_field_index(result->type, "fields", 2); |
| 17300 | 17293 | ||
| 17301 | TypeTableEntry *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField"); | 17294 | TypeTableEntry *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField", nullptr); |
| 17302 | uint32_t enum_field_count = type_entry->data.enumeration.src_field_count; | 17295 | uint32_t enum_field_count = type_entry->data.enumeration.src_field_count; |
| 17303 | 17296 | ||
| 17304 | ConstExprValue *enum_field_array = create_const_vals(1); | 17297 | ConstExprValue *enum_field_array = create_const_vals(1); |
| ... | @@ -17330,7 +17323,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17330,7 +17323,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17330 | { | 17323 | { |
| 17331 | result = create_const_vals(1); | 17324 | result = create_const_vals(1); |
| 17332 | result->special = ConstValSpecialStatic; | 17325 | result->special = ConstValSpecialStatic; |
| 17333 | result->type = ir_type_info_get_type(ira, "ErrorSet"); | 17326 | result->type = ir_type_info_get_type(ira, "ErrorSet", nullptr); |
| 17334 | 17327 | ||
| 17335 | ConstExprValue *fields = create_const_vals(1); | 17328 | ConstExprValue *fields = create_const_vals(1); |
| 17336 | result->data.x_struct.fields = fields; | 17329 | result->data.x_struct.fields = fields; |
| ... | @@ -17338,7 +17331,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17338,7 +17331,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17338 | // errors: []TypeInfo.Error | 17331 | // errors: []TypeInfo.Error |
| 17339 | ensure_field_index(result->type, "errors", 0); | 17332 | ensure_field_index(result->type, "errors", 0); |
| 17340 | 17333 | ||
| 17341 | TypeTableEntry *type_info_error_type = ir_type_info_get_type(ira, "Error"); | 17334 | TypeTableEntry *type_info_error_type = ir_type_info_get_type(ira, "Error", nullptr); |
| 17342 | uint32_t error_count = type_entry->data.error_set.err_count; | 17335 | uint32_t error_count = type_entry->data.error_set.err_count; |
| 17343 | ConstExprValue *error_array = create_const_vals(1); | 17336 | ConstExprValue *error_array = create_const_vals(1); |
| 17344 | error_array->special = ConstValSpecialStatic; | 17337 | error_array->special = ConstValSpecialStatic; |
| ... | @@ -17380,7 +17373,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17380,7 +17373,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17380 | { | 17373 | { |
| 17381 | result = create_const_vals(1); | 17374 | result = create_const_vals(1); |
| 17382 | result->special = ConstValSpecialStatic; | 17375 | result->special = ConstValSpecialStatic; |
| 17383 | result->type = ir_type_info_get_type(ira, "ErrorUnion"); | 17376 | result->type = ir_type_info_get_type(ira, "ErrorUnion", nullptr); |
| 17384 | 17377 | ||
| 17385 | ConstExprValue *fields = create_const_vals(2); | 17378 | ConstExprValue *fields = create_const_vals(2); |
| 17386 | result->data.x_struct.fields = fields; | 17379 | result->data.x_struct.fields = fields; |
| ... | @@ -17403,7 +17396,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17403,7 +17396,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17403 | { | 17396 | { |
| 17404 | result = create_const_vals(1); | 17397 | result = create_const_vals(1); |
| 17405 | result->special = ConstValSpecialStatic; | 17398 | result->special = ConstValSpecialStatic; |
| 17406 | result->type = ir_type_info_get_type(ira, "Union"); | 17399 | result->type = ir_type_info_get_type(ira, "Union", nullptr); |
| 17407 | 17400 | ||
| 17408 | ConstExprValue *fields = create_const_vals(4); | 17401 | ConstExprValue *fields = create_const_vals(4); |
| 17409 | result->data.x_struct.fields = fields; | 17402 | result->data.x_struct.fields = fields; |
| ... | @@ -17411,7 +17404,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17411,7 +17404,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17411 | // layout: ContainerLayout | 17404 | // layout: ContainerLayout |
| 17412 | ensure_field_index(result->type, "layout", 0); | 17405 | ensure_field_index(result->type, "layout", 0); |
| 17413 | fields[0].special = ConstValSpecialStatic; | 17406 | fields[0].special = ConstValSpecialStatic; |
| 17414 | fields[0].type = ir_type_info_get_type(ira, "ContainerLayout"); | 17407 | fields[0].type = ir_type_info_get_type(ira, "ContainerLayout", nullptr); |
| 17415 | bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.unionation.layout); | 17408 | bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.unionation.layout); |
| 17416 | // tag_type: ?type | 17409 | // tag_type: ?type |
| 17417 | ensure_field_index(result->type, "tag_type", 1); | 17410 | ensure_field_index(result->type, "tag_type", 1); |
| ... | @@ -17433,7 +17426,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17433,7 +17426,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17433 | // fields: []TypeInfo.UnionField | 17426 | // fields: []TypeInfo.UnionField |
| 17434 | ensure_field_index(result->type, "fields", 2); | 17427 | ensure_field_index(result->type, "fields", 2); |
| 17435 | 17428 | ||
| 17436 | TypeTableEntry *type_info_union_field_type = ir_type_info_get_type(ira, "UnionField"); | 17429 | TypeTableEntry *type_info_union_field_type = ir_type_info_get_type(ira, "UnionField", nullptr); |
| 17437 | uint32_t union_field_count = type_entry->data.unionation.src_field_count; | 17430 | uint32_t union_field_count = type_entry->data.unionation.src_field_count; |
| 17438 | 17431 | ||
| 17439 | ConstExprValue *union_field_array = create_const_vals(1); | 17432 | ConstExprValue *union_field_array = create_const_vals(1); |
| ... | @@ -17445,7 +17438,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17445,7 +17438,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17445 | 17438 | ||
| 17446 | init_const_slice(ira->codegen, &fields[2], union_field_array, 0, union_field_count, false); | 17439 | init_const_slice(ira->codegen, &fields[2], union_field_array, 0, union_field_count, false); |
| 17447 | 17440 | ||
| 17448 | TypeTableEntry *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField"); | 17441 | TypeTableEntry *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField", nullptr); |
| 17449 | 17442 | ||
| 17450 | for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) { | 17443 | for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) { |
| 17451 | TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index]; | 17444 | TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index]; |
| ... | @@ -17487,13 +17480,13 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17487,13 +17480,13 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17487 | case TypeTableEntryIdStruct: | 17480 | case TypeTableEntryIdStruct: |
| 17488 | { | 17481 | { |
| 17489 | if (type_entry->data.structure.is_slice) { | 17482 | if (type_entry->data.structure.is_slice) { |
| 17490 | result = create_ptr_like_type_info(type_entry); | 17483 | result = create_ptr_like_type_info(ira, type_entry); |
| 17491 | break; | 17484 | break; |
| 17492 | } | 17485 | } |
| 17493 | 17486 | ||
| 17494 | result = create_const_vals(1); | 17487 | result = create_const_vals(1); |
| 17495 | result->special = ConstValSpecialStatic; | 17488 | result->special = ConstValSpecialStatic; |
| 17496 | result->type = ir_type_info_get_type(ira, "Struct"); | 17489 | result->type = ir_type_info_get_type(ira, "Struct", nullptr); |
| 17497 | 17490 | ||
| 17498 | ConstExprValue *fields = create_const_vals(3); | 17491 | ConstExprValue *fields = create_const_vals(3); |
| 17499 | result->data.x_struct.fields = fields; | 17492 | result->data.x_struct.fields = fields; |
| ... | @@ -17501,12 +17494,12 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17501,12 +17494,12 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17501 | // layout: ContainerLayout | 17494 | // layout: ContainerLayout |
| 17502 | ensure_field_index(result->type, "layout", 0); | 17495 | ensure_field_index(result->type, "layout", 0); |
| 17503 | fields[0].special = ConstValSpecialStatic; | 17496 | fields[0].special = ConstValSpecialStatic; |
| 17504 | fields[0].type = ir_type_info_get_type(ira, "ContainerLayout"); | 17497 | fields[0].type = ir_type_info_get_type(ira, "ContainerLayout", nullptr); |
| 17505 | bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.structure.layout); | 17498 | bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.structure.layout); |
| 17506 | // fields: []TypeInfo.StructField | 17499 | // fields: []TypeInfo.StructField |
| 17507 | ensure_field_index(result->type, "fields", 1); | 17500 | ensure_field_index(result->type, "fields", 1); |
| 17508 | 17501 | ||
| 17509 | TypeTableEntry *type_info_struct_field_type = ir_type_info_get_type(ira, "StructField"); | 17502 | TypeTableEntry *type_info_struct_field_type = ir_type_info_get_type(ira, "StructField", nullptr); |
| 17510 | uint32_t struct_field_count = type_entry->data.structure.src_field_count; | 17503 | uint32_t struct_field_count = type_entry->data.structure.src_field_count; |
| 17511 | 17504 | ||
| 17512 | ConstExprValue *struct_field_array = create_const_vals(1); | 17505 | ConstExprValue *struct_field_array = create_const_vals(1); |
| ... | @@ -17562,7 +17555,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17562,7 +17555,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17562 | { | 17555 | { |
| 17563 | result = create_const_vals(1); | 17556 | result = create_const_vals(1); |
| 17564 | result->special = ConstValSpecialStatic; | 17557 | result->special = ConstValSpecialStatic; |
| 17565 | result->type = ir_type_info_get_type(ira, "Fn"); | 17558 | result->type = ir_type_info_get_type(ira, "Fn", nullptr); |
| 17566 | 17559 | ||
| 17567 | ConstExprValue *fields = create_const_vals(6); | 17560 | ConstExprValue *fields = create_const_vals(6); |
| 17568 | result->data.x_struct.fields = fields; | 17561 | result->data.x_struct.fields = fields; |
| ... | @@ -17570,7 +17563,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17570,7 +17563,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17570 | // calling_convention: TypeInfo.CallingConvention | 17563 | // calling_convention: TypeInfo.CallingConvention |
| 17571 | ensure_field_index(result->type, "calling_convention", 0); | 17564 | ensure_field_index(result->type, "calling_convention", 0); |
| 17572 | fields[0].special = ConstValSpecialStatic; | 17565 | fields[0].special = ConstValSpecialStatic; |
| 17573 | fields[0].type = ir_type_info_get_type(ira, "CallingConvention"); | 17566 | fields[0].type = ir_type_info_get_type(ira, "CallingConvention", nullptr); |
| 17574 | bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.fn.fn_type_id.cc); | 17567 | bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.fn.fn_type_id.cc); |
| 17575 | // is_generic: bool | 17568 | // is_generic: bool |
| 17576 | ensure_field_index(result->type, "is_generic", 1); | 17569 | ensure_field_index(result->type, "is_generic", 1); |
| ... | @@ -17611,7 +17604,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t | ... | @@ -17611,7 +17604,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t |
| 17611 | fields[4].data.x_optional = async_alloc_type; | 17604 | fields[4].data.x_optional = async_alloc_type; |
| 17612 | } | 17605 | } |
| 17613 | // args: []TypeInfo.FnArg | 17606 | // args: []TypeInfo.FnArg |
| 17614 | TypeTableEntry *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg"); | 17607 | TypeTableEntry *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg", nullptr); |
| 17615 | size_t fn_arg_count = type_entry->data.fn.fn_type_id.param_count - | 17608 | size_t fn_arg_count = type_entry->data.fn.fn_type_id.param_count - |
| 17616 | (is_varargs && type_entry->data.fn.fn_type_id.cc != CallingConventionC); | 17609 | (is_varargs && type_entry->data.fn.fn_type_id.cc != CallingConventionC); |
| 17617 | 17610 | ||
| ... | @@ -17686,7 +17679,7 @@ static TypeTableEntry *ir_analyze_instruction_type_info(IrAnalyze *ira, | ... | @@ -17686,7 +17679,7 @@ static TypeTableEntry *ir_analyze_instruction_type_info(IrAnalyze *ira, |
| 17686 | if (type_is_invalid(type_entry)) | 17679 | if (type_is_invalid(type_entry)) |
| 17687 | return ira->codegen->builtin_types.entry_invalid; | 17680 | return ira->codegen->builtin_types.entry_invalid; |
| 17688 | 17681 | ||
| 17689 | TypeTableEntry *result_type = ir_type_info_get_type(ira, nullptr); | 17682 | TypeTableEntry *result_type = ir_type_info_get_type(ira, nullptr, nullptr); |
| 17690 | 17683 | ||
| 17691 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | 17684 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 17692 | out_val->type = result_type; | 17685 | out_val->type = result_type; |
| ... | @@ -18896,13 +18889,13 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio | ... | @@ -18896,13 +18889,13 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio |
| 18896 | } | 18889 | } |
| 18897 | 18890 | ||
| 18898 | static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInstructionMemberCount *instruction) { | 18891 | static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInstructionMemberCount *instruction) { |
| 18892 | Error err; | ||
| 18899 | IrInstruction *container = instruction->container->other; | 18893 | IrInstruction *container = instruction->container->other; |
| 18900 | if (type_is_invalid(container->value.type)) | 18894 | if (type_is_invalid(container->value.type)) |
| 18901 | return ira->codegen->builtin_types.entry_invalid; | 18895 | return ira->codegen->builtin_types.entry_invalid; |
| 18902 | TypeTableEntry *container_type = ir_resolve_type(ira, container); | 18896 | TypeTableEntry *container_type = ir_resolve_type(ira, container); |
| 18903 | 18897 | ||
| 18904 | ensure_complete_type(ira->codegen, container_type); | 18898 | if ((err = ensure_complete_type(ira->codegen, container_type))) |
| 18905 | if (type_is_invalid(container_type)) | ||
| 18906 | return ira->codegen->builtin_types.entry_invalid; | 18899 | return ira->codegen->builtin_types.entry_invalid; |
| 18907 | 18900 | ||
| 18908 | uint64_t result; | 18901 | uint64_t result; |
| ... | @@ -18934,13 +18927,13 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns | ... | @@ -18934,13 +18927,13 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns |
| 18934 | } | 18927 | } |
| 18935 | 18928 | ||
| 18936 | static TypeTableEntry *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstructionMemberType *instruction) { | 18929 | static TypeTableEntry *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstructionMemberType *instruction) { |
| 18930 | Error err; | ||
| 18937 | IrInstruction *container_type_value = instruction->container_type->other; | 18931 | IrInstruction *container_type_value = instruction->container_type->other; |
| 18938 | TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value); | 18932 | TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value); |
| 18939 | if (type_is_invalid(container_type)) | 18933 | if (type_is_invalid(container_type)) |
| 18940 | return ira->codegen->builtin_types.entry_invalid; | 18934 | return ira->codegen->builtin_types.entry_invalid; |
| 18941 | 18935 | ||
| 18942 | ensure_complete_type(ira->codegen, container_type); | 18936 | if ((err = ensure_complete_type(ira->codegen, container_type))) |
| 18943 | if (type_is_invalid(container_type)) | ||
| 18944 | return ira->codegen->builtin_types.entry_invalid; | 18937 | return ira->codegen->builtin_types.entry_invalid; |
| 18945 | 18938 | ||
| 18946 | 18939 | ||
| ... | @@ -18981,13 +18974,13 @@ static TypeTableEntry *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInst | ... | @@ -18981,13 +18974,13 @@ static TypeTableEntry *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInst |
| 18981 | } | 18974 | } |
| 18982 | 18975 | ||
| 18983 | static TypeTableEntry *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstructionMemberName *instruction) { | 18976 | static TypeTableEntry *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstructionMemberName *instruction) { |
| 18977 | Error err; | ||
| 18984 | IrInstruction *container_type_value = instruction->container_type->other; | 18978 | IrInstruction *container_type_value = instruction->container_type->other; |
| 18985 | TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value); | 18979 | TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value); |
| 18986 | if (type_is_invalid(container_type)) | 18980 | if (type_is_invalid(container_type)) |
| 18987 | return ira->codegen->builtin_types.entry_invalid; | 18981 | return ira->codegen->builtin_types.entry_invalid; |
| 18988 | 18982 | ||
| 18989 | ensure_complete_type(ira->codegen, container_type); | 18983 | if ((err = ensure_complete_type(ira->codegen, container_type))) |
| 18990 | if (type_is_invalid(container_type)) | ||
| 18991 | return ira->codegen->builtin_types.entry_invalid; | 18984 | return ira->codegen->builtin_types.entry_invalid; |
| 18992 | 18985 | ||
| 18993 | uint64_t member_index; | 18986 | uint64_t member_index; |
| ... | @@ -19068,13 +19061,13 @@ static TypeTableEntry *ir_analyze_instruction_handle(IrAnalyze *ira, IrInstructi | ... | @@ -19068,13 +19061,13 @@ static TypeTableEntry *ir_analyze_instruction_handle(IrAnalyze *ira, IrInstructi |
| 19068 | } | 19061 | } |
| 19069 | 19062 | ||
| 19070 | static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAlignOf *instruction) { | 19063 | static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAlignOf *instruction) { |
| 19064 | Error err; | ||
| 19071 | IrInstruction *type_value = instruction->type_value->other; | 19065 | IrInstruction *type_value = instruction->type_value->other; |
| 19072 | if (type_is_invalid(type_value->value.type)) | 19066 | if (type_is_invalid(type_value->value.type)) |
| 19073 | return ira->codegen->builtin_types.entry_invalid; | 19067 | return ira->codegen->builtin_types.entry_invalid; |
| 19074 | TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); | 19068 | TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); |
| 19075 | 19069 | ||
| 19076 | type_ensure_zero_bits_known(ira->codegen, type_entry); | 19070 | if ((err = type_ensure_zero_bits_known(ira->codegen, type_entry))) |
| 19077 | if (type_is_invalid(type_entry)) | ||
| 19078 | return ira->codegen->builtin_types.entry_invalid; | 19071 | return ira->codegen->builtin_types.entry_invalid; |
| 19079 | 19072 | ||
| 19080 | switch (type_entry->id) { | 19073 | switch (type_entry->id) { |
| ... | @@ -19930,6 +19923,7 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue | ... | @@ -19930,6 +19923,7 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue |
| 19930 | } | 19923 | } |
| 19931 | 19924 | ||
| 19932 | static TypeTableEntry *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) { | 19925 | static TypeTableEntry *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) { |
| 19926 | Error err; | ||
| 19933 | IrInstruction *dest_type_value = instruction->dest_type->other; | 19927 | IrInstruction *dest_type_value = instruction->dest_type->other; |
| 19934 | TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value); | 19928 | TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value); |
| 19935 | if (type_is_invalid(dest_type)) | 19929 | if (type_is_invalid(dest_type)) |
| ... | @@ -19940,12 +19934,10 @@ static TypeTableEntry *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruc | ... | @@ -19940,12 +19934,10 @@ static TypeTableEntry *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruc |
| 19940 | if (type_is_invalid(src_type)) | 19934 | if (type_is_invalid(src_type)) |
| 19941 | return ira->codegen->builtin_types.entry_invalid; | 19935 | return ira->codegen->builtin_types.entry_invalid; |
| 19942 | 19936 | ||
| 19943 | ensure_complete_type(ira->codegen, dest_type); | 19937 | if ((err = ensure_complete_type(ira->codegen, dest_type))) |
| 19944 | if (type_is_invalid(dest_type)) | ||
| 19945 | return ira->codegen->builtin_types.entry_invalid; | 19938 | return ira->codegen->builtin_types.entry_invalid; |
| 19946 | 19939 | ||
| 19947 | ensure_complete_type(ira->codegen, src_type); | 19940 | if ((err = ensure_complete_type(ira->codegen, src_type))) |
| 19948 | if (type_is_invalid(src_type)) | ||
| 19949 | return ira->codegen->builtin_types.entry_invalid; | 19941 | return ira->codegen->builtin_types.entry_invalid; |
| 19950 | 19942 | ||
| 19951 | if (get_codegen_ptr_type(src_type) != nullptr) { | 19943 | if (get_codegen_ptr_type(src_type) != nullptr) { |
| ... | @@ -20031,6 +20023,7 @@ static TypeTableEntry *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruc | ... | @@ -20031,6 +20023,7 @@ static TypeTableEntry *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruc |
| 20031 | } | 20023 | } |
| 20032 | 20024 | ||
| 20033 | static TypeTableEntry *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionIntToPtr *instruction) { | 20025 | static TypeTableEntry *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionIntToPtr *instruction) { |
| 20026 | Error err; | ||
| 20034 | IrInstruction *dest_type_value = instruction->dest_type->other; | 20027 | IrInstruction *dest_type_value = instruction->dest_type->other; |
| 20035 | TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value); | 20028 | TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value); |
| 20036 | if (type_is_invalid(dest_type)) | 20029 | if (type_is_invalid(dest_type)) |
| ... | @@ -20041,7 +20034,8 @@ static TypeTableEntry *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstr | ... | @@ -20041,7 +20034,8 @@ static TypeTableEntry *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstr |
| 20041 | return ira->codegen->builtin_types.entry_invalid; | 20034 | return ira->codegen->builtin_types.entry_invalid; |
| 20042 | } | 20035 | } |
| 20043 | 20036 | ||
| 20044 | type_ensure_zero_bits_known(ira->codegen, dest_type); | 20037 | if ((err = type_ensure_zero_bits_known(ira->codegen, dest_type))) |
| 20038 | return ira->codegen->builtin_types.entry_invalid; | ||
| 20045 | if (!type_has_bits(dest_type)) { | 20039 | if (!type_has_bits(dest_type)) { |
| 20046 | ir_add_error(ira, dest_type_value, | 20040 | ir_add_error(ira, dest_type_value, |
| 20047 | buf_sprintf("type '%s' has 0 bits and cannot store information", buf_ptr(&dest_type->name))); | 20041 | buf_sprintf("type '%s' has 0 bits and cannot store information", buf_ptr(&dest_type->name))); |
| ... | @@ -20174,6 +20168,7 @@ static TypeTableEntry *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstr | ... | @@ -20174,6 +20168,7 @@ static TypeTableEntry *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstr |
| 20174 | } | 20168 | } |
| 20175 | 20169 | ||
| 20176 | static TypeTableEntry *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstructionPtrType *instruction) { | 20170 | static TypeTableEntry *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstructionPtrType *instruction) { |
| 20171 | Error err; | ||
| 20177 | TypeTableEntry *child_type = ir_resolve_type(ira, instruction->child_type->other); | 20172 | TypeTableEntry *child_type = ir_resolve_type(ira, instruction->child_type->other); |
| 20178 | if (type_is_invalid(child_type)) | 20173 | if (type_is_invalid(child_type)) |
| 20179 | return ira->codegen->builtin_types.entry_invalid; | 20174 | return ira->codegen->builtin_types.entry_invalid; |
| ... | @@ -20191,8 +20186,7 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruc | ... | @@ -20191,8 +20186,7 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruc |
| 20191 | if (!ir_resolve_align(ira, instruction->align_value->other, &align_bytes)) | 20186 | if (!ir_resolve_align(ira, instruction->align_value->other, &align_bytes)) |
| 20192 | return ira->codegen->builtin_types.entry_invalid; | 20187 | return ira->codegen->builtin_types.entry_invalid; |
| 20193 | } else { | 20188 | } else { |
| 20194 | type_ensure_zero_bits_known(ira->codegen, child_type); | 20189 | if ((err = type_ensure_zero_bits_known(ira->codegen, child_type))) |
| 20195 | if (type_is_invalid(child_type)) | ||
| 20196 | return ira->codegen->builtin_types.entry_invalid; | 20190 | return ira->codegen->builtin_types.entry_invalid; |
| 20197 | align_bytes = get_abi_alignment(ira->codegen, child_type); | 20191 | align_bytes = get_abi_alignment(ira->codegen, child_type); |
| 20198 | } | 20192 | } |
| ... | @@ -20312,22 +20306,21 @@ static TypeTableEntry *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruc | ... | @@ -20312,22 +20306,21 @@ static TypeTableEntry *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruc |
| 20312 | } | 20306 | } |
| 20313 | 20307 | ||
| 20314 | static TypeTableEntry *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstructionTagType *instruction) { | 20308 | static TypeTableEntry *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstructionTagType *instruction) { |
| 20309 | Error err; | ||
| 20315 | IrInstruction *target_inst = instruction->target->other; | 20310 | IrInstruction *target_inst = instruction->target->other; |
| 20316 | TypeTableEntry *enum_type = ir_resolve_type(ira, target_inst); | 20311 | TypeTableEntry *enum_type = ir_resolve_type(ira, target_inst); |
| 20317 | if (type_is_invalid(enum_type)) | 20312 | if (type_is_invalid(enum_type)) |
| 20318 | return ira->codegen->builtin_types.entry_invalid; | 20313 | return ira->codegen->builtin_types.entry_invalid; |
| 20319 | 20314 | ||
| 20320 | if (enum_type->id == TypeTableEntryIdEnum) { | 20315 | if (enum_type->id == TypeTableEntryIdEnum) { |
| 20321 | ensure_complete_type(ira->codegen, enum_type); | 20316 | if ((err = ensure_complete_type(ira->codegen, enum_type))) |
| 20322 | if (type_is_invalid(enum_type)) | ||
| 20323 | return ira->codegen->builtin_types.entry_invalid; | 20317 | return ira->codegen->builtin_types.entry_invalid; |
| 20324 | 20318 | ||
| 20325 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | 20319 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 20326 | out_val->data.x_type = enum_type->data.enumeration.tag_int_type; | 20320 | out_val->data.x_type = enum_type->data.enumeration.tag_int_type; |
| 20327 | return ira->codegen->builtin_types.entry_type; | 20321 | return ira->codegen->builtin_types.entry_type; |
| 20328 | } else if (enum_type->id == TypeTableEntryIdUnion) { | 20322 | } else if (enum_type->id == TypeTableEntryIdUnion) { |
| 20329 | ensure_complete_type(ira->codegen, enum_type); | 20323 | if ((err = ensure_complete_type(ira->codegen, enum_type))) |
| 20330 | if (type_is_invalid(enum_type)) | ||
| 20331 | return ira->codegen->builtin_types.entry_invalid; | 20324 | return ira->codegen->builtin_types.entry_invalid; |
| 20332 | 20325 | ||
| 20333 | AstNode *decl_node = enum_type->data.unionation.decl_node; | 20326 | AstNode *decl_node = enum_type->data.unionation.decl_node; |
| ... | @@ -20830,6 +20823,7 @@ static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstruction | ... | @@ -20830,6 +20823,7 @@ static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstruction |
| 20830 | } | 20823 | } |
| 20831 | 20824 | ||
| 20832 | static TypeTableEntry *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) { | 20825 | static TypeTableEntry *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) { |
| 20826 | Error err; | ||
| 20833 | IrInstruction *target = instruction->target->other; | 20827 | IrInstruction *target = instruction->target->other; |
| 20834 | if (type_is_invalid(target->value.type)) | 20828 | if (type_is_invalid(target->value.type)) |
| 20835 | return ira->codegen->builtin_types.entry_invalid; | 20829 | return ira->codegen->builtin_types.entry_invalid; |
| ... | @@ -20840,8 +20834,7 @@ static TypeTableEntry *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInst | ... | @@ -20840,8 +20834,7 @@ static TypeTableEntry *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInst |
| 20840 | return ira->codegen->builtin_types.entry_invalid; | 20834 | return ira->codegen->builtin_types.entry_invalid; |
| 20841 | } | 20835 | } |
| 20842 | 20836 | ||
| 20843 | type_ensure_zero_bits_known(ira->codegen, target->value.type); | 20837 | if ((err = type_ensure_zero_bits_known(ira->codegen, target->value.type))) |
| 20844 | if (type_is_invalid(target->value.type)) | ||
| 20845 | return ira->codegen->builtin_types.entry_invalid; | 20838 | return ira->codegen->builtin_types.entry_invalid; |
| 20846 | 20839 | ||
| 20847 | TypeTableEntry *tag_type = target->value.type->data.enumeration.tag_int_type; | 20840 | TypeTableEntry *tag_type = target->value.type->data.enumeration.tag_int_type; |
| ... | @@ -20852,6 +20845,7 @@ static TypeTableEntry *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInst | ... | @@ -20852,6 +20845,7 @@ static TypeTableEntry *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInst |
| 20852 | } | 20845 | } |
| 20853 | 20846 | ||
| 20854 | static TypeTableEntry *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) { | 20847 | static TypeTableEntry *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) { |
| 20848 | Error err; | ||
| 20855 | IrInstruction *dest_type_value = instruction->dest_type->other; | 20849 | IrInstruction *dest_type_value = instruction->dest_type->other; |
| 20856 | TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value); | 20850 | TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value); |
| 20857 | if (type_is_invalid(dest_type)) | 20851 | if (type_is_invalid(dest_type)) |
| ... | @@ -20863,8 +20857,7 @@ static TypeTableEntry *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInst | ... | @@ -20863,8 +20857,7 @@ static TypeTableEntry *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInst |
| 20863 | return ira->codegen->builtin_types.entry_invalid; | 20857 | return ira->codegen->builtin_types.entry_invalid; |
| 20864 | } | 20858 | } |
| 20865 | 20859 | ||
| 20866 | type_ensure_zero_bits_known(ira->codegen, dest_type); | 20860 | if ((err = type_ensure_zero_bits_known(ira->codegen, dest_type))) |
| 20867 | if (type_is_invalid(dest_type)) | ||
| 20868 | return ira->codegen->builtin_types.entry_invalid; | 20861 | return ira->codegen->builtin_types.entry_invalid; |
| 20869 | 20862 | ||
| 20870 | TypeTableEntry *tag_type = dest_type->data.enumeration.tag_int_type; | 20863 | TypeTableEntry *tag_type = dest_type->data.enumeration.tag_int_type; |
src/result.hpp created+36| ... | @@ -0,0 +1,36 @@ | ||
| 1 | /* | ||
| 2 | * Copyright (c) 2018 Andrew Kelley | ||
| 3 | * | ||
| 4 | * This file is part of zig, which is MIT licensed. | ||
| 5 | * See http://opensource.org/licenses/MIT | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef ZIG_RESULT_HPP | ||
| 9 | #define ZIG_RESULT_HPP | ||
| 10 | |||
| 11 | #include "error.hpp" | ||
| 12 | |||
| 13 | #include <assert.h> | ||
| 14 | |||
| 15 | static inline void assertNoError(Error err) { | ||
| 16 | assert(err == ErrorNone); | ||
| 17 | } | ||
| 18 | |||
| 19 | template<typename T> | ||
| 20 | struct Result { | ||
| 21 | T data; | ||
| 22 | Error err; | ||
| 23 | |||
| 24 | Result(T x) : data(x), err(ErrorNone) {} | ||
| 25 | |||
| 26 | Result(Error err) : err(err) { | ||
| 27 | assert(err != ErrorNone); | ||
| 28 | } | ||
| 29 | |||
| 30 | T unwrap() { | ||
| 31 | assert(err == ErrorNone); | ||
| 32 | return data; | ||
| 33 | } | ||
| 34 | }; | ||
| 35 | |||
| 36 | #endif | ||
src/util.hpp+2| ... | @@ -21,6 +21,7 @@ | ... | @@ -21,6 +21,7 @@ |
| 21 | #define ATTRIBUTE_PRINTF(a, b) | 21 | #define ATTRIBUTE_PRINTF(a, b) |
| 22 | #define ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict) | 22 | #define ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict) |
| 23 | #define ATTRIBUTE_NORETURN __declspec(noreturn) | 23 | #define ATTRIBUTE_NORETURN __declspec(noreturn) |
| 24 | #define ATTRIBUTE_MUST_USE | ||
| 24 | 25 | ||
| 25 | #else | 26 | #else |
| 26 | 27 | ||
| ... | @@ -28,6 +29,7 @@ | ... | @@ -28,6 +29,7 @@ |
| 28 | #define ATTRIBUTE_PRINTF(a, b) __attribute__((format(printf, a, b))) | 29 | #define ATTRIBUTE_PRINTF(a, b) __attribute__((format(printf, a, b))) |
| 29 | #define ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__)) | 30 | #define ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__)) |
| 30 | #define ATTRIBUTE_NORETURN __attribute__((noreturn)) | 31 | #define ATTRIBUTE_NORETURN __attribute__((noreturn)) |
| 32 | #define ATTRIBUTE_MUST_USE __attribute__((warn_unused_result)) | ||
| 31 | 33 | ||
| 32 | #endif | 34 | #endif |
| 33 | 35 |
std/c/darwin.zig+12| ... | @@ -1,5 +1,8 @@ | ... | @@ -1,5 +1,8 @@ |
| 1 | const macho = @import("../macho.zig"); | ||
| 2 | |||
| 1 | extern "c" fn __error() *c_int; | 3 | extern "c" fn __error() *c_int; |
| 2 | pub extern "c" fn _NSGetExecutablePath(buf: [*]u8, bufsize: *u32) c_int; | 4 | pub extern "c" fn _NSGetExecutablePath(buf: [*]u8, bufsize: *u32) c_int; |
| 5 | pub extern "c" fn _dyld_get_image_header(image_index: u32) ?*mach_header; | ||
| 3 | 6 | ||
| 4 | pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize; | 7 | pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize; |
| 5 | 8 | ||
| ... | @@ -33,6 +36,15 @@ pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usi | ... | @@ -33,6 +36,15 @@ pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usi |
| 33 | pub extern "c" fn bind(socket: c_int, address: ?*const sockaddr, address_len: socklen_t) c_int; | 36 | pub extern "c" fn bind(socket: c_int, address: ?*const sockaddr, address_len: socklen_t) c_int; |
| 34 | pub extern "c" fn socket(domain: c_int, type: c_int, protocol: c_int) c_int; | 37 | pub extern "c" fn socket(domain: c_int, type: c_int, protocol: c_int) c_int; |
| 35 | 38 | ||
| 39 | /// The value of the link editor defined symbol _MH_EXECUTE_SYM is the address | ||
| 40 | /// of the mach header in a Mach-O executable file type. It does not appear in | ||
| 41 | /// any file type other than a MH_EXECUTE file type. The type of the symbol is | ||
| 42 | /// absolute as the header is not part of any section. | ||
| 43 | pub extern "c" var _mh_execute_header: if (@sizeOf(usize) == 8) mach_header_64 else mach_header; | ||
| 44 | |||
| 45 | pub const mach_header_64 = macho.mach_header_64; | ||
| 46 | pub const mach_header = macho.mach_header; | ||
| 47 | |||
| 36 | pub use @import("../os/darwin/errno.zig"); | 48 | pub use @import("../os/darwin/errno.zig"); |
| 37 | 49 | ||
| 38 | pub const _errno = __error; | 50 | pub const _errno = __error; |
std/c/linux.zig+3| ... | @@ -8,3 +8,6 @@ pub const pthread_attr_t = extern struct { | ... | @@ -8,3 +8,6 @@ pub const pthread_attr_t = extern struct { |
| 8 | __size: [56]u8, | 8 | __size: [56]u8, |
| 9 | __align: c_long, | 9 | __align: c_long, |
| 10 | }; | 10 | }; |
| 11 | |||
| 12 | /// See std.elf for constants for this | ||
| 13 | pub extern fn getauxval(__type: c_ulong) c_ulong; |
std/debug/index.zig+629-150| ... | @@ -4,8 +4,8 @@ const mem = std.mem; | ... | @@ -4,8 +4,8 @@ const mem = std.mem; |
| 4 | const io = std.io; | 4 | const io = std.io; |
| 5 | const os = std.os; | 5 | const os = std.os; |
| 6 | const elf = std.elf; | 6 | const elf = std.elf; |
| 7 | const DW = std.dwarf; | ||
| 8 | const macho = std.macho; | 7 | const macho = std.macho; |
| 8 | const DW = std.dwarf; | ||
| 9 | const ArrayList = std.ArrayList; | 9 | const ArrayList = std.ArrayList; |
| 10 | const builtin = @import("builtin"); | 10 | const builtin = @import("builtin"); |
| 11 | 11 | ||
| ... | @@ -19,9 +19,10 @@ pub const runtime_safety = switch (builtin.mode) { | ... | @@ -19,9 +19,10 @@ pub const runtime_safety = switch (builtin.mode) { |
| 19 | 19 | ||
| 20 | /// Tries to write to stderr, unbuffered, and ignores any error returned. | 20 | /// Tries to write to stderr, unbuffered, and ignores any error returned. |
| 21 | /// Does not append a newline. | 21 | /// Does not append a newline. |
| 22 | /// TODO atomic/multithread support | ||
| 23 | var stderr_file: os.File = undefined; | 22 | var stderr_file: os.File = undefined; |
| 24 | var stderr_file_out_stream: io.FileOutStream = undefined; | 23 | var stderr_file_out_stream: io.FileOutStream = undefined; |
| 24 | |||
| 25 | /// TODO multithreaded awareness | ||
| 25 | var stderr_stream: ?*io.OutStream(io.FileOutStream.Error) = null; | 26 | var stderr_stream: ?*io.OutStream(io.FileOutStream.Error) = null; |
| 26 | var stderr_mutex = std.Mutex.init(); | 27 | var stderr_mutex = std.Mutex.init(); |
| 27 | pub fn warn(comptime fmt: []const u8, args: ...) void { | 28 | pub fn warn(comptime fmt: []const u8, args: ...) void { |
| ... | @@ -30,6 +31,7 @@ pub fn warn(comptime fmt: []const u8, args: ...) void { | ... | @@ -30,6 +31,7 @@ pub fn warn(comptime fmt: []const u8, args: ...) void { |
| 30 | const stderr = getStderrStream() catch return; | 31 | const stderr = getStderrStream() catch return; |
| 31 | stderr.print(fmt, args) catch return; | 32 | stderr.print(fmt, args) catch return; |
| 32 | } | 33 | } |
| 34 | |||
| 33 | pub fn getStderrStream() !*io.OutStream(io.FileOutStream.Error) { | 35 | pub fn getStderrStream() !*io.OutStream(io.FileOutStream.Error) { |
| 34 | if (stderr_stream) |st| { | 36 | if (stderr_stream) |st| { |
| 35 | return st; | 37 | return st; |
| ... | @@ -42,14 +44,15 @@ pub fn getStderrStream() !*io.OutStream(io.FileOutStream.Error) { | ... | @@ -42,14 +44,15 @@ pub fn getStderrStream() !*io.OutStream(io.FileOutStream.Error) { |
| 42 | } | 44 | } |
| 43 | } | 45 | } |
| 44 | 46 | ||
| 45 | var self_debug_info: ?*ElfStackTrace = null; | 47 | /// TODO multithreaded awareness |
| 46 | pub fn getSelfDebugInfo() !*ElfStackTrace { | 48 | var self_debug_info: ?DebugInfo = null; |
| 47 | if (self_debug_info) |info| { | 49 | |
| 50 | pub fn getSelfDebugInfo() !*DebugInfo { | ||
| 51 | if (self_debug_info) |*info| { | ||
| 48 | return info; | 52 | return info; |
| 49 | } else { | 53 | } else { |
| 50 | const info = try openSelfDebugInfo(getDebugInfoAllocator()); | 54 | self_debug_info = try openSelfDebugInfo(getDebugInfoAllocator()); |
| 51 | self_debug_info = info; | 55 | return &self_debug_info.?; |
| 52 | return info; | ||
| 53 | } | 56 | } |
| 54 | } | 57 | } |
| 55 | 58 | ||
| ... | @@ -60,6 +63,7 @@ fn wantTtyColor() bool { | ... | @@ -60,6 +63,7 @@ fn wantTtyColor() bool { |
| 60 | } | 63 | } |
| 61 | 64 | ||
| 62 | /// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned. | 65 | /// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned. |
| 66 | /// TODO multithreaded awareness | ||
| 63 | pub fn dumpCurrentStackTrace(start_addr: ?usize) void { | 67 | pub fn dumpCurrentStackTrace(start_addr: ?usize) void { |
| 64 | const stderr = getStderrStream() catch return; | 68 | const stderr = getStderrStream() catch return; |
| 65 | const debug_info = getSelfDebugInfo() catch |err| { | 69 | const debug_info = getSelfDebugInfo() catch |err| { |
| ... | @@ -73,6 +77,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { | ... | @@ -73,6 +77,7 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { |
| 73 | } | 77 | } |
| 74 | 78 | ||
| 75 | /// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned. | 79 | /// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned. |
| 80 | /// TODO multithreaded awareness | ||
| 76 | pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void { | 81 | pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void { |
| 77 | const stderr = getStderrStream() catch return; | 82 | const stderr = getStderrStream() catch return; |
| 78 | const debug_info = getSelfDebugInfo() catch |err| { | 83 | const debug_info = getSelfDebugInfo() catch |err| { |
| ... | @@ -127,6 +132,7 @@ pub fn panic(comptime format: []const u8, args: ...) noreturn { | ... | @@ -127,6 +132,7 @@ pub fn panic(comptime format: []const u8, args: ...) noreturn { |
| 127 | panicExtra(null, first_trace_addr, format, args); | 132 | panicExtra(null, first_trace_addr, format, args); |
| 128 | } | 133 | } |
| 129 | 134 | ||
| 135 | /// TODO multithreaded awareness | ||
| 130 | var panicking: u8 = 0; // TODO make this a bool | 136 | var panicking: u8 = 0; // TODO make this a bool |
| 131 | 137 | ||
| 132 | pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: ...) noreturn { | 138 | pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: ...) noreturn { |
| ... | @@ -155,7 +161,7 @@ const WHITE = "\x1b[37;1m"; | ... | @@ -155,7 +161,7 @@ const WHITE = "\x1b[37;1m"; |
| 155 | const DIM = "\x1b[2m"; | 161 | const DIM = "\x1b[2m"; |
| 156 | const RESET = "\x1b[0m"; | 162 | const RESET = "\x1b[0m"; |
| 157 | 163 | ||
| 158 | pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var, allocator: *mem.Allocator, debug_info: *ElfStackTrace, tty_color: bool) !void { | 164 | pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, tty_color: bool) !void { |
| 159 | var frame_index: usize = undefined; | 165 | var frame_index: usize = undefined; |
| 160 | var frames_left: usize = undefined; | 166 | var frames_left: usize = undefined; |
| 161 | if (stack_trace.index < stack_trace.instruction_addresses.len) { | 167 | if (stack_trace.index < stack_trace.instruction_addresses.len) { |
| ... | @@ -185,7 +191,7 @@ pub inline fn getReturnAddress(frame_count: usize) usize { | ... | @@ -185,7 +191,7 @@ pub inline fn getReturnAddress(frame_count: usize) usize { |
| 185 | return @intToPtr(*const usize, fp + @sizeOf(usize)).*; | 191 | return @intToPtr(*const usize, fp + @sizeOf(usize)).*; |
| 186 | } | 192 | } |
| 187 | 193 | ||
| 188 | pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_info: *ElfStackTrace, tty_color: bool, start_addr: ?usize) !void { | 194 | pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void { |
| 189 | const AddressState = union(enum) { | 195 | const AddressState = union(enum) { |
| 190 | NotLookingForStartAddress, | 196 | NotLookingForStartAddress, |
| 191 | LookingForStartAddress: usize, | 197 | LookingForStartAddress: usize, |
| ... | @@ -218,128 +224,290 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_ | ... | @@ -218,128 +224,290 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: *mem.Allocator, debug_ |
| 218 | } | 224 | } |
| 219 | } | 225 | } |
| 220 | 226 | ||
| 221 | pub fn printSourceAtAddress(debug_info: *ElfStackTrace, out_stream: var, address: usize, tty_color: bool) !void { | 227 | pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { |
| 222 | switch (builtin.os) { | 228 | switch (builtin.os) { |
| 223 | builtin.Os.windows => return error.UnsupportedDebugInfo, | 229 | builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color), |
| 224 | builtin.Os.macosx => { | 230 | builtin.Os.linux => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color), |
| 225 | // TODO(bnoordhuis) It's theoretically possible to obtain the | 231 | builtin.Os.windows => { |
| 226 | // compilation unit from the symbtab but it's not that useful | 232 | // TODO https://github.com/ziglang/zig/issues/721 |
| 227 | // in practice because the compiler dumps everything in a single | 233 | return error.UnsupportedOperatingSystem; |
| 228 | // object file. Future improvement: use external dSYM data when | ||
| 229 | // available. | ||
| 230 | const unknown = macho.Symbol{ | ||
| 231 | .name = "???", | ||
| 232 | .address = address, | ||
| 233 | }; | ||
| 234 | const symbol = debug_info.symbol_table.search(address) orelse &unknown; | ||
| 235 | try out_stream.print(WHITE ++ "{}" ++ RESET ++ ": " ++ DIM ++ "0x{x}" ++ " in ??? (???)" ++ RESET ++ "\n", symbol.name, address); | ||
| 236 | }, | 234 | }, |
| 237 | else => { | 235 | else => return error.UnsupportedOperatingSystem, |
| 238 | const compile_unit = findCompileUnit(debug_info, address) catch { | 236 | } |
| 239 | if (tty_color) { | 237 | } |
| 240 | try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n ???\n\n", address); | 238 | |
| 241 | } else { | 239 | fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol { |
| 242 | try out_stream.print("???:?:?: 0x{x} in ??? (???)\n ???\n\n", address); | 240 | var min: usize = 0; |
| 243 | } | 241 | var max: usize = symbols.len - 1; // Exclude sentinel. |
| 244 | return; | 242 | while (min < max) { |
| 245 | }; | 243 | const mid = min + (max - min) / 2; |
| 246 | const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name); | 244 | const curr = &symbols[mid]; |
| 247 | if (getLineNumberInfo(debug_info, compile_unit, address - 1)) |line_info| { | 245 | const next = &symbols[mid + 1]; |
| 248 | defer line_info.deinit(); | 246 | if (address >= next.address()) { |
| 249 | if (tty_color) { | 247 | min = mid + 1; |
| 250 | try out_stream.print( | 248 | } else if (address < curr.address()) { |
| 251 | WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++ DIM ++ "0x{x} in ??? ({})" ++ RESET ++ "\n", | 249 | max = mid; |
| 252 | line_info.file_name, | 250 | } else { |
| 253 | line_info.line, | 251 | return curr; |
| 254 | line_info.column, | 252 | } |
| 255 | address, | 253 | } |
| 256 | compile_unit_name, | 254 | return null; |
| 257 | ); | 255 | } |
| 258 | if (printLineFromFile(out_stream, line_info)) { | 256 | |
| 259 | if (line_info.column == 0) { | 257 | fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { |
| 260 | try out_stream.write("\n"); | 258 | const base_addr = @ptrToInt(&std.c._mh_execute_header); |
| 261 | } else { | 259 | const adjusted_addr = 0x100000000 + (address - base_addr); |
| 262 | { | 260 | |
| 263 | var col_i: usize = 1; | 261 | const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse { |
| 264 | while (col_i < line_info.column) : (col_i += 1) { | 262 | if (tty_color) { |
| 265 | try out_stream.writeByte(' '); | 263 | try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address); |
| 266 | } | 264 | } else { |
| 267 | } | 265 | try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", address); |
| 268 | try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n"); | 266 | } |
| 269 | } | 267 | return; |
| 270 | } else |err| switch (err) { | 268 | }; |
| 271 | error.EndOfFile => {}, | 269 | |
| 272 | else => return err, | 270 | const symbol_name = mem.toSliceConst(u8, di.strings.ptr + symbol.nlist.n_strx); |
| 273 | } | 271 | const compile_unit_name = if (symbol.ofile) |ofile| blk: { |
| 274 | } else { | 272 | const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx); |
| 275 | try out_stream.print( | 273 | break :blk os.path.basename(ofile_path); |
| 276 | "{}:{}:{}: 0x{x} in ??? ({})\n", | 274 | } else "???"; |
| 277 | line_info.file_name, | 275 | if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| { |
| 278 | line_info.line, | 276 | defer line_info.deinit(); |
| 279 | line_info.column, | 277 | try printLineInfo(di, out_stream, line_info, address, symbol_name, compile_unit_name, tty_color); |
| 280 | address, | 278 | } else |err| switch (err) { |
| 281 | compile_unit_name, | 279 | error.MissingDebugInfo, error.InvalidDebugInfo => { |
| 282 | ); | 280 | if (tty_color) { |
| 283 | } | 281 | try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in {} ({})" ++ RESET ++ "\n\n\n", address, symbol_name, compile_unit_name); |
| 284 | } else |err| switch (err) { | 282 | } else { |
| 285 | error.MissingDebugInfo, error.InvalidDebugInfo => { | 283 | try out_stream.print("???:?:?: 0x{x} in {} ({})\n\n\n", address, symbol_name, compile_unit_name); |
| 286 | try out_stream.print("0x{x} in ??? ({})\n", address, compile_unit_name); | ||
| 287 | }, | ||
| 288 | else => return err, | ||
| 289 | } | 284 | } |
| 290 | }, | 285 | }, |
| 286 | else => return err, | ||
| 291 | } | 287 | } |
| 292 | } | 288 | } |
| 293 | 289 | ||
| 294 | pub fn openSelfDebugInfo(allocator: *mem.Allocator) !*ElfStackTrace { | 290 | pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { |
| 295 | switch (builtin.object_format) { | 291 | const compile_unit = findCompileUnit(debug_info, address) catch { |
| 296 | builtin.ObjectFormat.elf => { | 292 | if (tty_color) { |
| 297 | const st = try allocator.create(ElfStackTrace{ | 293 | try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address); |
| 298 | .self_exe_file = undefined, | 294 | } else { |
| 299 | .elf = undefined, | 295 | try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", address); |
| 300 | .debug_info = undefined, | 296 | } |
| 301 | .debug_abbrev = undefined, | 297 | return; |
| 302 | .debug_str = undefined, | 298 | }; |
| 303 | .debug_line = undefined, | 299 | const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name); |
| 304 | .debug_ranges = null, | 300 | if (getLineNumberInfoLinux(debug_info, compile_unit, address - 1)) |line_info| { |
| 305 | .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator), | 301 | defer line_info.deinit(); |
| 306 | .compile_unit_list = ArrayList(CompileUnit).init(allocator), | 302 | const symbol_name = "???"; |
| 307 | }); | 303 | try printLineInfo(debug_info, out_stream, line_info, address, symbol_name, compile_unit_name, tty_color); |
| 308 | errdefer allocator.destroy(st); | 304 | } else |err| switch (err) { |
| 309 | st.self_exe_file = try os.openSelfExe(); | 305 | error.MissingDebugInfo, error.InvalidDebugInfo => { |
| 310 | errdefer st.self_exe_file.close(); | 306 | if (tty_color) { |
| 311 | 307 | try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? ({})" ++ RESET ++ "\n\n\n", address, compile_unit_name); | |
| 312 | try st.elf.openFile(allocator, &st.self_exe_file); | 308 | } else { |
| 313 | errdefer st.elf.close(); | 309 | try out_stream.print("???:?:?: 0x{x} in ??? ({})\n\n\n", address, compile_unit_name); |
| 314 | 310 | } | |
| 315 | st.debug_info = (try st.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo; | ||
| 316 | st.debug_abbrev = (try st.elf.findSection(".debug_abbrev")) orelse return error.MissingDebugInfo; | ||
| 317 | st.debug_str = (try st.elf.findSection(".debug_str")) orelse return error.MissingDebugInfo; | ||
| 318 | st.debug_line = (try st.elf.findSection(".debug_line")) orelse return error.MissingDebugInfo; | ||
| 319 | st.debug_ranges = (try st.elf.findSection(".debug_ranges")); | ||
| 320 | try scanAllCompileUnits(st); | ||
| 321 | return st; | ||
| 322 | }, | 311 | }, |
| 323 | builtin.ObjectFormat.macho => { | 312 | else => return err, |
| 324 | var exe_file = try os.openSelfExe(); | 313 | } |
| 325 | defer exe_file.close(); | 314 | } |
| 326 | 315 | ||
| 327 | const st = try allocator.create(ElfStackTrace{ .symbol_table = try macho.loadSymbols(allocator, &io.FileInStream.init(&exe_file)) }); | 316 | fn printLineInfo( |
| 328 | errdefer allocator.destroy(st); | 317 | debug_info: *DebugInfo, |
| 329 | return st; | 318 | out_stream: var, |
| 330 | }, | 319 | line_info: LineInfo, |
| 331 | builtin.ObjectFormat.coff => { | 320 | address: usize, |
| 332 | return error.TodoSupportCoffDebugInfo; | 321 | symbol_name: []const u8, |
| 333 | }, | 322 | compile_unit_name: []const u8, |
| 334 | builtin.ObjectFormat.wasm => { | 323 | tty_color: bool, |
| 335 | return error.TodoSupportCOFFDebugInfo; | 324 | ) !void { |
| 336 | }, | 325 | if (tty_color) { |
| 337 | builtin.ObjectFormat.unknown => { | 326 | try out_stream.print( |
| 338 | return error.UnknownObjectFormat; | 327 | WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++ DIM ++ "0x{x} in {} ({})" ++ RESET ++ "\n", |
| 328 | line_info.file_name, | ||
| 329 | line_info.line, | ||
| 330 | line_info.column, | ||
| 331 | address, | ||
| 332 | symbol_name, | ||
| 333 | compile_unit_name, | ||
| 334 | ); | ||
| 335 | if (printLineFromFile(out_stream, line_info)) { | ||
| 336 | if (line_info.column == 0) { | ||
| 337 | try out_stream.write("\n"); | ||
| 338 | } else { | ||
| 339 | { | ||
| 340 | var col_i: usize = 1; | ||
| 341 | while (col_i < line_info.column) : (col_i += 1) { | ||
| 342 | try out_stream.writeByte(' '); | ||
| 343 | } | ||
| 344 | } | ||
| 345 | try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n"); | ||
| 346 | } | ||
| 347 | } else |err| switch (err) { | ||
| 348 | error.EndOfFile => {}, | ||
| 349 | else => return err, | ||
| 350 | } | ||
| 351 | } else { | ||
| 352 | try out_stream.print( | ||
| 353 | "{}:{}:{}: 0x{x} in {} ({})\n", | ||
| 354 | line_info.file_name, | ||
| 355 | line_info.line, | ||
| 356 | line_info.column, | ||
| 357 | address, | ||
| 358 | symbol_name, | ||
| 359 | compile_unit_name, | ||
| 360 | ); | ||
| 361 | } | ||
| 362 | } | ||
| 363 | |||
| 364 | // TODO use this | ||
| 365 | pub const OpenSelfDebugInfoError = error{ | ||
| 366 | MissingDebugInfo, | ||
| 367 | OutOfMemory, | ||
| 368 | UnsupportedOperatingSystem, | ||
| 369 | }; | ||
| 370 | |||
| 371 | pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo { | ||
| 372 | switch (builtin.os) { | ||
| 373 | builtin.Os.linux => return openSelfDebugInfoLinux(allocator), | ||
| 374 | builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator), | ||
| 375 | builtin.Os.windows => { | ||
| 376 | // TODO: https://github.com/ziglang/zig/issues/721 | ||
| 377 | return error.UnsupportedOperatingSystem; | ||
| 339 | }, | 378 | }, |
| 379 | else => return error.UnsupportedOperatingSystem, | ||
| 340 | } | 380 | } |
| 341 | } | 381 | } |
| 342 | 382 | ||
| 383 | fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo { | ||
| 384 | var di = DebugInfo{ | ||
| 385 | .self_exe_file = undefined, | ||
| 386 | .elf = undefined, | ||
| 387 | .debug_info = undefined, | ||
| 388 | .debug_abbrev = undefined, | ||
| 389 | .debug_str = undefined, | ||
| 390 | .debug_line = undefined, | ||
| 391 | .debug_ranges = null, | ||
| 392 | .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator), | ||
| 393 | .compile_unit_list = ArrayList(CompileUnit).init(allocator), | ||
| 394 | }; | ||
| 395 | di.self_exe_file = try os.openSelfExe(); | ||
| 396 | errdefer di.self_exe_file.close(); | ||
| 397 | |||
| 398 | try di.elf.openFile(allocator, &di.self_exe_file); | ||
| 399 | errdefer di.elf.close(); | ||
| 400 | |||
| 401 | di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo; | ||
| 402 | di.debug_abbrev = (try di.elf.findSection(".debug_abbrev")) orelse return error.MissingDebugInfo; | ||
| 403 | di.debug_str = (try di.elf.findSection(".debug_str")) orelse return error.MissingDebugInfo; | ||
| 404 | di.debug_line = (try di.elf.findSection(".debug_line")) orelse return error.MissingDebugInfo; | ||
| 405 | di.debug_ranges = (try di.elf.findSection(".debug_ranges")); | ||
| 406 | try scanAllCompileUnits(&di); | ||
| 407 | return di; | ||
| 408 | } | ||
| 409 | |||
| 410 | pub fn findElfSection(elf: *Elf, name: []const u8) ?*elf.Shdr { | ||
| 411 | var file_stream = io.FileInStream.init(elf.in_file); | ||
| 412 | const in = &file_stream.stream; | ||
| 413 | |||
| 414 | section_loop: for (elf.section_headers) |*elf_section| { | ||
| 415 | if (elf_section.sh_type == SHT_NULL) continue; | ||
| 416 | |||
| 417 | const name_offset = elf.string_section.offset + elf_section.name; | ||
| 418 | try elf.in_file.seekTo(name_offset); | ||
| 419 | |||
| 420 | for (name) |expected_c| { | ||
| 421 | const target_c = try in.readByte(); | ||
| 422 | if (target_c == 0 or expected_c != target_c) continue :section_loop; | ||
| 423 | } | ||
| 424 | |||
| 425 | { | ||
| 426 | const null_byte = try in.readByte(); | ||
| 427 | if (null_byte == 0) return elf_section; | ||
| 428 | } | ||
| 429 | } | ||
| 430 | |||
| 431 | return null; | ||
| 432 | } | ||
| 433 | |||
| 434 | fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { | ||
| 435 | const hdr = &std.c._mh_execute_header; | ||
| 436 | assert(hdr.magic == std.macho.MH_MAGIC_64); | ||
| 437 | |||
| 438 | const hdr_base = @ptrCast([*]u8, hdr); | ||
| 439 | var ptr = hdr_base + @sizeOf(macho.mach_header_64); | ||
| 440 | var ncmd: u32 = hdr.ncmds; | ||
| 441 | const symtab = while (ncmd != 0) : (ncmd -= 1) { | ||
| 442 | const lc = @ptrCast(*std.macho.load_command, ptr); | ||
| 443 | switch (lc.cmd) { | ||
| 444 | std.macho.LC_SYMTAB => break @ptrCast(*std.macho.symtab_command, ptr), | ||
| 445 | else => {}, | ||
| 446 | } | ||
| 447 | ptr += lc.cmdsize; // TODO https://github.com/ziglang/zig/issues/1403 | ||
| 448 | } else { | ||
| 449 | return error.MissingDebugInfo; | ||
| 450 | }; | ||
| 451 | const syms = @ptrCast([*]macho.nlist_64, hdr_base + symtab.symoff)[0..symtab.nsyms]; | ||
| 452 | const strings = @ptrCast([*]u8, hdr_base + symtab.stroff)[0..symtab.strsize]; | ||
| 453 | |||
| 454 | const symbols_buf = try allocator.alloc(MachoSymbol, syms.len); | ||
| 455 | |||
| 456 | var ofile: ?*macho.nlist_64 = null; | ||
| 457 | var reloc: u64 = 0; | ||
| 458 | var symbol_index: usize = 0; | ||
| 459 | var last_len: u64 = 0; | ||
| 460 | for (syms) |*sym| { | ||
| 461 | if (sym.n_type & std.macho.N_STAB != 0) { | ||
| 462 | switch (sym.n_type) { | ||
| 463 | std.macho.N_OSO => { | ||
| 464 | ofile = sym; | ||
| 465 | reloc = 0; | ||
| 466 | }, | ||
| 467 | std.macho.N_FUN => { | ||
| 468 | if (sym.n_sect == 0) { | ||
| 469 | last_len = sym.n_value; | ||
| 470 | } else { | ||
| 471 | symbols_buf[symbol_index] = MachoSymbol{ | ||
| 472 | .nlist = sym, | ||
| 473 | .ofile = ofile, | ||
| 474 | .reloc = reloc, | ||
| 475 | }; | ||
| 476 | symbol_index += 1; | ||
| 477 | } | ||
| 478 | }, | ||
| 479 | std.macho.N_BNSYM => { | ||
| 480 | if (reloc == 0) { | ||
| 481 | reloc = sym.n_value; | ||
| 482 | } | ||
| 483 | }, | ||
| 484 | else => continue, | ||
| 485 | } | ||
| 486 | } | ||
| 487 | } | ||
| 488 | const sentinel = try allocator.createOne(macho.nlist_64); | ||
| 489 | sentinel.* = macho.nlist_64{ | ||
| 490 | .n_strx = 0, | ||
| 491 | .n_type = 36, | ||
| 492 | .n_sect = 0, | ||
| 493 | .n_desc = 0, | ||
| 494 | .n_value = symbols_buf[symbol_index - 1].nlist.n_value + last_len, | ||
| 495 | }; | ||
| 496 | |||
| 497 | const symbols = allocator.shrink(MachoSymbol, symbols_buf, symbol_index); | ||
| 498 | |||
| 499 | // Even though lld emits symbols in ascending order, this debug code | ||
| 500 | // should work for programs linked in any valid way. | ||
| 501 | // This sort is so that we can binary search later. | ||
| 502 | std.sort.sort(MachoSymbol, symbols, MachoSymbol.addressLessThan); | ||
| 503 | |||
| 504 | return DebugInfo{ | ||
| 505 | .ofiles = DebugInfo.OFileTable.init(allocator), | ||
| 506 | .symbols = symbols, | ||
| 507 | .strings = strings, | ||
| 508 | }; | ||
| 509 | } | ||
| 510 | |||
| 343 | fn printLineFromFile(out_stream: var, line_info: *const LineInfo) !void { | 511 | fn printLineFromFile(out_stream: var, line_info: *const LineInfo) !void { |
| 344 | var f = try os.File.openRead(line_info.file_name); | 512 | var f = try os.File.openRead(line_info.file_name); |
| 345 | defer f.close(); | 513 | defer f.close(); |
| ... | @@ -372,12 +540,42 @@ fn printLineFromFile(out_stream: var, line_info: *const LineInfo) !void { | ... | @@ -372,12 +540,42 @@ fn printLineFromFile(out_stream: var, line_info: *const LineInfo) !void { |
| 372 | } | 540 | } |
| 373 | } | 541 | } |
| 374 | 542 | ||
| 375 | pub const ElfStackTrace = switch (builtin.os) { | 543 | const MachoSymbol = struct { |
| 376 | builtin.Os.macosx => struct { | 544 | nlist: *macho.nlist_64, |
| 377 | symbol_table: macho.SymbolTable, | 545 | ofile: ?*macho.nlist_64, |
| 546 | reloc: u64, | ||
| 547 | |||
| 548 | /// Returns the address from the macho file | ||
| 549 | fn address(self: MachoSymbol) u64 { | ||
| 550 | return self.nlist.n_value; | ||
| 551 | } | ||
| 552 | |||
| 553 | fn addressLessThan(lhs: MachoSymbol, rhs: MachoSymbol) bool { | ||
| 554 | return lhs.address() < rhs.address(); | ||
| 555 | } | ||
| 556 | }; | ||
| 557 | |||
| 558 | const MachOFile = struct { | ||
| 559 | bytes: []align(@alignOf(macho.mach_header_64)) const u8, | ||
| 560 | sect_debug_info: ?*const macho.section_64, | ||
| 561 | sect_debug_line: ?*const macho.section_64, | ||
| 562 | }; | ||
| 378 | 563 | ||
| 379 | pub fn close(self: *ElfStackTrace) void { | 564 | pub const DebugInfo = switch (builtin.os) { |
| 380 | self.symbol_table.deinit(); | 565 | builtin.Os.macosx => struct { |
| 566 | symbols: []const MachoSymbol, | ||
| 567 | strings: []const u8, | ||
| 568 | ofiles: OFileTable, | ||
| 569 | |||
| 570 | const OFileTable = std.HashMap( | ||
| 571 | *macho.nlist_64, | ||
| 572 | MachOFile, | ||
| 573 | std.hash_map.getHashPtrAddrFn(*macho.nlist_64), | ||
| 574 | std.hash_map.getTrivialEqlFn(*macho.nlist_64), | ||
| 575 | ); | ||
| 576 | |||
| 577 | pub fn allocator(self: DebugInfo) *mem.Allocator { | ||
| 578 | return self.ofiles.allocator; | ||
| 381 | } | 579 | } |
| 382 | }, | 580 | }, |
| 383 | else => struct { | 581 | else => struct { |
| ... | @@ -391,17 +589,17 @@ pub const ElfStackTrace = switch (builtin.os) { | ... | @@ -391,17 +589,17 @@ pub const ElfStackTrace = switch (builtin.os) { |
| 391 | abbrev_table_list: ArrayList(AbbrevTableHeader), | 589 | abbrev_table_list: ArrayList(AbbrevTableHeader), |
| 392 | compile_unit_list: ArrayList(CompileUnit), | 590 | compile_unit_list: ArrayList(CompileUnit), |
| 393 | 591 | ||
| 394 | pub fn allocator(self: *const ElfStackTrace) *mem.Allocator { | 592 | pub fn allocator(self: DebugInfo) *mem.Allocator { |
| 395 | return self.abbrev_table_list.allocator; | 593 | return self.abbrev_table_list.allocator; |
| 396 | } | 594 | } |
| 397 | 595 | ||
| 398 | pub fn readString(self: *ElfStackTrace) ![]u8 { | 596 | pub fn readString(self: *DebugInfo) ![]u8 { |
| 399 | var in_file_stream = io.FileInStream.init(&self.self_exe_file); | 597 | var in_file_stream = io.FileInStream.init(&self.self_exe_file); |
| 400 | const in_stream = &in_file_stream.stream; | 598 | const in_stream = &in_file_stream.stream; |
| 401 | return readStringRaw(self.allocator(), in_stream); | 599 | return readStringRaw(self.allocator(), in_stream); |
| 402 | } | 600 | } |
| 403 | 601 | ||
| 404 | pub fn close(self: *ElfStackTrace) void { | 602 | pub fn close(self: *DebugInfo) void { |
| 405 | self.self_exe_file.close(); | 603 | self.self_exe_file.close(); |
| 406 | self.elf.close(); | 604 | self.elf.close(); |
| 407 | } | 605 | } |
| ... | @@ -508,7 +706,7 @@ const Die = struct { | ... | @@ -508,7 +706,7 @@ const Die = struct { |
| 508 | }; | 706 | }; |
| 509 | } | 707 | } |
| 510 | 708 | ||
| 511 | fn getAttrString(self: *const Die, st: *ElfStackTrace, id: u64) ![]u8 { | 709 | fn getAttrString(self: *const Die, st: *DebugInfo, id: u64) ![]u8 { |
| 512 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; | 710 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; |
| 513 | return switch (form_value.*) { | 711 | return switch (form_value.*) { |
| 514 | FormValue.String => |value| value, | 712 | FormValue.String => |value| value, |
| ... | @@ -623,7 +821,7 @@ fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 { | ... | @@ -623,7 +821,7 @@ fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 { |
| 623 | return buf.toSlice(); | 821 | return buf.toSlice(); |
| 624 | } | 822 | } |
| 625 | 823 | ||
| 626 | fn getString(st: *ElfStackTrace, offset: u64) ![]u8 { | 824 | fn getString(st: *DebugInfo, offset: u64) ![]u8 { |
| 627 | const pos = st.debug_str.offset + offset; | 825 | const pos = st.debug_str.offset + offset; |
| 628 | try st.self_exe_file.seekTo(pos); | 826 | try st.self_exe_file.seekTo(pos); |
| 629 | return st.readString(); | 827 | return st.readString(); |
| ... | @@ -730,7 +928,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 | ... | @@ -730,7 +928,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 |
| 730 | }; | 928 | }; |
| 731 | } | 929 | } |
| 732 | 930 | ||
| 733 | fn parseAbbrevTable(st: *ElfStackTrace) !AbbrevTable { | 931 | fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable { |
| 734 | const in_file = &st.self_exe_file; | 932 | const in_file = &st.self_exe_file; |
| 735 | var in_file_stream = io.FileInStream.init(in_file); | 933 | var in_file_stream = io.FileInStream.init(in_file); |
| 736 | const in_stream = &in_file_stream.stream; | 934 | const in_stream = &in_file_stream.stream; |
| ... | @@ -760,7 +958,7 @@ fn parseAbbrevTable(st: *ElfStackTrace) !AbbrevTable { | ... | @@ -760,7 +958,7 @@ fn parseAbbrevTable(st: *ElfStackTrace) !AbbrevTable { |
| 760 | 958 | ||
| 761 | /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found, | 959 | /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found, |
| 762 | /// seeks in the stream and parses it. | 960 | /// seeks in the stream and parses it. |
| 763 | fn getAbbrevTable(st: *ElfStackTrace, abbrev_offset: u64) !*const AbbrevTable { | 961 | fn getAbbrevTable(st: *DebugInfo, abbrev_offset: u64) !*const AbbrevTable { |
| 764 | for (st.abbrev_table_list.toSlice()) |*header| { | 962 | for (st.abbrev_table_list.toSlice()) |*header| { |
| 765 | if (header.offset == abbrev_offset) { | 963 | if (header.offset == abbrev_offset) { |
| 766 | return &header.table; | 964 | return &header.table; |
| ... | @@ -781,7 +979,7 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con | ... | @@ -781,7 +979,7 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con |
| 781 | return null; | 979 | return null; |
| 782 | } | 980 | } |
| 783 | 981 | ||
| 784 | fn parseDie(st: *ElfStackTrace, abbrev_table: *const AbbrevTable, is_64: bool) !Die { | 982 | fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die { |
| 785 | const in_file = &st.self_exe_file; | 983 | const in_file = &st.self_exe_file; |
| 786 | var in_file_stream = io.FileInStream.init(in_file); | 984 | var in_file_stream = io.FileInStream.init(in_file); |
| 787 | const in_stream = &in_file_stream.stream; | 985 | const in_stream = &in_file_stream.stream; |
| ... | @@ -803,12 +1001,210 @@ fn parseDie(st: *ElfStackTrace, abbrev_table: *const AbbrevTable, is_64: bool) ! | ... | @@ -803,12 +1001,210 @@ fn parseDie(st: *ElfStackTrace, abbrev_table: *const AbbrevTable, is_64: bool) ! |
| 803 | return result; | 1001 | return result; |
| 804 | } | 1002 | } |
| 805 | 1003 | ||
| 806 | fn getLineNumberInfo(st: *ElfStackTrace, compile_unit: *const CompileUnit, target_address: usize) !LineInfo { | 1004 | fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: usize) !LineInfo { |
| 807 | const compile_unit_cwd = try compile_unit.die.getAttrString(st, DW.AT_comp_dir); | 1005 | const ofile = symbol.ofile orelse return error.MissingDebugInfo; |
| 1006 | const gop = try di.ofiles.getOrPut(ofile); | ||
| 1007 | const mach_o_file = if (gop.found_existing) &gop.kv.value else blk: { | ||
| 1008 | errdefer _ = di.ofiles.remove(ofile); | ||
| 1009 | const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx); | ||
| 1010 | |||
| 1011 | gop.kv.value = MachOFile{ | ||
| 1012 | .bytes = try std.io.readFileAllocAligned(di.ofiles.allocator, ofile_path, @alignOf(macho.mach_header_64)), | ||
| 1013 | .sect_debug_info = null, | ||
| 1014 | .sect_debug_line = null, | ||
| 1015 | }; | ||
| 1016 | const hdr = @ptrCast(*const macho.mach_header_64, gop.kv.value.bytes.ptr); | ||
| 1017 | if (hdr.magic != std.macho.MH_MAGIC_64) return error.InvalidDebugInfo; | ||
| 1018 | |||
| 1019 | const hdr_base = @ptrCast([*]const u8, hdr); | ||
| 1020 | var ptr = hdr_base + @sizeOf(macho.mach_header_64); | ||
| 1021 | var ncmd: u32 = hdr.ncmds; | ||
| 1022 | const segcmd = while (ncmd != 0) : (ncmd -= 1) { | ||
| 1023 | const lc = @ptrCast(*const std.macho.load_command, ptr); | ||
| 1024 | switch (lc.cmd) { | ||
| 1025 | std.macho.LC_SEGMENT_64 => break @ptrCast(*const std.macho.segment_command_64, ptr), | ||
| 1026 | else => {}, | ||
| 1027 | } | ||
| 1028 | ptr += lc.cmdsize; // TODO https://github.com/ziglang/zig/issues/1403 | ||
| 1029 | } else { | ||
| 1030 | return error.MissingDebugInfo; | ||
| 1031 | }; | ||
| 1032 | const sections = @alignCast(@alignOf(macho.section_64), @ptrCast([*]const macho.section_64, ptr + @sizeOf(std.macho.segment_command_64)))[0..segcmd.nsects]; | ||
| 1033 | for (sections) |*sect| { | ||
| 1034 | if (sect.flags & macho.SECTION_TYPE == macho.S_REGULAR and | ||
| 1035 | (sect.flags & macho.SECTION_ATTRIBUTES) & macho.S_ATTR_DEBUG == macho.S_ATTR_DEBUG) | ||
| 1036 | { | ||
| 1037 | const sect_name = mem.toSliceConst(u8, &sect.sectname); | ||
| 1038 | if (mem.eql(u8, sect_name, "__debug_line")) { | ||
| 1039 | gop.kv.value.sect_debug_line = sect; | ||
| 1040 | } else if (mem.eql(u8, sect_name, "__debug_info")) { | ||
| 1041 | gop.kv.value.sect_debug_info = sect; | ||
| 1042 | } | ||
| 1043 | } | ||
| 1044 | } | ||
| 808 | 1045 | ||
| 809 | const in_file = &st.self_exe_file; | 1046 | break :blk &gop.kv.value; |
| 810 | const debug_line_end = st.debug_line.offset + st.debug_line.size; | 1047 | }; |
| 811 | var this_offset = st.debug_line.offset; | 1048 | |
| 1049 | const sect_debug_line = mach_o_file.sect_debug_line orelse return error.MissingDebugInfo; | ||
| 1050 | var ptr = mach_o_file.bytes.ptr + sect_debug_line.offset; | ||
| 1051 | |||
| 1052 | var is_64: bool = undefined; | ||
| 1053 | const unit_length = try readInitialLengthMem(&ptr, &is_64); | ||
| 1054 | if (unit_length == 0) return error.MissingDebugInfo; | ||
| 1055 | |||
| 1056 | const version = readIntMem(&ptr, u16, builtin.Endian.Little); | ||
| 1057 | // TODO support 3 and 5 | ||
| 1058 | if (version != 2 and version != 4) return error.InvalidDebugInfo; | ||
| 1059 | |||
| 1060 | const prologue_length = if (is_64) | ||
| 1061 | readIntMem(&ptr, u64, builtin.Endian.Little) | ||
| 1062 | else | ||
| 1063 | readIntMem(&ptr, u32, builtin.Endian.Little); | ||
| 1064 | const prog_start = ptr + prologue_length; | ||
| 1065 | |||
| 1066 | const minimum_instruction_length = readByteMem(&ptr); | ||
| 1067 | if (minimum_instruction_length == 0) return error.InvalidDebugInfo; | ||
| 1068 | |||
| 1069 | if (version >= 4) { | ||
| 1070 | // maximum_operations_per_instruction | ||
| 1071 | ptr += 1; | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | const default_is_stmt = readByteMem(&ptr) != 0; | ||
| 1075 | const line_base = readByteSignedMem(&ptr); | ||
| 1076 | |||
| 1077 | const line_range = readByteMem(&ptr); | ||
| 1078 | if (line_range == 0) return error.InvalidDebugInfo; | ||
| 1079 | |||
| 1080 | const opcode_base = readByteMem(&ptr); | ||
| 1081 | |||
| 1082 | const standard_opcode_lengths = ptr[0 .. opcode_base - 1]; | ||
| 1083 | ptr += opcode_base - 1; | ||
| 1084 | |||
| 1085 | var include_directories = ArrayList([]const u8).init(di.allocator()); | ||
| 1086 | try include_directories.append(""); | ||
| 1087 | while (true) { | ||
| 1088 | const dir = readStringMem(&ptr); | ||
| 1089 | if (dir.len == 0) break; | ||
| 1090 | try include_directories.append(dir); | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | var file_entries = ArrayList(FileEntry).init(di.allocator()); | ||
| 1094 | var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address); | ||
| 1095 | |||
| 1096 | while (true) { | ||
| 1097 | const file_name = readStringMem(&ptr); | ||
| 1098 | if (file_name.len == 0) break; | ||
| 1099 | const dir_index = try readULeb128Mem(&ptr); | ||
| 1100 | const mtime = try readULeb128Mem(&ptr); | ||
| 1101 | const len_bytes = try readULeb128Mem(&ptr); | ||
| 1102 | try file_entries.append(FileEntry{ | ||
| 1103 | .file_name = file_name, | ||
| 1104 | .dir_index = dir_index, | ||
| 1105 | .mtime = mtime, | ||
| 1106 | .len_bytes = len_bytes, | ||
| 1107 | }); | ||
| 1108 | } | ||
| 1109 | |||
| 1110 | ptr = prog_start; | ||
| 1111 | while (true) { | ||
| 1112 | const opcode = readByteMem(&ptr); | ||
| 1113 | |||
| 1114 | if (opcode == DW.LNS_extended_op) { | ||
| 1115 | const op_size = try readULeb128Mem(&ptr); | ||
| 1116 | if (op_size < 1) return error.InvalidDebugInfo; | ||
| 1117 | var sub_op = readByteMem(&ptr); | ||
| 1118 | switch (sub_op) { | ||
| 1119 | DW.LNE_end_sequence => { | ||
| 1120 | prog.end_sequence = true; | ||
| 1121 | if (try prog.checkLineMatch()) |info| return info; | ||
| 1122 | return error.MissingDebugInfo; | ||
| 1123 | }, | ||
| 1124 | DW.LNE_set_address => { | ||
| 1125 | const addr = readIntMem(&ptr, usize, builtin.Endian.Little); | ||
| 1126 | prog.address = symbol.reloc + addr; | ||
| 1127 | }, | ||
| 1128 | DW.LNE_define_file => { | ||
| 1129 | const file_name = readStringMem(&ptr); | ||
| 1130 | const dir_index = try readULeb128Mem(&ptr); | ||
| 1131 | const mtime = try readULeb128Mem(&ptr); | ||
| 1132 | const len_bytes = try readULeb128Mem(&ptr); | ||
| 1133 | try file_entries.append(FileEntry{ | ||
| 1134 | .file_name = file_name, | ||
| 1135 | .dir_index = dir_index, | ||
| 1136 | .mtime = mtime, | ||
| 1137 | .len_bytes = len_bytes, | ||
| 1138 | }); | ||
| 1139 | }, | ||
| 1140 | else => { | ||
| 1141 | ptr += op_size - 1; | ||
| 1142 | }, | ||
| 1143 | } | ||
| 1144 | } else if (opcode >= opcode_base) { | ||
| 1145 | // special opcodes | ||
| 1146 | const adjusted_opcode = opcode - opcode_base; | ||
| 1147 | const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range); | ||
| 1148 | const inc_line = i32(line_base) + i32(adjusted_opcode % line_range); | ||
| 1149 | prog.line += inc_line; | ||
| 1150 | prog.address += inc_addr; | ||
| 1151 | if (try prog.checkLineMatch()) |info| return info; | ||
| 1152 | prog.basic_block = false; | ||
| 1153 | } else { | ||
| 1154 | switch (opcode) { | ||
| 1155 | DW.LNS_copy => { | ||
| 1156 | if (try prog.checkLineMatch()) |info| return info; | ||
| 1157 | prog.basic_block = false; | ||
| 1158 | }, | ||
| 1159 | DW.LNS_advance_pc => { | ||
| 1160 | const arg = try readULeb128Mem(&ptr); | ||
| 1161 | prog.address += arg * minimum_instruction_length; | ||
| 1162 | }, | ||
| 1163 | DW.LNS_advance_line => { | ||
| 1164 | const arg = try readILeb128Mem(&ptr); | ||
| 1165 | prog.line += arg; | ||
| 1166 | }, | ||
| 1167 | DW.LNS_set_file => { | ||
| 1168 | const arg = try readULeb128Mem(&ptr); | ||
| 1169 | prog.file = arg; | ||
| 1170 | }, | ||
| 1171 | DW.LNS_set_column => { | ||
| 1172 | const arg = try readULeb128Mem(&ptr); | ||
| 1173 | prog.column = arg; | ||
| 1174 | }, | ||
| 1175 | DW.LNS_negate_stmt => { | ||
| 1176 | prog.is_stmt = !prog.is_stmt; | ||
| 1177 | }, | ||
| 1178 | DW.LNS_set_basic_block => { | ||
| 1179 | prog.basic_block = true; | ||
| 1180 | }, | ||
| 1181 | DW.LNS_const_add_pc => { | ||
| 1182 | const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range); | ||
| 1183 | prog.address += inc_addr; | ||
| 1184 | }, | ||
| 1185 | DW.LNS_fixed_advance_pc => { | ||
| 1186 | const arg = readIntMem(&ptr, u16, builtin.Endian.Little); | ||
| 1187 | prog.address += arg; | ||
| 1188 | }, | ||
| 1189 | DW.LNS_set_prologue_end => {}, | ||
| 1190 | else => { | ||
| 1191 | if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo; | ||
| 1192 | const len_bytes = standard_opcode_lengths[opcode - 1]; | ||
| 1193 | ptr += len_bytes; | ||
| 1194 | }, | ||
| 1195 | } | ||
| 1196 | } | ||
| 1197 | } | ||
| 1198 | |||
| 1199 | return error.MissingDebugInfo; | ||
| 1200 | } | ||
| 1201 | |||
| 1202 | fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo { | ||
| 1203 | const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir); | ||
| 1204 | |||
| 1205 | const in_file = &di.self_exe_file; | ||
| 1206 | const debug_line_end = di.debug_line.offset + di.debug_line.size; | ||
| 1207 | var this_offset = di.debug_line.offset; | ||
| 812 | var this_index: usize = 0; | 1208 | var this_index: usize = 0; |
| 813 | 1209 | ||
| 814 | var in_file_stream = io.FileInStream.init(in_file); | 1210 | var in_file_stream = io.FileInStream.init(in_file); |
| ... | @@ -827,11 +1223,11 @@ fn getLineNumberInfo(st: *ElfStackTrace, compile_unit: *const CompileUnit, targe | ... | @@ -827,11 +1223,11 @@ fn getLineNumberInfo(st: *ElfStackTrace, compile_unit: *const CompileUnit, targe |
| 827 | continue; | 1223 | continue; |
| 828 | } | 1224 | } |
| 829 | 1225 | ||
| 830 | const version = try in_stream.readInt(st.elf.endian, u16); | 1226 | const version = try in_stream.readInt(di.elf.endian, u16); |
| 831 | // TODO support 3 and 5 | 1227 | // TODO support 3 and 5 |
| 832 | if (version != 2 and version != 4) return error.InvalidDebugInfo; | 1228 | if (version != 2 and version != 4) return error.InvalidDebugInfo; |
| 833 | 1229 | ||
| 834 | const prologue_length = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32); | 1230 | const prologue_length = if (is_64) try in_stream.readInt(di.elf.endian, u64) else try in_stream.readInt(di.elf.endian, u32); |
| 835 | const prog_start_offset = (try in_file.getPos()) + prologue_length; | 1231 | const prog_start_offset = (try in_file.getPos()) + prologue_length; |
| 836 | 1232 | ||
| 837 | const minimum_instruction_length = try in_stream.readByte(); | 1233 | const minimum_instruction_length = try in_stream.readByte(); |
| ... | @@ -850,7 +1246,7 @@ fn getLineNumberInfo(st: *ElfStackTrace, compile_unit: *const CompileUnit, targe | ... | @@ -850,7 +1246,7 @@ fn getLineNumberInfo(st: *ElfStackTrace, compile_unit: *const CompileUnit, targe |
| 850 | 1246 | ||
| 851 | const opcode_base = try in_stream.readByte(); | 1247 | const opcode_base = try in_stream.readByte(); |
| 852 | 1248 | ||
| 853 | const standard_opcode_lengths = try st.allocator().alloc(u8, opcode_base - 1); | 1249 | const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1); |
| 854 | 1250 | ||
| 855 | { | 1251 | { |
| 856 | var i: usize = 0; | 1252 | var i: usize = 0; |
| ... | @@ -859,19 +1255,19 @@ fn getLineNumberInfo(st: *ElfStackTrace, compile_unit: *const CompileUnit, targe | ... | @@ -859,19 +1255,19 @@ fn getLineNumberInfo(st: *ElfStackTrace, compile_unit: *const CompileUnit, targe |
| 859 | } | 1255 | } |
| 860 | } | 1256 | } |
| 861 | 1257 | ||
| 862 | var include_directories = ArrayList([]u8).init(st.allocator()); | 1258 | var include_directories = ArrayList([]u8).init(di.allocator()); |
| 863 | try include_directories.append(compile_unit_cwd); | 1259 | try include_directories.append(compile_unit_cwd); |
| 864 | while (true) { | 1260 | while (true) { |
| 865 | const dir = try st.readString(); | 1261 | const dir = try di.readString(); |
| 866 | if (dir.len == 0) break; | 1262 | if (dir.len == 0) break; |
| 867 | try include_directories.append(dir); | 1263 | try include_directories.append(dir); |
| 868 | } | 1264 | } |
| 869 | 1265 | ||
| 870 | var file_entries = ArrayList(FileEntry).init(st.allocator()); | 1266 | var file_entries = ArrayList(FileEntry).init(di.allocator()); |
| 871 | var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address); | 1267 | var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(), &file_entries, target_address); |
| 872 | 1268 | ||
| 873 | while (true) { | 1269 | while (true) { |
| 874 | const file_name = try st.readString(); | 1270 | const file_name = try di.readString(); |
| 875 | if (file_name.len == 0) break; | 1271 | if (file_name.len == 0) break; |
| 876 | const dir_index = try readULeb128(in_stream); | 1272 | const dir_index = try readULeb128(in_stream); |
| 877 | const mtime = try readULeb128(in_stream); | 1273 | const mtime = try readULeb128(in_stream); |
| ... | @@ -900,11 +1296,11 @@ fn getLineNumberInfo(st: *ElfStackTrace, compile_unit: *const CompileUnit, targe | ... | @@ -900,11 +1296,11 @@ fn getLineNumberInfo(st: *ElfStackTrace, compile_unit: *const CompileUnit, targe |
| 900 | return error.MissingDebugInfo; | 1296 | return error.MissingDebugInfo; |
| 901 | }, | 1297 | }, |
| 902 | DW.LNE_set_address => { | 1298 | DW.LNE_set_address => { |
| 903 | const addr = try in_stream.readInt(st.elf.endian, usize); | 1299 | const addr = try in_stream.readInt(di.elf.endian, usize); |
| 904 | prog.address = addr; | 1300 | prog.address = addr; |
| 905 | }, | 1301 | }, |
| 906 | DW.LNE_define_file => { | 1302 | DW.LNE_define_file => { |
| 907 | const file_name = try st.readString(); | 1303 | const file_name = try di.readString(); |
| 908 | const dir_index = try readULeb128(in_stream); | 1304 | const dir_index = try readULeb128(in_stream); |
| 909 | const mtime = try readULeb128(in_stream); | 1305 | const mtime = try readULeb128(in_stream); |
| 910 | const len_bytes = try readULeb128(in_stream); | 1306 | const len_bytes = try readULeb128(in_stream); |
| ... | @@ -962,7 +1358,7 @@ fn getLineNumberInfo(st: *ElfStackTrace, compile_unit: *const CompileUnit, targe | ... | @@ -962,7 +1358,7 @@ fn getLineNumberInfo(st: *ElfStackTrace, compile_unit: *const CompileUnit, targe |
| 962 | prog.address += inc_addr; | 1358 | prog.address += inc_addr; |
| 963 | }, | 1359 | }, |
| 964 | DW.LNS_fixed_advance_pc => { | 1360 | DW.LNS_fixed_advance_pc => { |
| 965 | const arg = try in_stream.readInt(st.elf.endian, u16); | 1361 | const arg = try in_stream.readInt(di.elf.endian, u16); |
| 966 | prog.address += arg; | 1362 | prog.address += arg; |
| 967 | }, | 1363 | }, |
| 968 | DW.LNS_set_prologue_end => {}, | 1364 | DW.LNS_set_prologue_end => {}, |
| ... | @@ -981,7 +1377,7 @@ fn getLineNumberInfo(st: *ElfStackTrace, compile_unit: *const CompileUnit, targe | ... | @@ -981,7 +1377,7 @@ fn getLineNumberInfo(st: *ElfStackTrace, compile_unit: *const CompileUnit, targe |
| 981 | return error.MissingDebugInfo; | 1377 | return error.MissingDebugInfo; |
| 982 | } | 1378 | } |
| 983 | 1379 | ||
| 984 | fn scanAllCompileUnits(st: *ElfStackTrace) !void { | 1380 | fn scanAllCompileUnits(st: *DebugInfo) !void { |
| 985 | const debug_info_end = st.debug_info.offset + st.debug_info.size; | 1381 | const debug_info_end = st.debug_info.offset + st.debug_info.size; |
| 986 | var this_unit_offset = st.debug_info.offset; | 1382 | var this_unit_offset = st.debug_info.offset; |
| 987 | var cu_index: usize = 0; | 1383 | var cu_index: usize = 0; |
| ... | @@ -1051,7 +1447,7 @@ fn scanAllCompileUnits(st: *ElfStackTrace) !void { | ... | @@ -1051,7 +1447,7 @@ fn scanAllCompileUnits(st: *ElfStackTrace) !void { |
| 1051 | } | 1447 | } |
| 1052 | } | 1448 | } |
| 1053 | 1449 | ||
| 1054 | fn findCompileUnit(st: *ElfStackTrace, target_address: u64) !*const CompileUnit { | 1450 | fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit { |
| 1055 | var in_file_stream = io.FileInStream.init(&st.self_exe_file); | 1451 | var in_file_stream = io.FileInStream.init(&st.self_exe_file); |
| 1056 | const in_stream = &in_file_stream.stream; | 1452 | const in_stream = &in_file_stream.stream; |
| 1057 | for (st.compile_unit_list.toSlice()) |*compile_unit| { | 1453 | for (st.compile_unit_list.toSlice()) |*compile_unit| { |
| ... | @@ -1085,6 +1481,89 @@ fn findCompileUnit(st: *ElfStackTrace, target_address: u64) !*const CompileUnit | ... | @@ -1085,6 +1481,89 @@ fn findCompileUnit(st: *ElfStackTrace, target_address: u64) !*const CompileUnit |
| 1085 | return error.MissingDebugInfo; | 1481 | return error.MissingDebugInfo; |
| 1086 | } | 1482 | } |
| 1087 | 1483 | ||
| 1484 | fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T { | ||
| 1485 | const result = mem.readInt(ptr.*[0..@sizeOf(T)], T, endian); | ||
| 1486 | ptr.* += @sizeOf(T); | ||
| 1487 | return result; | ||
| 1488 | } | ||
| 1489 | |||
| 1490 | fn readByteMem(ptr: *[*]const u8) u8 { | ||
| 1491 | const result = ptr.*[0]; | ||
| 1492 | ptr.* += 1; | ||
| 1493 | return result; | ||
| 1494 | } | ||
| 1495 | |||
| 1496 | fn readByteSignedMem(ptr: *[*]const u8) i8 { | ||
| 1497 | return @bitCast(i8, readByteMem(ptr)); | ||
| 1498 | } | ||
| 1499 | |||
| 1500 | fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 { | ||
| 1501 | const first_32_bits = mem.readIntLE(u32, ptr.*[0..4]); | ||
| 1502 | is_64.* = (first_32_bits == 0xffffffff); | ||
| 1503 | if (is_64.*) { | ||
| 1504 | ptr.* += 4; | ||
| 1505 | const result = mem.readIntLE(u64, ptr.*[0..8]); | ||
| 1506 | ptr.* += 8; | ||
| 1507 | return result; | ||
| 1508 | } else { | ||
| 1509 | if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo; | ||
| 1510 | ptr.* += 4; | ||
| 1511 | return u64(first_32_bits); | ||
| 1512 | } | ||
| 1513 | } | ||
| 1514 | |||
| 1515 | fn readStringMem(ptr: *[*]const u8) []const u8 { | ||
| 1516 | const result = mem.toSliceConst(u8, ptr.*); | ||
| 1517 | ptr.* += result.len + 1; | ||
| 1518 | return result; | ||
| 1519 | } | ||
| 1520 | |||
| 1521 | fn readULeb128Mem(ptr: *[*]const u8) !u64 { | ||
| 1522 | var result: u64 = 0; | ||
| 1523 | var shift: usize = 0; | ||
| 1524 | var i: usize = 0; | ||
| 1525 | |||
| 1526 | while (true) { | ||
| 1527 | const byte = ptr.*[i]; | ||
| 1528 | i += 1; | ||
| 1529 | |||
| 1530 | var operand: u64 = undefined; | ||
| 1531 | |||
| 1532 | if (@shlWithOverflow(u64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo; | ||
| 1533 | |||
| 1534 | result |= operand; | ||
| 1535 | |||
| 1536 | if ((byte & 0b10000000) == 0) { | ||
| 1537 | ptr.* += i; | ||
| 1538 | return result; | ||
| 1539 | } | ||
| 1540 | |||
| 1541 | shift += 7; | ||
| 1542 | } | ||
| 1543 | } | ||
| 1544 | fn readILeb128Mem(ptr: *[*]const u8) !i64 { | ||
| 1545 | var result: i64 = 0; | ||
| 1546 | var shift: usize = 0; | ||
| 1547 | var i: usize = 0; | ||
| 1548 | |||
| 1549 | while (true) { | ||
| 1550 | const byte = ptr.*[i]; | ||
| 1551 | i += 1; | ||
| 1552 | |||
| 1553 | var operand: i64 = undefined; | ||
| 1554 | if (@shlWithOverflow(i64, byte & 0b01111111, @intCast(u6, shift), &operand)) return error.InvalidDebugInfo; | ||
| 1555 | |||
| 1556 | result |= operand; | ||
| 1557 | shift += 7; | ||
| 1558 | |||
| 1559 | if ((byte & 0b10000000) == 0) { | ||
| 1560 | if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0) result |= -(i64(1) << @intCast(u6, shift)); | ||
| 1561 | ptr.* += i; | ||
| 1562 | return result; | ||
| 1563 | } | ||
| 1564 | } | ||
| 1565 | } | ||
| 1566 | |||
| 1088 | fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 { | 1567 | fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 { |
| 1089 | const first_32_bits = try in_stream.readIntLe(u32); | 1568 | const first_32_bits = try in_stream.readIntLe(u32); |
| 1090 | is_64.* = (first_32_bits == 0xffffffff); | 1569 | is_64.* = (first_32_bits == 0xffffffff); |
| ... | @@ -1141,7 +1620,7 @@ pub const global_allocator = &global_fixed_allocator.allocator; | ... | @@ -1141,7 +1620,7 @@ pub const global_allocator = &global_fixed_allocator.allocator; |
| 1141 | var global_fixed_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(global_allocator_mem[0..]); | 1620 | var global_fixed_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(global_allocator_mem[0..]); |
| 1142 | var global_allocator_mem: [100 * 1024]u8 = undefined; | 1621 | var global_allocator_mem: [100 * 1024]u8 = undefined; |
| 1143 | 1622 | ||
| 1144 | // TODO make thread safe | 1623 | /// TODO multithreaded awareness |
| 1145 | var debug_info_allocator: ?*mem.Allocator = null; | 1624 | var debug_info_allocator: ?*mem.Allocator = null; |
| 1146 | var debug_info_direct_allocator: std.heap.DirectAllocator = undefined; | 1625 | var debug_info_direct_allocator: std.heap.DirectAllocator = undefined; |
| 1147 | var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined; | 1626 | var debug_info_arena_allocator: std.heap.ArenaAllocator = undefined; |
std/elf.zig+5| ... | @@ -869,6 +869,11 @@ pub const Phdr = switch (@sizeOf(usize)) { | ... | @@ -869,6 +869,11 @@ pub const Phdr = switch (@sizeOf(usize)) { |
| 869 | 8 => Elf64_Phdr, | 869 | 8 => Elf64_Phdr, |
| 870 | else => @compileError("expected pointer size of 32 or 64"), | 870 | else => @compileError("expected pointer size of 32 or 64"), |
| 871 | }; | 871 | }; |
| 872 | pub const Shdr = switch (@sizeOf(usize)) { | ||
| 873 | 4 => Elf32_Shdr, | ||
| 874 | 8 => Elf64_Shdr, | ||
| 875 | else => @compileError("expected pointer size of 32 or 64"), | ||
| 876 | }; | ||
| 872 | pub const Sym = switch (@sizeOf(usize)) { | 877 | pub const Sym = switch (@sizeOf(usize)) { |
| 873 | 4 => Elf32_Sym, | 878 | 4 => Elf32_Sym, |
| 874 | 8 => Elf64_Sym, | 879 | 8 => Elf64_Sym, |
std/hash_map.zig+16| ... | @@ -408,6 +408,22 @@ test "iterator hash map" { | ... | @@ -408,6 +408,22 @@ test "iterator hash map" { |
| 408 | assert(entry.value == values[0]); | 408 | assert(entry.value == values[0]); |
| 409 | } | 409 | } |
| 410 | 410 | ||
| 411 | pub fn getHashPtrAddrFn(comptime K: type) (fn (K) u32) { | ||
| 412 | return struct { | ||
| 413 | fn hash(key: K) u32 { | ||
| 414 | return getAutoHashFn(usize)(@ptrToInt(key)); | ||
| 415 | } | ||
| 416 | }.hash; | ||
| 417 | } | ||
| 418 | |||
| 419 | pub fn getTrivialEqlFn(comptime K: type) (fn (K, K) bool) { | ||
| 420 | return struct { | ||
| 421 | fn eql(a: K, b: K) bool { | ||
| 422 | return a == b; | ||
| 423 | } | ||
| 424 | }.eql; | ||
| 425 | } | ||
| 426 | |||
| 411 | pub fn getAutoHashFn(comptime K: type) (fn (K) u32) { | 427 | pub fn getAutoHashFn(comptime K: type) (fn (K) u32) { |
| 412 | return struct { | 428 | return struct { |
| 413 | fn hash(key: K) u32 { | 429 | fn hash(key: K) u32 { |
std/index.zig+1| ... | @@ -24,6 +24,7 @@ pub const empty_import = @import("empty.zig"); | ... | @@ -24,6 +24,7 @@ pub const empty_import = @import("empty.zig"); |
| 24 | pub const event = @import("event.zig"); | 24 | pub const event = @import("event.zig"); |
| 25 | pub const fmt = @import("fmt/index.zig"); | 25 | pub const fmt = @import("fmt/index.zig"); |
| 26 | pub const hash = @import("hash/index.zig"); | 26 | pub const hash = @import("hash/index.zig"); |
| 27 | pub const hash_map = @import("hash_map.zig"); | ||
| 27 | pub const heap = @import("heap.zig"); | 28 | pub const heap = @import("heap.zig"); |
| 28 | pub const io = @import("io.zig"); | 29 | pub const io = @import("io.zig"); |
| 29 | pub const json = @import("json.zig"); | 30 | pub const json = @import("json.zig"); |
std/io.zig+6| ... | @@ -207,6 +207,12 @@ pub fn InStream(comptime ReadError: type) type { | ... | @@ -207,6 +207,12 @@ pub fn InStream(comptime ReadError: type) type { |
| 207 | _ = try self.readByte(); | 207 | _ = try self.readByte(); |
| 208 | } | 208 | } |
| 209 | } | 209 | } |
| 210 | |||
| 211 | pub fn readStruct(self: *Self, comptime T: type, ptr: *T) !void { | ||
| 212 | // Only extern and packed structs have defined in-memory layout. | ||
| 213 | assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto); | ||
| 214 | return self.readNoEof(@sliceToBytes((*[1]T)(ptr)[0..])); | ||
| 215 | } | ||
| 210 | }; | 216 | }; |
| 211 | } | 217 | } |
| 212 | 218 |
std/macho.zig+322-146| ... | @@ -1,16 +1,18 @@ | ... | @@ -1,16 +1,18 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("index.zig"); | ||
| 3 | const io = std.io; | ||
| 4 | const mem = std.mem; | ||
| 5 | 1 | ||
| 6 | const MH_MAGIC_64 = 0xFEEDFACF; | 2 | pub const mach_header = extern struct { |
| 7 | const MH_PIE = 0x200000; | 3 | magic: u32, |
| 8 | const LC_SYMTAB = 2; | 4 | cputype: cpu_type_t, |
| 5 | cpusubtype: cpu_subtype_t, | ||
| 6 | filetype: u32, | ||
| 7 | ncmds: u32, | ||
| 8 | sizeofcmds: u32, | ||
| 9 | flags: u32, | ||
| 10 | }; | ||
| 9 | 11 | ||
| 10 | const MachHeader64 = packed struct { | 12 | pub const mach_header_64 = extern struct { |
| 11 | magic: u32, | 13 | magic: u32, |
| 12 | cputype: u32, | 14 | cputype: cpu_type_t, |
| 13 | cpusubtype: u32, | 15 | cpusubtype: cpu_subtype_t, |
| 14 | filetype: u32, | 16 | filetype: u32, |
| 15 | ncmds: u32, | 17 | ncmds: u32, |
| 16 | sizeofcmds: u32, | 18 | sizeofcmds: u32, |
| ... | @@ -18,19 +20,138 @@ const MachHeader64 = packed struct { | ... | @@ -18,19 +20,138 @@ const MachHeader64 = packed struct { |
| 18 | reserved: u32, | 20 | reserved: u32, |
| 19 | }; | 21 | }; |
| 20 | 22 | ||
| 21 | const LoadCommand = packed struct { | 23 | pub const load_command = extern struct { |
| 22 | cmd: u32, | 24 | cmd: u32, |
| 23 | cmdsize: u32, | 25 | cmdsize: u32, |
| 24 | }; | 26 | }; |
| 25 | 27 | ||
| 26 | const SymtabCommand = packed struct { | 28 | |
| 27 | symoff: u32, | 29 | /// The symtab_command contains the offsets and sizes of the link-edit 4.3BSD |
| 28 | nsyms: u32, | 30 | /// "stab" style symbol table information as described in the header files |
| 29 | stroff: u32, | 31 | /// <nlist.h> and <stab.h>. |
| 30 | strsize: u32, | 32 | pub const symtab_command = extern struct { |
| 33 | cmd: u32, /// LC_SYMTAB | ||
| 34 | cmdsize: u32, /// sizeof(struct symtab_command) | ||
| 35 | symoff: u32, /// symbol table offset | ||
| 36 | nsyms: u32, /// number of symbol table entries | ||
| 37 | stroff: u32, /// string table offset | ||
| 38 | strsize: u32, /// string table size in bytes | ||
| 39 | }; | ||
| 40 | |||
| 41 | /// The linkedit_data_command contains the offsets and sizes of a blob | ||
| 42 | /// of data in the __LINKEDIT segment. | ||
| 43 | const linkedit_data_command = extern struct { | ||
| 44 | cmd: u32,/// LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS or LC_LINKER_OPTIMIZATION_HINT. | ||
| 45 | cmdsize: u32, /// sizeof(struct linkedit_data_command) | ||
| 46 | dataoff: u32 , /// file offset of data in __LINKEDIT segment | ||
| 47 | datasize: u32 , /// file size of data in __LINKEDIT segment | ||
| 48 | }; | ||
| 49 | |||
| 50 | /// The segment load command indicates that a part of this file is to be | ||
| 51 | /// mapped into the task's address space. The size of this segment in memory, | ||
| 52 | /// vmsize, maybe equal to or larger than the amount to map from this file, | ||
| 53 | /// filesize. The file is mapped starting at fileoff to the beginning of | ||
| 54 | /// the segment in memory, vmaddr. The rest of the memory of the segment, | ||
| 55 | /// if any, is allocated zero fill on demand. The segment's maximum virtual | ||
| 56 | /// memory protection and initial virtual memory protection are specified | ||
| 57 | /// by the maxprot and initprot fields. If the segment has sections then the | ||
| 58 | /// section structures directly follow the segment command and their size is | ||
| 59 | /// reflected in cmdsize. | ||
| 60 | pub const segment_command = extern struct { | ||
| 61 | cmd: u32,/// LC_SEGMENT | ||
| 62 | cmdsize: u32,/// includes sizeof section structs | ||
| 63 | segname: [16]u8,/// segment name | ||
| 64 | vmaddr: u32,/// memory address of this segment | ||
| 65 | vmsize: u32,/// memory size of this segment | ||
| 66 | fileoff: u32,/// file offset of this segment | ||
| 67 | filesize: u32,/// amount to map from the file | ||
| 68 | maxprot: vm_prot_t,/// maximum VM protection | ||
| 69 | initprot: vm_prot_t,/// initial VM protection | ||
| 70 | nsects: u32,/// number of sections in segment | ||
| 71 | flags: u32, | ||
| 72 | }; | ||
| 73 | |||
| 74 | /// The 64-bit segment load command indicates that a part of this file is to be | ||
| 75 | /// mapped into a 64-bit task's address space. If the 64-bit segment has | ||
| 76 | /// sections then section_64 structures directly follow the 64-bit segment | ||
| 77 | /// command and their size is reflected in cmdsize. | ||
| 78 | pub const segment_command_64 = extern struct { | ||
| 79 | cmd: u32, /// LC_SEGMENT_64 | ||
| 80 | cmdsize: u32, /// includes sizeof section_64 structs | ||
| 81 | segname: [16]u8, /// segment name | ||
| 82 | vmaddr: u64, /// memory address of this segment | ||
| 83 | vmsize: u64, /// memory size of this segment | ||
| 84 | fileoff: u64, /// file offset of this segment | ||
| 85 | filesize: u64, /// amount to map from the file | ||
| 86 | maxprot: vm_prot_t, /// maximum VM protection | ||
| 87 | initprot: vm_prot_t, /// initial VM protection | ||
| 88 | nsects: u32, /// number of sections in segment | ||
| 89 | flags: u32, | ||
| 90 | }; | ||
| 91 | |||
| 92 | /// A segment is made up of zero or more sections. Non-MH_OBJECT files have | ||
| 93 | /// all of their segments with the proper sections in each, and padded to the | ||
| 94 | /// specified segment alignment when produced by the link editor. The first | ||
| 95 | /// segment of a MH_EXECUTE and MH_FVMLIB format file contains the mach_header | ||
| 96 | /// and load commands of the object file before its first section. The zero | ||
| 97 | /// fill sections are always last in their segment (in all formats). This | ||
| 98 | /// allows the zeroed segment padding to be mapped into memory where zero fill | ||
| 99 | /// sections might be. The gigabyte zero fill sections, those with the section | ||
| 100 | /// type S_GB_ZEROFILL, can only be in a segment with sections of this type. | ||
| 101 | /// These segments are then placed after all other segments. | ||
| 102 | /// | ||
| 103 | /// The MH_OBJECT format has all of its sections in one segment for | ||
| 104 | /// compactness. There is no padding to a specified segment boundary and the | ||
| 105 | /// mach_header and load commands are not part of the segment. | ||
| 106 | /// | ||
| 107 | /// Sections with the same section name, sectname, going into the same segment, | ||
| 108 | /// segname, are combined by the link editor. The resulting section is aligned | ||
| 109 | /// to the maximum alignment of the combined sections and is the new section's | ||
| 110 | /// alignment. The combined sections are aligned to their original alignment in | ||
| 111 | /// the combined section. Any padded bytes to get the specified alignment are | ||
| 112 | /// zeroed. | ||
| 113 | /// | ||
| 114 | /// The format of the relocation entries referenced by the reloff and nreloc | ||
| 115 | /// fields of the section structure for mach object files is described in the | ||
| 116 | /// header file <reloc.h>. | ||
| 117 | pub const @"section" = extern struct { | ||
| 118 | sectname: [16]u8, /// name of this section | ||
| 119 | segname: [16]u8, /// segment this section goes in | ||
| 120 | addr: u32, /// memory address of this section | ||
| 121 | size: u32, /// size in bytes of this section | ||
| 122 | offset: u32, /// file offset of this section | ||
| 123 | @"align": u32, /// section alignment (power of 2) | ||
| 124 | reloff: u32, /// file offset of relocation entries | ||
| 125 | nreloc: u32, /// number of relocation entries | ||
| 126 | flags: u32, /// flags (section type and attributes | ||
| 127 | reserved1: u32, /// reserved (for offset or index) | ||
| 128 | reserved2: u32, /// reserved (for count or sizeof) | ||
| 129 | }; | ||
| 130 | |||
| 131 | pub const section_64 = extern struct { | ||
| 132 | sectname: [16]u8, /// name of this section | ||
| 133 | segname: [16]u8, /// segment this section goes in | ||
| 134 | addr: u64, /// memory address of this section | ||
| 135 | size: u64, /// size in bytes of this section | ||
| 136 | offset: u32, /// file offset of this section | ||
| 137 | @"align": u32, /// section alignment (power of 2) | ||
| 138 | reloff: u32, /// file offset of relocation entries | ||
| 139 | nreloc: u32, /// number of relocation entries | ||
| 140 | flags: u32, /// flags (section type and attributes | ||
| 141 | reserved1: u32, /// reserved (for offset or index) | ||
| 142 | reserved2: u32, /// reserved (for count or sizeof) | ||
| 143 | reserved3: u32, /// reserved | ||
| 144 | }; | ||
| 145 | |||
| 146 | pub const nlist = extern struct { | ||
| 147 | n_strx: u32, | ||
| 148 | n_type: u8, | ||
| 149 | n_sect: u8, | ||
| 150 | n_desc: i16, | ||
| 151 | n_value: u32, | ||
| 31 | }; | 152 | }; |
| 32 | 153 | ||
| 33 | const Nlist64 = packed struct { | 154 | pub const nlist_64 = extern struct { |
| 34 | n_strx: u32, | 155 | n_strx: u32, |
| 35 | n_type: u8, | 156 | n_type: u8, |
| 36 | n_sect: u8, | 157 | n_sect: u8, |
| ... | @@ -38,135 +159,190 @@ const Nlist64 = packed struct { | ... | @@ -38,135 +159,190 @@ const Nlist64 = packed struct { |
| 38 | n_value: u64, | 159 | n_value: u64, |
| 39 | }; | 160 | }; |
| 40 | 161 | ||
| 41 | pub const Symbol = struct { | 162 | /// After MacOS X 10.1 when a new load command is added that is required to be |
| 42 | name: []const u8, | 163 | /// understood by the dynamic linker for the image to execute properly the |
| 43 | address: u64, | 164 | /// LC_REQ_DYLD bit will be or'ed into the load command constant. If the dynamic |
| 165 | /// linker sees such a load command it it does not understand will issue a | ||
| 166 | /// "unknown load command required for execution" error and refuse to use the | ||
| 167 | /// image. Other load commands without this bit that are not understood will | ||
| 168 | /// simply be ignored. | ||
| 169 | pub const LC_REQ_DYLD = 0x80000000; | ||
| 44 | 170 | ||
| 45 | fn addressLessThan(lhs: Symbol, rhs: Symbol) bool { | 171 | pub const LC_SEGMENT = 0x1; /// segment of this file to be mapped |
| 46 | return lhs.address < rhs.address; | 172 | pub const LC_SYMTAB = 0x2; /// link-edit stab symbol table info |
| 47 | } | 173 | pub const LC_SYMSEG = 0x3; /// link-edit gdb symbol table info (obsolete) |
| 48 | }; | 174 | pub const LC_THREAD = 0x4; /// thread |
| 175 | pub const LC_UNIXTHREAD = 0x5; /// unix thread (includes a stack) | ||
| 176 | pub const LC_LOADFVMLIB = 0x6; /// load a specified fixed VM shared library | ||
| 177 | pub const LC_IDFVMLIB = 0x7; /// fixed VM shared library identification | ||
| 178 | pub const LC_IDENT = 0x8; /// object identification info (obsolete) | ||
| 179 | pub const LC_FVMFILE = 0x9; /// fixed VM file inclusion (internal use) | ||
| 180 | pub const LC_PREPAGE = 0xa; /// prepage command (internal use) | ||
| 181 | pub const LC_DYSYMTAB = 0xb; /// dynamic link-edit symbol table info | ||
| 182 | pub const LC_LOAD_DYLIB = 0xc; /// load a dynamically linked shared library | ||
| 183 | pub const LC_ID_DYLIB = 0xd; /// dynamically linked shared lib ident | ||
| 184 | pub const LC_LOAD_DYLINKER = 0xe; /// load a dynamic linker | ||
| 185 | pub const LC_ID_DYLINKER = 0xf; /// dynamic linker identification | ||
| 186 | pub const LC_PREBOUND_DYLIB = 0x10; /// modules prebound for a dynamically | ||
| 187 | pub const LC_ROUTINES = 0x11; /// image routines | ||
| 188 | pub const LC_SUB_FRAMEWORK = 0x12; /// sub framework | ||
| 189 | pub const LC_SUB_UMBRELLA = 0x13; /// sub umbrella | ||
| 190 | pub const LC_SUB_CLIENT = 0x14; /// sub client | ||
| 191 | pub const LC_SUB_LIBRARY = 0x15; /// sub library | ||
| 192 | pub const LC_TWOLEVEL_HINTS = 0x16; /// two-level namespace lookup hints | ||
| 193 | pub const LC_PREBIND_CKSUM = 0x17; /// prebind checksum | ||
| 49 | 194 | ||
| 50 | pub const SymbolTable = struct { | 195 | /// load a dynamically linked shared library that is allowed to be missing |
| 51 | allocator: *mem.Allocator, | 196 | /// (all symbols are weak imported). |
| 52 | symbols: []const Symbol, | 197 | pub const LC_LOAD_WEAK_DYLIB = (0x18 | LC_REQ_DYLD); |
| 53 | strings: []const u8, | 198 | |
| 54 | 199 | pub const LC_SEGMENT_64 = 0x19; /// 64-bit segment of this file to be mapped | |
| 55 | // Doubles as an eyecatcher to calculate the PIE slide, see loadSymbols(). | 200 | pub const LC_ROUTINES_64 = 0x1a; /// 64-bit image routines |
| 56 | // Ideally we'd use _mh_execute_header because it's always at 0x100000000 | 201 | pub const LC_UUID = 0x1b; /// the uuid |
| 57 | // in the image but as it's located in a different section than executable | 202 | pub const LC_RPATH = (0x1c | LC_REQ_DYLD); /// runpath additions |
| 58 | // code, its displacement is different. | 203 | pub const LC_CODE_SIGNATURE = 0x1d; /// local of code signature |
| 59 | pub fn deinit(self: *SymbolTable) void { | 204 | pub const LC_SEGMENT_SPLIT_INFO = 0x1e; /// local of info to split segments |
| 60 | self.allocator.free(self.symbols); | 205 | pub const LC_REEXPORT_DYLIB = (0x1f | LC_REQ_DYLD); /// load and re-export dylib |
| 61 | self.symbols = []const Symbol{}; | 206 | pub const LC_LAZY_LOAD_DYLIB = 0x20; /// delay load of dylib until first use |
| 62 | 207 | pub const LC_ENCRYPTION_INFO = 0x21; /// encrypted segment information | |
| 63 | self.allocator.free(self.strings); | 208 | pub const LC_DYLD_INFO = 0x22; /// compressed dyld information |
| 64 | self.strings = []const u8{}; | 209 | pub const LC_DYLD_INFO_ONLY = (0x22|LC_REQ_DYLD); /// compressed dyld information only |
| 65 | } | 210 | pub const LC_LOAD_UPWARD_DYLIB = (0x23 | LC_REQ_DYLD); /// load upward dylib |
| 66 | 211 | pub const LC_VERSION_MIN_MACOSX = 0x24; /// build for MacOSX min OS version | |
| 67 | pub fn search(self: *const SymbolTable, address: usize) ?*const Symbol { | 212 | pub const LC_VERSION_MIN_IPHONEOS = 0x25; /// build for iPhoneOS min OS version |
| 68 | var min: usize = 0; | 213 | pub const LC_FUNCTION_STARTS = 0x26; /// compressed table of function start addresses |
| 69 | var max: usize = self.symbols.len - 1; // Exclude sentinel. | 214 | pub const LC_DYLD_ENVIRONMENT = 0x27; /// string for dyld to treat like environment variable |
| 70 | while (min < max) { | 215 | pub const LC_MAIN = (0x28|LC_REQ_DYLD); /// replacement for LC_UNIXTHREAD |
| 71 | const mid = min + (max - min) / 2; | 216 | pub const LC_DATA_IN_CODE = 0x29; /// table of non-instructions in __text |
| 72 | const curr = &self.symbols[mid]; | 217 | pub const LC_SOURCE_VERSION = 0x2A; /// source version used to build binary |
| 73 | const next = &self.symbols[mid + 1]; | 218 | pub const LC_DYLIB_CODE_SIGN_DRS = 0x2B; /// Code signing DRs copied from linked dylibs |
| 74 | if (address >= next.address) { | 219 | pub const LC_ENCRYPTION_INFO_64 = 0x2C; /// 64-bit encrypted segment information |
| 75 | min = mid + 1; | 220 | pub const LC_LINKER_OPTION = 0x2D; /// linker options in MH_OBJECT files |
| 76 | } else if (address < curr.address) { | 221 | pub const LC_LINKER_OPTIMIZATION_HINT = 0x2E; /// optimization hints in MH_OBJECT files |
| 77 | max = mid; | 222 | pub const LC_VERSION_MIN_TVOS = 0x2F; /// build for AppleTV min OS version |
| 78 | } else { | 223 | pub const LC_VERSION_MIN_WATCHOS = 0x30; /// build for Watch min OS version |
| 79 | return curr; | 224 | pub const LC_NOTE = 0x31; /// arbitrary data included within a Mach-O file |
| 80 | } | 225 | pub const LC_BUILD_VERSION = 0x32; /// build for platform min OS version |
| 81 | } | 226 | |
| 82 | return null; | 227 | pub const MH_MAGIC = 0xfeedface; /// the mach magic number |
| 83 | } | 228 | pub const MH_CIGAM = 0xcefaedfe; /// NXSwapInt(MH_MAGIC) |
| 84 | }; | 229 | |
| 230 | pub const MH_MAGIC_64 = 0xfeedfacf; /// the 64-bit mach magic number | ||
| 231 | pub const MH_CIGAM_64 = 0xcffaedfe; /// NXSwapInt(MH_MAGIC_64) | ||
| 232 | |||
| 233 | pub const MH_OBJECT = 0x1; /// relocatable object file | ||
| 234 | pub const MH_EXECUTE = 0x2; /// demand paged executable file | ||
| 235 | pub const MH_FVMLIB = 0x3; /// fixed VM shared library file | ||
| 236 | pub const MH_CORE = 0x4; /// core file | ||
| 237 | pub const MH_PRELOAD = 0x5; /// preloaded executable file | ||
| 238 | pub const MH_DYLIB = 0x6; /// dynamically bound shared library | ||
| 239 | pub const MH_DYLINKER = 0x7; /// dynamic link editor | ||
| 240 | pub const MH_BUNDLE = 0x8; /// dynamically bound bundle file | ||
| 241 | pub const MH_DYLIB_STUB = 0x9; /// shared library stub for static linking only, no section contents | ||
| 242 | pub const MH_DSYM = 0xa; /// companion file with only debug sections | ||
| 243 | pub const MH_KEXT_BUNDLE = 0xb; /// x86_64 kexts | ||
| 244 | |||
| 245 | // Constants for the flags field of the mach_header | ||
| 246 | |||
| 247 | pub const MH_NOUNDEFS = 0x1; /// the object file has no undefined references | ||
| 248 | pub const MH_INCRLINK = 0x2; /// the object file is the output of an incremental link against a base file and can't be link edited again | ||
| 249 | pub const MH_DYLDLINK = 0x4; /// the object file is input for the dynamic linker and can't be staticly link edited again | ||
| 250 | pub const MH_BINDATLOAD = 0x8; /// the object file's undefined references are bound by the dynamic linker when loaded. | ||
| 251 | pub const MH_PREBOUND = 0x10; /// the file has its dynamic undefined references prebound. | ||
| 252 | pub const MH_SPLIT_SEGS = 0x20; /// the file has its read-only and read-write segments split | ||
| 253 | pub const MH_LAZY_INIT = 0x40; /// the shared library init routine is to be run lazily via catching memory faults to its writeable segments (obsolete) | ||
| 254 | pub const MH_TWOLEVEL = 0x80; /// the image is using two-level name space bindings | ||
| 255 | pub const MH_FORCE_FLAT = 0x100; /// the executable is forcing all images to use flat name space bindings | ||
| 256 | pub const MH_NOMULTIDEFS = 0x200; /// this umbrella guarantees no multiple defintions of symbols in its sub-images so the two-level namespace hints can always be used. | ||
| 257 | pub const MH_NOFIXPREBINDING = 0x400; /// do not have dyld notify the prebinding agent about this executable | ||
| 258 | pub const MH_PREBINDABLE = 0x800; /// the binary is not prebound but can have its prebinding redone. only used when MH_PREBOUND is not set. | ||
| 259 | pub const MH_ALLMODSBOUND = 0x1000; /// indicates that this binary binds to all two-level namespace modules of its dependent libraries. only used when MH_PREBINDABLE and MH_TWOLEVEL are both set. | ||
| 260 | pub const MH_SUBSECTIONS_VIA_SYMBOLS = 0x2000;/// safe to divide up the sections into sub-sections via symbols for dead code stripping | ||
| 261 | pub const MH_CANONICAL = 0x4000; /// the binary has been canonicalized via the unprebind operation | ||
| 262 | pub const MH_WEAK_DEFINES = 0x8000; /// the final linked image contains external weak symbols | ||
| 263 | pub const MH_BINDS_TO_WEAK = 0x10000; /// the final linked image uses weak symbols | ||
| 264 | |||
| 265 | pub const MH_ALLOW_STACK_EXECUTION = 0x20000;/// When this bit is set, all stacks in the task will be given stack execution privilege. Only used in MH_EXECUTE filetypes. | ||
| 266 | pub const MH_ROOT_SAFE = 0x40000; /// When this bit is set, the binary declares it is safe for use in processes with uid zero | ||
| 267 | |||
| 268 | pub const MH_SETUID_SAFE = 0x80000; /// When this bit is set, the binary declares it is safe for use in processes when issetugid() is true | ||
| 269 | |||
| 270 | pub const MH_NO_REEXPORTED_DYLIBS = 0x100000; /// When this bit is set on a dylib, the static linker does not need to examine dependent dylibs to see if any are re-exported | ||
| 271 | pub const MH_PIE = 0x200000; /// When this bit is set, the OS will load the main executable at a random address. Only used in MH_EXECUTE filetypes. | ||
| 272 | pub const MH_DEAD_STRIPPABLE_DYLIB = 0x400000; /// Only for use on dylibs. When linking against a dylib that has this bit set, the static linker will automatically not create a LC_LOAD_DYLIB load command to the dylib if no symbols are being referenced from the dylib. | ||
| 273 | pub const MH_HAS_TLV_DESCRIPTORS = 0x800000; /// Contains a section of type S_THREAD_LOCAL_VARIABLES | ||
| 274 | |||
| 275 | pub const MH_NO_HEAP_EXECUTION = 0x1000000; /// When this bit is set, the OS will run the main executable with a non-executable heap even on platforms (e.g. i386) that don't require it. Only used in MH_EXECUTE filetypes. | ||
| 276 | |||
| 277 | pub const MH_APP_EXTENSION_SAFE = 0x02000000; /// The code was linked for use in an application extension. | ||
| 278 | |||
| 279 | pub const MH_NLIST_OUTOFSYNC_WITH_DYLDINFO = 0x04000000; /// The external symbols listed in the nlist symbol table do not include all the symbols listed in the dyld info. | ||
| 280 | |||
| 281 | |||
| 282 | /// The flags field of a section structure is separated into two parts a section | ||
| 283 | /// type and section attributes. The section types are mutually exclusive (it | ||
| 284 | /// can only have one type) but the section attributes are not (it may have more | ||
| 285 | /// than one attribute). | ||
| 286 | /// 256 section types | ||
| 287 | pub const SECTION_TYPE = 0x000000ff; | ||
| 288 | pub const SECTION_ATTRIBUTES = 0xffffff00; /// 24 section attributes | ||
| 289 | |||
| 290 | pub const S_REGULAR = 0x0; /// regular section | ||
| 291 | pub const S_ZEROFILL = 0x1; /// zero fill on demand section | ||
| 292 | pub const S_CSTRING_LITERALS = 0x2; /// section with only literal C string | ||
| 293 | pub const S_4BYTE_LITERALS = 0x3; /// section with only 4 byte literals | ||
| 294 | pub const S_8BYTE_LITERALS = 0x4; /// section with only 8 byte literals | ||
| 295 | pub const S_LITERAL_POINTERS = 0x5; /// section with only pointers to | ||
| 296 | |||
| 297 | |||
| 298 | pub const N_STAB = 0xe0; /// if any of these bits set, a symbolic debugging entry | ||
| 299 | pub const N_PEXT = 0x10; /// private external symbol bit | ||
| 300 | pub const N_TYPE = 0x0e; /// mask for the type bits | ||
| 301 | pub const N_EXT = 0x01; /// external symbol bit, set for external symbols | ||
| 302 | |||
| 303 | |||
| 304 | pub const N_GSYM = 0x20; /// global symbol: name,,NO_SECT,type,0 | ||
| 305 | pub const N_FNAME = 0x22; /// procedure name (f77 kludge): name,,NO_SECT,0,0 | ||
| 306 | pub const N_FUN = 0x24; /// procedure: name,,n_sect,linenumber,address | ||
| 307 | pub const N_STSYM = 0x26; /// static symbol: name,,n_sect,type,address | ||
| 308 | pub const N_LCSYM = 0x28; /// .lcomm symbol: name,,n_sect,type,address | ||
| 309 | pub const N_BNSYM = 0x2e; /// begin nsect sym: 0,,n_sect,0,address | ||
| 310 | pub const N_AST = 0x32; /// AST file path: name,,NO_SECT,0,0 | ||
| 311 | pub const N_OPT = 0x3c; /// emitted with gcc2_compiled and in gcc source | ||
| 312 | pub const N_RSYM = 0x40; /// register sym: name,,NO_SECT,type,register | ||
| 313 | pub const N_SLINE = 0x44; /// src line: 0,,n_sect,linenumber,address | ||
| 314 | pub const N_ENSYM = 0x4e; /// end nsect sym: 0,,n_sect,0,address | ||
| 315 | pub const N_SSYM = 0x60; /// structure elt: name,,NO_SECT,type,struct_offset | ||
| 316 | pub const N_SO = 0x64; /// source file name: name,,n_sect,0,address | ||
| 317 | pub const N_OSO = 0x66; /// object file name: name,,0,0,st_mtime | ||
| 318 | pub const N_LSYM = 0x80; /// local sym: name,,NO_SECT,type,offset | ||
| 319 | pub const N_BINCL = 0x82; /// include file beginning: name,,NO_SECT,0,sum | ||
| 320 | pub const N_SOL = 0x84; /// #included file name: name,,n_sect,0,address | ||
| 321 | pub const N_PARAMS = 0x86; /// compiler parameters: name,,NO_SECT,0,0 | ||
| 322 | pub const N_VERSION = 0x88; /// compiler version: name,,NO_SECT,0,0 | ||
| 323 | pub const N_OLEVEL = 0x8A; /// compiler -O level: name,,NO_SECT,0,0 | ||
| 324 | pub const N_PSYM = 0xa0; /// parameter: name,,NO_SECT,type,offset | ||
| 325 | pub const N_EINCL = 0xa2; /// include file end: name,,NO_SECT,0,0 | ||
| 326 | pub const N_ENTRY = 0xa4; /// alternate entry: name,,n_sect,linenumber,address | ||
| 327 | pub const N_LBRAC = 0xc0; /// left bracket: 0,,NO_SECT,nesting level,address | ||
| 328 | pub const N_EXCL = 0xc2; /// deleted include file: name,,NO_SECT,0,sum | ||
| 329 | pub const N_RBRAC = 0xe0; /// right bracket: 0,,NO_SECT,nesting level,address | ||
| 330 | pub const N_BCOMM = 0xe2; /// begin common: name,,NO_SECT,0,0 | ||
| 331 | pub const N_ECOMM = 0xe4; /// end common: name,,n_sect,0,0 | ||
| 332 | pub const N_ECOML = 0xe8; /// end common (local name): 0,,n_sect,0,address | ||
| 333 | pub const N_LENG = 0xfe; /// second stab entry with length information | ||
| 334 | |||
| 335 | /// If a segment contains any sections marked with S_ATTR_DEBUG then all | ||
| 336 | /// sections in that segment must have this attribute. No section other than | ||
| 337 | /// a section marked with this attribute may reference the contents of this | ||
| 338 | /// section. A section with this attribute may contain no symbols and must have | ||
| 339 | /// a section type S_REGULAR. The static linker will not copy section contents | ||
| 340 | /// from sections with this attribute into its output file. These sections | ||
| 341 | /// generally contain DWARF debugging info. | ||
| 342 | pub const S_ATTR_DEBUG = 0x02000000; /// a debug section | ||
| 343 | |||
| 344 | pub const cpu_type_t = integer_t; | ||
| 345 | pub const cpu_subtype_t = integer_t; | ||
| 346 | pub const integer_t = c_int; | ||
| 347 | pub const vm_prot_t = c_int; | ||
| 85 | 348 | ||
| 86 | pub fn loadSymbols(allocator: *mem.Allocator, in: *io.FileInStream) !SymbolTable { | ||
| 87 | var file = in.file; | ||
| 88 | try file.seekTo(0); | ||
| 89 | |||
| 90 | var hdr: MachHeader64 = undefined; | ||
| 91 | try readOneNoEof(in, MachHeader64, &hdr); | ||
| 92 | if (hdr.magic != MH_MAGIC_64) return error.MissingDebugInfo; | ||
| 93 | const is_pie = MH_PIE == (hdr.flags & MH_PIE); | ||
| 94 | |||
| 95 | var pos: usize = @sizeOf(@typeOf(hdr)); | ||
| 96 | var ncmd: u32 = hdr.ncmds; | ||
| 97 | while (ncmd != 0) : (ncmd -= 1) { | ||
| 98 | try file.seekTo(pos); | ||
| 99 | var lc: LoadCommand = undefined; | ||
| 100 | try readOneNoEof(in, LoadCommand, &lc); | ||
| 101 | if (lc.cmd == LC_SYMTAB) break; | ||
| 102 | pos += lc.cmdsize; | ||
| 103 | } else { | ||
| 104 | return error.MissingDebugInfo; | ||
| 105 | } | ||
| 106 | |||
| 107 | var cmd: SymtabCommand = undefined; | ||
| 108 | try readOneNoEof(in, SymtabCommand, &cmd); | ||
| 109 | |||
| 110 | try file.seekTo(cmd.symoff); | ||
| 111 | var syms = try allocator.alloc(Nlist64, cmd.nsyms); | ||
| 112 | defer allocator.free(syms); | ||
| 113 | try readNoEof(in, Nlist64, syms); | ||
| 114 | |||
| 115 | try file.seekTo(cmd.stroff); | ||
| 116 | var strings = try allocator.alloc(u8, cmd.strsize); | ||
| 117 | errdefer allocator.free(strings); | ||
| 118 | try in.stream.readNoEof(strings); | ||
| 119 | |||
| 120 | var nsyms: usize = 0; | ||
| 121 | for (syms) |sym| | ||
| 122 | if (isSymbol(sym)) nsyms += 1; | ||
| 123 | if (nsyms == 0) return error.MissingDebugInfo; | ||
| 124 | |||
| 125 | var symbols = try allocator.alloc(Symbol, nsyms + 1); // Room for sentinel. | ||
| 126 | errdefer allocator.free(symbols); | ||
| 127 | |||
| 128 | var pie_slide: usize = 0; | ||
| 129 | var nsym: usize = 0; | ||
| 130 | for (syms) |sym| { | ||
| 131 | if (!isSymbol(sym)) continue; | ||
| 132 | const start = sym.n_strx; | ||
| 133 | const end = mem.indexOfScalarPos(u8, strings, start, 0).?; | ||
| 134 | const name = strings[start..end]; | ||
| 135 | const address = sym.n_value; | ||
| 136 | symbols[nsym] = Symbol{ .name = name, .address = address }; | ||
| 137 | nsym += 1; | ||
| 138 | if (is_pie and mem.eql(u8, name, "_SymbolTable_deinit")) { | ||
| 139 | pie_slide = @ptrToInt(SymbolTable.deinit) - address; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | // Effectively a no-op, lld emits symbols in ascending order. | ||
| 144 | std.sort.sort(Symbol, symbols[0..nsyms], Symbol.addressLessThan); | ||
| 145 | |||
| 146 | // Insert the sentinel. Since we don't know where the last function ends, | ||
| 147 | // we arbitrarily limit it to the start address + 4 KB. | ||
| 148 | const top = symbols[nsyms - 1].address + 4096; | ||
| 149 | symbols[nsyms] = Symbol{ .name = "", .address = top }; | ||
| 150 | |||
| 151 | if (pie_slide != 0) { | ||
| 152 | for (symbols) |*symbol| | ||
| 153 | symbol.address += pie_slide; | ||
| 154 | } | ||
| 155 | |||
| 156 | return SymbolTable{ | ||
| 157 | .allocator = allocator, | ||
| 158 | .symbols = symbols, | ||
| 159 | .strings = strings, | ||
| 160 | }; | ||
| 161 | } | ||
| 162 | |||
| 163 | fn readNoEof(in: *io.FileInStream, comptime T: type, result: []T) !void { | ||
| 164 | return in.stream.readNoEof(@sliceToBytes(result)); | ||
| 165 | } | ||
| 166 | fn readOneNoEof(in: *io.FileInStream, comptime T: type, result: *T) !void { | ||
| 167 | return readNoEof(in, T, (*[1]T)(result)[0..]); | ||
| 168 | } | ||
| 169 | |||
| 170 | fn isSymbol(sym: *const Nlist64) bool { | ||
| 171 | return sym.n_value != 0 and sym.n_desc == 0; | ||
| 172 | } |
std/os/index.zig+29| ... | @@ -635,6 +635,35 @@ fn posixExecveErrnoToErr(err: usize) PosixExecveError { | ... | @@ -635,6 +635,35 @@ fn posixExecveErrnoToErr(err: usize) PosixExecveError { |
| 635 | pub var linux_aux_raw = []usize{0} ** 38; | 635 | pub var linux_aux_raw = []usize{0} ** 38; |
| 636 | pub var posix_environ_raw: [][*]u8 = undefined; | 636 | pub var posix_environ_raw: [][*]u8 = undefined; |
| 637 | 637 | ||
| 638 | /// See std.elf for the constants. | ||
| 639 | pub fn linuxGetAuxVal(index: usize) usize { | ||
| 640 | if (builtin.link_libc) { | ||
| 641 | return usize(std.c.getauxval(index)); | ||
| 642 | } else { | ||
| 643 | return linux_aux_raw[index]; | ||
| 644 | } | ||
| 645 | } | ||
| 646 | |||
| 647 | pub fn getBaseAddress() usize { | ||
| 648 | switch (builtin.os) { | ||
| 649 | builtin.Os.linux => { | ||
| 650 | const base = linuxGetAuxVal(std.elf.AT_BASE); | ||
| 651 | if (base != 0) { | ||
| 652 | return base; | ||
| 653 | } | ||
| 654 | const phdr = linuxGetAuxVal(std.elf.AT_PHDR); | ||
| 655 | const ElfHeader = switch (@sizeOf(usize)) { | ||
| 656 | 4 => std.elf.Elf32_Ehdr, | ||
| 657 | 8 => std.elf.Elf64_Ehdr, | ||
| 658 | else => @compileError("Unsupported architecture"), | ||
| 659 | }; | ||
| 660 | return phdr - @sizeOf(ElfHeader); | ||
| 661 | }, | ||
| 662 | builtin.Os.macosx => return @ptrToInt(&std.c._mh_execute_header), | ||
| 663 | else => @compileError("Unsupported OS"), | ||
| 664 | } | ||
| 665 | } | ||
| 666 | |||
| 638 | /// Caller must free result when done. | 667 | /// Caller must free result when done. |
| 639 | /// TODO make this go through libc when we have it | 668 | /// TODO make this go through libc when we have it |
| 640 | pub fn getEnvMap(allocator: *Allocator) !BufMap { | 669 | pub fn getEnvMap(allocator: *Allocator) !BufMap { |