| author | |
| committer | |
| log | 91ef68f9b1121d2a08f175a81f88321664c90a61 |
| tree | 73e2c9cf0b1f24b9855095757e65c4ac981517ef |
| parent | 9a4da6c8d8d55f47609b8e900e9a4bb1ac34d5e7 |
| parent | 70662830044418fc2d637c166fc100fe72d60fcf |
33 files changed, 6945 insertions(+), 4651 deletions(-)
CMakeLists.txt+1-1| ... | ... | @@ -339,7 +339,7 @@ set(ZIG_SOURCES |
| 339 | 339 | "${CMAKE_SOURCE_DIR}/src/target.cpp" |
| 340 | 340 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" |
| 341 | 341 | "${CMAKE_SOURCE_DIR}/src/util.cpp" |
| 342 | "${CMAKE_SOURCE_DIR}/src/parsec.cpp" | |
| 342 | "${CMAKE_SOURCE_DIR}/src/translate_c.cpp" | |
| 343 | 343 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" |
| 344 | 344 | ) |
| 345 | 345 |
build.zig+1-1| ... | ... | @@ -58,5 +58,5 @@ pub fn build(b: &Builder) { |
| 58 | 58 | test_step.dependOn(tests.addCompileErrorTests(b, test_filter)); |
| 59 | 59 | test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter)); |
| 60 | 60 | test_step.dependOn(tests.addDebugSafetyTests(b, test_filter)); |
| 61 | test_step.dependOn(tests.addParseCTests(b, test_filter)); | |
| 61 | test_step.dependOn(tests.addTranslateCTests(b, test_filter)); | |
| 62 | 62 | } |
ci/travis_osx_script+1-1| ... | ... | @@ -22,4 +22,4 @@ make install |
| 22 | 22 | ./zig build --build-file ../build.zig test-compile-errors --verbose |
| 23 | 23 | ./zig build --build-file ../build.zig test-asm-link --verbose |
| 24 | 24 | ./zig build --build-file ../build.zig test-debug-safety --verbose |
| 25 | ./zig build --build-file ../build.zig test-parsec --verbose | |
| 25 | ./zig build --build-file ../build.zig test-translate-c --verbose |
doc/home.html.in+6-2| ... | ... | @@ -70,10 +70,14 @@ |
| 70 | 70 | <li><a href="#mersenne">Mersenne Twister Random Number Generator</a></li> |
| 71 | 71 | </ul> |
| 72 | 72 | <h3 id="hello">Hello World</h3> |
| 73 | <pre><code class="zig">const io = @import("std").io; | |
| 73 | <pre><code class="zig">const std = @import("std"); | |
| 74 | 74 | |
| 75 | 75 | pub fn main() -&gt; %void { |
| 76 | %return io.stdout.printf("Hello, world!\n"); | |
| 76 | // If this program is run without stdout attached, exit with an error. | |
| 77 | var stdout_file = %return std.io.getStdOut(); | |
| 78 | // If this program encounters pipe failure when printing to stdout, exit | |
| 79 | // with an error. | |
| 80 | %return stdout_file.write("Hello, world!\n"); | |
| 77 | 81 | }</code></pre> |
| 78 | 82 | <p>Build this with:</p> |
| 79 | 83 | <pre>zig build-exe hello.zig</pre> |
doc/langref.html.in+15-4| ... | ... | @@ -75,6 +75,7 @@ |
| 75 | 75 | <li><a href="#slices">Slices</a></li> |
| 76 | 76 | <li><a href="#struct">struct</a></li> |
| 77 | 77 | <li><a href="#enum">enum</a></li> |
| 78 | <li><a href="#union">union</a></li> | |
| 78 | 79 | <li><a href="#switch">switch</a></li> |
| 79 | 80 | <li><a href="#while">while</a></li> |
| 80 | 81 | <li><a href="#for">for</a></li> |
| ... | ... | @@ -209,6 +210,7 @@ |
| 209 | 210 | <li><a href="#undef-invalid-error-code">Invalid Error Code</a></li> |
| 210 | 211 | <li><a href="#undef-invalid-enum-cast">Invalid Enum Cast</a></li> |
| 211 | 212 | <li><a href="#undef-incorrect-pointer-alignment">Incorrect Pointer Alignment</a></li> |
| 213 | <li><a href="#undef-bad-union-field">Wrong Union Field Access</a></li> | |
| 212 | 214 | </ul> |
| 213 | 215 | </li> |
| 214 | 216 | <li><a href="#memory">Memory</a></li> |
| ... | ... | @@ -2189,6 +2191,8 @@ Test 4/4 enum builtins...OK</code></pre> |
| 2189 | 2191 | <li><a href="#builtin-enumTagName">@enumTagName</a></li> |
| 2190 | 2192 | <li><a href="#builtin-memberCount">@memberCount</a></li> |
| 2191 | 2193 | </ul> |
| 2194 | <h2 id="union">union</h2> | |
| 2195 | <p>TODO union documentation</p> | |
| 2192 | 2196 | <h2 id="switch">switch</h2> |
| 2193 | 2197 | <pre><code class="zig">const assert = @import("std").debug.assert; |
| 2194 | 2198 | const builtin = @import("builtin"); |
| ... | ... | @@ -5117,6 +5121,9 @@ comptime { |
| 5117 | 5121 | <h3 id="undef-incorrect-pointer-alignment">Incorrect Pointer Alignment</h3> |
| 5118 | 5122 | <p>TODO</p> |
| 5119 | 5123 | |
| 5124 | <h3 id="undef-bad-union-field">Wrong Union Field Access</h3> | |
| 5125 | <p>TODO</p> | |
| 5126 | ||
| 5120 | 5127 | <h2 id="memory">Memory</h2> |
| 5121 | 5128 | <p>TODO: explain no default allocator in zig</p> |
| 5122 | 5129 | <p>TODO: show how to use the allocator interface</p> |
| ... | ... | @@ -5405,10 +5412,14 @@ const c = @cImport({ |
| 5405 | 5412 | export fn decode_base_64(dest_ptr: &amp;u8, dest_len: usize, |
| 5406 | 5413 | source_ptr: &amp;const u8, source_len: usize) -&gt; usize |
| 5407 | 5414 | { |
| 5408 | const src = source_ptr[0...source_len]; | |
| 5409 | const dest = dest_ptr[0...dest_len]; | |
| 5410 | return base64.decode(dest, src).len; | |
| 5411 | }</code></pre> | |
| 5415 | const src = source_ptr[0..source_len]; | |
| 5416 | const dest = dest_ptr[0..dest_len]; | |
| 5417 | const base64_decoder = base64.standard_decoder_unsafe; | |
| 5418 | const decoded_size = base64_decoder.calcSize(src); | |
| 5419 | base64_decoder.decode(dest[0..decoded_size], src); | |
| 5420 | return decoded_size; | |
| 5421 | } | |
| 5422 | </code></pre> | |
| 5412 | 5423 | <h4>test.c</h4> |
| 5413 | 5424 | <pre><code class="c">// This header is generated by zig from base64.zig |
| 5414 | 5425 | #include "base64.h" |
example/mix_o_files/base64.zig+4-1| ... | ... | @@ -3,5 +3,8 @@ const base64 = @import("std").base64; |
| 3 | 3 | export fn decode_base_64(dest_ptr: &u8, dest_len: usize, source_ptr: &const u8, source_len: usize) -> usize { |
| 4 | 4 | const src = source_ptr[0..source_len]; |
| 5 | 5 | const dest = dest_ptr[0..dest_len]; |
| 6 | return base64.decode(dest, src).len; | |
| 6 | const base64_decoder = base64.standard_decoder_unsafe; | |
| 7 | const decoded_size = base64_decoder.calcSize(src); | |
| 8 | base64_decoder.decode(dest[0..decoded_size], src); | |
| 9 | return decoded_size; | |
| 7 | 10 | } |
src-self-hosted/main.zig+1-1| ... | ... | @@ -208,7 +208,7 @@ fn printUsage(outstream: &io.OutStream) -> %void { |
| 208 | 208 | \\ build-exe [source] create executable from source or object files |
| 209 | 209 | \\ build-lib [source] create library from source or object files |
| 210 | 210 | \\ build-obj [source] create object from source or assembly |
| 211 | \\ parsec [source] convert c code to zig code | |
| 211 | \\ translate-c [source] convert c code to zig code | |
| 212 | 212 | \\ targets list available compilation targets |
| 213 | 213 | \\ test [source] create and run a test build |
| 214 | 214 | \\ version print version number and exit |
src/all_types.hpp+55-2| ... | ... | @@ -36,6 +36,7 @@ struct IrInstructionCast; |
| 36 | 36 | struct IrBasicBlock; |
| 37 | 37 | struct ScopeDecls; |
| 38 | 38 | struct ZigWindowsSDK; |
| 39 | struct Tld; | |
| 39 | 40 | |
| 40 | 41 | struct IrGotoItem { |
| 41 | 42 | AstNode *source_node; |
| ... | ... | @@ -59,7 +60,9 @@ struct IrExecutable { |
| 59 | 60 | Buf *c_import_buf; |
| 60 | 61 | AstNode *source_node; |
| 61 | 62 | IrExecutable *parent_exec; |
| 63 | IrExecutable *source_exec; | |
| 62 | 64 | Scope *begin_scope; |
| 65 | ZigList<Tld *> tld_list; | |
| 63 | 66 | }; |
| 64 | 67 | |
| 65 | 68 | enum OutType { |
| ... | ... | @@ -73,6 +76,7 @@ enum ConstParentId { |
| 73 | 76 | ConstParentIdNone, |
| 74 | 77 | ConstParentIdStruct, |
| 75 | 78 | ConstParentIdArray, |
| 79 | ConstParentIdUnion, | |
| 76 | 80 | }; |
| 77 | 81 | |
| 78 | 82 | struct ConstParent { |
| ... | ... | @@ -87,6 +91,9 @@ struct ConstParent { |
| 87 | 91 | ConstExprValue *struct_val; |
| 88 | 92 | size_t field_index; |
| 89 | 93 | } p_struct; |
| 94 | struct { | |
| 95 | ConstExprValue *union_val; | |
| 96 | } p_union; | |
| 90 | 97 | } data; |
| 91 | 98 | }; |
| 92 | 99 | |
| ... | ... | @@ -100,6 +107,12 @@ struct ConstStructValue { |
| 100 | 107 | ConstParent parent; |
| 101 | 108 | }; |
| 102 | 109 | |
| 110 | struct ConstUnionValue { | |
| 111 | uint64_t tag; | |
| 112 | ConstExprValue *payload; | |
| 113 | ConstParent parent; | |
| 114 | }; | |
| 115 | ||
| 103 | 116 | enum ConstArraySpecial { |
| 104 | 117 | ConstArraySpecialNone, |
| 105 | 118 | ConstArraySpecialUndef, |
| ... | ... | @@ -238,6 +251,7 @@ struct ConstExprValue { |
| 238 | 251 | ErrorTableEntry *x_pure_err; |
| 239 | 252 | ConstEnumValue x_enum; |
| 240 | 253 | ConstStructValue x_struct; |
| 254 | ConstUnionValue x_union; | |
| 241 | 255 | ConstArrayValue x_array; |
| 242 | 256 | ConstPtrValue x_ptr; |
| 243 | 257 | ImportTableEntry *x_import; |
| ... | ... | @@ -336,6 +350,13 @@ struct TypeEnumField { |
| 336 | 350 | uint32_t gen_index; |
| 337 | 351 | }; |
| 338 | 352 | |
| 353 | struct TypeUnionField { | |
| 354 | Buf *name; | |
| 355 | TypeTableEntry *type_entry; | |
| 356 | uint32_t value; | |
| 357 | uint32_t gen_index; | |
| 358 | }; | |
| 359 | ||
| 339 | 360 | enum NodeType { |
| 340 | 361 | NodeTypeRoot, |
| 341 | 362 | NodeTypeFnProto, |
| ... | ... | @@ -1021,14 +1042,19 @@ struct TypeTableEntryEnumTag { |
| 1021 | 1042 | LLVMValueRef name_table; |
| 1022 | 1043 | }; |
| 1023 | 1044 | |
| 1045 | uint32_t type_ptr_hash(const TypeTableEntry *ptr); | |
| 1046 | bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b); | |
| 1047 | ||
| 1024 | 1048 | struct TypeTableEntryUnion { |
| 1025 | 1049 | AstNode *decl_node; |
| 1026 | 1050 | ContainerLayout layout; |
| 1027 | 1051 | uint32_t src_field_count; |
| 1028 | 1052 | uint32_t gen_field_count; |
| 1029 | TypeStructField *fields; | |
| 1030 | uint64_t size_bytes; | |
| 1053 | TypeUnionField *fields; | |
| 1031 | 1054 | bool is_invalid; // true if any fields are invalid |
| 1055 | TypeTableEntry *tag_type; | |
| 1056 | LLVMTypeRef union_type_ref; | |
| 1057 | ||
| 1032 | 1058 | ScopeDecls *decls_scope; |
| 1033 | 1059 | |
| 1034 | 1060 | // set this flag temporarily to detect infinite loops |
| ... | ... | @@ -1039,6 +1065,13 @@ struct TypeTableEntryUnion { |
| 1039 | 1065 | |
| 1040 | 1066 | bool zero_bits_loop_flag; |
| 1041 | 1067 | bool zero_bits_known; |
| 1068 | uint32_t abi_alignment; // also figured out with zero_bits pass | |
| 1069 | ||
| 1070 | size_t gen_union_index; | |
| 1071 | size_t gen_tag_index; | |
| 1072 | ||
| 1073 | uint32_t union_size_bytes; | |
| 1074 | TypeTableEntry *most_aligned_union_member; | |
| 1042 | 1075 | }; |
| 1043 | 1076 | |
| 1044 | 1077 | struct FnGenParamInfo { |
| ... | ... | @@ -1287,6 +1320,7 @@ enum PanicMsgId { |
| 1287 | 1320 | PanicMsgIdUnwrapMaybeFail, |
| 1288 | 1321 | PanicMsgIdInvalidErrorCode, |
| 1289 | 1322 | PanicMsgIdIncorrectAlignment, |
| 1323 | PanicMsgIdBadUnionField, | |
| 1290 | 1324 | |
| 1291 | 1325 | PanicMsgIdCount, |
| 1292 | 1326 | }; |
| ... | ... | @@ -1796,6 +1830,7 @@ enum IrInstructionId { |
| 1796 | 1830 | IrInstructionIdFieldPtr, |
| 1797 | 1831 | IrInstructionIdStructFieldPtr, |
| 1798 | 1832 | IrInstructionIdEnumFieldPtr, |
| 1833 | IrInstructionIdUnionFieldPtr, | |
| 1799 | 1834 | IrInstructionIdElemPtr, |
| 1800 | 1835 | IrInstructionIdVarPtr, |
| 1801 | 1836 | IrInstructionIdCall, |
| ... | ... | @@ -1805,6 +1840,7 @@ enum IrInstructionId { |
| 1805 | 1840 | IrInstructionIdContainerInitList, |
| 1806 | 1841 | IrInstructionIdContainerInitFields, |
| 1807 | 1842 | IrInstructionIdStructInit, |
| 1843 | IrInstructionIdUnionInit, | |
| 1808 | 1844 | IrInstructionIdUnreachable, |
| 1809 | 1845 | IrInstructionIdTypeOf, |
| 1810 | 1846 | IrInstructionIdToPtrType, |
| ... | ... | @@ -2060,6 +2096,14 @@ struct IrInstructionEnumFieldPtr { |
| 2060 | 2096 | bool is_const; |
| 2061 | 2097 | }; |
| 2062 | 2098 | |
| 2099 | struct IrInstructionUnionFieldPtr { | |
| 2100 | IrInstruction base; | |
| 2101 | ||
| 2102 | IrInstruction *union_ptr; | |
| 2103 | TypeUnionField *field; | |
| 2104 | bool is_const; | |
| 2105 | }; | |
| 2106 | ||
| 2063 | 2107 | struct IrInstructionElemPtr { |
| 2064 | 2108 | IrInstruction base; |
| 2065 | 2109 | |
| ... | ... | @@ -2150,6 +2194,15 @@ struct IrInstructionStructInit { |
| 2150 | 2194 | LLVMValueRef tmp_ptr; |
| 2151 | 2195 | }; |
| 2152 | 2196 | |
| 2197 | struct IrInstructionUnionInit { | |
| 2198 | IrInstruction base; | |
| 2199 | ||
| 2200 | TypeTableEntry *union_type; | |
| 2201 | TypeUnionField *field; | |
| 2202 | IrInstruction *init_value; | |
| 2203 | LLVMValueRef tmp_ptr; | |
| 2204 | }; | |
| 2205 | ||
| 2153 | 2206 | struct IrInstructionUnreachable { |
| 2154 | 2207 | IrInstruction base; |
| 2155 | 2208 | }; |
src/analyze.cpp+334-9| ... | ... | @@ -28,7 +28,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type); |
| 28 | 28 | |
| 29 | 29 | ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { |
| 30 | 30 | if (node->owner->c_import_node != nullptr) { |
| 31 | // if this happens, then parsec generated code that | |
| 31 | // if this happens, then translate_c generated code that | |
| 32 | 32 | // failed semantic analysis, which isn't supposed to happen |
| 33 | 33 | ErrorMsg *err = add_node_error(g, node->owner->c_import_node, |
| 34 | 34 | buf_sprintf("compiler bug: @cImport generated invalid zig code")); |
| ... | ... | @@ -48,7 +48,7 @@ ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { |
| 48 | 48 | |
| 49 | 49 | ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) { |
| 50 | 50 | if (node->owner->c_import_node != nullptr) { |
| 51 | // if this happens, then parsec generated code that | |
| 51 | // if this happens, then translate_c generated code that | |
| 52 | 52 | // failed semantic analysis, which isn't supposed to happen |
| 53 | 53 | |
| 54 | 54 | Buf *note_path = buf_create_from_str("?.c"); |
| ... | ... | @@ -338,7 +338,7 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) { |
| 338 | 338 | TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const, |
| 339 | 339 | bool is_volatile, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count) |
| 340 | 340 | { |
| 341 | assert(child_type->id != TypeTableEntryIdInvalid); | |
| 341 | assert(!type_is_invalid(child_type)); | |
| 342 | 342 | |
| 343 | 343 | TypeId type_id = {}; |
| 344 | 344 | TypeTableEntry **parent_pointer = nullptr; |
| ... | ... | @@ -1008,11 +1008,12 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi |
| 1008 | 1008 | } |
| 1009 | 1009 | |
| 1010 | 1010 | size_t line = decl_node ? decl_node->line : 0; |
| 1011 | unsigned dwarf_kind = ZigLLVMTag_DW_structure_type(); | |
| 1011 | 1012 | |
| 1012 | 1013 | ImportTableEntry *import = get_scope_import(scope); |
| 1013 | 1014 | entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name); |
| 1014 | 1015 | entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, |
| 1015 | ZigLLVMTag_DW_structure_type(), name, | |
| 1016 | dwarf_kind, name, | |
| 1016 | 1017 | ZigLLVMFileToScope(import->di_file), import->di_file, (unsigned)(line + 1)); |
| 1017 | 1018 | |
| 1018 | 1019 | buf_init_from_str(&entry->name, name); |
| ... | ... | @@ -1285,7 +1286,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1285 | 1286 | return; |
| 1286 | 1287 | |
| 1287 | 1288 | resolve_enum_zero_bits(g, enum_type); |
| 1288 | if (enum_type->data.enumeration.is_invalid) | |
| 1289 | if (type_is_invalid(enum_type)) | |
| 1289 | 1290 | return; |
| 1290 | 1291 | |
| 1291 | 1292 | AstNode *decl_node = enum_type->data.enumeration.decl_node; |
| ... | ... | @@ -1834,7 +1835,246 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 1834 | 1835 | } |
| 1835 | 1836 | |
| 1836 | 1837 | static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 1837 | zig_panic("TODO"); | |
| 1838 | assert(union_type->id == TypeTableEntryIdUnion); | |
| 1839 | ||
| 1840 | if (union_type->data.unionation.complete) | |
| 1841 | return; | |
| 1842 | ||
| 1843 | resolve_union_zero_bits(g, union_type); | |
| 1844 | if (type_is_invalid(union_type)) | |
| 1845 | return; | |
| 1846 | ||
| 1847 | AstNode *decl_node = union_type->data.unionation.decl_node; | |
| 1848 | ||
| 1849 | if (union_type->data.unionation.embedded_in_current) { | |
| 1850 | if (!union_type->data.unionation.reported_infinite_err) { | |
| 1851 | union_type->data.unionation.reported_infinite_err = true; | |
| 1852 | add_node_error(g, decl_node, buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name))); | |
| 1853 | } | |
| 1854 | return; | |
| 1855 | } | |
| 1856 | ||
| 1857 | assert(!union_type->data.unionation.zero_bits_loop_flag); | |
| 1858 | assert(decl_node->type == NodeTypeContainerDecl); | |
| 1859 | assert(union_type->di_type); | |
| 1860 | ||
| 1861 | uint32_t field_count = union_type->data.unionation.src_field_count; | |
| 1862 | ||
| 1863 | assert(union_type->data.unionation.fields); | |
| 1864 | ||
| 1865 | uint32_t gen_field_count = union_type->data.unionation.gen_field_count; | |
| 1866 | ZigLLVMDIType **union_inner_di_types = allocate<ZigLLVMDIType*>(gen_field_count); | |
| 1867 | ||
| 1868 | TypeTableEntry *most_aligned_union_member = nullptr; | |
| 1869 | uint64_t size_of_most_aligned_member_in_bits = 0; | |
| 1870 | uint64_t biggest_align_in_bits = 0; | |
| 1871 | uint64_t biggest_size_in_bits = 0; | |
| 1872 | ||
| 1873 | bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto); | |
| 1874 | ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count); | |
| 1875 | ||
| 1876 | Scope *scope = &union_type->data.unionation.decls_scope->base; | |
| 1877 | ImportTableEntry *import = get_scope_import(scope); | |
| 1878 | ||
| 1879 | // set temporary flag | |
| 1880 | union_type->data.unionation.embedded_in_current = true; | |
| 1881 | ||
| 1882 | for (uint32_t i = 0; i < field_count; i += 1) { | |
| 1883 | AstNode *field_node = decl_node->data.container_decl.fields.at(i); | |
| 1884 | TypeUnionField *type_union_field = &union_type->data.unionation.fields[i]; | |
| 1885 | TypeTableEntry *field_type = type_union_field->type_entry; | |
| 1886 | ||
| 1887 | ensure_complete_type(g, field_type); | |
| 1888 | if (type_is_invalid(field_type)) { | |
| 1889 | union_type->data.unionation.is_invalid = true; | |
| 1890 | continue; | |
| 1891 | } | |
| 1892 | ||
| 1893 | if (!type_has_bits(field_type)) | |
| 1894 | continue; | |
| 1895 | ||
| 1896 | di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(type_union_field->name), i); | |
| 1897 | ||
| 1898 | uint64_t store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref); | |
| 1899 | uint64_t abi_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref); | |
| 1900 | ||
| 1901 | assert(store_size_in_bits > 0); | |
| 1902 | assert(abi_align_in_bits > 0); | |
| 1903 | ||
| 1904 | union_inner_di_types[type_union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, | |
| 1905 | ZigLLVMTypeToScope(union_type->di_type), buf_ptr(type_union_field->name), | |
| 1906 | import->di_file, (unsigned)(field_node->line + 1), | |
| 1907 | store_size_in_bits, | |
| 1908 | abi_align_in_bits, | |
| 1909 | 0, | |
| 1910 | 0, field_type->di_type); | |
| 1911 | ||
| 1912 | biggest_size_in_bits = max(biggest_size_in_bits, store_size_in_bits); | |
| 1913 | ||
| 1914 | if (!most_aligned_union_member || abi_align_in_bits > biggest_align_in_bits) { | |
| 1915 | most_aligned_union_member = field_type; | |
| 1916 | biggest_align_in_bits = abi_align_in_bits; | |
| 1917 | size_of_most_aligned_member_in_bits = store_size_in_bits; | |
| 1918 | } | |
| 1919 | } | |
| 1920 | ||
| 1921 | // unset temporary flag | |
| 1922 | union_type->data.unionation.embedded_in_current = false; | |
| 1923 | union_type->data.unionation.complete = true; | |
| 1924 | union_type->data.unionation.union_size_bytes = biggest_size_in_bits / 8; | |
| 1925 | union_type->data.unionation.most_aligned_union_member = most_aligned_union_member; | |
| 1926 | ||
| 1927 | if (union_type->data.unionation.is_invalid) | |
| 1928 | return; | |
| 1929 | ||
| 1930 | if (union_type->zero_bits) { | |
| 1931 | union_type->type_ref = LLVMVoidType(); | |
| 1932 | ||
| 1933 | uint64_t debug_size_in_bits = 0; | |
| 1934 | uint64_t debug_align_in_bits = 0; | |
| 1935 | ZigLLVMDIType **di_root_members = nullptr; | |
| 1936 | size_t debug_member_count = 0; | |
| 1937 | ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, | |
| 1938 | ZigLLVMFileToScope(import->di_file), | |
| 1939 | buf_ptr(&union_type->name), | |
| 1940 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1941 | debug_size_in_bits, | |
| 1942 | debug_align_in_bits, | |
| 1943 | 0, di_root_members, (int)debug_member_count, 0, ""); | |
| 1944 | ||
| 1945 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type); | |
| 1946 | union_type->di_type = replacement_di_type; | |
| 1947 | return; | |
| 1948 | } | |
| 1949 | ||
| 1950 | assert(most_aligned_union_member != nullptr); | |
| 1951 | ||
| 1952 | bool want_safety = auto_layout && (field_count >= 2); | |
| 1953 | uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits; | |
| 1954 | ||
| 1955 | ||
| 1956 | if (!want_safety) { | |
| 1957 | if (padding_in_bits > 0) { | |
| 1958 | TypeTableEntry *u8_type = get_int_type(g, false, 8); | |
| 1959 | TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8); | |
| 1960 | LLVMTypeRef union_element_types[] = { | |
| 1961 | most_aligned_union_member->type_ref, | |
| 1962 | padding_array->type_ref, | |
| 1963 | }; | |
| 1964 | LLVMStructSetBody(union_type->type_ref, union_element_types, 2, false); | |
| 1965 | } else { | |
| 1966 | LLVMStructSetBody(union_type->type_ref, &most_aligned_union_member->type_ref, 1, false); | |
| 1967 | } | |
| 1968 | union_type->data.unionation.union_type_ref = union_type->type_ref; | |
| 1969 | union_type->data.unionation.gen_tag_index = SIZE_MAX; | |
| 1970 | union_type->data.unionation.gen_union_index = SIZE_MAX; | |
| 1971 | ||
| 1972 | assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type->type_ref) >= biggest_align_in_bits); | |
| 1973 | assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref) >= biggest_size_in_bits); | |
| 1974 | ||
| 1975 | // create debug type for union | |
| 1976 | ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, | |
| 1977 | ZigLLVMFileToScope(import->di_file), buf_ptr(&union_type->name), | |
| 1978 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1979 | biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types, | |
| 1980 | gen_field_count, 0, ""); | |
| 1981 | ||
| 1982 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type); | |
| 1983 | union_type->di_type = replacement_di_type; | |
| 1984 | return; | |
| 1985 | } | |
| 1986 | ||
| 1987 | LLVMTypeRef union_type_ref; | |
| 1988 | if (padding_in_bits > 0) { | |
| 1989 | TypeTableEntry *u8_type = get_int_type(g, false, 8); | |
| 1990 | TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8); | |
| 1991 | LLVMTypeRef union_element_types[] = { | |
| 1992 | most_aligned_union_member->type_ref, | |
| 1993 | padding_array->type_ref, | |
| 1994 | }; | |
| 1995 | union_type_ref = LLVMStructType(union_element_types, 2, false); | |
| 1996 | } else { | |
| 1997 | union_type_ref = most_aligned_union_member->type_ref; | |
| 1998 | } | |
| 1999 | union_type->data.unionation.union_type_ref = union_type_ref; | |
| 2000 | ||
| 2001 | assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits); | |
| 2002 | assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits); | |
| 2003 | ||
| 2004 | // create llvm type for root struct | |
| 2005 | TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1); | |
| 2006 | TypeTableEntry *tag_type_entry = tag_int_type; | |
| 2007 | union_type->data.unionation.tag_type = tag_type_entry; | |
| 2008 | uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref); | |
| 2009 | ||
| 2010 | if (align_of_tag_in_bits >= biggest_align_in_bits) { | |
| 2011 | union_type->data.unionation.gen_tag_index = 0; | |
| 2012 | union_type->data.unionation.gen_union_index = 1; | |
| 2013 | } else { | |
| 2014 | union_type->data.unionation.gen_union_index = 0; | |
| 2015 | union_type->data.unionation.gen_tag_index = 1; | |
| 2016 | } | |
| 2017 | ||
| 2018 | LLVMTypeRef root_struct_element_types[2]; | |
| 2019 | root_struct_element_types[union_type->data.unionation.gen_tag_index] = tag_type_entry->type_ref; | |
| 2020 | root_struct_element_types[union_type->data.unionation.gen_union_index] = union_type_ref; | |
| 2021 | LLVMStructSetBody(union_type->type_ref, root_struct_element_types, 2, false); | |
| 2022 | ||
| 2023 | ||
| 2024 | // create debug type for root struct | |
| 2025 | ||
| 2026 | // create debug type for tag | |
| 2027 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref); | |
| 2028 | uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref); | |
| 2029 | ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, | |
| 2030 | ZigLLVMTypeToScope(union_type->di_type), "AnonEnum", | |
| 2031 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 2032 | tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count, | |
| 2033 | tag_type_entry->di_type, ""); | |
| 2034 | ||
| 2035 | // create debug type for union | |
| 2036 | ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, | |
| 2037 | ZigLLVMTypeToScope(union_type->di_type), "AnonUnion", | |
| 2038 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 2039 | biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types, | |
| 2040 | gen_field_count, 0, ""); | |
| 2041 | ||
| 2042 | uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->type_ref, | |
| 2043 | union_type->data.unionation.gen_union_index); | |
| 2044 | uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->type_ref, | |
| 2045 | union_type->data.unionation.gen_tag_index); | |
| 2046 | ||
| 2047 | ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, | |
| 2048 | ZigLLVMTypeToScope(union_type->di_type), "union_field", | |
| 2049 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 2050 | biggest_size_in_bits, | |
| 2051 | biggest_align_in_bits, | |
| 2052 | union_offset_in_bits, | |
| 2053 | 0, union_di_type); | |
| 2054 | ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, | |
| 2055 | ZigLLVMTypeToScope(union_type->di_type), "tag_field", | |
| 2056 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 2057 | tag_debug_size_in_bits, | |
| 2058 | tag_debug_align_in_bits, | |
| 2059 | tag_offset_in_bits, | |
| 2060 | 0, tag_di_type); | |
| 2061 | ||
| 2062 | ZigLLVMDIType *di_root_members[2]; | |
| 2063 | di_root_members[union_type->data.unionation.gen_tag_index] = tag_member_di_type; | |
| 2064 | di_root_members[union_type->data.unionation.gen_union_index] = union_member_di_type; | |
| 2065 | ||
| 2066 | uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref); | |
| 2067 | uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, union_type->type_ref); | |
| 2068 | ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, | |
| 2069 | ZigLLVMFileToScope(import->di_file), | |
| 2070 | buf_ptr(&union_type->name), | |
| 2071 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 2072 | debug_size_in_bits, | |
| 2073 | debug_align_in_bits, | |
| 2074 | 0, nullptr, di_root_members, 2, 0, nullptr, ""); | |
| 2075 | ||
| 2076 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type); | |
| 2077 | union_type->di_type = replacement_di_type; | |
| 1838 | 2078 | } |
| 1839 | 2079 | |
| 1840 | 2080 | static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { |
| ... | ... | @@ -1873,7 +2113,7 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { |
| 1873 | 2113 | type_enum_field->value = i; |
| 1874 | 2114 | |
| 1875 | 2115 | type_ensure_zero_bits_known(g, field_type); |
| 1876 | if (field_type->id == TypeTableEntryIdInvalid) { | |
| 2116 | if (type_is_invalid(field_type)) { | |
| 1877 | 2117 | enum_type->data.enumeration.is_invalid = true; |
| 1878 | 2118 | continue; |
| 1879 | 2119 | } |
| ... | ... | @@ -1980,7 +2220,69 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { |
| 1980 | 2220 | } |
| 1981 | 2221 | |
| 1982 | 2222 | static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 1983 | zig_panic("TODO resolve_union_zero_bits"); | |
| 2223 | assert(union_type->id == TypeTableEntryIdUnion); | |
| 2224 | ||
| 2225 | if (union_type->data.unionation.zero_bits_known) | |
| 2226 | return; | |
| 2227 | ||
| 2228 | if (union_type->data.unionation.zero_bits_loop_flag) { | |
| 2229 | union_type->data.unionation.zero_bits_known = true; | |
| 2230 | return; | |
| 2231 | } | |
| 2232 | ||
| 2233 | union_type->data.unionation.zero_bits_loop_flag = true; | |
| 2234 | ||
| 2235 | AstNode *decl_node = union_type->data.unionation.decl_node; | |
| 2236 | assert(decl_node->type == NodeTypeContainerDecl); | |
| 2237 | assert(union_type->di_type); | |
| 2238 | ||
| 2239 | assert(!union_type->data.unionation.fields); | |
| 2240 | uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; | |
| 2241 | union_type->data.unionation.src_field_count = field_count; | |
| 2242 | union_type->data.unionation.fields = allocate<TypeUnionField>(field_count); | |
| 2243 | ||
| 2244 | uint32_t biggest_align_bytes = 0; | |
| 2245 | ||
| 2246 | Scope *scope = &union_type->data.unionation.decls_scope->base; | |
| 2247 | ||
| 2248 | uint32_t gen_field_index = 0; | |
| 2249 | for (uint32_t i = 0; i < field_count; i += 1) { | |
| 2250 | AstNode *field_node = decl_node->data.container_decl.fields.at(i); | |
| 2251 | TypeUnionField *type_union_field = &union_type->data.unionation.fields[i]; | |
| 2252 | type_union_field->name = field_node->data.struct_field.name; | |
| 2253 | TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); | |
| 2254 | type_union_field->type_entry = field_type; | |
| 2255 | type_union_field->value = i; | |
| 2256 | ||
| 2257 | type_ensure_zero_bits_known(g, field_type); | |
| 2258 | if (type_is_invalid(field_type)) { | |
| 2259 | union_type->data.unionation.is_invalid = true; | |
| 2260 | continue; | |
| 2261 | } | |
| 2262 | ||
| 2263 | if (!type_has_bits(field_type)) | |
| 2264 | continue; | |
| 2265 | ||
| 2266 | type_union_field->gen_index = gen_field_index; | |
| 2267 | gen_field_index += 1; | |
| 2268 | ||
| 2269 | uint32_t field_align_bytes = get_abi_alignment(g, field_type); | |
| 2270 | if (field_align_bytes > biggest_align_bytes) { | |
| 2271 | biggest_align_bytes = field_align_bytes; | |
| 2272 | } | |
| 2273 | } | |
| 2274 | ||
| 2275 | bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto); | |
| 2276 | ||
| 2277 | union_type->data.unionation.zero_bits_loop_flag = false; | |
| 2278 | union_type->data.unionation.gen_field_count = gen_field_index; | |
| 2279 | union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !auto_layout)); | |
| 2280 | union_type->data.unionation.zero_bits_known = true; | |
| 2281 | ||
| 2282 | // also compute abi_alignment | |
| 2283 | if (!union_type->zero_bits) { | |
| 2284 | union_type->data.unionation.abi_alignment = biggest_align_bytes; | |
| 2285 | } | |
| 1984 | 2286 | } |
| 1985 | 2287 | |
| 1986 | 2288 | static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) { |
| ... | ... | @@ -2851,6 +3153,18 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) { |
| 2851 | 3153 | return nullptr; |
| 2852 | 3154 | } |
| 2853 | 3155 | |
| 3156 | TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) { | |
| 3157 | assert(type_entry->id == TypeTableEntryIdUnion); | |
| 3158 | assert(type_entry->data.unionation.complete); | |
| 3159 | for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { | |
| 3160 | TypeUnionField *field = &type_entry->data.unionation.fields[i]; | |
| 3161 | if (buf_eql_buf(field->name, name)) { | |
| 3162 | return field; | |
| 3163 | } | |
| 3164 | } | |
| 3165 | return nullptr; | |
| 3166 | } | |
| 3167 | ||
| 2854 | 3168 | static bool is_container(TypeTableEntry *type_entry) { |
| 2855 | 3169 | switch (type_entry->id) { |
| 2856 | 3170 | case TypeTableEntryIdInvalid: |
| ... | ... | @@ -4703,6 +5017,8 @@ ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { |
| 4703 | 5017 | return &value->data.x_array.s_none.parent; |
| 4704 | 5018 | } else if (type_entry->id == TypeTableEntryIdStruct) { |
| 4705 | 5019 | return &value->data.x_struct.parent; |
| 5020 | } else if (type_entry->id == TypeTableEntryIdUnion) { | |
| 5021 | return &value->data.x_union.parent; | |
| 4706 | 5022 | } |
| 4707 | 5023 | return nullptr; |
| 4708 | 5024 | } |
| ... | ... | @@ -4914,7 +5230,8 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) { |
| 4914 | 5230 | assert(type_entry->data.enumeration.abi_alignment != 0); |
| 4915 | 5231 | return type_entry->data.enumeration.abi_alignment; |
| 4916 | 5232 | } else if (type_entry->id == TypeTableEntryIdUnion) { |
| 4917 | zig_panic("TODO"); | |
| 5233 | assert(type_entry->data.unionation.abi_alignment != 0); | |
| 5234 | return type_entry->data.unionation.abi_alignment; | |
| 4918 | 5235 | } else if (type_entry->id == TypeTableEntryIdOpaque) { |
| 4919 | 5236 | return 1; |
| 4920 | 5237 | } else { |
| ... | ... | @@ -4929,3 +5246,11 @@ TypeTableEntry *get_align_amt_type(CodeGen *g) { |
| 4929 | 5246 | } |
| 4930 | 5247 | return g->align_amt_type; |
| 4931 | 5248 | } |
| 5249 | ||
| 5250 | uint32_t type_ptr_hash(const TypeTableEntry *ptr) { | |
| 5251 | return hash_ptr((void*)ptr); | |
| 5252 | } | |
| 5253 | ||
| 5254 | bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) { | |
| 5255 | return a == b; | |
| 5256 | } |
src/analyze.hpp+1| ... | ... | @@ -63,6 +63,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry); |
| 63 | 63 | TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name); |
| 64 | 64 | ScopeDecls *get_container_scope(TypeTableEntry *type_entry); |
| 65 | 65 | TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name); |
| 66 | TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name); | |
| 66 | 67 | bool is_container_ref(TypeTableEntry *type_entry); |
| 67 | 68 | void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); |
| 68 | 69 | void scan_import(CodeGen *g, ImportTableEntry *import); |
src/c_tokenizer.cpp+5-3| ... | ... | @@ -120,6 +120,7 @@ static void begin_token(CTokenize *ctok, CTokId id) { |
| 120 | 120 | case CTokIdLParen: |
| 121 | 121 | case CTokIdRParen: |
| 122 | 122 | case CTokIdEOF: |
| 123 | case CTokIdDot: | |
| 123 | 124 | break; |
| 124 | 125 | } |
| 125 | 126 | } |
| ... | ... | @@ -216,9 +217,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { |
| 216 | 217 | buf_append_char(&ctok->buf, '0'); |
| 217 | 218 | break; |
| 218 | 219 | case '.': |
| 219 | begin_token(ctok, CTokIdNumLitFloat); | |
| 220 | ctok->state = CTokStateFloat; | |
| 221 | buf_init_from_str(&ctok->buf, "0."); | |
| 220 | begin_token(ctok, CTokIdDot); | |
| 221 | end_token(ctok); | |
| 222 | 222 | break; |
| 223 | 223 | case '(': |
| 224 | 224 | begin_token(ctok, CTokIdLParen); |
| ... | ... | @@ -238,6 +238,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { |
| 238 | 238 | break; |
| 239 | 239 | case CTokStateFloat: |
| 240 | 240 | switch (*c) { |
| 241 | case '.': | |
| 242 | break; | |
| 241 | 243 | case 'e': |
| 242 | 244 | case 'E': |
| 243 | 245 | buf_append_char(&ctok->buf, 'e'); |
src/c_tokenizer.hpp+1| ... | ... | @@ -21,6 +21,7 @@ enum CTokId { |
| 21 | 21 | CTokIdLParen, |
| 22 | 22 | CTokIdRParen, |
| 23 | 23 | CTokIdEOF, |
| 24 | CTokIdDot, | |
| 24 | 25 | }; |
| 25 | 26 | |
| 26 | 27 | enum CNumLitSuffix { |
src/codegen.cpp+155-6| ... | ... | @@ -15,7 +15,7 @@ |
| 15 | 15 | #include "ir.hpp" |
| 16 | 16 | #include "link.hpp" |
| 17 | 17 | #include "os.hpp" |
| 18 | #include "parsec.hpp" | |
| 18 | #include "translate_c.hpp" | |
| 19 | 19 | #include "target.hpp" |
| 20 | 20 | #include "zig_llvm.hpp" |
| 21 | 21 | |
| ... | ... | @@ -810,6 +810,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { |
| 810 | 810 | return buf_create_from_str("invalid error code"); |
| 811 | 811 | case PanicMsgIdIncorrectAlignment: |
| 812 | 812 | return buf_create_from_str("incorrect alignment"); |
| 813 | case PanicMsgIdBadUnionField: | |
| 814 | return buf_create_from_str("access of inactive union field"); | |
| 813 | 815 | } |
| 814 | 816 | zig_unreachable(); |
| 815 | 817 | } |
| ... | ... | @@ -2393,6 +2395,50 @@ static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executabl |
| 2393 | 2395 | return bitcasted_union_field_ptr; |
| 2394 | 2396 | } |
| 2395 | 2397 | |
| 2398 | static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executable, | |
| 2399 | IrInstructionUnionFieldPtr *instruction) | |
| 2400 | { | |
| 2401 | TypeTableEntry *union_ptr_type = instruction->union_ptr->value.type; | |
| 2402 | assert(union_ptr_type->id == TypeTableEntryIdPointer); | |
| 2403 | TypeTableEntry *union_type = union_ptr_type->data.pointer.child_type; | |
| 2404 | assert(union_type->id == TypeTableEntryIdUnion); | |
| 2405 | ||
| 2406 | TypeUnionField *field = instruction->field; | |
| 2407 | ||
| 2408 | if (!type_has_bits(field->type_entry)) | |
| 2409 | return nullptr; | |
| 2410 | ||
| 2411 | LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr); | |
| 2412 | LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0); | |
| 2413 | ||
| 2414 | if (union_type->data.unionation.gen_tag_index == SIZE_MAX) { | |
| 2415 | LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, 0, ""); | |
| 2416 | LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); | |
| 2417 | return bitcasted_union_field_ptr; | |
| 2418 | } | |
| 2419 | ||
| 2420 | if (ir_want_debug_safety(g, &instruction->base)) { | |
| 2421 | LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_tag_index, ""); | |
| 2422 | LLVMValueRef tag_value = gen_load_untyped(g, tag_field_ptr, 0, false, ""); | |
| 2423 | LLVMValueRef expected_tag_value = LLVMConstInt(union_type->data.unionation.tag_type->type_ref, | |
| 2424 | field->value, false); | |
| 2425 | ||
| 2426 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckOk"); | |
| 2427 | LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckFail"); | |
| 2428 | LLVMValueRef ok_val = LLVMBuildICmp(g->builder, LLVMIntEQ, tag_value, expected_tag_value, ""); | |
| 2429 | LLVMBuildCondBr(g->builder, ok_val, ok_block, bad_block); | |
| 2430 | ||
| 2431 | LLVMPositionBuilderAtEnd(g->builder, bad_block); | |
| 2432 | gen_debug_safety_crash(g, PanicMsgIdBadUnionField); | |
| 2433 | ||
| 2434 | LLVMPositionBuilderAtEnd(g->builder, ok_block); | |
| 2435 | } | |
| 2436 | ||
| 2437 | LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_union_index, ""); | |
| 2438 | LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); | |
| 2439 | return bitcasted_union_field_ptr; | |
| 2440 | } | |
| 2441 | ||
| 2396 | 2442 | static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) { |
| 2397 | 2443 | const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2; |
| 2398 | 2444 | size_t len = tok->end - tok->start - 2; |
| ... | ... | @@ -3365,6 +3411,42 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, |
| 3365 | 3411 | return instruction->tmp_ptr; |
| 3366 | 3412 | } |
| 3367 | 3413 | |
| 3414 | static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, IrInstructionUnionInit *instruction) { | |
| 3415 | TypeUnionField *type_union_field = instruction->field; | |
| 3416 | ||
| 3417 | if (!type_has_bits(type_union_field->type_entry)) | |
| 3418 | return nullptr; | |
| 3419 | ||
| 3420 | uint32_t field_align_bytes = get_abi_alignment(g, type_union_field->type_entry); | |
| 3421 | TypeTableEntry *ptr_type = get_pointer_to_type_extra(g, type_union_field->type_entry, | |
| 3422 | false, false, field_align_bytes, | |
| 3423 | 0, 0); | |
| 3424 | ||
| 3425 | LLVMValueRef uncasted_union_ptr; | |
| 3426 | // Even if safety is off in this block, if the union type has the safety field, we have to populate it | |
| 3427 | // correctly. Otherwise safety code somewhere other than here could fail. | |
| 3428 | TypeTableEntry *union_type = instruction->union_type; | |
| 3429 | if (union_type->data.unionation.gen_tag_index != SIZE_MAX) { | |
| 3430 | LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, | |
| 3431 | union_type->data.unionation.gen_tag_index, ""); | |
| 3432 | LLVMValueRef tag_value = LLVMConstInt(union_type->data.unionation.tag_type->type_ref, | |
| 3433 | type_union_field->value, false); | |
| 3434 | gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); | |
| 3435 | ||
| 3436 | uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, | |
| 3437 | (unsigned)union_type->data.unionation.gen_union_index, ""); | |
| 3438 | } else { | |
| 3439 | uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, (unsigned)0, ""); | |
| 3440 | } | |
| 3441 | ||
| 3442 | LLVMValueRef field_ptr = LLVMBuildBitCast(g->builder, uncasted_union_ptr, ptr_type->type_ref, ""); | |
| 3443 | LLVMValueRef value = ir_llvm_value(g, instruction->init_value); | |
| 3444 | ||
| 3445 | gen_assign_raw(g, field_ptr, ptr_type, value); | |
| 3446 | ||
| 3447 | return instruction->tmp_ptr; | |
| 3448 | } | |
| 3449 | ||
| 3368 | 3450 | static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable, |
| 3369 | 3451 | IrInstructionContainerInitList *instruction) |
| 3370 | 3452 | { |
| ... | ... | @@ -3486,6 +3568,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3486 | 3568 | return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction); |
| 3487 | 3569 | case IrInstructionIdEnumFieldPtr: |
| 3488 | 3570 | return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction); |
| 3571 | case IrInstructionIdUnionFieldPtr: | |
| 3572 | return ir_render_union_field_ptr(g, executable, (IrInstructionUnionFieldPtr *)instruction); | |
| 3489 | 3573 | case IrInstructionIdAsm: |
| 3490 | 3574 | return ir_render_asm(g, executable, (IrInstructionAsm *)instruction); |
| 3491 | 3575 | case IrInstructionIdTestNonNull: |
| ... | ... | @@ -3544,6 +3628,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3544 | 3628 | return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction); |
| 3545 | 3629 | case IrInstructionIdStructInit: |
| 3546 | 3630 | return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); |
| 3631 | case IrInstructionIdUnionInit: | |
| 3632 | return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); | |
| 3547 | 3633 | case IrInstructionIdPtrCast: |
| 3548 | 3634 | return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction); |
| 3549 | 3635 | case IrInstructionIdBitCast: |
| ... | ... | @@ -3595,6 +3681,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) { |
| 3595 | 3681 | |
| 3596 | 3682 | static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index); |
| 3597 | 3683 | static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index); |
| 3684 | static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *array_const_val); | |
| 3598 | 3685 | |
| 3599 | 3686 | static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) { |
| 3600 | 3687 | switch (parent->id) { |
| ... | ... | @@ -3608,6 +3695,8 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent |
| 3608 | 3695 | case ConstParentIdArray: |
| 3609 | 3696 | return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val, |
| 3610 | 3697 | parent->data.p_array.elem_index); |
| 3698 | case ConstParentIdUnion: | |
| 3699 | return gen_const_ptr_union_recursive(g, parent->data.p_union.union_val); | |
| 3611 | 3700 | } |
| 3612 | 3701 | zig_unreachable(); |
| 3613 | 3702 | } |
| ... | ... | @@ -3637,6 +3726,18 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s |
| 3637 | 3726 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); |
| 3638 | 3727 | } |
| 3639 | 3728 | |
| 3729 | static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val) { | |
| 3730 | ConstParent *parent = &union_const_val->data.x_union.parent; | |
| 3731 | LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent); | |
| 3732 | ||
| 3733 | TypeTableEntry *u32 = g->builtin_types.entry_u32; | |
| 3734 | LLVMValueRef indices[] = { | |
| 3735 | LLVMConstNull(u32->type_ref), | |
| 3736 | LLVMConstInt(u32->type_ref, 0, false), | |
| 3737 | }; | |
| 3738 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); | |
| 3739 | } | |
| 3740 | ||
| 3640 | 3741 | static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) { |
| 3641 | 3742 | switch (const_val->special) { |
| 3642 | 3743 | case ConstValSpecialRuntime: |
| ... | ... | @@ -3872,10 +3973,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3872 | 3973 | return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count); |
| 3873 | 3974 | } |
| 3874 | 3975 | } |
| 3875 | case TypeTableEntryIdUnion: | |
| 3876 | { | |
| 3877 | zig_panic("TODO"); | |
| 3878 | } | |
| 3879 | 3976 | case TypeTableEntryIdArray: |
| 3880 | 3977 | { |
| 3881 | 3978 | uint64_t len = type_entry->data.array.len; |
| ... | ... | @@ -3898,6 +3995,55 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3898 | 3995 | return LLVMConstArray(element_type_ref, values, (unsigned)len); |
| 3899 | 3996 | } |
| 3900 | 3997 | } |
| 3998 | case TypeTableEntryIdUnion: | |
| 3999 | { | |
| 4000 | LLVMTypeRef union_type_ref = type_entry->data.unionation.union_type_ref; | |
| 4001 | ConstExprValue *payload_value = const_val->data.x_union.payload; | |
| 4002 | assert(payload_value != nullptr); | |
| 4003 | ||
| 4004 | if (!type_has_bits(payload_value->type)) { | |
| 4005 | return LLVMGetUndef(union_type_ref); | |
| 4006 | } | |
| 4007 | ||
| 4008 | uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref); | |
| 4009 | uint64_t pad_bytes = type_entry->data.unionation.union_size_bytes - field_type_bytes; | |
| 4010 | LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value); | |
| 4011 | bool make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) || | |
| 4012 | payload_value->type != type_entry->data.unionation.most_aligned_union_member; | |
| 4013 | ||
| 4014 | LLVMValueRef union_value_ref; | |
| 4015 | { | |
| 4016 | if (pad_bytes == 0) { | |
| 4017 | union_value_ref = correctly_typed_value; | |
| 4018 | } else { | |
| 4019 | LLVMValueRef fields[2]; | |
| 4020 | fields[0] = correctly_typed_value; | |
| 4021 | fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes)); | |
| 4022 | if (make_unnamed_struct || type_entry->data.unionation.gen_tag_index != SIZE_MAX) { | |
| 4023 | union_value_ref = LLVMConstStruct(fields, 2, false); | |
| 4024 | } else { | |
| 4025 | union_value_ref = LLVMConstNamedStruct(union_type_ref, fields, 2); | |
| 4026 | } | |
| 4027 | } | |
| 4028 | } | |
| 4029 | ||
| 4030 | if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) { | |
| 4031 | return union_value_ref; | |
| 4032 | } | |
| 4033 | ||
| 4034 | LLVMValueRef tag_value = LLVMConstInt(type_entry->data.unionation.tag_type->type_ref, const_val->data.x_union.tag, false); | |
| 4035 | ||
| 4036 | LLVMValueRef fields[2]; | |
| 4037 | fields[type_entry->data.unionation.gen_union_index] = union_value_ref; | |
| 4038 | fields[type_entry->data.unionation.gen_tag_index] = tag_value; | |
| 4039 | ||
| 4040 | if (make_unnamed_struct) { | |
| 4041 | return LLVMConstStruct(fields, 2, false); | |
| 4042 | } else { | |
| 4043 | return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); | |
| 4044 | } | |
| 4045 | ||
| 4046 | } | |
| 3901 | 4047 | case TypeTableEntryIdEnum: |
| 3902 | 4048 | { |
| 3903 | 4049 | LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref; |
| ... | ... | @@ -4376,6 +4522,9 @@ static void do_code_gen(CodeGen *g) { |
| 4376 | 4522 | } else if (instruction->id == IrInstructionIdStructInit) { |
| 4377 | 4523 | IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction; |
| 4378 | 4524 | slot = &struct_init_instruction->tmp_ptr; |
| 4525 | } else if (instruction->id == IrInstructionIdUnionInit) { | |
| 4526 | IrInstructionUnionInit *union_init_instruction = (IrInstructionUnionInit *)instruction; | |
| 4527 | slot = &union_init_instruction->tmp_ptr; | |
| 4379 | 4528 | } else if (instruction->id == IrInstructionIdCall) { |
| 4380 | 4529 | IrInstructionCall *call_instruction = (IrInstructionCall *)instruction; |
| 4381 | 4530 | slot = &call_instruction->tmp_ptr; |
| ... | ... | @@ -5204,7 +5353,7 @@ static void init(CodeGen *g) { |
| 5204 | 5353 | define_builtin_compile_vars(g); |
| 5205 | 5354 | } |
| 5206 | 5355 | |
| 5207 | void codegen_parsec(CodeGen *g, Buf *full_path) { | |
| 5356 | void codegen_translate_c(CodeGen *g, Buf *full_path) { | |
| 5208 | 5357 | find_libc_include_path(g); |
| 5209 | 5358 | |
| 5210 | 5359 | Buf *src_basename = buf_alloc(); |
src/codegen.hpp+1-1| ... | ... | @@ -56,7 +56,7 @@ PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, |
| 56 | 56 | void codegen_add_assembly(CodeGen *g, Buf *path); |
| 57 | 57 | void codegen_add_object(CodeGen *g, Buf *object_path); |
| 58 | 58 | |
| 59 | void codegen_parsec(CodeGen *g, Buf *path); | |
| 59 | void codegen_translate_c(CodeGen *g, Buf *path); | |
| 60 | 60 | |
| 61 | 61 | |
| 62 | 62 | #endif |
src/ir.cpp+221-38| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | #include "ir.hpp" |
| 12 | 12 | #include "ir_print.hpp" |
| 13 | 13 | #include "os.hpp" |
| 14 | #include "parsec.hpp" | |
| 14 | #include "translate_c.hpp" | |
| 15 | 15 | #include "range_set.hpp" |
| 16 | 16 | #include "softfloat.hpp" |
| 17 | 17 | |
| ... | ... | @@ -227,6 +227,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumFieldPtr *) |
| 227 | 227 | return IrInstructionIdEnumFieldPtr; |
| 228 | 228 | } |
| 229 | 229 | |
| 230 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionFieldPtr *) { | |
| 231 | return IrInstructionIdUnionFieldPtr; | |
| 232 | } | |
| 233 | ||
| 230 | 234 | static constexpr IrInstructionId ir_instruction_id(IrInstructionElemPtr *) { |
| 231 | 235 | return IrInstructionIdElemPtr; |
| 232 | 236 | } |
| ... | ... | @@ -351,6 +355,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) { |
| 351 | 355 | return IrInstructionIdStructInit; |
| 352 | 356 | } |
| 353 | 357 | |
| 358 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit *) { | |
| 359 | return IrInstructionIdUnionInit; | |
| 360 | } | |
| 361 | ||
| 354 | 362 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMinValue *) { |
| 355 | 363 | return IrInstructionIdMinValue; |
| 356 | 364 | } |
| ... | ... | @@ -922,6 +930,27 @@ static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction |
| 922 | 930 | return new_instruction; |
| 923 | 931 | } |
| 924 | 932 | |
| 933 | static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 934 | IrInstruction *union_ptr, TypeUnionField *field) | |
| 935 | { | |
| 936 | IrInstructionUnionFieldPtr *instruction = ir_build_instruction<IrInstructionUnionFieldPtr>(irb, scope, source_node); | |
| 937 | instruction->union_ptr = union_ptr; | |
| 938 | instruction->field = field; | |
| 939 | ||
| 940 | ir_ref_instruction(union_ptr, irb->current_basic_block); | |
| 941 | ||
| 942 | return &instruction->base; | |
| 943 | } | |
| 944 | ||
| 945 | static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, | |
| 946 | IrInstruction *union_ptr, TypeUnionField *type_union_field) | |
| 947 | { | |
| 948 | IrInstruction *new_instruction = ir_build_union_field_ptr(irb, old_instruction->scope, | |
| 949 | old_instruction->source_node, union_ptr, type_union_field); | |
| 950 | ir_link_new_instruction(new_instruction, old_instruction); | |
| 951 | return new_instruction; | |
| 952 | } | |
| 953 | ||
| 925 | 954 | static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 926 | 955 | FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 927 | 956 | bool is_comptime, bool is_inline) |
| ... | ... | @@ -1112,6 +1141,28 @@ static IrInstruction *ir_build_struct_init_from(IrBuilder *irb, IrInstruction *o |
| 1112 | 1141 | return new_instruction; |
| 1113 | 1142 | } |
| 1114 | 1143 | |
| 1144 | static IrInstruction *ir_build_union_init(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 1145 | TypeTableEntry *union_type, TypeUnionField *field, IrInstruction *init_value) | |
| 1146 | { | |
| 1147 | IrInstructionUnionInit *union_init_instruction = ir_build_instruction<IrInstructionUnionInit>(irb, scope, source_node); | |
| 1148 | union_init_instruction->union_type = union_type; | |
| 1149 | union_init_instruction->field = field; | |
| 1150 | union_init_instruction->init_value = init_value; | |
| 1151 | ||
| 1152 | ir_ref_instruction(init_value, irb->current_basic_block); | |
| 1153 | ||
| 1154 | return &union_init_instruction->base; | |
| 1155 | } | |
| 1156 | ||
| 1157 | static IrInstruction *ir_build_union_init_from(IrBuilder *irb, IrInstruction *old_instruction, | |
| 1158 | TypeTableEntry *union_type, TypeUnionField *field, IrInstruction *init_value) | |
| 1159 | { | |
| 1160 | IrInstruction *new_instruction = ir_build_union_init(irb, old_instruction->scope, | |
| 1161 | old_instruction->source_node, union_type, field, init_value); | |
| 1162 | ir_link_new_instruction(new_instruction, old_instruction); | |
| 1163 | return new_instruction; | |
| 1164 | } | |
| 1165 | ||
| 1115 | 1166 | static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 1116 | 1167 | IrInstructionUnreachable *unreachable_instruction = |
| 1117 | 1168 | ir_build_instruction<IrInstructionUnreachable>(irb, scope, source_node); |
| ... | ... | @@ -2422,6 +2473,13 @@ static IrInstruction *ir_instruction_enumfieldptr_get_dep(IrInstructionEnumField |
| 2422 | 2473 | } |
| 2423 | 2474 | } |
| 2424 | 2475 | |
| 2476 | static IrInstruction *ir_instruction_unionfieldptr_get_dep(IrInstructionUnionFieldPtr *instruction, size_t index) { | |
| 2477 | switch (index) { | |
| 2478 | case 0: return instruction->union_ptr; | |
| 2479 | default: return nullptr; | |
| 2480 | } | |
| 2481 | } | |
| 2482 | ||
| 2425 | 2483 | static IrInstruction *ir_instruction_elemptr_get_dep(IrInstructionElemPtr *instruction, size_t index) { |
| 2426 | 2484 | switch (index) { |
| 2427 | 2485 | case 0: return instruction->array_ptr; |
| ... | ... | @@ -2485,6 +2543,13 @@ static IrInstruction *ir_instruction_structinit_get_dep(IrInstructionStructInit |
| 2485 | 2543 | return nullptr; |
| 2486 | 2544 | } |
| 2487 | 2545 | |
| 2546 | static IrInstruction *ir_instruction_unioninit_get_dep(IrInstructionUnionInit *instruction, size_t index) { | |
| 2547 | switch (index) { | |
| 2548 | case 0: return instruction->init_value; | |
| 2549 | default: return nullptr; | |
| 2550 | } | |
| 2551 | } | |
| 2552 | ||
| 2488 | 2553 | static IrInstruction *ir_instruction_unreachable_get_dep(IrInstructionUnreachable *instruction, size_t index) { |
| 2489 | 2554 | return nullptr; |
| 2490 | 2555 | } |
| ... | ... | @@ -3099,6 +3164,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3099 | 3164 | return ir_instruction_structfieldptr_get_dep((IrInstructionStructFieldPtr *) instruction, index); |
| 3100 | 3165 | case IrInstructionIdEnumFieldPtr: |
| 3101 | 3166 | return ir_instruction_enumfieldptr_get_dep((IrInstructionEnumFieldPtr *) instruction, index); |
| 3167 | case IrInstructionIdUnionFieldPtr: | |
| 3168 | return ir_instruction_unionfieldptr_get_dep((IrInstructionUnionFieldPtr *) instruction, index); | |
| 3102 | 3169 | case IrInstructionIdElemPtr: |
| 3103 | 3170 | return ir_instruction_elemptr_get_dep((IrInstructionElemPtr *) instruction, index); |
| 3104 | 3171 | case IrInstructionIdVarPtr: |
| ... | ... | @@ -3117,6 +3184,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3117 | 3184 | return ir_instruction_containerinitfields_get_dep((IrInstructionContainerInitFields *) instruction, index); |
| 3118 | 3185 | case IrInstructionIdStructInit: |
| 3119 | 3186 | return ir_instruction_structinit_get_dep((IrInstructionStructInit *) instruction, index); |
| 3187 | case IrInstructionIdUnionInit: | |
| 3188 | return ir_instruction_unioninit_get_dep((IrInstructionUnionInit *) instruction, index); | |
| 3120 | 3189 | case IrInstructionIdUnreachable: |
| 3121 | 3190 | return ir_instruction_unreachable_get_dep((IrInstructionUnreachable *) instruction, index); |
| 3122 | 3191 | case IrInstructionIdTypeOf: |
| ... | ... | @@ -6233,8 +6302,9 @@ static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char |
| 6233 | 6302 | buf_appendf(name, ")"); |
| 6234 | 6303 | return name; |
| 6235 | 6304 | } else { |
| 6305 | //Note: C-imports do not have valid location information | |
| 6236 | 6306 | return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name, |
| 6237 | buf_ptr(source_node->owner->path), source_node->line + 1, source_node->column + 1); | |
| 6307 | (source_node->owner->path != nullptr) ? buf_ptr(source_node->owner->path) : "(null)", source_node->line + 1, source_node->column + 1); | |
| 6238 | 6308 | } |
| 6239 | 6309 | } |
| 6240 | 6310 | } |
| ... | ... | @@ -6263,6 +6333,9 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope, |
| 6263 | 6333 | } |
| 6264 | 6334 | irb->codegen->resolve_queue.append(&tld_container->base); |
| 6265 | 6335 | |
| 6336 | // Add this to the list to mark as invalid if analyzing this exec fails. | |
| 6337 | irb->exec->tld_list.append(&tld_container->base); | |
| 6338 | ||
| 6266 | 6339 | return ir_build_const_type(irb, parent_scope, node, container_type); |
| 6267 | 6340 | } |
| 6268 | 6341 | |
| ... | ... | @@ -6485,6 +6558,20 @@ static bool ir_goto_pass2(IrBuilder *irb) { |
| 6485 | 6558 | return true; |
| 6486 | 6559 | } |
| 6487 | 6560 | |
| 6561 | static void invalidate_exec(IrExecutable *exec) { | |
| 6562 | if (exec->invalid) | |
| 6563 | return; | |
| 6564 | ||
| 6565 | exec->invalid = true; | |
| 6566 | ||
| 6567 | for (size_t i = 0; i < exec->tld_list.length; i += 1) { | |
| 6568 | exec->tld_list.items[i]->resolution = TldResolutionInvalid; | |
| 6569 | } | |
| 6570 | ||
| 6571 | if (exec->source_exec != nullptr) | |
| 6572 | invalidate_exec(exec->source_exec); | |
| 6573 | } | |
| 6574 | ||
| 6488 | 6575 | bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_executable) { |
| 6489 | 6576 | assert(node->owner); |
| 6490 | 6577 | |
| ... | ... | @@ -6508,7 +6595,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6508 | 6595 | } |
| 6509 | 6596 | |
| 6510 | 6597 | if (!ir_goto_pass2(irb)) { |
| 6511 | irb->exec->invalid = true; | |
| 6598 | invalidate_exec(ir_executable); | |
| 6512 | 6599 | return false; |
| 6513 | 6600 | } |
| 6514 | 6601 | |
| ... | ... | @@ -6534,7 +6621,7 @@ static void add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, ErrorMsg |
| 6534 | 6621 | } |
| 6535 | 6622 | |
| 6536 | 6623 | static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) { |
| 6537 | exec->invalid = true; | |
| 6624 | invalidate_exec(exec); | |
| 6538 | 6625 | ErrorMsg *err_msg = add_node_error(codegen, source_node, msg); |
| 6539 | 6626 | if (exec->parent_exec) { |
| 6540 | 6627 | add_call_stack_errors(codegen, exec, err_msg, 10); |
| ... | ... | @@ -7897,6 +7984,9 @@ static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instructio |
| 7897 | 7984 | ConstExprValue *const_val = &const_instr->value; |
| 7898 | 7985 | const_val->type = pointee_type; |
| 7899 | 7986 | type_ensure_zero_bits_known(ira->codegen, type_entry); |
| 7987 | if (type_is_invalid(type_entry)) { | |
| 7988 | return ira->codegen->invalid_instruction; | |
| 7989 | } | |
| 7900 | 7990 | const_val->data.x_type = get_pointer_to_type_extra(ira->codegen, type_entry, |
| 7901 | 7991 | ptr_is_const, ptr_is_volatile, get_abi_alignment(ira->codegen, type_entry), 0, 0); |
| 7902 | 7992 | return const_instr; |
| ... | ... | @@ -7984,6 +8074,7 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node |
| 7984 | 8074 | IrExecutable analyzed_executable = {0}; |
| 7985 | 8075 | analyzed_executable.source_node = source_node; |
| 7986 | 8076 | analyzed_executable.parent_exec = parent_exec; |
| 8077 | analyzed_executable.source_exec = &ir_executable; | |
| 7987 | 8078 | analyzed_executable.name = exec_name; |
| 7988 | 8079 | analyzed_executable.is_inline = true; |
| 7989 | 8080 | analyzed_executable.fn_entry = fn_entry; |
| ... | ... | @@ -10279,30 +10370,40 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 10279 | 10370 | |
| 10280 | 10371 | bool is_const = (var->value->type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const; |
| 10281 | 10372 | bool is_volatile = (var->value->type->id == TypeTableEntryIdMetaType) ? is_volatile_ptr : false; |
| 10282 | if (mem_slot && mem_slot->special != ConstValSpecialRuntime) { | |
| 10283 | ConstPtrMut ptr_mut; | |
| 10284 | if (comptime_var_mem) { | |
| 10285 | ptr_mut = ConstPtrMutComptimeVar; | |
| 10286 | } else if (var->gen_is_const) { | |
| 10287 | ptr_mut = ConstPtrMutComptimeConst; | |
| 10288 | } else { | |
| 10289 | assert(!comptime_var_mem); | |
| 10290 | ptr_mut = ConstPtrMutRuntimeVar; | |
| 10373 | if (mem_slot != nullptr) { | |
| 10374 | switch (mem_slot->special) { | |
| 10375 | case ConstValSpecialRuntime: | |
| 10376 | goto no_mem_slot; | |
| 10377 | case ConstValSpecialStatic: // fallthrough | |
| 10378 | case ConstValSpecialUndef: { | |
| 10379 | ConstPtrMut ptr_mut; | |
| 10380 | if (comptime_var_mem) { | |
| 10381 | ptr_mut = ConstPtrMutComptimeVar; | |
| 10382 | } else if (var->gen_is_const) { | |
| 10383 | ptr_mut = ConstPtrMutComptimeConst; | |
| 10384 | } else { | |
| 10385 | assert(!comptime_var_mem); | |
| 10386 | ptr_mut = ConstPtrMutRuntimeVar; | |
| 10387 | } | |
| 10388 | return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type, | |
| 10389 | ptr_mut, is_const, is_volatile, var->align_bytes); | |
| 10390 | } | |
| 10291 | 10391 | } |
| 10292 | return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type, | |
| 10293 | ptr_mut, is_const, is_volatile, var->align_bytes); | |
| 10294 | } else { | |
| 10295 | IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb, | |
| 10296 | instruction->scope, instruction->source_node, var, is_const, is_volatile); | |
| 10297 | var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type, | |
| 10298 | var->src_is_const, is_volatile, var->align_bytes, 0, 0); | |
| 10299 | type_ensure_zero_bits_known(ira->codegen, var->value->type); | |
| 10392 | zig_unreachable(); | |
| 10393 | } | |
| 10300 | 10394 | |
| 10301 | bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); | |
| 10302 | var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack; | |
| 10395 | no_mem_slot: | |
| 10303 | 10396 | |
| 10304 | return var_ptr_instruction; | |
| 10305 | } | |
| 10397 | IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb, | |
| 10398 | instruction->scope, instruction->source_node, var, is_const, is_volatile); | |
| 10399 | var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type, | |
| 10400 | var->src_is_const, is_volatile, var->align_bytes, 0, 0); | |
| 10401 | type_ensure_zero_bits_known(ira->codegen, var->value->type); | |
| 10402 | ||
| 10403 | bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); | |
| 10404 | var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack; | |
| 10405 | ||
| 10406 | return var_ptr_instruction; | |
| 10306 | 10407 | } |
| 10307 | 10408 | |
| 10308 | 10409 | static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, |
| ... | ... | @@ -10408,10 +10509,11 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 10408 | 10509 | result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type, |
| 10409 | 10510 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, |
| 10410 | 10511 | nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec); |
| 10411 | if (type_is_invalid(result->value.type)) | |
| 10412 | return ira->codegen->builtin_types.entry_invalid; | |
| 10413 | 10512 | |
| 10414 | 10513 | ira->codegen->memoized_fn_eval_table.put(exec_scope, result); |
| 10514 | ||
| 10515 | if (type_is_invalid(result->value.type)) | |
| 10516 | return ira->codegen->builtin_types.entry_invalid; | |
| 10415 | 10517 | } |
| 10416 | 10518 | |
| 10417 | 10519 | ConstExprValue *out_val = ir_build_const_from(ira, &call_instruction->base); |
| ... | ... | @@ -11417,8 +11519,20 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira, |
| 11417 | 11519 | return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value, true, false); |
| 11418 | 11520 | } |
| 11419 | 11521 | } |
| 11522 | const char *prefix_name; | |
| 11523 | if (is_slice(bare_struct_type)) { | |
| 11524 | prefix_name = ""; | |
| 11525 | } else if (bare_struct_type->id == TypeTableEntryIdStruct) { | |
| 11526 | prefix_name = "struct "; | |
| 11527 | } else if (bare_struct_type->id == TypeTableEntryIdEnum) { | |
| 11528 | prefix_name = "enum "; | |
| 11529 | } else if (bare_struct_type->id == TypeTableEntryIdUnion) { | |
| 11530 | prefix_name = "union "; | |
| 11531 | } else { | |
| 11532 | prefix_name = ""; | |
| 11533 | } | |
| 11420 | 11534 | ir_add_error_node(ira, field_ptr_instruction->base.source_node, |
| 11421 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&bare_struct_type->name))); | |
| 11535 | buf_sprintf("no member named '%s' in %s'%s'", buf_ptr(field_name), prefix_name, buf_ptr(&bare_struct_type->name))); | |
| 11422 | 11536 | return ira->codegen->builtin_types.entry_invalid; |
| 11423 | 11537 | } |
| 11424 | 11538 | |
| ... | ... | @@ -11428,14 +11542,13 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field |
| 11428 | 11542 | { |
| 11429 | 11543 | TypeTableEntry *bare_type = container_ref_type(container_type); |
| 11430 | 11544 | ensure_complete_type(ira->codegen, bare_type); |
| 11545 | if (type_is_invalid(bare_type)) | |
| 11546 | return ira->codegen->builtin_types.entry_invalid; | |
| 11431 | 11547 | |
| 11432 | 11548 | assert(container_ptr->value.type->id == TypeTableEntryIdPointer); |
| 11433 | 11549 | bool is_const = container_ptr->value.type->data.pointer.is_const; |
| 11434 | 11550 | bool is_volatile = container_ptr->value.type->data.pointer.is_volatile; |
| 11435 | 11551 | if (bare_type->id == TypeTableEntryIdStruct) { |
| 11436 | if (bare_type->data.structure.is_invalid) | |
| 11437 | return ira->codegen->builtin_types.entry_invalid; | |
| 11438 | ||
| 11439 | 11552 | TypeStructField *field = find_struct_type_field(bare_type, field_name); |
| 11440 | 11553 | if (field) { |
| 11441 | 11554 | bool is_packed = (bare_type->data.structure.layout == ContainerLayoutPacked); |
| ... | ... | @@ -11476,9 +11589,6 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field |
| 11476 | 11589 | field_ptr_instruction, container_ptr, container_type); |
| 11477 | 11590 | } |
| 11478 | 11591 | } else if (bare_type->id == TypeTableEntryIdEnum) { |
| 11479 | if (bare_type->data.enumeration.is_invalid) | |
| 11480 | return ira->codegen->builtin_types.entry_invalid; | |
| 11481 | ||
| 11482 | 11592 | TypeEnumField *field = find_enum_type_field(bare_type, field_name); |
| 11483 | 11593 | if (field) { |
| 11484 | 11594 | ir_build_enum_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field); |
| ... | ... | @@ -11489,7 +11599,15 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field |
| 11489 | 11599 | field_ptr_instruction, container_ptr, container_type); |
| 11490 | 11600 | } |
| 11491 | 11601 | } else if (bare_type->id == TypeTableEntryIdUnion) { |
| 11492 | zig_panic("TODO"); | |
| 11602 | TypeUnionField *field = find_union_type_field(bare_type, field_name); | |
| 11603 | if (field) { | |
| 11604 | ir_build_union_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field); | |
| 11605 | return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, | |
| 11606 | get_abi_alignment(ira->codegen, field->type_entry), 0, 0); | |
| 11607 | } else { | |
| 11608 | return ir_analyze_container_member_access_inner(ira, bare_type, field_name, | |
| 11609 | field_ptr_instruction, container_ptr, container_type); | |
| 11610 | } | |
| 11493 | 11611 | } else { |
| 11494 | 11612 | zig_unreachable(); |
| 11495 | 11613 | } |
| ... | ... | @@ -13033,9 +13151,71 @@ static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionR |
| 13033 | 13151 | return ir_analyze_ref(ira, &ref_instruction->base, value, ref_instruction->is_const, ref_instruction->is_volatile); |
| 13034 | 13152 | } |
| 13035 | 13153 | |
| 13154 | static TypeTableEntry *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruction *instruction, | |
| 13155 | TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields) | |
| 13156 | { | |
| 13157 | assert(container_type->id == TypeTableEntryIdUnion); | |
| 13158 | ||
| 13159 | ensure_complete_type(ira->codegen, container_type); | |
| 13160 | ||
| 13161 | if (instr_field_count != 1) { | |
| 13162 | ir_add_error(ira, instruction, | |
| 13163 | buf_sprintf("union initialization expects exactly one field")); | |
| 13164 | return ira->codegen->builtin_types.entry_invalid; | |
| 13165 | } | |
| 13166 | ||
| 13167 | IrInstructionContainerInitFieldsField *field = &fields[0]; | |
| 13168 | IrInstruction *field_value = field->value->other; | |
| 13169 | if (type_is_invalid(field_value->value.type)) | |
| 13170 | return ira->codegen->builtin_types.entry_invalid; | |
| 13171 | ||
| 13172 | TypeUnionField *type_field = find_union_type_field(container_type, field->name); | |
| 13173 | if (!type_field) { | |
| 13174 | ir_add_error_node(ira, field->source_node, | |
| 13175 | buf_sprintf("no member named '%s' in union '%s'", | |
| 13176 | buf_ptr(field->name), buf_ptr(&container_type->name))); | |
| 13177 | return ira->codegen->builtin_types.entry_invalid; | |
| 13178 | } | |
| 13179 | ||
| 13180 | if (type_is_invalid(type_field->type_entry)) | |
| 13181 | return ira->codegen->builtin_types.entry_invalid; | |
| 13182 | ||
| 13183 | IrInstruction *casted_field_value = ir_implicit_cast(ira, field_value, type_field->type_entry); | |
| 13184 | if (casted_field_value == ira->codegen->invalid_instruction) | |
| 13185 | return ira->codegen->builtin_types.entry_invalid; | |
| 13186 | ||
| 13187 | bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope); | |
| 13188 | if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime) { | |
| 13189 | ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk); | |
| 13190 | if (!field_val) | |
| 13191 | return ira->codegen->builtin_types.entry_invalid; | |
| 13192 | ||
| 13193 | ConstExprValue *out_val = ir_build_const_from(ira, instruction); | |
| 13194 | out_val->data.x_union.payload = field_val; | |
| 13195 | out_val->data.x_union.tag = type_field->value; | |
| 13196 | ||
| 13197 | ConstParent *parent = get_const_val_parent(ira->codegen, field_val); | |
| 13198 | if (parent != nullptr) { | |
| 13199 | parent->id = ConstParentIdUnion; | |
| 13200 | parent->data.p_union.union_val = out_val; | |
| 13201 | } | |
| 13202 | ||
| 13203 | return container_type; | |
| 13204 | } | |
| 13205 | ||
| 13206 | IrInstruction *new_instruction = ir_build_union_init_from(&ira->new_irb, instruction, | |
| 13207 | container_type, type_field, casted_field_value); | |
| 13208 | ||
| 13209 | ir_add_alloca(ira, new_instruction, container_type); | |
| 13210 | return container_type; | |
| 13211 | } | |
| 13212 | ||
| 13036 | 13213 | static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction, |
| 13037 | 13214 | TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields) |
| 13038 | 13215 | { |
| 13216 | if (container_type->id == TypeTableEntryIdUnion) { | |
| 13217 | return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count, fields); | |
| 13218 | } | |
| 13039 | 13219 | if (container_type->id != TypeTableEntryIdStruct || is_slice(container_type)) { |
| 13040 | 13220 | ir_add_error(ira, instruction, |
| 13041 | 13221 | buf_sprintf("type '%s' does not support struct initialization syntax", |
| ... | ... | @@ -13043,8 +13223,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru |
| 13043 | 13223 | return ira->codegen->builtin_types.entry_invalid; |
| 13044 | 13224 | } |
| 13045 | 13225 | |
| 13046 | if (!type_is_complete(container_type)) | |
| 13047 | resolve_container_type(ira->codegen, container_type); | |
| 13226 | ensure_complete_type(ira->codegen, container_type); | |
| 13048 | 13227 | |
| 13049 | 13228 | size_t actual_field_count = container_type->data.structure.src_field_count; |
| 13050 | 13229 | |
| ... | ... | @@ -13070,7 +13249,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru |
| 13070 | 13249 | TypeStructField *type_field = find_struct_type_field(container_type, field->name); |
| 13071 | 13250 | if (!type_field) { |
| 13072 | 13251 | ir_add_error_node(ira, field->source_node, |
| 13073 | buf_sprintf("no member named '%s' in '%s'", | |
| 13252 | buf_sprintf("no member named '%s' in struct '%s'", | |
| 13074 | 13253 | buf_ptr(field->name), buf_ptr(&container_type->name))); |
| 13075 | 13254 | return ira->codegen->builtin_types.entry_invalid; |
| 13076 | 13255 | } |
| ... | ... | @@ -15657,8 +15836,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 15657 | 15836 | case IrInstructionIdIntToErr: |
| 15658 | 15837 | case IrInstructionIdErrToInt: |
| 15659 | 15838 | case IrInstructionIdStructInit: |
| 15839 | case IrInstructionIdUnionInit: | |
| 15660 | 15840 | case IrInstructionIdStructFieldPtr: |
| 15661 | 15841 | case IrInstructionIdEnumFieldPtr: |
| 15842 | case IrInstructionIdUnionFieldPtr: | |
| 15662 | 15843 | case IrInstructionIdInitEnum: |
| 15663 | 15844 | case IrInstructionIdMaybeWrap: |
| 15664 | 15845 | case IrInstructionIdErrWrapCode: |
| ... | ... | @@ -15968,6 +16149,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 15968 | 16149 | case IrInstructionIdContainerInitList: |
| 15969 | 16150 | case IrInstructionIdContainerInitFields: |
| 15970 | 16151 | case IrInstructionIdStructInit: |
| 16152 | case IrInstructionIdUnionInit: | |
| 15971 | 16153 | case IrInstructionIdFieldPtr: |
| 15972 | 16154 | case IrInstructionIdElemPtr: |
| 15973 | 16155 | case IrInstructionIdVarPtr: |
| ... | ... | @@ -15977,6 +16159,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 15977 | 16159 | case IrInstructionIdArrayLen: |
| 15978 | 16160 | case IrInstructionIdStructFieldPtr: |
| 15979 | 16161 | case IrInstructionIdEnumFieldPtr: |
| 16162 | case IrInstructionIdUnionFieldPtr: | |
| 15980 | 16163 | case IrInstructionIdArrayType: |
| 15981 | 16164 | case IrInstructionIdSliceType: |
| 15982 | 16165 | case IrInstructionIdSizeOf: |
src/ir_print.cpp+22| ... | ... | @@ -290,6 +290,15 @@ static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruct |
| 290 | 290 | fprintf(irp->f, "} // struct init"); |
| 291 | 291 | } |
| 292 | 292 | |
| 293 | static void ir_print_union_init(IrPrint *irp, IrInstructionUnionInit *instruction) { | |
| 294 | Buf *field_name = instruction->field->name; | |
| 295 | ||
| 296 | fprintf(irp->f, "%s {", buf_ptr(&instruction->union_type->name)); | |
| 297 | fprintf(irp->f, ".%s = ", buf_ptr(field_name)); | |
| 298 | ir_print_other_instruction(irp, instruction->init_value); | |
| 299 | fprintf(irp->f, "} // union init"); | |
| 300 | } | |
| 301 | ||
| 293 | 302 | static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) { |
| 294 | 303 | fprintf(irp->f, "unreachable"); |
| 295 | 304 | } |
| ... | ... | @@ -359,6 +368,13 @@ static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *ins |
| 359 | 368 | fprintf(irp->f, ")"); |
| 360 | 369 | } |
| 361 | 370 | |
| 371 | static void ir_print_union_field_ptr(IrPrint *irp, IrInstructionUnionFieldPtr *instruction) { | |
| 372 | fprintf(irp->f, "@UnionFieldPtr(&"); | |
| 373 | ir_print_other_instruction(irp, instruction->union_ptr); | |
| 374 | fprintf(irp->f, ".%s", buf_ptr(instruction->field->name)); | |
| 375 | fprintf(irp->f, ")"); | |
| 376 | } | |
| 377 | ||
| 362 | 378 | static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety *instruction) { |
| 363 | 379 | fprintf(irp->f, "@setDebugSafety("); |
| 364 | 380 | ir_print_other_instruction(irp, instruction->scope_value); |
| ... | ... | @@ -1023,6 +1039,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1023 | 1039 | case IrInstructionIdStructInit: |
| 1024 | 1040 | ir_print_struct_init(irp, (IrInstructionStructInit *)instruction); |
| 1025 | 1041 | break; |
| 1042 | case IrInstructionIdUnionInit: | |
| 1043 | ir_print_union_init(irp, (IrInstructionUnionInit *)instruction); | |
| 1044 | break; | |
| 1026 | 1045 | case IrInstructionIdUnreachable: |
| 1027 | 1046 | ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction); |
| 1028 | 1047 | break; |
| ... | ... | @@ -1056,6 +1075,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1056 | 1075 | case IrInstructionIdEnumFieldPtr: |
| 1057 | 1076 | ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction); |
| 1058 | 1077 | break; |
| 1078 | case IrInstructionIdUnionFieldPtr: | |
| 1079 | ir_print_union_field_ptr(irp, (IrInstructionUnionFieldPtr *)instruction); | |
| 1080 | break; | |
| 1059 | 1081 | case IrInstructionIdSetDebugSafety: |
| 1060 | 1082 | ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction); |
| 1061 | 1083 | break; |
src/main.cpp+11-11| ... | ... | @@ -23,7 +23,7 @@ static int usage(const char *arg0) { |
| 23 | 23 | " build-exe [source] create executable from source or object files\n" |
| 24 | 24 | " build-lib [source] create library from source or object files\n" |
| 25 | 25 | " build-obj [source] create object from source or assembly\n" |
| 26 | " parsec [source] convert c code to zig code\n" | |
| 26 | " translate-c [source] convert c code to zig code\n" | |
| 27 | 27 | " targets list available compilation targets\n" |
| 28 | 28 | " test [source] create and run a test build\n" |
| 29 | 29 | " version print version number and exit\n" |
| ... | ... | @@ -229,7 +229,7 @@ enum Cmd { |
| 229 | 229 | CmdTest, |
| 230 | 230 | CmdVersion, |
| 231 | 231 | CmdZen, |
| 232 | CmdParseC, | |
| 232 | CmdTranslateC, | |
| 233 | 233 | CmdTargets, |
| 234 | 234 | }; |
| 235 | 235 | |
| ... | ... | @@ -632,8 +632,8 @@ int main(int argc, char **argv) { |
| 632 | 632 | cmd = CmdVersion; |
| 633 | 633 | } else if (strcmp(arg, "zen") == 0) { |
| 634 | 634 | cmd = CmdZen; |
| 635 | } else if (strcmp(arg, "parsec") == 0) { | |
| 636 | cmd = CmdParseC; | |
| 635 | } else if (strcmp(arg, "translate-c") == 0) { | |
| 636 | cmd = CmdTranslateC; | |
| 637 | 637 | } else if (strcmp(arg, "test") == 0) { |
| 638 | 638 | cmd = CmdTest; |
| 639 | 639 | out_type = OutTypeExe; |
| ... | ... | @@ -646,7 +646,7 @@ int main(int argc, char **argv) { |
| 646 | 646 | } else { |
| 647 | 647 | switch (cmd) { |
| 648 | 648 | case CmdBuild: |
| 649 | case CmdParseC: | |
| 649 | case CmdTranslateC: | |
| 650 | 650 | case CmdTest: |
| 651 | 651 | if (!in_file) { |
| 652 | 652 | in_file = arg; |
| ... | ... | @@ -703,13 +703,13 @@ int main(int argc, char **argv) { |
| 703 | 703 | |
| 704 | 704 | switch (cmd) { |
| 705 | 705 | case CmdBuild: |
| 706 | case CmdParseC: | |
| 706 | case CmdTranslateC: | |
| 707 | 707 | case CmdTest: |
| 708 | 708 | { |
| 709 | 709 | if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) { |
| 710 | 710 | fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n"); |
| 711 | 711 | return usage(arg0); |
| 712 | } else if ((cmd == CmdParseC || cmd == CmdTest) && !in_file) { | |
| 712 | } else if ((cmd == CmdTranslateC || cmd == CmdTest) && !in_file) { | |
| 713 | 713 | fprintf(stderr, "Expected source file argument.\n"); |
| 714 | 714 | return usage(arg0); |
| 715 | 715 | } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) { |
| ... | ... | @@ -719,7 +719,7 @@ int main(int argc, char **argv) { |
| 719 | 719 | |
| 720 | 720 | assert(cmd != CmdBuild || out_type != OutTypeUnknown); |
| 721 | 721 | |
| 722 | bool need_name = (cmd == CmdBuild || cmd == CmdParseC); | |
| 722 | bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC); | |
| 723 | 723 | |
| 724 | 724 | Buf *in_file_buf = nullptr; |
| 725 | 725 | |
| ... | ... | @@ -742,7 +742,7 @@ int main(int argc, char **argv) { |
| 742 | 742 | return usage(arg0); |
| 743 | 743 | } |
| 744 | 744 | |
| 745 | Buf *zig_root_source_file = (cmd == CmdParseC) ? nullptr : in_file_buf; | |
| 745 | Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf; | |
| 746 | 746 | |
| 747 | 747 | Buf *full_cache_dir = buf_alloc(); |
| 748 | 748 | os_path_resolve(buf_create_from_str("."), |
| ... | ... | @@ -841,8 +841,8 @@ int main(int argc, char **argv) { |
| 841 | 841 | if (timing_info) |
| 842 | 842 | codegen_print_timing_report(g, stdout); |
| 843 | 843 | return EXIT_SUCCESS; |
| 844 | } else if (cmd == CmdParseC) { | |
| 845 | codegen_parsec(g, in_file_buf); | |
| 844 | } else if (cmd == CmdTranslateC) { | |
| 845 | codegen_translate_c(g, in_file_buf); | |
| 846 | 846 | ast_render(g, stdout, g->root_import->root, 4); |
| 847 | 847 | if (timing_info) |
| 848 | 848 | codegen_print_timing_report(g, stdout); |
src/parsec.cpp deleted-3514| ... | ... | @@ -1,3514 +0,0 @@ |
| 1 | /* | |
| 2 | * Copyright (c) 2015 Andrew Kelley | |
| 3 | * | |
| 4 | * This file is part of zig, which is MIT licensed. | |
| 5 | * See http://opensource.org/licenses/MIT | |
| 6 | */ | |
| 7 | ||
| 8 | #include "all_types.hpp" | |
| 9 | #include "analyze.hpp" | |
| 10 | #include "c_tokenizer.hpp" | |
| 11 | #include "error.hpp" | |
| 12 | #include "ir.hpp" | |
| 13 | #include "os.hpp" | |
| 14 | #include "parsec.hpp" | |
| 15 | #include "parser.hpp" | |
| 16 | ||
| 17 | ||
| 18 | #include <clang/Frontend/ASTUnit.h> | |
| 19 | #include <clang/Frontend/CompilerInstance.h> | |
| 20 | #include <clang/AST/Expr.h> | |
| 21 | ||
| 22 | #include <string.h> | |
| 23 | ||
| 24 | using namespace clang; | |
| 25 | ||
| 26 | struct MacroSymbol { | |
| 27 | Buf *name; | |
| 28 | Buf *value; | |
| 29 | }; | |
| 30 | ||
| 31 | struct Alias { | |
| 32 | Buf *new_name; | |
| 33 | Buf *canon_name; | |
| 34 | }; | |
| 35 | ||
| 36 | struct Context { | |
| 37 | ImportTableEntry *import; | |
| 38 | ZigList<ErrorMsg *> *errors; | |
| 39 | VisibMod visib_mod; | |
| 40 | VisibMod export_visib_mod; | |
| 41 | AstNode *root; | |
| 42 | HashMap<const void *, AstNode *, ptr_hash, ptr_eq> decl_table; | |
| 43 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> macro_table; | |
| 44 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> global_table; | |
| 45 | SourceManager *source_manager; | |
| 46 | ZigList<Alias> aliases; | |
| 47 | ZigList<MacroSymbol> macro_symbols; | |
| 48 | AstNode *source_node; | |
| 49 | bool warnings_on; | |
| 50 | ||
| 51 | CodeGen *codegen; | |
| 52 | ASTContext *ctx; | |
| 53 | ||
| 54 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> ptr_params; | |
| 55 | }; | |
| 56 | ||
| 57 | static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl); | |
| 58 | static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl); | |
| 59 | static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl); | |
| 60 | ||
| 61 | ||
| 62 | ATTRIBUTE_PRINTF(3, 4) | |
| 63 | static void emit_warning(Context *c, const SourceLocation &sl, const char *format, ...) { | |
| 64 | if (!c->warnings_on) { | |
| 65 | return; | |
| 66 | } | |
| 67 | ||
| 68 | va_list ap; | |
| 69 | va_start(ap, format); | |
| 70 | Buf *msg = buf_vprintf(format, ap); | |
| 71 | va_end(ap); | |
| 72 | ||
| 73 | StringRef filename = c->source_manager->getFilename(sl); | |
| 74 | const char *filename_bytes = (const char *)filename.bytes_begin(); | |
| 75 | Buf *path; | |
| 76 | if (filename_bytes) { | |
| 77 | path = buf_create_from_str(filename_bytes); | |
| 78 | } else { | |
| 79 | path = buf_sprintf("(no file)"); | |
| 80 | } | |
| 81 | unsigned line = c->source_manager->getSpellingLineNumber(sl); | |
| 82 | unsigned column = c->source_manager->getSpellingColumnNumber(sl); | |
| 83 | fprintf(stderr, "%s:%u:%u: warning: %s\n", buf_ptr(path), line, column, buf_ptr(msg)); | |
| 84 | } | |
| 85 | ||
| 86 | static void add_global_weak_alias(Context *c, Buf *new_name, Buf *canon_name) { | |
| 87 | Alias *alias = c->aliases.add_one(); | |
| 88 | alias->new_name = new_name; | |
| 89 | alias->canon_name = canon_name; | |
| 90 | } | |
| 91 | ||
| 92 | static AstNode * trans_create_node(Context *c, NodeType id) { | |
| 93 | AstNode *node = allocate<AstNode>(1); | |
| 94 | node->type = id; | |
| 95 | node->owner = c->import; | |
| 96 | // TODO line/column. mapping to C file?? | |
| 97 | return node; | |
| 98 | } | |
| 99 | ||
| 100 | static AstNode *trans_create_node_float_lit(Context *c, double value) { | |
| 101 | AstNode *node = trans_create_node(c, NodeTypeFloatLiteral); | |
| 102 | node->data.float_literal.bigfloat = allocate<BigFloat>(1); | |
| 103 | bigfloat_init_64(node->data.float_literal.bigfloat, value); | |
| 104 | return node; | |
| 105 | } | |
| 106 | ||
| 107 | static AstNode *trans_create_node_symbol(Context *c, Buf *name) { | |
| 108 | AstNode *node = trans_create_node(c, NodeTypeSymbol); | |
| 109 | node->data.symbol_expr.symbol = name; | |
| 110 | return node; | |
| 111 | } | |
| 112 | ||
| 113 | static AstNode *trans_create_node_symbol_str(Context *c, const char *name) { | |
| 114 | return trans_create_node_symbol(c, buf_create_from_str(name)); | |
| 115 | } | |
| 116 | ||
| 117 | static AstNode *trans_create_node_builtin_fn_call(Context *c, Buf *name) { | |
| 118 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 119 | node->data.fn_call_expr.fn_ref_expr = trans_create_node_symbol(c, name); | |
| 120 | node->data.fn_call_expr.is_builtin = true; | |
| 121 | return node; | |
| 122 | } | |
| 123 | ||
| 124 | static AstNode *trans_create_node_builtin_fn_call_str(Context *c, const char *name) { | |
| 125 | return trans_create_node_builtin_fn_call(c, buf_create_from_str(name)); | |
| 126 | } | |
| 127 | ||
| 128 | static AstNode *trans_create_node_opaque(Context *c) { | |
| 129 | return trans_create_node_builtin_fn_call_str(c, "OpaqueType"); | |
| 130 | } | |
| 131 | ||
| 132 | static AstNode *trans_create_node_fn_call_1(Context *c, AstNode *fn_ref_expr, AstNode *arg1) { | |
| 133 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 134 | node->data.fn_call_expr.fn_ref_expr = fn_ref_expr; | |
| 135 | node->data.fn_call_expr.params.append(arg1); | |
| 136 | return node; | |
| 137 | } | |
| 138 | ||
| 139 | static AstNode *trans_create_node_field_access(Context *c, AstNode *container, Buf *field_name) { | |
| 140 | AstNode *node = trans_create_node(c, NodeTypeFieldAccessExpr); | |
| 141 | if (container->type == NodeTypeSymbol) { | |
| 142 | assert(container->data.symbol_expr.symbol != nullptr); | |
| 143 | } | |
| 144 | node->data.field_access_expr.struct_expr = container; | |
| 145 | node->data.field_access_expr.field_name = field_name; | |
| 146 | return node; | |
| 147 | } | |
| 148 | ||
| 149 | static AstNode *trans_create_node_field_access_str(Context *c, AstNode *container, const char *field_name) { | |
| 150 | return trans_create_node_field_access(c, container, buf_create_from_str(field_name)); | |
| 151 | } | |
| 152 | ||
| 153 | static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *child_node) { | |
| 154 | AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); | |
| 155 | node->data.prefix_op_expr.prefix_op = op; | |
| 156 | node->data.prefix_op_expr.primary_expr = child_node; | |
| 157 | return node; | |
| 158 | } | |
| 159 | ||
| 160 | static AstNode *trans_create_node_bin_op(Context *c, AstNode *lhs_node, BinOpType op, AstNode *rhs_node) { | |
| 161 | AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); | |
| 162 | node->data.bin_op_expr.op1 = lhs_node; | |
| 163 | node->data.bin_op_expr.bin_op = op; | |
| 164 | node->data.bin_op_expr.op2 = rhs_node; | |
| 165 | return node; | |
| 166 | } | |
| 167 | ||
| 168 | static AstNode *maybe_suppress_result(Context *c, bool result_used, AstNode *node) { | |
| 169 | if (result_used) return node; | |
| 170 | return trans_create_node_bin_op(c, | |
| 171 | trans_create_node_symbol_str(c, "_"), | |
| 172 | BinOpTypeAssign, | |
| 173 | node); | |
| 174 | } | |
| 175 | ||
| 176 | static AstNode *trans_create_node_addr_of(Context *c, bool is_const, bool is_volatile, AstNode *child_node) { | |
| 177 | AstNode *node = trans_create_node(c, NodeTypeAddrOfExpr); | |
| 178 | node->data.addr_of_expr.is_const = is_const; | |
| 179 | node->data.addr_of_expr.is_volatile = is_volatile; | |
| 180 | node->data.addr_of_expr.op_expr = child_node; | |
| 181 | return node; | |
| 182 | } | |
| 183 | ||
| 184 | static AstNode *trans_create_node_str_lit_c(Context *c, Buf *buf) { | |
| 185 | AstNode *node = trans_create_node(c, NodeTypeStringLiteral); | |
| 186 | node->data.string_literal.buf = buf; | |
| 187 | node->data.string_literal.c = true; | |
| 188 | return node; | |
| 189 | } | |
| 190 | ||
| 191 | static AstNode *trans_create_node_str_lit_non_c(Context *c, Buf *buf) { | |
| 192 | AstNode *node = trans_create_node(c, NodeTypeStringLiteral); | |
| 193 | node->data.string_literal.buf = buf; | |
| 194 | node->data.string_literal.c = false; | |
| 195 | return node; | |
| 196 | } | |
| 197 | ||
| 198 | static AstNode *trans_create_node_unsigned_negative(Context *c, uint64_t x, bool is_negative) { | |
| 199 | AstNode *node = trans_create_node(c, NodeTypeIntLiteral); | |
| 200 | node->data.int_literal.bigint = allocate<BigInt>(1); | |
| 201 | bigint_init_data(node->data.int_literal.bigint, &x, 1, is_negative); | |
| 202 | return node; | |
| 203 | } | |
| 204 | ||
| 205 | static AstNode *trans_create_node_unsigned(Context *c, uint64_t x) { | |
| 206 | return trans_create_node_unsigned_negative(c, x, false); | |
| 207 | } | |
| 208 | ||
| 209 | static AstNode *trans_create_node_cast(Context *c, AstNode *dest, AstNode *src) { | |
| 210 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 211 | node->data.fn_call_expr.fn_ref_expr = dest; | |
| 212 | node->data.fn_call_expr.params.resize(1); | |
| 213 | node->data.fn_call_expr.params.items[0] = src; | |
| 214 | return node; | |
| 215 | } | |
| 216 | ||
| 217 | static AstNode *trans_create_node_unsigned_negative_type(Context *c, uint64_t x, bool is_negative, | |
| 218 | const char *type_name) | |
| 219 | { | |
| 220 | AstNode *lit_node = trans_create_node_unsigned_negative(c, x, is_negative); | |
| 221 | return trans_create_node_cast(c, trans_create_node_symbol_str(c, type_name), lit_node); | |
| 222 | } | |
| 223 | ||
| 224 | static AstNode *trans_create_node_array_type(Context *c, AstNode *size_node, AstNode *child_type_node) { | |
| 225 | AstNode *node = trans_create_node(c, NodeTypeArrayType); | |
| 226 | node->data.array_type.size = size_node; | |
| 227 | node->data.array_type.child_type = child_type_node; | |
| 228 | return node; | |
| 229 | } | |
| 230 | ||
| 231 | static AstNode *trans_create_node_var_decl(Context *c, VisibMod visib_mod, bool is_const, Buf *var_name, | |
| 232 | AstNode *type_node, AstNode *init_node) | |
| 233 | { | |
| 234 | AstNode *node = trans_create_node(c, NodeTypeVariableDeclaration); | |
| 235 | node->data.variable_declaration.visib_mod = visib_mod; | |
| 236 | node->data.variable_declaration.symbol = var_name; | |
| 237 | node->data.variable_declaration.is_const = is_const; | |
| 238 | node->data.variable_declaration.type = type_node; | |
| 239 | node->data.variable_declaration.expr = init_node; | |
| 240 | return node; | |
| 241 | } | |
| 242 | ||
| 243 | static AstNode *trans_create_node_var_decl_global(Context *c, bool is_const, Buf *var_name, AstNode *type_node, | |
| 244 | AstNode *init_node) | |
| 245 | { | |
| 246 | return trans_create_node_var_decl(c, c->visib_mod, is_const, var_name, type_node, init_node); | |
| 247 | } | |
| 248 | ||
| 249 | static AstNode *trans_create_node_var_decl_local(Context *c, bool is_const, Buf *var_name, AstNode *type_node, | |
| 250 | AstNode *init_node) | |
| 251 | { | |
| 252 | return trans_create_node_var_decl(c, VisibModPrivate, is_const, var_name, type_node, init_node); | |
| 253 | } | |
| 254 | ||
| 255 | ||
| 256 | static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_name, AstNode *src_proto_node) { | |
| 257 | AstNode *fn_def = trans_create_node(c, NodeTypeFnDef); | |
| 258 | AstNode *fn_proto = trans_create_node(c, NodeTypeFnProto); | |
| 259 | fn_proto->data.fn_proto.visib_mod = c->visib_mod; | |
| 260 | fn_proto->data.fn_proto.name = fn_name; | |
| 261 | fn_proto->data.fn_proto.is_inline = true; | |
| 262 | fn_proto->data.fn_proto.return_type = src_proto_node->data.fn_proto.return_type; // TODO ok for these to alias? | |
| 263 | ||
| 264 | fn_def->data.fn_def.fn_proto = fn_proto; | |
| 265 | fn_proto->data.fn_proto.fn_def_node = fn_def; | |
| 266 | ||
| 267 | AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, trans_create_node_symbol(c, var_name)); | |
| 268 | AstNode *fn_call_node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 269 | fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node; | |
| 270 | ||
| 271 | for (size_t i = 0; i < src_proto_node->data.fn_proto.params.length; i += 1) { | |
| 272 | AstNode *src_param_node = src_proto_node->data.fn_proto.params.at(i); | |
| 273 | Buf *param_name = src_param_node->data.param_decl.name; | |
| 274 | if (!param_name) param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i); | |
| 275 | ||
| 276 | AstNode *dest_param_node = trans_create_node(c, NodeTypeParamDecl); | |
| 277 | dest_param_node->data.param_decl.name = param_name; | |
| 278 | dest_param_node->data.param_decl.type = src_param_node->data.param_decl.type; | |
| 279 | dest_param_node->data.param_decl.is_noalias = src_param_node->data.param_decl.is_noalias; | |
| 280 | fn_proto->data.fn_proto.params.append(dest_param_node); | |
| 281 | ||
| 282 | fn_call_node->data.fn_call_expr.params.append(trans_create_node_symbol(c, param_name)); | |
| 283 | ||
| 284 | } | |
| 285 | ||
| 286 | AstNode *block = trans_create_node(c, NodeTypeBlock); | |
| 287 | block->data.block.statements.resize(1); | |
| 288 | block->data.block.statements.items[0] = fn_call_node; | |
| 289 | block->data.block.last_statement_is_result_expression = true; | |
| 290 | ||
| 291 | fn_def->data.fn_def.body = block; | |
| 292 | return fn_def; | |
| 293 | } | |
| 294 | ||
| 295 | static AstNode *trans_create_node_unwrap_null(Context *c, AstNode *child) { | |
| 296 | return trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, child); | |
| 297 | } | |
| 298 | ||
| 299 | static AstNode *get_global(Context *c, Buf *name) { | |
| 300 | { | |
| 301 | auto entry = c->global_table.maybe_get(name); | |
| 302 | if (entry) { | |
| 303 | return entry->value; | |
| 304 | } | |
| 305 | } | |
| 306 | { | |
| 307 | auto entry = c->macro_table.maybe_get(name); | |
| 308 | if (entry) | |
| 309 | return entry->value; | |
| 310 | } | |
| 311 | return nullptr; | |
| 312 | } | |
| 313 | ||
| 314 | static void add_top_level_decl(Context *c, Buf *name, AstNode *node) { | |
| 315 | c->global_table.put(name, node); | |
| 316 | c->root->data.root.top_level_decls.append(node); | |
| 317 | } | |
| 318 | ||
| 319 | static AstNode *add_global_var(Context *c, Buf *var_name, AstNode *value_node) { | |
| 320 | bool is_const = true; | |
| 321 | AstNode *type_node = nullptr; | |
| 322 | AstNode *node = trans_create_node_var_decl_global(c, is_const, var_name, type_node, value_node); | |
| 323 | add_top_level_decl(c, var_name, node); | |
| 324 | return node; | |
| 325 | } | |
| 326 | ||
| 327 | static const char *decl_name(const Decl *decl) { | |
| 328 | const NamedDecl *named_decl = static_cast<const NamedDecl *>(decl); | |
| 329 | return (const char *)named_decl->getName().bytes_begin(); | |
| 330 | } | |
| 331 | ||
| 332 | static AstNode *trans_create_node_apint(Context *c, const llvm::APSInt &aps_int) { | |
| 333 | AstNode *node = trans_create_node(c, NodeTypeIntLiteral); | |
| 334 | node->data.int_literal.bigint = allocate<BigInt>(1); | |
| 335 | bigint_init_data(node->data.int_literal.bigint, aps_int.getRawData(), aps_int.getNumWords(), aps_int.isNegative()); | |
| 336 | return node; | |
| 337 | ||
| 338 | } | |
| 339 | ||
| 340 | static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc); | |
| 341 | ||
| 342 | static bool is_c_void_type(AstNode *node) { | |
| 343 | return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void")); | |
| 344 | } | |
| 345 | ||
| 346 | static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location, const QualType &qt, AstNode *expr) { | |
| 347 | // TODO: maybe widen to increase size | |
| 348 | // TODO: maybe bitcast to change sign | |
| 349 | // TODO: maybe truncate to reduce size | |
| 350 | return trans_create_node_fn_call_1(c, trans_qual_type(c, qt, source_location), expr); | |
| 351 | } | |
| 352 | ||
| 353 | static bool qual_type_is_fn_ptr(Context *c, const QualType &qt) { | |
| 354 | const Type *ty = qt.getTypePtr(); | |
| 355 | if (ty->getTypeClass() != Type::Pointer) { | |
| 356 | return false; | |
| 357 | } | |
| 358 | const PointerType *pointer_ty = static_cast<const PointerType*>(ty); | |
| 359 | QualType child_qt = pointer_ty->getPointeeType(); | |
| 360 | const Type *child_ty = child_qt.getTypePtr(); | |
| 361 | if (child_ty->getTypeClass() != Type::Paren) { | |
| 362 | return false; | |
| 363 | } | |
| 364 | const ParenType *paren_ty = static_cast<const ParenType *>(child_ty); | |
| 365 | return paren_ty->getInnerType().getTypePtr()->getTypeClass() == Type::FunctionProto; | |
| 366 | } | |
| 367 | ||
| 368 | static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const SourceLocation &source_loc) { | |
| 369 | const Type *ty = qt.getTypePtr(); | |
| 370 | switch (ty->getTypeClass()) { | |
| 371 | case Type::Builtin: | |
| 372 | { | |
| 373 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty); | |
| 374 | switch (builtin_ty->getKind()) { | |
| 375 | case BuiltinType::Char_U: | |
| 376 | case BuiltinType::UChar: | |
| 377 | case BuiltinType::Char_S: | |
| 378 | case BuiltinType::SChar: | |
| 379 | return 8; | |
| 380 | case BuiltinType::UInt128: | |
| 381 | case BuiltinType::Int128: | |
| 382 | return 128; | |
| 383 | default: | |
| 384 | return 0; | |
| 385 | } | |
| 386 | zig_unreachable(); | |
| 387 | } | |
| 388 | case Type::Typedef: | |
| 389 | { | |
| 390 | const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty); | |
| 391 | const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); | |
| 392 | const char *type_name = decl_name(typedef_decl); | |
| 393 | if (strcmp(type_name, "uint8_t") == 0 || strcmp(type_name, "int8_t") == 0) { | |
| 394 | return 8; | |
| 395 | } else if (strcmp(type_name, "uint16_t") == 0 || strcmp(type_name, "int16_t") == 0) { | |
| 396 | return 16; | |
| 397 | } else if (strcmp(type_name, "uint32_t") == 0 || strcmp(type_name, "int32_t") == 0) { | |
| 398 | return 32; | |
| 399 | } else if (strcmp(type_name, "uint64_t") == 0 || strcmp(type_name, "int64_t") == 0) { | |
| 400 | return 64; | |
| 401 | } else { | |
| 402 | return 0; | |
| 403 | } | |
| 404 | } | |
| 405 | default: | |
| 406 | return 0; | |
| 407 | } | |
| 408 | zig_unreachable(); | |
| 409 | } | |
| 410 | ||
| 411 | ||
| 412 | static AstNode *qual_type_to_log2_int_ref(Context *c, const QualType &qt, | |
| 413 | const SourceLocation &source_loc) | |
| 414 | { | |
| 415 | uint32_t int_bit_width = qual_type_int_bit_width(c, qt, source_loc); | |
| 416 | if (int_bit_width != 0) { | |
| 417 | // we can perform the log2 now. | |
| 418 | uint64_t cast_bit_width = log2_u64(int_bit_width); | |
| 419 | return trans_create_node_symbol(c, buf_sprintf("u%" ZIG_PRI_u64, cast_bit_width)); | |
| 420 | } | |
| 421 | ||
| 422 | AstNode *zig_type_node = trans_qual_type(c, qt, source_loc); | |
| 423 | ||
| 424 | // @import("std").math.Log2Int(c_long); | |
| 425 | // | |
| 426 | // FnCall | |
| 427 | // FieldAccess | |
| 428 | // FieldAccess | |
| 429 | // FnCall (.builtin = true) | |
| 430 | // Symbol "import" | |
| 431 | // StringLiteral "std" | |
| 432 | // Symbol "math" | |
| 433 | // Symbol "Log2Int" | |
| 434 | // zig_type_node | |
| 435 | ||
| 436 | AstNode *import_fn_call = trans_create_node_builtin_fn_call_str(c, "import"); | |
| 437 | import_fn_call->data.fn_call_expr.params.append(trans_create_node_str_lit_non_c(c, buf_create_from_str("std"))); | |
| 438 | AstNode *inner_field_access = trans_create_node_field_access_str(c, import_fn_call, "math"); | |
| 439 | AstNode *outer_field_access = trans_create_node_field_access_str(c, inner_field_access, "Log2Int"); | |
| 440 | AstNode *log2int_fn_call = trans_create_node_fn_call_1(c, outer_field_access, zig_type_node); | |
| 441 | ||
| 442 | return log2int_fn_call; | |
| 443 | } | |
| 444 | ||
| 445 | static bool qual_type_child_is_fn_proto(const QualType &qt) { | |
| 446 | if (qt.getTypePtr()->getTypeClass() == Type::Paren) { | |
| 447 | const ParenType *paren_type = static_cast<const ParenType *>(qt.getTypePtr()); | |
| 448 | if (paren_type->getInnerType()->getTypeClass() == Type::FunctionProto) { | |
| 449 | return true; | |
| 450 | } | |
| 451 | } else if (qt.getTypePtr()->getTypeClass() == Type::Attributed) { | |
| 452 | const AttributedType *attr_type = static_cast<const AttributedType *>(qt.getTypePtr()); | |
| 453 | return qual_type_child_is_fn_proto(attr_type->getEquivalentType()); | |
| 454 | } | |
| 455 | return false; | |
| 456 | } | |
| 457 | ||
| 458 | static QualType resolve_any_typedef(Context *c, QualType qt) { | |
| 459 | const Type * ty = qt.getTypePtr(); | |
| 460 | if (ty->getTypeClass() != Type::Typedef) | |
| 461 | return qt; | |
| 462 | const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty); | |
| 463 | const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); | |
| 464 | return typedef_decl->getUnderlyingType(); | |
| 465 | } | |
| 466 | ||
| 467 | static bool c_is_signed_integer(Context *c, QualType qt) { | |
| 468 | const Type *c_type = resolve_any_typedef(c, qt).getTypePtr(); | |
| 469 | if (c_type->getTypeClass() != Type::Builtin) | |
| 470 | return false; | |
| 471 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); | |
| 472 | switch (builtin_ty->getKind()) { | |
| 473 | case BuiltinType::SChar: | |
| 474 | case BuiltinType::Short: | |
| 475 | case BuiltinType::Int: | |
| 476 | case BuiltinType::Long: | |
| 477 | case BuiltinType::LongLong: | |
| 478 | case BuiltinType::Int128: | |
| 479 | case BuiltinType::WChar_S: | |
| 480 | return true; | |
| 481 | default: | |
| 482 | return false; | |
| 483 | } | |
| 484 | } | |
| 485 | ||
| 486 | static bool c_is_unsigned_integer(Context *c, QualType qt) { | |
| 487 | const Type *c_type = resolve_any_typedef(c, qt).getTypePtr(); | |
| 488 | if (c_type->getTypeClass() != Type::Builtin) | |
| 489 | return false; | |
| 490 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); | |
| 491 | switch (builtin_ty->getKind()) { | |
| 492 | case BuiltinType::Char_U: | |
| 493 | case BuiltinType::UChar: | |
| 494 | case BuiltinType::Char_S: | |
| 495 | case BuiltinType::UShort: | |
| 496 | case BuiltinType::UInt: | |
| 497 | case BuiltinType::ULong: | |
| 498 | case BuiltinType::ULongLong: | |
| 499 | case BuiltinType::UInt128: | |
| 500 | case BuiltinType::WChar_U: | |
| 501 | return true; | |
| 502 | default: | |
| 503 | return false; | |
| 504 | } | |
| 505 | } | |
| 506 | ||
| 507 | static bool c_is_float(Context *c, QualType qt) { | |
| 508 | const Type *c_type = qt.getTypePtr(); | |
| 509 | if (c_type->getTypeClass() != Type::Builtin) | |
| 510 | return false; | |
| 511 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); | |
| 512 | switch (builtin_ty->getKind()) { | |
| 513 | case BuiltinType::Half: | |
| 514 | case BuiltinType::Float: | |
| 515 | case BuiltinType::Double: | |
| 516 | case BuiltinType::Float128: | |
| 517 | case BuiltinType::LongDouble: | |
| 518 | return true; | |
| 519 | default: | |
| 520 | return false; | |
| 521 | } | |
| 522 | } | |
| 523 | ||
| 524 | static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) { | |
| 525 | if (c_is_signed_integer(c, qt) || c_is_float(c, qt)) { | |
| 526 | // float and signed integer overflow is undefined behavior. | |
| 527 | return false; | |
| 528 | } else { | |
| 529 | // unsigned integer overflow wraps around. | |
| 530 | return true; | |
| 531 | } | |
| 532 | } | |
| 533 | ||
| 534 | enum TransLRValue { | |
| 535 | TransLValue, | |
| 536 | TransRValue, | |
| 537 | }; | |
| 538 | ||
| 539 | static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrval); | |
| 540 | static AstNode *const skip_add_to_block_node = (AstNode *) 0x2; | |
| 541 | ||
| 542 | static AstNode *trans_expr(Context *c, bool result_used, AstNode *block, Expr *expr, TransLRValue lrval) { | |
| 543 | return trans_stmt(c, result_used, block, expr, lrval); | |
| 544 | } | |
| 545 | ||
| 546 | static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) { | |
| 547 | switch (ty->getTypeClass()) { | |
| 548 | case Type::Builtin: | |
| 549 | { | |
| 550 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty); | |
| 551 | switch (builtin_ty->getKind()) { | |
| 552 | case BuiltinType::Void: | |
| 553 | return trans_create_node_symbol_str(c, "c_void"); | |
| 554 | case BuiltinType::Bool: | |
| 555 | return trans_create_node_symbol_str(c, "bool"); | |
| 556 | case BuiltinType::Char_U: | |
| 557 | case BuiltinType::UChar: | |
| 558 | case BuiltinType::Char_S: | |
| 559 | return trans_create_node_symbol_str(c, "u8"); | |
| 560 | case BuiltinType::SChar: | |
| 561 | return trans_create_node_symbol_str(c, "i8"); | |
| 562 | case BuiltinType::UShort: | |
| 563 | return trans_create_node_symbol_str(c, "c_ushort"); | |
| 564 | case BuiltinType::UInt: | |
| 565 | return trans_create_node_symbol_str(c, "c_uint"); | |
| 566 | case BuiltinType::ULong: | |
| 567 | return trans_create_node_symbol_str(c, "c_ulong"); | |
| 568 | case BuiltinType::ULongLong: | |
| 569 | return trans_create_node_symbol_str(c, "c_ulonglong"); | |
| 570 | case BuiltinType::Short: | |
| 571 | return trans_create_node_symbol_str(c, "c_short"); | |
| 572 | case BuiltinType::Int: | |
| 573 | return trans_create_node_symbol_str(c, "c_int"); | |
| 574 | case BuiltinType::Long: | |
| 575 | return trans_create_node_symbol_str(c, "c_long"); | |
| 576 | case BuiltinType::LongLong: | |
| 577 | return trans_create_node_symbol_str(c, "c_longlong"); | |
| 578 | case BuiltinType::UInt128: | |
| 579 | return trans_create_node_symbol_str(c, "u128"); | |
| 580 | case BuiltinType::Int128: | |
| 581 | return trans_create_node_symbol_str(c, "i128"); | |
| 582 | case BuiltinType::Float: | |
| 583 | return trans_create_node_symbol_str(c, "f32"); | |
| 584 | case BuiltinType::Double: | |
| 585 | return trans_create_node_symbol_str(c, "f64"); | |
| 586 | case BuiltinType::Float128: | |
| 587 | return trans_create_node_symbol_str(c, "f128"); | |
| 588 | case BuiltinType::Float16: | |
| 589 | return trans_create_node_symbol_str(c, "f16"); | |
| 590 | case BuiltinType::LongDouble: | |
| 591 | return trans_create_node_symbol_str(c, "c_longdouble"); | |
| 592 | case BuiltinType::WChar_U: | |
| 593 | case BuiltinType::Char16: | |
| 594 | case BuiltinType::Char32: | |
| 595 | case BuiltinType::WChar_S: | |
| 596 | case BuiltinType::Half: | |
| 597 | case BuiltinType::NullPtr: | |
| 598 | case BuiltinType::ObjCId: | |
| 599 | case BuiltinType::ObjCClass: | |
| 600 | case BuiltinType::ObjCSel: | |
| 601 | case BuiltinType::OMPArraySection: | |
| 602 | case BuiltinType::Dependent: | |
| 603 | case BuiltinType::Overload: | |
| 604 | case BuiltinType::BoundMember: | |
| 605 | case BuiltinType::PseudoObject: | |
| 606 | case BuiltinType::UnknownAny: | |
| 607 | case BuiltinType::BuiltinFn: | |
| 608 | case BuiltinType::ARCUnbridgedCast: | |
| 609 | ||
| 610 | case BuiltinType::OCLImage1dRO: | |
| 611 | case BuiltinType::OCLImage1dArrayRO: | |
| 612 | case BuiltinType::OCLImage1dBufferRO: | |
| 613 | case BuiltinType::OCLImage2dRO: | |
| 614 | case BuiltinType::OCLImage2dArrayRO: | |
| 615 | case BuiltinType::OCLImage2dDepthRO: | |
| 616 | case BuiltinType::OCLImage2dArrayDepthRO: | |
| 617 | case BuiltinType::OCLImage2dMSAARO: | |
| 618 | case BuiltinType::OCLImage2dArrayMSAARO: | |
| 619 | case BuiltinType::OCLImage2dMSAADepthRO: | |
| 620 | case BuiltinType::OCLImage2dArrayMSAADepthRO: | |
| 621 | case BuiltinType::OCLImage3dRO: | |
| 622 | case BuiltinType::OCLImage1dWO: | |
| 623 | case BuiltinType::OCLImage1dArrayWO: | |
| 624 | case BuiltinType::OCLImage1dBufferWO: | |
| 625 | case BuiltinType::OCLImage2dWO: | |
| 626 | case BuiltinType::OCLImage2dArrayWO: | |
| 627 | case BuiltinType::OCLImage2dDepthWO: | |
| 628 | case BuiltinType::OCLImage2dArrayDepthWO: | |
| 629 | case BuiltinType::OCLImage2dMSAAWO: | |
| 630 | case BuiltinType::OCLImage2dArrayMSAAWO: | |
| 631 | case BuiltinType::OCLImage2dMSAADepthWO: | |
| 632 | case BuiltinType::OCLImage2dArrayMSAADepthWO: | |
| 633 | case BuiltinType::OCLImage3dWO: | |
| 634 | case BuiltinType::OCLImage1dRW: | |
| 635 | case BuiltinType::OCLImage1dArrayRW: | |
| 636 | case BuiltinType::OCLImage1dBufferRW: | |
| 637 | case BuiltinType::OCLImage2dRW: | |
| 638 | case BuiltinType::OCLImage2dArrayRW: | |
| 639 | case BuiltinType::OCLImage2dDepthRW: | |
| 640 | case BuiltinType::OCLImage2dArrayDepthRW: | |
| 641 | case BuiltinType::OCLImage2dMSAARW: | |
| 642 | case BuiltinType::OCLImage2dArrayMSAARW: | |
| 643 | case BuiltinType::OCLImage2dMSAADepthRW: | |
| 644 | case BuiltinType::OCLImage2dArrayMSAADepthRW: | |
| 645 | case BuiltinType::OCLImage3dRW: | |
| 646 | case BuiltinType::OCLSampler: | |
| 647 | case BuiltinType::OCLEvent: | |
| 648 | case BuiltinType::OCLClkEvent: | |
| 649 | case BuiltinType::OCLQueue: | |
| 650 | case BuiltinType::OCLReserveID: | |
| 651 | emit_warning(c, source_loc, "unsupported builtin type"); | |
| 652 | return nullptr; | |
| 653 | } | |
| 654 | break; | |
| 655 | } | |
| 656 | case Type::Pointer: | |
| 657 | { | |
| 658 | const PointerType *pointer_ty = static_cast<const PointerType*>(ty); | |
| 659 | QualType child_qt = pointer_ty->getPointeeType(); | |
| 660 | AstNode *child_node = trans_qual_type(c, child_qt, source_loc); | |
| 661 | if (child_node == nullptr) { | |
| 662 | emit_warning(c, source_loc, "pointer to unsupported type"); | |
| 663 | return nullptr; | |
| 664 | } | |
| 665 | ||
| 666 | if (qual_type_child_is_fn_proto(child_qt)) { | |
| 667 | return trans_create_node_prefix_op(c, PrefixOpMaybe, child_node); | |
| 668 | } | |
| 669 | ||
| 670 | AstNode *pointer_node = trans_create_node_addr_of(c, child_qt.isConstQualified(), | |
| 671 | child_qt.isVolatileQualified(), child_node); | |
| 672 | return trans_create_node_prefix_op(c, PrefixOpMaybe, pointer_node); | |
| 673 | } | |
| 674 | case Type::Typedef: | |
| 675 | { | |
| 676 | const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty); | |
| 677 | const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); | |
| 678 | return resolve_typedef_decl(c, typedef_decl); | |
| 679 | } | |
| 680 | case Type::Elaborated: | |
| 681 | { | |
| 682 | const ElaboratedType *elaborated_ty = static_cast<const ElaboratedType*>(ty); | |
| 683 | switch (elaborated_ty->getKeyword()) { | |
| 684 | case ETK_Struct: | |
| 685 | return trans_qual_type(c, elaborated_ty->getNamedType(), source_loc); | |
| 686 | case ETK_Enum: | |
| 687 | return trans_qual_type(c, elaborated_ty->getNamedType(), source_loc); | |
| 688 | case ETK_Interface: | |
| 689 | case ETK_Union: | |
| 690 | case ETK_Class: | |
| 691 | case ETK_Typename: | |
| 692 | case ETK_None: | |
| 693 | emit_warning(c, source_loc, "unsupported elaborated type"); | |
| 694 | return nullptr; | |
| 695 | } | |
| 696 | } | |
| 697 | case Type::FunctionProto: | |
| 698 | { | |
| 699 | const FunctionProtoType *fn_proto_ty = static_cast<const FunctionProtoType*>(ty); | |
| 700 | ||
| 701 | AstNode *proto_node = trans_create_node(c, NodeTypeFnProto); | |
| 702 | switch (fn_proto_ty->getCallConv()) { | |
| 703 | case CC_C: // __attribute__((cdecl)) | |
| 704 | proto_node->data.fn_proto.cc = CallingConventionC; | |
| 705 | proto_node->data.fn_proto.is_extern = true; | |
| 706 | break; | |
| 707 | case CC_X86StdCall: // __attribute__((stdcall)) | |
| 708 | proto_node->data.fn_proto.cc = CallingConventionStdcall; | |
| 709 | break; | |
| 710 | case CC_X86FastCall: // __attribute__((fastcall)) | |
| 711 | emit_warning(c, source_loc, "unsupported calling convention: x86 fastcall"); | |
| 712 | return nullptr; | |
| 713 | case CC_X86ThisCall: // __attribute__((thiscall)) | |
| 714 | emit_warning(c, source_loc, "unsupported calling convention: x86 thiscall"); | |
| 715 | return nullptr; | |
| 716 | case CC_X86VectorCall: // __attribute__((vectorcall)) | |
| 717 | emit_warning(c, source_loc, "unsupported calling convention: x86 vectorcall"); | |
| 718 | return nullptr; | |
| 719 | case CC_X86Pascal: // __attribute__((pascal)) | |
| 720 | emit_warning(c, source_loc, "unsupported calling convention: x86 pascal"); | |
| 721 | return nullptr; | |
| 722 | case CC_Win64: // __attribute__((ms_abi)) | |
| 723 | emit_warning(c, source_loc, "unsupported calling convention: win64"); | |
| 724 | return nullptr; | |
| 725 | case CC_X86_64SysV: // __attribute__((sysv_abi)) | |
| 726 | emit_warning(c, source_loc, "unsupported calling convention: x86 64sysv"); | |
| 727 | return nullptr; | |
| 728 | case CC_X86RegCall: | |
| 729 | emit_warning(c, source_loc, "unsupported calling convention: x86 reg"); | |
| 730 | return nullptr; | |
| 731 | case CC_AAPCS: // __attribute__((pcs("aapcs"))) | |
| 732 | emit_warning(c, source_loc, "unsupported calling convention: aapcs"); | |
| 733 | return nullptr; | |
| 734 | case CC_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp"))) | |
| 735 | emit_warning(c, source_loc, "unsupported calling convention: aapcs-vfp"); | |
| 736 | return nullptr; | |
| 737 | case CC_IntelOclBicc: // __attribute__((intel_ocl_bicc)) | |
| 738 | emit_warning(c, source_loc, "unsupported calling convention: intel_ocl_bicc"); | |
| 739 | return nullptr; | |
| 740 | case CC_SpirFunction: // default for OpenCL functions on SPIR target | |
| 741 | emit_warning(c, source_loc, "unsupported calling convention: SPIR function"); | |
| 742 | return nullptr; | |
| 743 | case CC_OpenCLKernel: | |
| 744 | emit_warning(c, source_loc, "unsupported calling convention: OpenCLKernel"); | |
| 745 | return nullptr; | |
| 746 | case CC_Swift: | |
| 747 | emit_warning(c, source_loc, "unsupported calling convention: Swift"); | |
| 748 | return nullptr; | |
| 749 | case CC_PreserveMost: | |
| 750 | emit_warning(c, source_loc, "unsupported calling convention: PreserveMost"); | |
| 751 | return nullptr; | |
| 752 | case CC_PreserveAll: | |
| 753 | emit_warning(c, source_loc, "unsupported calling convention: PreserveAll"); | |
| 754 | return nullptr; | |
| 755 | } | |
| 756 | ||
| 757 | proto_node->data.fn_proto.is_var_args = fn_proto_ty->isVariadic(); | |
| 758 | size_t param_count = fn_proto_ty->getNumParams(); | |
| 759 | ||
| 760 | if (fn_proto_ty->getNoReturnAttr()) { | |
| 761 | proto_node->data.fn_proto.return_type = trans_create_node_symbol_str(c, "noreturn"); | |
| 762 | } else { | |
| 763 | proto_node->data.fn_proto.return_type = trans_qual_type(c, fn_proto_ty->getReturnType(), | |
| 764 | source_loc); | |
| 765 | if (proto_node->data.fn_proto.return_type == nullptr) { | |
| 766 | emit_warning(c, source_loc, "unsupported function proto return type"); | |
| 767 | return nullptr; | |
| 768 | } | |
| 769 | // convert c_void to actual void (only for return type) | |
| 770 | if (is_c_void_type(proto_node->data.fn_proto.return_type)) { | |
| 771 | proto_node->data.fn_proto.return_type = nullptr; | |
| 772 | } | |
| 773 | } | |
| 774 | ||
| 775 | //emit_warning(c, source_loc, "TODO figure out fn prototype fn name"); | |
| 776 | const char *fn_name = nullptr; | |
| 777 | if (fn_name != nullptr) { | |
| 778 | proto_node->data.fn_proto.name = buf_create_from_str(fn_name); | |
| 779 | } | |
| 780 | ||
| 781 | for (size_t i = 0; i < param_count; i += 1) { | |
| 782 | QualType qt = fn_proto_ty->getParamType(i); | |
| 783 | AstNode *param_type_node = trans_qual_type(c, qt, source_loc); | |
| 784 | ||
| 785 | if (param_type_node == nullptr) { | |
| 786 | emit_warning(c, source_loc, "unresolved function proto parameter type"); | |
| 787 | return nullptr; | |
| 788 | } | |
| 789 | ||
| 790 | AstNode *param_node = trans_create_node(c, NodeTypeParamDecl); | |
| 791 | //emit_warning(c, source_loc, "TODO figure out fn prototype param name"); | |
| 792 | const char *param_name = nullptr; | |
| 793 | if (param_name != nullptr) { | |
| 794 | param_node->data.param_decl.name = buf_create_from_str(param_name); | |
| 795 | } | |
| 796 | param_node->data.param_decl.is_noalias = qt.isRestrictQualified(); | |
| 797 | param_node->data.param_decl.type = param_type_node; | |
| 798 | proto_node->data.fn_proto.params.append(param_node); | |
| 799 | } | |
| 800 | // TODO check for always_inline attribute | |
| 801 | // TODO check for align attribute | |
| 802 | ||
| 803 | return proto_node; | |
| 804 | } | |
| 805 | case Type::Record: | |
| 806 | { | |
| 807 | const RecordType *record_ty = static_cast<const RecordType*>(ty); | |
| 808 | return resolve_record_decl(c, record_ty->getDecl()); | |
| 809 | } | |
| 810 | case Type::Enum: | |
| 811 | { | |
| 812 | const EnumType *enum_ty = static_cast<const EnumType*>(ty); | |
| 813 | return resolve_enum_decl(c, enum_ty->getDecl()); | |
| 814 | } | |
| 815 | case Type::ConstantArray: | |
| 816 | { | |
| 817 | const ConstantArrayType *const_arr_ty = static_cast<const ConstantArrayType *>(ty); | |
| 818 | AstNode *child_type_node = trans_qual_type(c, const_arr_ty->getElementType(), source_loc); | |
| 819 | if (child_type_node == nullptr) { | |
| 820 | emit_warning(c, source_loc, "unresolved array element type"); | |
| 821 | return nullptr; | |
| 822 | } | |
| 823 | uint64_t size = const_arr_ty->getSize().getLimitedValue(); | |
| 824 | AstNode *size_node = trans_create_node_unsigned(c, size); | |
| 825 | return trans_create_node_array_type(c, size_node, child_type_node); | |
| 826 | } | |
| 827 | case Type::Paren: | |
| 828 | { | |
| 829 | const ParenType *paren_ty = static_cast<const ParenType *>(ty); | |
| 830 | return trans_qual_type(c, paren_ty->getInnerType(), source_loc); | |
| 831 | } | |
| 832 | case Type::Decayed: | |
| 833 | { | |
| 834 | const DecayedType *decayed_ty = static_cast<const DecayedType *>(ty); | |
| 835 | return trans_qual_type(c, decayed_ty->getDecayedType(), source_loc); | |
| 836 | } | |
| 837 | case Type::Attributed: | |
| 838 | { | |
| 839 | const AttributedType *attributed_ty = static_cast<const AttributedType *>(ty); | |
| 840 | return trans_qual_type(c, attributed_ty->getEquivalentType(), source_loc); | |
| 841 | } | |
| 842 | case Type::BlockPointer: | |
| 843 | case Type::LValueReference: | |
| 844 | case Type::RValueReference: | |
| 845 | case Type::MemberPointer: | |
| 846 | case Type::IncompleteArray: | |
| 847 | case Type::VariableArray: | |
| 848 | case Type::DependentSizedArray: | |
| 849 | case Type::DependentSizedExtVector: | |
| 850 | case Type::Vector: | |
| 851 | case Type::ExtVector: | |
| 852 | case Type::FunctionNoProto: | |
| 853 | case Type::UnresolvedUsing: | |
| 854 | case Type::Adjusted: | |
| 855 | case Type::TypeOfExpr: | |
| 856 | case Type::TypeOf: | |
| 857 | case Type::Decltype: | |
| 858 | case Type::UnaryTransform: | |
| 859 | case Type::TemplateTypeParm: | |
| 860 | case Type::SubstTemplateTypeParm: | |
| 861 | case Type::SubstTemplateTypeParmPack: | |
| 862 | case Type::TemplateSpecialization: | |
| 863 | case Type::Auto: | |
| 864 | case Type::InjectedClassName: | |
| 865 | case Type::DependentName: | |
| 866 | case Type::DependentTemplateSpecialization: | |
| 867 | case Type::PackExpansion: | |
| 868 | case Type::ObjCObject: | |
| 869 | case Type::ObjCInterface: | |
| 870 | case Type::Complex: | |
| 871 | case Type::ObjCObjectPointer: | |
| 872 | case Type::Atomic: | |
| 873 | case Type::Pipe: | |
| 874 | case Type::ObjCTypeParam: | |
| 875 | case Type::DeducedTemplateSpecialization: | |
| 876 | case Type::DependentAddressSpace: | |
| 877 | emit_warning(c, source_loc, "unsupported type: '%s'", ty->getTypeClassName()); | |
| 878 | return nullptr; | |
| 879 | } | |
| 880 | zig_unreachable(); | |
| 881 | } | |
| 882 | ||
| 883 | static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc) { | |
| 884 | return trans_type(c, qt.getTypePtr(), source_loc); | |
| 885 | } | |
| 886 | ||
| 887 | static AstNode *trans_compound_stmt(Context *c, AstNode *parent, CompoundStmt *stmt) { | |
| 888 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | |
| 889 | for (CompoundStmt::body_iterator it = stmt->body_begin(), end_it = stmt->body_end(); it != end_it; ++it) { | |
| 890 | AstNode *child_node = trans_stmt(c, false, child_block, *it, TransRValue); | |
| 891 | if (child_node == nullptr) | |
| 892 | return nullptr; | |
| 893 | if (child_node != skip_add_to_block_node) | |
| 894 | child_block->data.block.statements.append(child_node); | |
| 895 | } | |
| 896 | return child_block; | |
| 897 | } | |
| 898 | ||
| 899 | static AstNode *trans_return_stmt(Context *c, AstNode *block, ReturnStmt *stmt) { | |
| 900 | Expr *value_expr = stmt->getRetValue(); | |
| 901 | if (value_expr == nullptr) { | |
| 902 | emit_warning(c, stmt->getLocStart(), "TODO handle C return void"); | |
| 903 | return nullptr; | |
| 904 | } else { | |
| 905 | AstNode *return_node = trans_create_node(c, NodeTypeReturnExpr); | |
| 906 | return_node->data.return_expr.expr = trans_expr(c, true, block, value_expr, TransRValue); | |
| 907 | if (return_node->data.return_expr.expr == nullptr) | |
| 908 | return nullptr; | |
| 909 | return return_node; | |
| 910 | } | |
| 911 | } | |
| 912 | ||
| 913 | static AstNode *trans_integer_literal(Context *c, IntegerLiteral *stmt) { | |
| 914 | llvm::APSInt result; | |
| 915 | if (!stmt->EvaluateAsInt(result, *c->ctx)) { | |
| 916 | emit_warning(c, stmt->getLocStart(), "invalid integer literal"); | |
| 917 | return nullptr; | |
| 918 | } | |
| 919 | return trans_create_node_apint(c, result); | |
| 920 | } | |
| 921 | ||
| 922 | static AstNode *trans_conditional_operator(Context *c, bool result_used, AstNode *block, ConditionalOperator *stmt) { | |
| 923 | AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr); | |
| 924 | ||
| 925 | Expr *cond_expr = stmt->getCond(); | |
| 926 | Expr *true_expr = stmt->getTrueExpr(); | |
| 927 | Expr *false_expr = stmt->getFalseExpr(); | |
| 928 | ||
| 929 | node->data.if_bool_expr.condition = trans_expr(c, true, block, cond_expr, TransRValue); | |
| 930 | if (node->data.if_bool_expr.condition == nullptr) | |
| 931 | return nullptr; | |
| 932 | ||
| 933 | node->data.if_bool_expr.then_block = trans_expr(c, result_used, block, true_expr, TransRValue); | |
| 934 | if (node->data.if_bool_expr.then_block == nullptr) | |
| 935 | return nullptr; | |
| 936 | ||
| 937 | node->data.if_bool_expr.else_node = trans_expr(c, result_used, block, false_expr, TransRValue); | |
| 938 | if (node->data.if_bool_expr.else_node == nullptr) | |
| 939 | return nullptr; | |
| 940 | ||
| 941 | return maybe_suppress_result(c, result_used, node); | |
| 942 | } | |
| 943 | ||
| 944 | static AstNode *trans_create_bin_op(Context *c, AstNode *block, Expr *lhs, BinOpType bin_op, Expr *rhs) { | |
| 945 | AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); | |
| 946 | node->data.bin_op_expr.bin_op = bin_op; | |
| 947 | ||
| 948 | node->data.bin_op_expr.op1 = trans_expr(c, true, block, lhs, TransRValue); | |
| 949 | if (node->data.bin_op_expr.op1 == nullptr) | |
| 950 | return nullptr; | |
| 951 | ||
| 952 | node->data.bin_op_expr.op2 = trans_expr(c, true, block, rhs, TransRValue); | |
| 953 | if (node->data.bin_op_expr.op2 == nullptr) | |
| 954 | return nullptr; | |
| 955 | ||
| 956 | return node; | |
| 957 | } | |
| 958 | ||
| 959 | static AstNode *trans_create_assign(Context *c, bool result_used, AstNode *block, Expr *lhs, Expr *rhs) { | |
| 960 | if (!result_used) { | |
| 961 | // common case | |
| 962 | AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); | |
| 963 | node->data.bin_op_expr.bin_op = BinOpTypeAssign; | |
| 964 | ||
| 965 | node->data.bin_op_expr.op1 = trans_expr(c, true, block, lhs, TransLValue); | |
| 966 | if (node->data.bin_op_expr.op1 == nullptr) | |
| 967 | return nullptr; | |
| 968 | ||
| 969 | node->data.bin_op_expr.op2 = trans_expr(c, true, block, rhs, TransRValue); | |
| 970 | if (node->data.bin_op_expr.op2 == nullptr) | |
| 971 | return nullptr; | |
| 972 | ||
| 973 | return node; | |
| 974 | } else { | |
| 975 | // worst case | |
| 976 | // c: lhs = rhs | |
| 977 | // zig: { | |
| 978 | // zig: const _tmp = rhs; | |
| 979 | // zig: lhs = _tmp; | |
| 980 | // zig: _tmp | |
| 981 | // zig: } | |
| 982 | ||
| 983 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | |
| 984 | ||
| 985 | // const _tmp = rhs; | |
| 986 | AstNode *rhs_node = trans_expr(c, true, child_block, rhs, TransRValue); | |
| 987 | if (rhs_node == nullptr) return nullptr; | |
| 988 | // TODO: avoid name collisions with generated variable names | |
| 989 | Buf* tmp_var_name = buf_create_from_str("_tmp"); | |
| 990 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, rhs_node); | |
| 991 | child_block->data.block.statements.append(tmp_var_decl); | |
| 992 | ||
| 993 | // lhs = _tmp; | |
| 994 | AstNode *lhs_node = trans_expr(c, true, child_block, lhs, TransLValue); | |
| 995 | if (lhs_node == nullptr) return nullptr; | |
| 996 | child_block->data.block.statements.append( | |
| 997 | trans_create_node_bin_op(c, lhs_node, BinOpTypeAssign, | |
| 998 | trans_create_node_symbol(c, tmp_var_name))); | |
| 999 | ||
| 1000 | // _tmp | |
| 1001 | child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name)); | |
| 1002 | child_block->data.block.last_statement_is_result_expression = true; | |
| 1003 | ||
| 1004 | return child_block; | |
| 1005 | } | |
| 1006 | } | |
| 1007 | ||
| 1008 | static AstNode *trans_create_shift_op(Context *c, AstNode *block, QualType result_type, Expr *lhs_expr, BinOpType bin_op, Expr *rhs_expr) { | |
| 1009 | const SourceLocation &rhs_location = rhs_expr->getLocStart(); | |
| 1010 | AstNode *rhs_type = qual_type_to_log2_int_ref(c, result_type, rhs_location); | |
| 1011 | // lhs >> u5(rh) | |
| 1012 | ||
| 1013 | AstNode *lhs = trans_expr(c, true, block, lhs_expr, TransLValue); | |
| 1014 | if (lhs == nullptr) return nullptr; | |
| 1015 | ||
| 1016 | AstNode *rhs = trans_expr(c, true, block, rhs_expr, TransRValue); | |
| 1017 | if (rhs == nullptr) return nullptr; | |
| 1018 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); | |
| 1019 | ||
| 1020 | return trans_create_node_bin_op(c, lhs, bin_op, coerced_rhs); | |
| 1021 | } | |
| 1022 | ||
| 1023 | static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *block, BinaryOperator *stmt) { | |
| 1024 | switch (stmt->getOpcode()) { | |
| 1025 | case BO_PtrMemD: | |
| 1026 | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_PtrMemD"); | |
| 1027 | return nullptr; | |
| 1028 | case BO_PtrMemI: | |
| 1029 | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_PtrMemI"); | |
| 1030 | return nullptr; | |
| 1031 | case BO_Mul: | |
| 1032 | return trans_create_bin_op(c, block, stmt->getLHS(), | |
| 1033 | qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeMultWrap : BinOpTypeMult, | |
| 1034 | stmt->getRHS()); | |
| 1035 | case BO_Div: | |
| 1036 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) { | |
| 1037 | // unsigned/float division uses the operator | |
| 1038 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeDiv, stmt->getRHS()); | |
| 1039 | } else { | |
| 1040 | // signed integer division uses @divTrunc | |
| 1041 | AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "divTrunc"); | |
| 1042 | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); | |
| 1043 | if (lhs == nullptr) return nullptr; | |
| 1044 | fn_call->data.fn_call_expr.params.append(lhs); | |
| 1045 | AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransLValue); | |
| 1046 | if (rhs == nullptr) return nullptr; | |
| 1047 | fn_call->data.fn_call_expr.params.append(rhs); | |
| 1048 | return fn_call; | |
| 1049 | } | |
| 1050 | case BO_Rem: | |
| 1051 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) { | |
| 1052 | // unsigned/float division uses the operator | |
| 1053 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeMod, stmt->getRHS()); | |
| 1054 | } else { | |
| 1055 | // signed integer division uses @rem | |
| 1056 | AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "rem"); | |
| 1057 | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); | |
| 1058 | if (lhs == nullptr) return nullptr; | |
| 1059 | fn_call->data.fn_call_expr.params.append(lhs); | |
| 1060 | AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransLValue); | |
| 1061 | if (rhs == nullptr) return nullptr; | |
| 1062 | fn_call->data.fn_call_expr.params.append(rhs); | |
| 1063 | return fn_call; | |
| 1064 | } | |
| 1065 | case BO_Add: | |
| 1066 | return trans_create_bin_op(c, block, stmt->getLHS(), | |
| 1067 | qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeAddWrap : BinOpTypeAdd, | |
| 1068 | stmt->getRHS()); | |
| 1069 | case BO_Sub: | |
| 1070 | return trans_create_bin_op(c, block, stmt->getLHS(), | |
| 1071 | qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeSubWrap : BinOpTypeSub, | |
| 1072 | stmt->getRHS()); | |
| 1073 | case BO_Shl: | |
| 1074 | return trans_create_shift_op(c, block, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftLeft, stmt->getRHS()); | |
| 1075 | case BO_Shr: | |
| 1076 | return trans_create_shift_op(c, block, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftRight, stmt->getRHS()); | |
| 1077 | case BO_LT: | |
| 1078 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpLessThan, stmt->getRHS()); | |
| 1079 | case BO_GT: | |
| 1080 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpGreaterThan, stmt->getRHS()); | |
| 1081 | case BO_LE: | |
| 1082 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpLessOrEq, stmt->getRHS()); | |
| 1083 | case BO_GE: | |
| 1084 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpGreaterOrEq, stmt->getRHS()); | |
| 1085 | case BO_EQ: | |
| 1086 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpEq, stmt->getRHS()); | |
| 1087 | case BO_NE: | |
| 1088 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpNotEq, stmt->getRHS()); | |
| 1089 | case BO_And: | |
| 1090 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBinAnd, stmt->getRHS()); | |
| 1091 | case BO_Xor: | |
| 1092 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBinXor, stmt->getRHS()); | |
| 1093 | case BO_Or: | |
| 1094 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBinOr, stmt->getRHS()); | |
| 1095 | case BO_LAnd: | |
| 1096 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS()); | |
| 1097 | case BO_LOr: | |
| 1098 | // TODO: int vs bool | |
| 1099 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS()); | |
| 1100 | case BO_Assign: | |
| 1101 | return trans_create_assign(c, result_used, block, stmt->getLHS(), stmt->getRHS()); | |
| 1102 | case BO_Comma: | |
| 1103 | { | |
| 1104 | block = trans_create_node(c, NodeTypeBlock); | |
| 1105 | AstNode *lhs = trans_expr(c, false, block, stmt->getLHS(), TransRValue); | |
| 1106 | if (lhs == nullptr) return nullptr; | |
| 1107 | block->data.block.statements.append(maybe_suppress_result(c, false, lhs)); | |
| 1108 | AstNode *rhs = trans_expr(c, result_used, block, stmt->getRHS(), TransRValue); | |
| 1109 | if (rhs == nullptr) return nullptr; | |
| 1110 | block->data.block.statements.append(maybe_suppress_result(c, result_used, rhs)); | |
| 1111 | block->data.block.last_statement_is_result_expression = true; | |
| 1112 | return block; | |
| 1113 | } | |
| 1114 | case BO_MulAssign: | |
| 1115 | case BO_DivAssign: | |
| 1116 | case BO_RemAssign: | |
| 1117 | case BO_AddAssign: | |
| 1118 | case BO_SubAssign: | |
| 1119 | case BO_ShlAssign: | |
| 1120 | case BO_ShrAssign: | |
| 1121 | case BO_AndAssign: | |
| 1122 | case BO_XorAssign: | |
| 1123 | case BO_OrAssign: | |
| 1124 | zig_unreachable(); | |
| 1125 | } | |
| 1126 | ||
| 1127 | zig_unreachable(); | |
| 1128 | } | |
| 1129 | ||
| 1130 | static AstNode *trans_create_compound_assign_shift(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) { | |
| 1131 | const SourceLocation &rhs_location = stmt->getRHS()->getLocStart(); | |
| 1132 | AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location); | |
| 1133 | ||
| 1134 | bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr(); | |
| 1135 | if (!use_intermediate_casts && !result_used) { | |
| 1136 | // simple common case, where the C and Zig are identical: | |
| 1137 | // lhs >>= rhs | |
| 1138 | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); | |
| 1139 | if (lhs == nullptr) return nullptr; | |
| 1140 | ||
| 1141 | AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue); | |
| 1142 | if (rhs == nullptr) return nullptr; | |
| 1143 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); | |
| 1144 | ||
| 1145 | return trans_create_node_bin_op(c, lhs, assign_op, coerced_rhs); | |
| 1146 | } else { | |
| 1147 | // need more complexity. worst case, this looks like this: | |
| 1148 | // c: lhs >>= rhs | |
| 1149 | // zig: { | |
| 1150 | // zig: const _ref = &lhs; | |
| 1151 | // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs)); | |
| 1152 | // zig: *_ref | |
| 1153 | // zig: } | |
| 1154 | // where u5 is the appropriate type | |
| 1155 | ||
| 1156 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | |
| 1157 | ||
| 1158 | // const _ref = &lhs; | |
| 1159 | AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue); | |
| 1160 | if (lhs == nullptr) return nullptr; | |
| 1161 | AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs); | |
| 1162 | // TODO: avoid name collisions with generated variable names | |
| 1163 | Buf* tmp_var_name = buf_create_from_str("_ref"); | |
| 1164 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs); | |
| 1165 | child_block->data.block.statements.append(tmp_var_decl); | |
| 1166 | ||
| 1167 | // *_ref = result_type(operation_type(*_ref) >> u5(rhs)); | |
| 1168 | ||
| 1169 | AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue); | |
| 1170 | if (rhs == nullptr) return nullptr; | |
| 1171 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); | |
| 1172 | ||
| 1173 | AstNode *assign_statement = trans_create_node_bin_op(c, | |
| 1174 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1175 | trans_create_node_symbol(c, tmp_var_name)), | |
| 1176 | BinOpTypeAssign, | |
| 1177 | trans_c_cast(c, rhs_location, | |
| 1178 | stmt->getComputationResultType(), | |
| 1179 | trans_create_node_bin_op(c, | |
| 1180 | trans_c_cast(c, rhs_location, | |
| 1181 | stmt->getComputationLHSType(), | |
| 1182 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1183 | trans_create_node_symbol(c, tmp_var_name))), | |
| 1184 | bin_op, | |
| 1185 | coerced_rhs))); | |
| 1186 | child_block->data.block.statements.append(assign_statement); | |
| 1187 | ||
| 1188 | if (result_used) { | |
| 1189 | // *_ref | |
| 1190 | child_block->data.block.statements.append( | |
| 1191 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1192 | trans_create_node_symbol(c, tmp_var_name))); | |
| 1193 | child_block->data.block.last_statement_is_result_expression = true; | |
| 1194 | } | |
| 1195 | ||
| 1196 | return child_block; | |
| 1197 | } | |
| 1198 | } | |
| 1199 | ||
| 1200 | static AstNode *trans_create_compound_assign(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) { | |
| 1201 | if (!result_used) { | |
| 1202 | // simple common case, where the C and Zig are identical: | |
| 1203 | // lhs += rhs | |
| 1204 | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); | |
| 1205 | if (lhs == nullptr) return nullptr; | |
| 1206 | AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue); | |
| 1207 | if (rhs == nullptr) return nullptr; | |
| 1208 | return trans_create_node_bin_op(c, lhs, assign_op, rhs); | |
| 1209 | } else { | |
| 1210 | // need more complexity. worst case, this looks like this: | |
| 1211 | // c: lhs += rhs | |
| 1212 | // zig: { | |
| 1213 | // zig: const _ref = &lhs; | |
| 1214 | // zig: *_ref = *_ref + rhs; | |
| 1215 | // zig: *_ref | |
| 1216 | // zig: } | |
| 1217 | ||
| 1218 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | |
| 1219 | ||
| 1220 | // const _ref = &lhs; | |
| 1221 | AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue); | |
| 1222 | if (lhs == nullptr) return nullptr; | |
| 1223 | AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs); | |
| 1224 | // TODO: avoid name collisions with generated variable names | |
| 1225 | Buf* tmp_var_name = buf_create_from_str("_ref"); | |
| 1226 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs); | |
| 1227 | child_block->data.block.statements.append(tmp_var_decl); | |
| 1228 | ||
| 1229 | // *_ref = *_ref + rhs; | |
| 1230 | ||
| 1231 | AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue); | |
| 1232 | if (rhs == nullptr) return nullptr; | |
| 1233 | ||
| 1234 | AstNode *assign_statement = trans_create_node_bin_op(c, | |
| 1235 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1236 | trans_create_node_symbol(c, tmp_var_name)), | |
| 1237 | BinOpTypeAssign, | |
| 1238 | trans_create_node_bin_op(c, | |
| 1239 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1240 | trans_create_node_symbol(c, tmp_var_name)), | |
| 1241 | bin_op, | |
| 1242 | rhs)); | |
| 1243 | child_block->data.block.statements.append(assign_statement); | |
| 1244 | ||
| 1245 | // *_ref | |
| 1246 | child_block->data.block.statements.append( | |
| 1247 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1248 | trans_create_node_symbol(c, tmp_var_name))); | |
| 1249 | child_block->data.block.last_statement_is_result_expression = true; | |
| 1250 | ||
| 1251 | return child_block; | |
| 1252 | } | |
| 1253 | } | |
| 1254 | ||
| 1255 | ||
| 1256 | static AstNode *trans_compound_assign_operator(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt) { | |
| 1257 | switch (stmt->getOpcode()) { | |
| 1258 | case BO_MulAssign: | |
| 1259 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1260 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignTimesWrap, BinOpTypeMultWrap); | |
| 1261 | else | |
| 1262 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignTimes, BinOpTypeMult); | |
| 1263 | case BO_DivAssign: | |
| 1264 | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_DivAssign"); | |
| 1265 | return nullptr; | |
| 1266 | case BO_RemAssign: | |
| 1267 | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_RemAssign"); | |
| 1268 | return nullptr; | |
| 1269 | case BO_AddAssign: | |
| 1270 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1271 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignPlusWrap, BinOpTypeAddWrap); | |
| 1272 | else | |
| 1273 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignPlus, BinOpTypeAdd); | |
| 1274 | case BO_SubAssign: | |
| 1275 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1276 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignMinusWrap, BinOpTypeSubWrap); | |
| 1277 | else | |
| 1278 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignMinus, BinOpTypeSub); | |
| 1279 | case BO_ShlAssign: | |
| 1280 | return trans_create_compound_assign_shift(c, result_used, block, stmt, BinOpTypeAssignBitShiftLeft, BinOpTypeBitShiftLeft); | |
| 1281 | case BO_ShrAssign: | |
| 1282 | return trans_create_compound_assign_shift(c, result_used, block, stmt, BinOpTypeAssignBitShiftRight, BinOpTypeBitShiftRight); | |
| 1283 | case BO_AndAssign: | |
| 1284 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitAnd, BinOpTypeBinAnd); | |
| 1285 | case BO_XorAssign: | |
| 1286 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitXor, BinOpTypeBinXor); | |
| 1287 | case BO_OrAssign: | |
| 1288 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitOr, BinOpTypeBinOr); | |
| 1289 | case BO_PtrMemD: | |
| 1290 | case BO_PtrMemI: | |
| 1291 | case BO_Assign: | |
| 1292 | case BO_Mul: | |
| 1293 | case BO_Div: | |
| 1294 | case BO_Rem: | |
| 1295 | case BO_Add: | |
| 1296 | case BO_Sub: | |
| 1297 | case BO_Shl: | |
| 1298 | case BO_Shr: | |
| 1299 | case BO_LT: | |
| 1300 | case BO_GT: | |
| 1301 | case BO_LE: | |
| 1302 | case BO_GE: | |
| 1303 | case BO_EQ: | |
| 1304 | case BO_NE: | |
| 1305 | case BO_And: | |
| 1306 | case BO_Xor: | |
| 1307 | case BO_Or: | |
| 1308 | case BO_LAnd: | |
| 1309 | case BO_LOr: | |
| 1310 | case BO_Comma: | |
| 1311 | zig_unreachable(); | |
| 1312 | } | |
| 1313 | ||
| 1314 | zig_unreachable(); | |
| 1315 | } | |
| 1316 | ||
| 1317 | static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCastExpr *stmt) { | |
| 1318 | switch (stmt->getCastKind()) { | |
| 1319 | case CK_LValueToRValue: | |
| 1320 | return trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); | |
| 1321 | case CK_IntegralCast: | |
| 1322 | { | |
| 1323 | AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); | |
| 1324 | if (target_node == nullptr) | |
| 1325 | return nullptr; | |
| 1326 | return trans_c_cast(c, stmt->getExprLoc(), stmt->getType(), target_node); | |
| 1327 | } | |
| 1328 | case CK_FunctionToPointerDecay: | |
| 1329 | case CK_ArrayToPointerDecay: | |
| 1330 | { | |
| 1331 | AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); | |
| 1332 | if (target_node == nullptr) | |
| 1333 | return nullptr; | |
| 1334 | return target_node; | |
| 1335 | } | |
| 1336 | case CK_BitCast: | |
| 1337 | { | |
| 1338 | AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); | |
| 1339 | if (target_node == nullptr) | |
| 1340 | return nullptr; | |
| 1341 | ||
| 1342 | AstNode *dest_type_node = trans_qual_type(c, stmt->getType(), stmt->getLocStart()); | |
| 1343 | ||
| 1344 | AstNode *node = trans_create_node_builtin_fn_call_str(c, "ptrCast"); | |
| 1345 | node->data.fn_call_expr.params.append(dest_type_node); | |
| 1346 | node->data.fn_call_expr.params.append(target_node); | |
| 1347 | return node; | |
| 1348 | } | |
| 1349 | case CK_NullToPointer: | |
| 1350 | return trans_create_node(c, NodeTypeNullLiteral); | |
| 1351 | case CK_Dependent: | |
| 1352 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent"); | |
| 1353 | return nullptr; | |
| 1354 | case CK_LValueBitCast: | |
| 1355 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_LValueBitCast"); | |
| 1356 | return nullptr; | |
| 1357 | case CK_NoOp: | |
| 1358 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NoOp"); | |
| 1359 | return nullptr; | |
| 1360 | case CK_BaseToDerived: | |
| 1361 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BaseToDerived"); | |
| 1362 | return nullptr; | |
| 1363 | case CK_DerivedToBase: | |
| 1364 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_DerivedToBase"); | |
| 1365 | return nullptr; | |
| 1366 | case CK_UncheckedDerivedToBase: | |
| 1367 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_UncheckedDerivedToBase"); | |
| 1368 | return nullptr; | |
| 1369 | case CK_Dynamic: | |
| 1370 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dynamic"); | |
| 1371 | return nullptr; | |
| 1372 | case CK_ToUnion: | |
| 1373 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ToUnion"); | |
| 1374 | return nullptr; | |
| 1375 | case CK_NullToMemberPointer: | |
| 1376 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NullToMemberPointer"); | |
| 1377 | return nullptr; | |
| 1378 | case CK_BaseToDerivedMemberPointer: | |
| 1379 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BaseToDerivedMemberPointer"); | |
| 1380 | return nullptr; | |
| 1381 | case CK_DerivedToBaseMemberPointer: | |
| 1382 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_DerivedToBaseMemberPointer"); | |
| 1383 | return nullptr; | |
| 1384 | case CK_MemberPointerToBoolean: | |
| 1385 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_MemberPointerToBoolean"); | |
| 1386 | return nullptr; | |
| 1387 | case CK_ReinterpretMemberPointer: | |
| 1388 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ReinterpretMemberPointer"); | |
| 1389 | return nullptr; | |
| 1390 | case CK_UserDefinedConversion: | |
| 1391 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_UserDefinedConversion"); | |
| 1392 | return nullptr; | |
| 1393 | case CK_ConstructorConversion: | |
| 1394 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ConstructorConversion"); | |
| 1395 | return nullptr; | |
| 1396 | case CK_IntegralToPointer: | |
| 1397 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralToPointer"); | |
| 1398 | return nullptr; | |
| 1399 | case CK_PointerToIntegral: | |
| 1400 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_PointerToIntegral"); | |
| 1401 | return nullptr; | |
| 1402 | case CK_PointerToBoolean: | |
| 1403 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_PointerToBoolean"); | |
| 1404 | return nullptr; | |
| 1405 | case CK_ToVoid: | |
| 1406 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ToVoid"); | |
| 1407 | return nullptr; | |
| 1408 | case CK_VectorSplat: | |
| 1409 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_VectorSplat"); | |
| 1410 | return nullptr; | |
| 1411 | case CK_IntegralToBoolean: | |
| 1412 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralToBoolean"); | |
| 1413 | return nullptr; | |
| 1414 | case CK_IntegralToFloating: | |
| 1415 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralToFloating"); | |
| 1416 | return nullptr; | |
| 1417 | case CK_FloatingToIntegral: | |
| 1418 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingToIntegral"); | |
| 1419 | return nullptr; | |
| 1420 | case CK_FloatingToBoolean: | |
| 1421 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingToBoolean"); | |
| 1422 | return nullptr; | |
| 1423 | case CK_BooleanToSignedIntegral: | |
| 1424 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BooleanToSignedIntegral"); | |
| 1425 | return nullptr; | |
| 1426 | case CK_FloatingCast: | |
| 1427 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingCast"); | |
| 1428 | return nullptr; | |
| 1429 | case CK_CPointerToObjCPointerCast: | |
| 1430 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_CPointerToObjCPointerCast"); | |
| 1431 | return nullptr; | |
| 1432 | case CK_BlockPointerToObjCPointerCast: | |
| 1433 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BlockPointerToObjCPointerCast"); | |
| 1434 | return nullptr; | |
| 1435 | case CK_AnyPointerToBlockPointerCast: | |
| 1436 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_AnyPointerToBlockPointerCast"); | |
| 1437 | return nullptr; | |
| 1438 | case CK_ObjCObjectLValueCast: | |
| 1439 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ObjCObjectLValueCast"); | |
| 1440 | return nullptr; | |
| 1441 | case CK_FloatingRealToComplex: | |
| 1442 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingRealToComplex"); | |
| 1443 | return nullptr; | |
| 1444 | case CK_FloatingComplexToReal: | |
| 1445 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexToReal"); | |
| 1446 | return nullptr; | |
| 1447 | case CK_FloatingComplexToBoolean: | |
| 1448 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexToBoolean"); | |
| 1449 | return nullptr; | |
| 1450 | case CK_FloatingComplexCast: | |
| 1451 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexCast"); | |
| 1452 | return nullptr; | |
| 1453 | case CK_FloatingComplexToIntegralComplex: | |
| 1454 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexToIntegralComplex"); | |
| 1455 | return nullptr; | |
| 1456 | case CK_IntegralRealToComplex: | |
| 1457 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralRealToComplex"); | |
| 1458 | return nullptr; | |
| 1459 | case CK_IntegralComplexToReal: | |
| 1460 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexToReal"); | |
| 1461 | return nullptr; | |
| 1462 | case CK_IntegralComplexToBoolean: | |
| 1463 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexToBoolean"); | |
| 1464 | return nullptr; | |
| 1465 | case CK_IntegralComplexCast: | |
| 1466 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexCast"); | |
| 1467 | return nullptr; | |
| 1468 | case CK_IntegralComplexToFloatingComplex: | |
| 1469 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexToFloatingComplex"); | |
| 1470 | return nullptr; | |
| 1471 | case CK_ARCProduceObject: | |
| 1472 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCProduceObject"); | |
| 1473 | return nullptr; | |
| 1474 | case CK_ARCConsumeObject: | |
| 1475 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCConsumeObject"); | |
| 1476 | return nullptr; | |
| 1477 | case CK_ARCReclaimReturnedObject: | |
| 1478 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCReclaimReturnedObject"); | |
| 1479 | return nullptr; | |
| 1480 | case CK_ARCExtendBlockObject: | |
| 1481 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCExtendBlockObject"); | |
| 1482 | return nullptr; | |
| 1483 | case CK_AtomicToNonAtomic: | |
| 1484 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_AtomicToNonAtomic"); | |
| 1485 | return nullptr; | |
| 1486 | case CK_NonAtomicToAtomic: | |
| 1487 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NonAtomicToAtomic"); | |
| 1488 | return nullptr; | |
| 1489 | case CK_CopyAndAutoreleaseBlockObject: | |
| 1490 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_CopyAndAutoreleaseBlockObject"); | |
| 1491 | return nullptr; | |
| 1492 | case CK_BuiltinFnToFnPtr: | |
| 1493 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BuiltinFnToFnPtr"); | |
| 1494 | return nullptr; | |
| 1495 | case CK_ZeroToOCLEvent: | |
| 1496 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ZeroToOCLEvent"); | |
| 1497 | return nullptr; | |
| 1498 | case CK_ZeroToOCLQueue: | |
| 1499 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ZeroToOCLQueue"); | |
| 1500 | return nullptr; | |
| 1501 | case CK_AddressSpaceConversion: | |
| 1502 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_AddressSpaceConversion"); | |
| 1503 | return nullptr; | |
| 1504 | case CK_IntToOCLSampler: | |
| 1505 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntToOCLSampler"); | |
| 1506 | return nullptr; | |
| 1507 | } | |
| 1508 | zig_unreachable(); | |
| 1509 | } | |
| 1510 | ||
| 1511 | static AstNode *trans_decl_ref_expr(Context *c, DeclRefExpr *stmt, TransLRValue lrval) { | |
| 1512 | ValueDecl *value_decl = stmt->getDecl(); | |
| 1513 | Buf *symbol_name = buf_create_from_str(decl_name(value_decl)); | |
| 1514 | if (lrval == TransLValue) { | |
| 1515 | c->ptr_params.put(symbol_name, true); | |
| 1516 | } | |
| 1517 | return trans_create_node_symbol(c, symbol_name); | |
| 1518 | } | |
| 1519 | ||
| 1520 | static AstNode *trans_create_post_crement(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt, BinOpType assign_op) { | |
| 1521 | Expr *op_expr = stmt->getSubExpr(); | |
| 1522 | ||
| 1523 | if (!result_used) { | |
| 1524 | // common case | |
| 1525 | // c: expr++ | |
| 1526 | // zig: expr += 1 | |
| 1527 | return trans_create_node_bin_op(c, | |
| 1528 | trans_expr(c, true, block, op_expr, TransLValue), | |
| 1529 | assign_op, | |
| 1530 | trans_create_node_unsigned(c, 1)); | |
| 1531 | } else { | |
| 1532 | // worst case | |
| 1533 | // c: expr++ | |
| 1534 | // zig: { | |
| 1535 | // zig: const _ref = &expr; | |
| 1536 | // zig: const _tmp = *_ref; | |
| 1537 | // zig: *_ref += 1; | |
| 1538 | // zig: _tmp | |
| 1539 | // zig: } | |
| 1540 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | |
| 1541 | ||
| 1542 | // const _ref = &expr; | |
| 1543 | AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue); | |
| 1544 | if (expr == nullptr) return nullptr; | |
| 1545 | AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr); | |
| 1546 | // TODO: avoid name collisions with generated variable names | |
| 1547 | Buf* ref_var_name = buf_create_from_str("_ref"); | |
| 1548 | AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr); | |
| 1549 | child_block->data.block.statements.append(ref_var_decl); | |
| 1550 | ||
| 1551 | // const _tmp = *_ref; | |
| 1552 | Buf* tmp_var_name = buf_create_from_str("_tmp"); | |
| 1553 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, | |
| 1554 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1555 | trans_create_node_symbol(c, ref_var_name))); | |
| 1556 | child_block->data.block.statements.append(tmp_var_decl); | |
| 1557 | ||
| 1558 | // *_ref += 1; | |
| 1559 | AstNode *assign_statement = trans_create_node_bin_op(c, | |
| 1560 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1561 | trans_create_node_symbol(c, ref_var_name)), | |
| 1562 | assign_op, | |
| 1563 | trans_create_node_unsigned(c, 1)); | |
| 1564 | child_block->data.block.statements.append(assign_statement); | |
| 1565 | ||
| 1566 | // _tmp | |
| 1567 | child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name)); | |
| 1568 | child_block->data.block.last_statement_is_result_expression = true; | |
| 1569 | ||
| 1570 | return child_block; | |
| 1571 | } | |
| 1572 | } | |
| 1573 | ||
| 1574 | static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) { | |
| 1575 | switch (stmt->getOpcode()) { | |
| 1576 | case UO_PostInc: | |
| 1577 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1578 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlusWrap); | |
| 1579 | else | |
| 1580 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlus); | |
| 1581 | case UO_PostDec: | |
| 1582 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1583 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinusWrap); | |
| 1584 | else | |
| 1585 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinus); | |
| 1586 | case UO_PreInc: | |
| 1587 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreInc"); | |
| 1588 | return nullptr; | |
| 1589 | case UO_PreDec: | |
| 1590 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreDec"); | |
| 1591 | return nullptr; | |
| 1592 | case UO_AddrOf: | |
| 1593 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_AddrOf"); | |
| 1594 | return nullptr; | |
| 1595 | case UO_Deref: | |
| 1596 | { | |
| 1597 | bool is_fn_ptr = qual_type_is_fn_ptr(c, stmt->getSubExpr()->getType()); | |
| 1598 | AstNode *value_node = trans_expr(c, result_used, block, stmt->getSubExpr(), TransRValue); | |
| 1599 | if (is_fn_ptr) | |
| 1600 | return value_node; | |
| 1601 | AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node); | |
| 1602 | return trans_create_node_prefix_op(c, PrefixOpDereference, unwrapped); | |
| 1603 | } | |
| 1604 | case UO_Plus: | |
| 1605 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Plus"); | |
| 1606 | return nullptr; | |
| 1607 | case UO_Minus: | |
| 1608 | { | |
| 1609 | Expr *op_expr = stmt->getSubExpr(); | |
| 1610 | if (!qual_type_has_wrapping_overflow(c, op_expr->getType())) { | |
| 1611 | AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); | |
| 1612 | node->data.prefix_op_expr.prefix_op = PrefixOpNegation; | |
| 1613 | ||
| 1614 | node->data.prefix_op_expr.primary_expr = trans_expr(c, true, block, op_expr, TransRValue); | |
| 1615 | if (node->data.prefix_op_expr.primary_expr == nullptr) | |
| 1616 | return nullptr; | |
| 1617 | ||
| 1618 | return node; | |
| 1619 | } else if (c_is_unsigned_integer(c, op_expr->getType())) { | |
| 1620 | // we gotta emit 0 -% x | |
| 1621 | AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); | |
| 1622 | node->data.bin_op_expr.op1 = trans_create_node_unsigned(c, 0); | |
| 1623 | ||
| 1624 | node->data.bin_op_expr.op2 = trans_expr(c, true, block, op_expr, TransRValue); | |
| 1625 | if (node->data.bin_op_expr.op2 == nullptr) | |
| 1626 | return nullptr; | |
| 1627 | ||
| 1628 | node->data.bin_op_expr.bin_op = BinOpTypeSubWrap; | |
| 1629 | return node; | |
| 1630 | } else { | |
| 1631 | emit_warning(c, stmt->getLocStart(), "C negation with non float non integer"); | |
| 1632 | return nullptr; | |
| 1633 | } | |
| 1634 | } | |
| 1635 | case UO_Not: | |
| 1636 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Not"); | |
| 1637 | return nullptr; | |
| 1638 | case UO_LNot: | |
| 1639 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_LNot"); | |
| 1640 | return nullptr; | |
| 1641 | case UO_Real: | |
| 1642 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Real"); | |
| 1643 | return nullptr; | |
| 1644 | case UO_Imag: | |
| 1645 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Imag"); | |
| 1646 | return nullptr; | |
| 1647 | case UO_Extension: | |
| 1648 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Extension"); | |
| 1649 | return nullptr; | |
| 1650 | case UO_Coawait: | |
| 1651 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Coawait"); | |
| 1652 | return nullptr; | |
| 1653 | } | |
| 1654 | zig_unreachable(); | |
| 1655 | } | |
| 1656 | ||
| 1657 | static AstNode *trans_local_declaration(Context *c, AstNode *block, DeclStmt *stmt) { | |
| 1658 | for (auto iter = stmt->decl_begin(); iter != stmt->decl_end(); iter++) { | |
| 1659 | Decl *decl = *iter; | |
| 1660 | switch (decl->getKind()) { | |
| 1661 | case Decl::Var: { | |
| 1662 | VarDecl *var_decl = (VarDecl *)decl; | |
| 1663 | QualType qual_type = var_decl->getTypeSourceInfo()->getType(); | |
| 1664 | AstNode *init_node = nullptr; | |
| 1665 | if (var_decl->hasInit()) { | |
| 1666 | init_node = trans_expr(c, true, block, var_decl->getInit(), TransRValue); | |
| 1667 | if (init_node == nullptr) | |
| 1668 | return nullptr; | |
| 1669 | ||
| 1670 | } | |
| 1671 | AstNode *type_node = trans_qual_type(c, qual_type, stmt->getLocStart()); | |
| 1672 | if (type_node == nullptr) | |
| 1673 | return nullptr; | |
| 1674 | ||
| 1675 | Buf *symbol_name = buf_create_from_str(decl_name(var_decl)); | |
| 1676 | ||
| 1677 | AstNode *node = trans_create_node_var_decl_local(c, qual_type.isConstQualified(), | |
| 1678 | symbol_name, type_node, init_node); | |
| 1679 | block->data.block.statements.append(node); | |
| 1680 | continue; | |
| 1681 | } | |
| 1682 | case Decl::AccessSpec: | |
| 1683 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind AccessSpec"); | |
| 1684 | return nullptr; | |
| 1685 | case Decl::Block: | |
| 1686 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Block"); | |
| 1687 | return nullptr; | |
| 1688 | case Decl::Captured: | |
| 1689 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Captured"); | |
| 1690 | return nullptr; | |
| 1691 | case Decl::ClassScopeFunctionSpecialization: | |
| 1692 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassScopeFunctionSpecialization"); | |
| 1693 | return nullptr; | |
| 1694 | case Decl::Empty: | |
| 1695 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Empty"); | |
| 1696 | return nullptr; | |
| 1697 | case Decl::Export: | |
| 1698 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Export"); | |
| 1699 | return nullptr; | |
| 1700 | case Decl::ExternCContext: | |
| 1701 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ExternCContext"); | |
| 1702 | return nullptr; | |
| 1703 | case Decl::FileScopeAsm: | |
| 1704 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FileScopeAsm"); | |
| 1705 | return nullptr; | |
| 1706 | case Decl::Friend: | |
| 1707 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Friend"); | |
| 1708 | return nullptr; | |
| 1709 | case Decl::FriendTemplate: | |
| 1710 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FriendTemplate"); | |
| 1711 | return nullptr; | |
| 1712 | case Decl::Import: | |
| 1713 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Import"); | |
| 1714 | return nullptr; | |
| 1715 | case Decl::LinkageSpec: | |
| 1716 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind LinkageSpec"); | |
| 1717 | return nullptr; | |
| 1718 | case Decl::Label: | |
| 1719 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Label"); | |
| 1720 | return nullptr; | |
| 1721 | case Decl::Namespace: | |
| 1722 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Namespace"); | |
| 1723 | return nullptr; | |
| 1724 | case Decl::NamespaceAlias: | |
| 1725 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind NamespaceAlias"); | |
| 1726 | return nullptr; | |
| 1727 | case Decl::ObjCCompatibleAlias: | |
| 1728 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCompatibleAlias"); | |
| 1729 | return nullptr; | |
| 1730 | case Decl::ObjCCategory: | |
| 1731 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCategory"); | |
| 1732 | return nullptr; | |
| 1733 | case Decl::ObjCCategoryImpl: | |
| 1734 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCategoryImpl"); | |
| 1735 | return nullptr; | |
| 1736 | case Decl::ObjCImplementation: | |
| 1737 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCImplementation"); | |
| 1738 | return nullptr; | |
| 1739 | case Decl::ObjCInterface: | |
| 1740 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCInterface"); | |
| 1741 | return nullptr; | |
| 1742 | case Decl::ObjCProtocol: | |
| 1743 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCProtocol"); | |
| 1744 | return nullptr; | |
| 1745 | case Decl::ObjCMethod: | |
| 1746 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCMethod"); | |
| 1747 | return nullptr; | |
| 1748 | case Decl::ObjCProperty: | |
| 1749 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCProperty"); | |
| 1750 | return nullptr; | |
| 1751 | case Decl::BuiltinTemplate: | |
| 1752 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind BuiltinTemplate"); | |
| 1753 | return nullptr; | |
| 1754 | case Decl::ClassTemplate: | |
| 1755 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplate"); | |
| 1756 | return nullptr; | |
| 1757 | case Decl::FunctionTemplate: | |
| 1758 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FunctionTemplate"); | |
| 1759 | return nullptr; | |
| 1760 | case Decl::TypeAliasTemplate: | |
| 1761 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TypeAliasTemplate"); | |
| 1762 | return nullptr; | |
| 1763 | case Decl::VarTemplate: | |
| 1764 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplate"); | |
| 1765 | return nullptr; | |
| 1766 | case Decl::TemplateTemplateParm: | |
| 1767 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TemplateTemplateParm"); | |
| 1768 | return nullptr; | |
| 1769 | case Decl::Enum: | |
| 1770 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Enum"); | |
| 1771 | return nullptr; | |
| 1772 | case Decl::Record: | |
| 1773 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Record"); | |
| 1774 | return nullptr; | |
| 1775 | case Decl::CXXRecord: | |
| 1776 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXRecord"); | |
| 1777 | return nullptr; | |
| 1778 | case Decl::ClassTemplateSpecialization: | |
| 1779 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplateSpecialization"); | |
| 1780 | return nullptr; | |
| 1781 | case Decl::ClassTemplatePartialSpecialization: | |
| 1782 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplatePartialSpecialization"); | |
| 1783 | return nullptr; | |
| 1784 | case Decl::TemplateTypeParm: | |
| 1785 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TemplateTypeParm"); | |
| 1786 | return nullptr; | |
| 1787 | case Decl::ObjCTypeParam: | |
| 1788 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCTypeParam"); | |
| 1789 | return nullptr; | |
| 1790 | case Decl::TypeAlias: | |
| 1791 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TypeAlias"); | |
| 1792 | return nullptr; | |
| 1793 | case Decl::Typedef: | |
| 1794 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Typedef"); | |
| 1795 | return nullptr; | |
| 1796 | case Decl::UnresolvedUsingTypename: | |
| 1797 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UnresolvedUsingTypename"); | |
| 1798 | return nullptr; | |
| 1799 | case Decl::Using: | |
| 1800 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Using"); | |
| 1801 | return nullptr; | |
| 1802 | case Decl::UsingDirective: | |
| 1803 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingDirective"); | |
| 1804 | return nullptr; | |
| 1805 | case Decl::UsingPack: | |
| 1806 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingPack"); | |
| 1807 | return nullptr; | |
| 1808 | case Decl::UsingShadow: | |
| 1809 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingShadow"); | |
| 1810 | return nullptr; | |
| 1811 | case Decl::ConstructorUsingShadow: | |
| 1812 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ConstructorUsingShadow"); | |
| 1813 | return nullptr; | |
| 1814 | case Decl::Binding: | |
| 1815 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Binding"); | |
| 1816 | return nullptr; | |
| 1817 | case Decl::Field: | |
| 1818 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Field"); | |
| 1819 | return nullptr; | |
| 1820 | case Decl::ObjCAtDefsField: | |
| 1821 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCAtDefsField"); | |
| 1822 | return nullptr; | |
| 1823 | case Decl::ObjCIvar: | |
| 1824 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCIvar"); | |
| 1825 | return nullptr; | |
| 1826 | case Decl::Function: | |
| 1827 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Function"); | |
| 1828 | return nullptr; | |
| 1829 | case Decl::CXXDeductionGuide: | |
| 1830 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXDeductionGuide"); | |
| 1831 | return nullptr; | |
| 1832 | case Decl::CXXMethod: | |
| 1833 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXMethod"); | |
| 1834 | return nullptr; | |
| 1835 | case Decl::CXXConstructor: | |
| 1836 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXConstructor"); | |
| 1837 | return nullptr; | |
| 1838 | case Decl::CXXConversion: | |
| 1839 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXConversion"); | |
| 1840 | return nullptr; | |
| 1841 | case Decl::CXXDestructor: | |
| 1842 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXDestructor"); | |
| 1843 | return nullptr; | |
| 1844 | case Decl::MSProperty: | |
| 1845 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind MSProperty"); | |
| 1846 | return nullptr; | |
| 1847 | case Decl::NonTypeTemplateParm: | |
| 1848 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind NonTypeTemplateParm"); | |
| 1849 | return nullptr; | |
| 1850 | case Decl::Decomposition: | |
| 1851 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Decomposition"); | |
| 1852 | return nullptr; | |
| 1853 | case Decl::ImplicitParam: | |
| 1854 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ImplicitParam"); | |
| 1855 | return nullptr; | |
| 1856 | case Decl::OMPCapturedExpr: | |
| 1857 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPCapturedExpr"); | |
| 1858 | return nullptr; | |
| 1859 | case Decl::ParmVar: | |
| 1860 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ParmVar"); | |
| 1861 | return nullptr; | |
| 1862 | case Decl::VarTemplateSpecialization: | |
| 1863 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplateSpecialization"); | |
| 1864 | return nullptr; | |
| 1865 | case Decl::VarTemplatePartialSpecialization: | |
| 1866 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplatePartialSpecialization"); | |
| 1867 | return nullptr; | |
| 1868 | case Decl::EnumConstant: | |
| 1869 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind EnumConstant"); | |
| 1870 | return nullptr; | |
| 1871 | case Decl::IndirectField: | |
| 1872 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind IndirectField"); | |
| 1873 | return nullptr; | |
| 1874 | case Decl::OMPDeclareReduction: | |
| 1875 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPDeclareReduction"); | |
| 1876 | return nullptr; | |
| 1877 | case Decl::UnresolvedUsingValue: | |
| 1878 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UnresolvedUsingValue"); | |
| 1879 | return nullptr; | |
| 1880 | case Decl::OMPThreadPrivate: | |
| 1881 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPThreadPrivate"); | |
| 1882 | return nullptr; | |
| 1883 | case Decl::ObjCPropertyImpl: | |
| 1884 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCPropertyImpl"); | |
| 1885 | return nullptr; | |
| 1886 | case Decl::PragmaComment: | |
| 1887 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind PragmaComment"); | |
| 1888 | return nullptr; | |
| 1889 | case Decl::PragmaDetectMismatch: | |
| 1890 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind PragmaDetectMismatch"); | |
| 1891 | return nullptr; | |
| 1892 | case Decl::StaticAssert: | |
| 1893 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind StaticAssert"); | |
| 1894 | return nullptr; | |
| 1895 | case Decl::TranslationUnit: | |
| 1896 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TranslationUnit"); | |
| 1897 | return nullptr; | |
| 1898 | } | |
| 1899 | zig_unreachable(); | |
| 1900 | } | |
| 1901 | ||
| 1902 | // declarations were already added | |
| 1903 | return skip_add_to_block_node; | |
| 1904 | } | |
| 1905 | ||
| 1906 | static AstNode *trans_while_loop(Context *c, AstNode *block, WhileStmt *stmt) { | |
| 1907 | AstNode *while_node = trans_create_node(c, NodeTypeWhileExpr); | |
| 1908 | ||
| 1909 | while_node->data.while_expr.condition = trans_expr(c, true, block, stmt->getCond(), TransRValue); | |
| 1910 | if (while_node->data.while_expr.condition == nullptr) | |
| 1911 | return nullptr; | |
| 1912 | ||
| 1913 | while_node->data.while_expr.body = trans_stmt(c, false, block, stmt->getBody(), TransRValue); | |
| 1914 | if (while_node->data.while_expr.body == nullptr) | |
| 1915 | return nullptr; | |
| 1916 | ||
| 1917 | return while_node; | |
| 1918 | } | |
| 1919 | ||
| 1920 | static AstNode *trans_if_statement(Context *c, AstNode *block, IfStmt *stmt) { | |
| 1921 | // if (c) t | |
| 1922 | // if (c) t else e | |
| 1923 | AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr); | |
| 1924 | ||
| 1925 | // TODO: condition != 0 | |
| 1926 | AstNode *condition_node = trans_expr(c, true, block, stmt->getCond(), TransRValue); | |
| 1927 | if (condition_node == nullptr) | |
| 1928 | return nullptr; | |
| 1929 | if_node->data.if_bool_expr.condition = condition_node; | |
| 1930 | ||
| 1931 | if_node->data.if_bool_expr.then_block = trans_stmt(c, false, block, stmt->getThen(), TransRValue); | |
| 1932 | if (if_node->data.if_bool_expr.then_block == nullptr) | |
| 1933 | return nullptr; | |
| 1934 | ||
| 1935 | if (stmt->getElse() != nullptr) { | |
| 1936 | if_node->data.if_bool_expr.else_node = trans_stmt(c, false, block, stmt->getElse(), TransRValue); | |
| 1937 | if (if_node->data.if_bool_expr.else_node == nullptr) | |
| 1938 | return nullptr; | |
| 1939 | } | |
| 1940 | ||
| 1941 | return if_node; | |
| 1942 | } | |
| 1943 | ||
| 1944 | static AstNode *trans_call_expr(Context *c, bool result_used, AstNode *block, CallExpr *stmt) { | |
| 1945 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 1946 | ||
| 1947 | AstNode *callee_raw_node = trans_expr(c, true, block, stmt->getCallee(), TransRValue); | |
| 1948 | if (callee_raw_node == nullptr) | |
| 1949 | return nullptr; | |
| 1950 | ||
| 1951 | AstNode *callee_node; | |
| 1952 | if (qual_type_is_fn_ptr(c, stmt->getCallee()->getType())) { | |
| 1953 | callee_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, callee_raw_node); | |
| 1954 | } else { | |
| 1955 | callee_node = callee_raw_node; | |
| 1956 | } | |
| 1957 | ||
| 1958 | node->data.fn_call_expr.fn_ref_expr = callee_node; | |
| 1959 | ||
| 1960 | unsigned num_args = stmt->getNumArgs(); | |
| 1961 | Expr **args = stmt->getArgs(); | |
| 1962 | for (unsigned i = 0; i < num_args; i += 1) { | |
| 1963 | AstNode *arg_node = trans_expr(c, true, block, args[i], TransRValue); | |
| 1964 | if (arg_node == nullptr) | |
| 1965 | return nullptr; | |
| 1966 | ||
| 1967 | node->data.fn_call_expr.params.append(arg_node); | |
| 1968 | } | |
| 1969 | ||
| 1970 | return node; | |
| 1971 | } | |
| 1972 | ||
| 1973 | static AstNode *trans_member_expr(Context *c, AstNode *block, MemberExpr *stmt) { | |
| 1974 | AstNode *container_node = trans_expr(c, true, block, stmt->getBase(), TransRValue); | |
| 1975 | if (container_node == nullptr) | |
| 1976 | return nullptr; | |
| 1977 | ||
| 1978 | if (stmt->isArrow()) { | |
| 1979 | container_node = trans_create_node_unwrap_null(c, container_node); | |
| 1980 | } | |
| 1981 | ||
| 1982 | const char *name = decl_name(stmt->getMemberDecl()); | |
| 1983 | ||
| 1984 | AstNode *node = trans_create_node_field_access_str(c, container_node, name); | |
| 1985 | return node; | |
| 1986 | } | |
| 1987 | ||
| 1988 | static AstNode *trans_array_subscript_expr(Context *c, AstNode *block, ArraySubscriptExpr *stmt) { | |
| 1989 | AstNode *container_node = trans_expr(c, true, block, stmt->getBase(), TransRValue); | |
| 1990 | if (container_node == nullptr) | |
| 1991 | return nullptr; | |
| 1992 | ||
| 1993 | AstNode *idx_node = trans_expr(c, true, block, stmt->getIdx(), TransRValue); | |
| 1994 | if (idx_node == nullptr) | |
| 1995 | return nullptr; | |
| 1996 | ||
| 1997 | ||
| 1998 | AstNode *node = trans_create_node(c, NodeTypeArrayAccessExpr); | |
| 1999 | node->data.array_access_expr.array_ref_expr = container_node; | |
| 2000 | node->data.array_access_expr.subscript = idx_node; | |
| 2001 | return node; | |
| 2002 | } | |
| 2003 | ||
| 2004 | static AstNode *trans_c_style_cast_expr(Context *c, bool result_used, AstNode *block, | |
| 2005 | CStyleCastExpr *stmt, TransLRValue lrvalue) | |
| 2006 | { | |
| 2007 | AstNode *sub_expr_node = trans_expr(c, result_used, block, stmt->getSubExpr(), lrvalue); | |
| 2008 | if (sub_expr_node == nullptr) | |
| 2009 | return nullptr; | |
| 2010 | ||
| 2011 | return trans_c_cast(c, stmt->getLocStart(), stmt->getType(), sub_expr_node); | |
| 2012 | } | |
| 2013 | ||
| 2014 | static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, AstNode *block, UnaryExprOrTypeTraitExpr *stmt) { | |
| 2015 | AstNode *type_node = trans_qual_type(c, stmt->getTypeOfArgument(), stmt->getLocStart()); | |
| 2016 | if (type_node == nullptr) | |
| 2017 | return nullptr; | |
| 2018 | ||
| 2019 | AstNode *node = trans_create_node_builtin_fn_call_str(c, "sizeOf"); | |
| 2020 | node->data.fn_call_expr.params.append(type_node); | |
| 2021 | return node; | |
| 2022 | } | |
| 2023 | ||
| 2024 | static AstNode *trans_do_loop(Context *c, AstNode *block, DoStmt *stmt) { | |
| 2025 | stmt->getBody(); | |
| 2026 | stmt->getCond(); | |
| 2027 | ||
| 2028 | AstNode *while_node = trans_create_node(c, NodeTypeWhileExpr); | |
| 2029 | ||
| 2030 | AstNode *true_node = trans_create_node(c, NodeTypeBoolLiteral); | |
| 2031 | true_node->data.bool_literal.value = true; | |
| 2032 | while_node->data.while_expr.condition = true_node; | |
| 2033 | ||
| 2034 | AstNode *body_node; | |
| 2035 | if (stmt->getBody()->getStmtClass() == Stmt::CompoundStmtClass) { | |
| 2036 | // there's already a block in C, so we'll append our condition to it. | |
| 2037 | // c: do { | |
| 2038 | // c: a; | |
| 2039 | // c: b; | |
| 2040 | // c: } while(c); | |
| 2041 | // zig: while (true) { | |
| 2042 | // zig: a; | |
| 2043 | // zig: b; | |
| 2044 | // zig: if (!cond) break; | |
| 2045 | // zig: } | |
| 2046 | body_node = trans_stmt(c, false, block, stmt->getBody(), TransRValue); | |
| 2047 | if (body_node == nullptr) return nullptr; | |
| 2048 | assert(body_node->type == NodeTypeBlock); | |
| 2049 | } else { | |
| 2050 | // the C statement is without a block, so we need to create a block to contain it. | |
| 2051 | // c: do | |
| 2052 | // c: a; | |
| 2053 | // c: while(c); | |
| 2054 | // zig: while (true) { | |
| 2055 | // zig: a; | |
| 2056 | // zig: if (!cond) break; | |
| 2057 | // zig: } | |
| 2058 | body_node = trans_create_node(c, NodeTypeBlock); | |
| 2059 | AstNode *child_statement = trans_stmt(c, false, body_node, stmt->getBody(), TransRValue); | |
| 2060 | if (child_statement == nullptr) return nullptr; | |
| 2061 | body_node->data.block.statements.append(child_statement); | |
| 2062 | } | |
| 2063 | ||
| 2064 | // if (!cond) break; | |
| 2065 | AstNode *condition_node = trans_expr(c, true, body_node, stmt->getCond(), TransRValue); | |
| 2066 | if (condition_node == nullptr) return nullptr; | |
| 2067 | AstNode *terminator_node = trans_create_node(c, NodeTypeIfBoolExpr); | |
| 2068 | terminator_node->data.if_bool_expr.condition = trans_create_node_prefix_op(c, PrefixOpBoolNot, condition_node); | |
| 2069 | terminator_node->data.if_bool_expr.then_block = trans_create_node(c, NodeTypeBreak); | |
| 2070 | body_node->data.block.statements.append(terminator_node); | |
| 2071 | ||
| 2072 | while_node->data.while_expr.body = body_node; | |
| 2073 | ||
| 2074 | return while_node; | |
| 2075 | } | |
| 2076 | ||
| 2077 | static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrvalue) { | |
| 2078 | Stmt::StmtClass sc = stmt->getStmtClass(); | |
| 2079 | switch (sc) { | |
| 2080 | case Stmt::ReturnStmtClass: | |
| 2081 | return trans_return_stmt(c, block, (ReturnStmt *)stmt); | |
| 2082 | case Stmt::CompoundStmtClass: | |
| 2083 | return trans_compound_stmt(c, block, (CompoundStmt *)stmt); | |
| 2084 | case Stmt::IntegerLiteralClass: | |
| 2085 | return trans_integer_literal(c, (IntegerLiteral *)stmt); | |
| 2086 | case Stmt::ConditionalOperatorClass: | |
| 2087 | return trans_conditional_operator(c, result_used, block, (ConditionalOperator *)stmt); | |
| 2088 | case Stmt::BinaryOperatorClass: | |
| 2089 | return trans_binary_operator(c, result_used, block, (BinaryOperator *)stmt); | |
| 2090 | case Stmt::CompoundAssignOperatorClass: | |
| 2091 | return trans_compound_assign_operator(c, result_used, block, (CompoundAssignOperator *)stmt); | |
| 2092 | case Stmt::ImplicitCastExprClass: | |
| 2093 | return trans_implicit_cast_expr(c, block, (ImplicitCastExpr *)stmt); | |
| 2094 | case Stmt::DeclRefExprClass: | |
| 2095 | return trans_decl_ref_expr(c, (DeclRefExpr *)stmt, lrvalue); | |
| 2096 | case Stmt::UnaryOperatorClass: | |
| 2097 | return trans_unary_operator(c, result_used, block, (UnaryOperator *)stmt); | |
| 2098 | case Stmt::DeclStmtClass: | |
| 2099 | return trans_local_declaration(c, block, (DeclStmt *)stmt); | |
| 2100 | case Stmt::WhileStmtClass: | |
| 2101 | return trans_while_loop(c, block, (WhileStmt *)stmt); | |
| 2102 | case Stmt::IfStmtClass: | |
| 2103 | return trans_if_statement(c, block, (IfStmt *)stmt); | |
| 2104 | case Stmt::CallExprClass: | |
| 2105 | return trans_call_expr(c, result_used, block, (CallExpr *)stmt); | |
| 2106 | case Stmt::NullStmtClass: | |
| 2107 | return skip_add_to_block_node; | |
| 2108 | case Stmt::MemberExprClass: | |
| 2109 | return trans_member_expr(c, block, (MemberExpr *)stmt); | |
| 2110 | case Stmt::ArraySubscriptExprClass: | |
| 2111 | return trans_array_subscript_expr(c, block, (ArraySubscriptExpr *)stmt); | |
| 2112 | case Stmt::CStyleCastExprClass: | |
| 2113 | return trans_c_style_cast_expr(c, result_used, block, (CStyleCastExpr *)stmt, lrvalue); | |
| 2114 | case Stmt::UnaryExprOrTypeTraitExprClass: | |
| 2115 | return trans_unary_expr_or_type_trait_expr(c, block, (UnaryExprOrTypeTraitExpr *)stmt); | |
| 2116 | case Stmt::DoStmtClass: | |
| 2117 | return trans_do_loop(c, block, (DoStmt *)stmt); | |
| 2118 | case Stmt::CaseStmtClass: | |
| 2119 | emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass"); | |
| 2120 | return nullptr; | |
| 2121 | case Stmt::DefaultStmtClass: | |
| 2122 | emit_warning(c, stmt->getLocStart(), "TODO handle C DefaultStmtClass"); | |
| 2123 | return nullptr; | |
| 2124 | case Stmt::SwitchStmtClass: | |
| 2125 | emit_warning(c, stmt->getLocStart(), "TODO handle C SwitchStmtClass"); | |
| 2126 | return nullptr; | |
| 2127 | case Stmt::NoStmtClass: | |
| 2128 | emit_warning(c, stmt->getLocStart(), "TODO handle C NoStmtClass"); | |
| 2129 | return nullptr; | |
| 2130 | case Stmt::GCCAsmStmtClass: | |
| 2131 | emit_warning(c, stmt->getLocStart(), "TODO handle C GCCAsmStmtClass"); | |
| 2132 | return nullptr; | |
| 2133 | case Stmt::MSAsmStmtClass: | |
| 2134 | emit_warning(c, stmt->getLocStart(), "TODO handle C MSAsmStmtClass"); | |
| 2135 | return nullptr; | |
| 2136 | case Stmt::AttributedStmtClass: | |
| 2137 | emit_warning(c, stmt->getLocStart(), "TODO handle C AttributedStmtClass"); | |
| 2138 | return nullptr; | |
| 2139 | case Stmt::BreakStmtClass: | |
| 2140 | emit_warning(c, stmt->getLocStart(), "TODO handle C BreakStmtClass"); | |
| 2141 | return nullptr; | |
| 2142 | case Stmt::CXXCatchStmtClass: | |
| 2143 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXCatchStmtClass"); | |
| 2144 | return nullptr; | |
| 2145 | case Stmt::CXXForRangeStmtClass: | |
| 2146 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXForRangeStmtClass"); | |
| 2147 | return nullptr; | |
| 2148 | case Stmt::CXXTryStmtClass: | |
| 2149 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTryStmtClass"); | |
| 2150 | return nullptr; | |
| 2151 | case Stmt::CapturedStmtClass: | |
| 2152 | emit_warning(c, stmt->getLocStart(), "TODO handle C CapturedStmtClass"); | |
| 2153 | return nullptr; | |
| 2154 | case Stmt::ContinueStmtClass: | |
| 2155 | emit_warning(c, stmt->getLocStart(), "TODO handle C ContinueStmtClass"); | |
| 2156 | return nullptr; | |
| 2157 | case Stmt::CoreturnStmtClass: | |
| 2158 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoreturnStmtClass"); | |
| 2159 | return nullptr; | |
| 2160 | case Stmt::CoroutineBodyStmtClass: | |
| 2161 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoroutineBodyStmtClass"); | |
| 2162 | return nullptr; | |
| 2163 | case Stmt::BinaryConditionalOperatorClass: | |
| 2164 | emit_warning(c, stmt->getLocStart(), "TODO handle C BinaryConditionalOperatorClass"); | |
| 2165 | return nullptr; | |
| 2166 | case Stmt::AddrLabelExprClass: | |
| 2167 | emit_warning(c, stmt->getLocStart(), "TODO handle C AddrLabelExprClass"); | |
| 2168 | return nullptr; | |
| 2169 | case Stmt::ArrayInitIndexExprClass: | |
| 2170 | emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayInitIndexExprClass"); | |
| 2171 | return nullptr; | |
| 2172 | case Stmt::ArrayInitLoopExprClass: | |
| 2173 | emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayInitLoopExprClass"); | |
| 2174 | return nullptr; | |
| 2175 | case Stmt::ArrayTypeTraitExprClass: | |
| 2176 | emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayTypeTraitExprClass"); | |
| 2177 | return nullptr; | |
| 2178 | case Stmt::AsTypeExprClass: | |
| 2179 | emit_warning(c, stmt->getLocStart(), "TODO handle C AsTypeExprClass"); | |
| 2180 | return nullptr; | |
| 2181 | case Stmt::AtomicExprClass: | |
| 2182 | emit_warning(c, stmt->getLocStart(), "TODO handle C AtomicExprClass"); | |
| 2183 | return nullptr; | |
| 2184 | case Stmt::BlockExprClass: | |
| 2185 | emit_warning(c, stmt->getLocStart(), "TODO handle C BlockExprClass"); | |
| 2186 | return nullptr; | |
| 2187 | case Stmt::CXXBindTemporaryExprClass: | |
| 2188 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXBindTemporaryExprClass"); | |
| 2189 | return nullptr; | |
| 2190 | case Stmt::CXXBoolLiteralExprClass: | |
| 2191 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXBoolLiteralExprClass"); | |
| 2192 | return nullptr; | |
| 2193 | case Stmt::CXXConstructExprClass: | |
| 2194 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXConstructExprClass"); | |
| 2195 | return nullptr; | |
| 2196 | case Stmt::CXXTemporaryObjectExprClass: | |
| 2197 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTemporaryObjectExprClass"); | |
| 2198 | return nullptr; | |
| 2199 | case Stmt::CXXDefaultArgExprClass: | |
| 2200 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDefaultArgExprClass"); | |
| 2201 | return nullptr; | |
| 2202 | case Stmt::CXXDefaultInitExprClass: | |
| 2203 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDefaultInitExprClass"); | |
| 2204 | return nullptr; | |
| 2205 | case Stmt::CXXDeleteExprClass: | |
| 2206 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDeleteExprClass"); | |
| 2207 | return nullptr; | |
| 2208 | case Stmt::CXXDependentScopeMemberExprClass: | |
| 2209 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDependentScopeMemberExprClass"); | |
| 2210 | return nullptr; | |
| 2211 | case Stmt::CXXFoldExprClass: | |
| 2212 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXFoldExprClass"); | |
| 2213 | return nullptr; | |
| 2214 | case Stmt::CXXInheritedCtorInitExprClass: | |
| 2215 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXInheritedCtorInitExprClass"); | |
| 2216 | return nullptr; | |
| 2217 | case Stmt::CXXNewExprClass: | |
| 2218 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNewExprClass"); | |
| 2219 | return nullptr; | |
| 2220 | case Stmt::CXXNoexceptExprClass: | |
| 2221 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNoexceptExprClass"); | |
| 2222 | return nullptr; | |
| 2223 | case Stmt::CXXNullPtrLiteralExprClass: | |
| 2224 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNullPtrLiteralExprClass"); | |
| 2225 | return nullptr; | |
| 2226 | case Stmt::CXXPseudoDestructorExprClass: | |
| 2227 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXPseudoDestructorExprClass"); | |
| 2228 | return nullptr; | |
| 2229 | case Stmt::CXXScalarValueInitExprClass: | |
| 2230 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXScalarValueInitExprClass"); | |
| 2231 | return nullptr; | |
| 2232 | case Stmt::CXXStdInitializerListExprClass: | |
| 2233 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXStdInitializerListExprClass"); | |
| 2234 | return nullptr; | |
| 2235 | case Stmt::CXXThisExprClass: | |
| 2236 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXThisExprClass"); | |
| 2237 | return nullptr; | |
| 2238 | case Stmt::CXXThrowExprClass: | |
| 2239 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXThrowExprClass"); | |
| 2240 | return nullptr; | |
| 2241 | case Stmt::CXXTypeidExprClass: | |
| 2242 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTypeidExprClass"); | |
| 2243 | return nullptr; | |
| 2244 | case Stmt::CXXUnresolvedConstructExprClass: | |
| 2245 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUnresolvedConstructExprClass"); | |
| 2246 | return nullptr; | |
| 2247 | case Stmt::CXXUuidofExprClass: | |
| 2248 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUuidofExprClass"); | |
| 2249 | return nullptr; | |
| 2250 | case Stmt::CUDAKernelCallExprClass: | |
| 2251 | emit_warning(c, stmt->getLocStart(), "TODO handle C CUDAKernelCallExprClass"); | |
| 2252 | return nullptr; | |
| 2253 | case Stmt::CXXMemberCallExprClass: | |
| 2254 | (void)result_used; | |
| 2255 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXMemberCallExprClass"); | |
| 2256 | return nullptr; | |
| 2257 | case Stmt::CXXOperatorCallExprClass: | |
| 2258 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXOperatorCallExprClass"); | |
| 2259 | return nullptr; | |
| 2260 | case Stmt::UserDefinedLiteralClass: | |
| 2261 | emit_warning(c, stmt->getLocStart(), "TODO handle C UserDefinedLiteralClass"); | |
| 2262 | return nullptr; | |
| 2263 | case Stmt::CXXFunctionalCastExprClass: | |
| 2264 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXFunctionalCastExprClass"); | |
| 2265 | return nullptr; | |
| 2266 | case Stmt::CXXConstCastExprClass: | |
| 2267 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXConstCastExprClass"); | |
| 2268 | return nullptr; | |
| 2269 | case Stmt::CXXDynamicCastExprClass: | |
| 2270 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDynamicCastExprClass"); | |
| 2271 | return nullptr; | |
| 2272 | case Stmt::CXXReinterpretCastExprClass: | |
| 2273 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXReinterpretCastExprClass"); | |
| 2274 | return nullptr; | |
| 2275 | case Stmt::CXXStaticCastExprClass: | |
| 2276 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXStaticCastExprClass"); | |
| 2277 | return nullptr; | |
| 2278 | case Stmt::ObjCBridgedCastExprClass: | |
| 2279 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBridgedCastExprClass"); | |
| 2280 | return nullptr; | |
| 2281 | case Stmt::CharacterLiteralClass: | |
| 2282 | emit_warning(c, stmt->getLocStart(), "TODO handle C CharacterLiteralClass"); | |
| 2283 | return nullptr; | |
| 2284 | case Stmt::ChooseExprClass: | |
| 2285 | emit_warning(c, stmt->getLocStart(), "TODO handle C ChooseExprClass"); | |
| 2286 | return nullptr; | |
| 2287 | case Stmt::CompoundLiteralExprClass: | |
| 2288 | emit_warning(c, stmt->getLocStart(), "TODO handle C CompoundLiteralExprClass"); | |
| 2289 | return nullptr; | |
| 2290 | case Stmt::ConvertVectorExprClass: | |
| 2291 | emit_warning(c, stmt->getLocStart(), "TODO handle C ConvertVectorExprClass"); | |
| 2292 | return nullptr; | |
| 2293 | case Stmt::CoawaitExprClass: | |
| 2294 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoawaitExprClass"); | |
| 2295 | return nullptr; | |
| 2296 | case Stmt::CoyieldExprClass: | |
| 2297 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoyieldExprClass"); | |
| 2298 | return nullptr; | |
| 2299 | case Stmt::DependentCoawaitExprClass: | |
| 2300 | emit_warning(c, stmt->getLocStart(), "TODO handle C DependentCoawaitExprClass"); | |
| 2301 | return nullptr; | |
| 2302 | case Stmt::DependentScopeDeclRefExprClass: | |
| 2303 | emit_warning(c, stmt->getLocStart(), "TODO handle C DependentScopeDeclRefExprClass"); | |
| 2304 | return nullptr; | |
| 2305 | case Stmt::DesignatedInitExprClass: | |
| 2306 | emit_warning(c, stmt->getLocStart(), "TODO handle C DesignatedInitExprClass"); | |
| 2307 | return nullptr; | |
| 2308 | case Stmt::DesignatedInitUpdateExprClass: | |
| 2309 | emit_warning(c, stmt->getLocStart(), "TODO handle C DesignatedInitUpdateExprClass"); | |
| 2310 | return nullptr; | |
| 2311 | case Stmt::ExprWithCleanupsClass: | |
| 2312 | emit_warning(c, stmt->getLocStart(), "TODO handle C ExprWithCleanupsClass"); | |
| 2313 | return nullptr; | |
| 2314 | case Stmt::ExpressionTraitExprClass: | |
| 2315 | emit_warning(c, stmt->getLocStart(), "TODO handle C ExpressionTraitExprClass"); | |
| 2316 | return nullptr; | |
| 2317 | case Stmt::ExtVectorElementExprClass: | |
| 2318 | emit_warning(c, stmt->getLocStart(), "TODO handle C ExtVectorElementExprClass"); | |
| 2319 | return nullptr; | |
| 2320 | case Stmt::FloatingLiteralClass: | |
| 2321 | emit_warning(c, stmt->getLocStart(), "TODO handle C FloatingLiteralClass"); | |
| 2322 | return nullptr; | |
| 2323 | case Stmt::FunctionParmPackExprClass: | |
| 2324 | emit_warning(c, stmt->getLocStart(), "TODO handle C FunctionParmPackExprClass"); | |
| 2325 | return nullptr; | |
| 2326 | case Stmt::GNUNullExprClass: | |
| 2327 | emit_warning(c, stmt->getLocStart(), "TODO handle C GNUNullExprClass"); | |
| 2328 | return nullptr; | |
| 2329 | case Stmt::GenericSelectionExprClass: | |
| 2330 | emit_warning(c, stmt->getLocStart(), "TODO handle C GenericSelectionExprClass"); | |
| 2331 | return nullptr; | |
| 2332 | case Stmt::ImaginaryLiteralClass: | |
| 2333 | emit_warning(c, stmt->getLocStart(), "TODO handle C ImaginaryLiteralClass"); | |
| 2334 | return nullptr; | |
| 2335 | case Stmt::ImplicitValueInitExprClass: | |
| 2336 | emit_warning(c, stmt->getLocStart(), "TODO handle C ImplicitValueInitExprClass"); | |
| 2337 | return nullptr; | |
| 2338 | case Stmt::InitListExprClass: | |
| 2339 | emit_warning(c, stmt->getLocStart(), "TODO handle C InitListExprClass"); | |
| 2340 | return nullptr; | |
| 2341 | case Stmt::LambdaExprClass: | |
| 2342 | emit_warning(c, stmt->getLocStart(), "TODO handle C LambdaExprClass"); | |
| 2343 | return nullptr; | |
| 2344 | case Stmt::MSPropertyRefExprClass: | |
| 2345 | emit_warning(c, stmt->getLocStart(), "TODO handle C MSPropertyRefExprClass"); | |
| 2346 | return nullptr; | |
| 2347 | case Stmt::MSPropertySubscriptExprClass: | |
| 2348 | emit_warning(c, stmt->getLocStart(), "TODO handle C MSPropertySubscriptExprClass"); | |
| 2349 | return nullptr; | |
| 2350 | case Stmt::MaterializeTemporaryExprClass: | |
| 2351 | emit_warning(c, stmt->getLocStart(), "TODO handle C MaterializeTemporaryExprClass"); | |
| 2352 | return nullptr; | |
| 2353 | case Stmt::NoInitExprClass: | |
| 2354 | emit_warning(c, stmt->getLocStart(), "TODO handle C NoInitExprClass"); | |
| 2355 | return nullptr; | |
| 2356 | case Stmt::OMPArraySectionExprClass: | |
| 2357 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPArraySectionExprClass"); | |
| 2358 | return nullptr; | |
| 2359 | case Stmt::ObjCArrayLiteralClass: | |
| 2360 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCArrayLiteralClass"); | |
| 2361 | return nullptr; | |
| 2362 | case Stmt::ObjCAvailabilityCheckExprClass: | |
| 2363 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAvailabilityCheckExprClass"); | |
| 2364 | return nullptr; | |
| 2365 | case Stmt::ObjCBoolLiteralExprClass: | |
| 2366 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBoolLiteralExprClass"); | |
| 2367 | return nullptr; | |
| 2368 | case Stmt::ObjCBoxedExprClass: | |
| 2369 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBoxedExprClass"); | |
| 2370 | return nullptr; | |
| 2371 | case Stmt::ObjCDictionaryLiteralClass: | |
| 2372 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCDictionaryLiteralClass"); | |
| 2373 | return nullptr; | |
| 2374 | case Stmt::ObjCEncodeExprClass: | |
| 2375 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCEncodeExprClass"); | |
| 2376 | return nullptr; | |
| 2377 | case Stmt::ObjCIndirectCopyRestoreExprClass: | |
| 2378 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIndirectCopyRestoreExprClass"); | |
| 2379 | return nullptr; | |
| 2380 | case Stmt::ObjCIsaExprClass: | |
| 2381 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIsaExprClass"); | |
| 2382 | return nullptr; | |
| 2383 | case Stmt::ObjCIvarRefExprClass: | |
| 2384 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIvarRefExprClass"); | |
| 2385 | return nullptr; | |
| 2386 | case Stmt::ObjCMessageExprClass: | |
| 2387 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCMessageExprClass"); | |
| 2388 | return nullptr; | |
| 2389 | case Stmt::ObjCPropertyRefExprClass: | |
| 2390 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCPropertyRefExprClass"); | |
| 2391 | return nullptr; | |
| 2392 | case Stmt::ObjCProtocolExprClass: | |
| 2393 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCProtocolExprClass"); | |
| 2394 | return nullptr; | |
| 2395 | case Stmt::ObjCSelectorExprClass: | |
| 2396 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCSelectorExprClass"); | |
| 2397 | return nullptr; | |
| 2398 | case Stmt::ObjCStringLiteralClass: | |
| 2399 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCStringLiteralClass"); | |
| 2400 | return nullptr; | |
| 2401 | case Stmt::ObjCSubscriptRefExprClass: | |
| 2402 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCSubscriptRefExprClass"); | |
| 2403 | return nullptr; | |
| 2404 | case Stmt::OffsetOfExprClass: | |
| 2405 | emit_warning(c, stmt->getLocStart(), "TODO handle C OffsetOfExprClass"); | |
| 2406 | return nullptr; | |
| 2407 | case Stmt::OpaqueValueExprClass: | |
| 2408 | emit_warning(c, stmt->getLocStart(), "TODO handle C OpaqueValueExprClass"); | |
| 2409 | return nullptr; | |
| 2410 | case Stmt::UnresolvedLookupExprClass: | |
| 2411 | emit_warning(c, stmt->getLocStart(), "TODO handle C UnresolvedLookupExprClass"); | |
| 2412 | return nullptr; | |
| 2413 | case Stmt::UnresolvedMemberExprClass: | |
| 2414 | emit_warning(c, stmt->getLocStart(), "TODO handle C UnresolvedMemberExprClass"); | |
| 2415 | return nullptr; | |
| 2416 | case Stmt::PackExpansionExprClass: | |
| 2417 | emit_warning(c, stmt->getLocStart(), "TODO handle C PackExpansionExprClass"); | |
| 2418 | return nullptr; | |
| 2419 | case Stmt::ParenExprClass: | |
| 2420 | return trans_expr(c, result_used, block, ((ParenExpr*)stmt)->getSubExpr(), lrvalue); | |
| 2421 | case Stmt::ParenListExprClass: | |
| 2422 | emit_warning(c, stmt->getLocStart(), "TODO handle C ParenListExprClass"); | |
| 2423 | return nullptr; | |
| 2424 | case Stmt::PredefinedExprClass: | |
| 2425 | emit_warning(c, stmt->getLocStart(), "TODO handle C PredefinedExprClass"); | |
| 2426 | return nullptr; | |
| 2427 | case Stmt::PseudoObjectExprClass: | |
| 2428 | emit_warning(c, stmt->getLocStart(), "TODO handle C PseudoObjectExprClass"); | |
| 2429 | return nullptr; | |
| 2430 | case Stmt::ShuffleVectorExprClass: | |
| 2431 | emit_warning(c, stmt->getLocStart(), "TODO handle C ShuffleVectorExprClass"); | |
| 2432 | return nullptr; | |
| 2433 | case Stmt::SizeOfPackExprClass: | |
| 2434 | emit_warning(c, stmt->getLocStart(), "TODO handle C SizeOfPackExprClass"); | |
| 2435 | return nullptr; | |
| 2436 | case Stmt::StmtExprClass: | |
| 2437 | emit_warning(c, stmt->getLocStart(), "TODO handle C StmtExprClass"); | |
| 2438 | return nullptr; | |
| 2439 | case Stmt::StringLiteralClass: | |
| 2440 | emit_warning(c, stmt->getLocStart(), "TODO handle C StringLiteralClass"); | |
| 2441 | return nullptr; | |
| 2442 | case Stmt::SubstNonTypeTemplateParmExprClass: | |
| 2443 | emit_warning(c, stmt->getLocStart(), "TODO handle C SubstNonTypeTemplateParmExprClass"); | |
| 2444 | return nullptr; | |
| 2445 | case Stmt::SubstNonTypeTemplateParmPackExprClass: | |
| 2446 | emit_warning(c, stmt->getLocStart(), "TODO handle C SubstNonTypeTemplateParmPackExprClass"); | |
| 2447 | return nullptr; | |
| 2448 | case Stmt::TypeTraitExprClass: | |
| 2449 | emit_warning(c, stmt->getLocStart(), "TODO handle C TypeTraitExprClass"); | |
| 2450 | return nullptr; | |
| 2451 | case Stmt::TypoExprClass: | |
| 2452 | emit_warning(c, stmt->getLocStart(), "TODO handle C TypoExprClass"); | |
| 2453 | return nullptr; | |
| 2454 | case Stmt::VAArgExprClass: | |
| 2455 | emit_warning(c, stmt->getLocStart(), "TODO handle C VAArgExprClass"); | |
| 2456 | return nullptr; | |
| 2457 | case Stmt::ForStmtClass: | |
| 2458 | emit_warning(c, stmt->getLocStart(), "TODO handle C ForStmtClass"); | |
| 2459 | return nullptr; | |
| 2460 | case Stmt::GotoStmtClass: | |
| 2461 | emit_warning(c, stmt->getLocStart(), "TODO handle C GotoStmtClass"); | |
| 2462 | return nullptr; | |
| 2463 | case Stmt::IndirectGotoStmtClass: | |
| 2464 | emit_warning(c, stmt->getLocStart(), "TODO handle C IndirectGotoStmtClass"); | |
| 2465 | return nullptr; | |
| 2466 | case Stmt::LabelStmtClass: | |
| 2467 | emit_warning(c, stmt->getLocStart(), "TODO handle C LabelStmtClass"); | |
| 2468 | return nullptr; | |
| 2469 | case Stmt::MSDependentExistsStmtClass: | |
| 2470 | emit_warning(c, stmt->getLocStart(), "TODO handle C MSDependentExistsStmtClass"); | |
| 2471 | return nullptr; | |
| 2472 | case Stmt::OMPAtomicDirectiveClass: | |
| 2473 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPAtomicDirectiveClass"); | |
| 2474 | return nullptr; | |
| 2475 | case Stmt::OMPBarrierDirectiveClass: | |
| 2476 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPBarrierDirectiveClass"); | |
| 2477 | return nullptr; | |
| 2478 | case Stmt::OMPCancelDirectiveClass: | |
| 2479 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCancelDirectiveClass"); | |
| 2480 | return nullptr; | |
| 2481 | case Stmt::OMPCancellationPointDirectiveClass: | |
| 2482 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCancellationPointDirectiveClass"); | |
| 2483 | return nullptr; | |
| 2484 | case Stmt::OMPCriticalDirectiveClass: | |
| 2485 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCriticalDirectiveClass"); | |
| 2486 | return nullptr; | |
| 2487 | case Stmt::OMPFlushDirectiveClass: | |
| 2488 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPFlushDirectiveClass"); | |
| 2489 | return nullptr; | |
| 2490 | case Stmt::OMPDistributeDirectiveClass: | |
| 2491 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeDirectiveClass"); | |
| 2492 | return nullptr; | |
| 2493 | case Stmt::OMPDistributeParallelForDirectiveClass: | |
| 2494 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeParallelForDirectiveClass"); | |
| 2495 | return nullptr; | |
| 2496 | case Stmt::OMPDistributeParallelForSimdDirectiveClass: | |
| 2497 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeParallelForSimdDirectiveClass"); | |
| 2498 | return nullptr; | |
| 2499 | case Stmt::OMPDistributeSimdDirectiveClass: | |
| 2500 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeSimdDirectiveClass"); | |
| 2501 | return nullptr; | |
| 2502 | case Stmt::OMPForDirectiveClass: | |
| 2503 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPForDirectiveClass"); | |
| 2504 | return nullptr; | |
| 2505 | case Stmt::OMPForSimdDirectiveClass: | |
| 2506 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPForSimdDirectiveClass"); | |
| 2507 | return nullptr; | |
| 2508 | case Stmt::OMPParallelForDirectiveClass: | |
| 2509 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelForDirectiveClass"); | |
| 2510 | return nullptr; | |
| 2511 | case Stmt::OMPParallelForSimdDirectiveClass: | |
| 2512 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelForSimdDirectiveClass"); | |
| 2513 | return nullptr; | |
| 2514 | case Stmt::OMPSimdDirectiveClass: | |
| 2515 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSimdDirectiveClass"); | |
| 2516 | return nullptr; | |
| 2517 | case Stmt::OMPTargetParallelForSimdDirectiveClass: | |
| 2518 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelForSimdDirectiveClass"); | |
| 2519 | return nullptr; | |
| 2520 | case Stmt::OMPTargetSimdDirectiveClass: | |
| 2521 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetSimdDirectiveClass"); | |
| 2522 | return nullptr; | |
| 2523 | case Stmt::OMPTargetTeamsDistributeDirectiveClass: | |
| 2524 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeDirectiveClass"); | |
| 2525 | return nullptr; | |
| 2526 | case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass: | |
| 2527 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeParallelForDirectiveClass"); | |
| 2528 | return nullptr; | |
| 2529 | case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass: | |
| 2530 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeParallelForSimdDirectiveClass"); | |
| 2531 | return nullptr; | |
| 2532 | case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: | |
| 2533 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeSimdDirectiveClass"); | |
| 2534 | return nullptr; | |
| 2535 | case Stmt::OMPTaskLoopDirectiveClass: | |
| 2536 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskLoopDirectiveClass"); | |
| 2537 | return nullptr; | |
| 2538 | case Stmt::OMPTaskLoopSimdDirectiveClass: | |
| 2539 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskLoopSimdDirectiveClass"); | |
| 2540 | return nullptr; | |
| 2541 | case Stmt::OMPTeamsDistributeDirectiveClass: | |
| 2542 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeDirectiveClass"); | |
| 2543 | return nullptr; | |
| 2544 | case Stmt::OMPTeamsDistributeParallelForDirectiveClass: | |
| 2545 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeParallelForDirectiveClass"); | |
| 2546 | return nullptr; | |
| 2547 | case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass: | |
| 2548 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeParallelForSimdDirectiveClass"); | |
| 2549 | return nullptr; | |
| 2550 | case Stmt::OMPTeamsDistributeSimdDirectiveClass: | |
| 2551 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeSimdDirectiveClass"); | |
| 2552 | return nullptr; | |
| 2553 | case Stmt::OMPMasterDirectiveClass: | |
| 2554 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPMasterDirectiveClass"); | |
| 2555 | return nullptr; | |
| 2556 | case Stmt::OMPOrderedDirectiveClass: | |
| 2557 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPOrderedDirectiveClass"); | |
| 2558 | return nullptr; | |
| 2559 | case Stmt::OMPParallelDirectiveClass: | |
| 2560 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelDirectiveClass"); | |
| 2561 | return nullptr; | |
| 2562 | case Stmt::OMPParallelSectionsDirectiveClass: | |
| 2563 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelSectionsDirectiveClass"); | |
| 2564 | return nullptr; | |
| 2565 | case Stmt::OMPSectionDirectiveClass: | |
| 2566 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSectionDirectiveClass"); | |
| 2567 | return nullptr; | |
| 2568 | case Stmt::OMPSectionsDirectiveClass: | |
| 2569 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSectionsDirectiveClass"); | |
| 2570 | return nullptr; | |
| 2571 | case Stmt::OMPSingleDirectiveClass: | |
| 2572 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSingleDirectiveClass"); | |
| 2573 | return nullptr; | |
| 2574 | case Stmt::OMPTargetDataDirectiveClass: | |
| 2575 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetDataDirectiveClass"); | |
| 2576 | return nullptr; | |
| 2577 | case Stmt::OMPTargetDirectiveClass: | |
| 2578 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetDirectiveClass"); | |
| 2579 | return nullptr; | |
| 2580 | case Stmt::OMPTargetEnterDataDirectiveClass: | |
| 2581 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetEnterDataDirectiveClass"); | |
| 2582 | return nullptr; | |
| 2583 | case Stmt::OMPTargetExitDataDirectiveClass: | |
| 2584 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetExitDataDirectiveClass"); | |
| 2585 | return nullptr; | |
| 2586 | case Stmt::OMPTargetParallelDirectiveClass: | |
| 2587 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelDirectiveClass"); | |
| 2588 | return nullptr; | |
| 2589 | case Stmt::OMPTargetParallelForDirectiveClass: | |
| 2590 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelForDirectiveClass"); | |
| 2591 | return nullptr; | |
| 2592 | case Stmt::OMPTargetTeamsDirectiveClass: | |
| 2593 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDirectiveClass"); | |
| 2594 | return nullptr; | |
| 2595 | case Stmt::OMPTargetUpdateDirectiveClass: | |
| 2596 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetUpdateDirectiveClass"); | |
| 2597 | return nullptr; | |
| 2598 | case Stmt::OMPTaskDirectiveClass: | |
| 2599 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskDirectiveClass"); | |
| 2600 | return nullptr; | |
| 2601 | case Stmt::OMPTaskgroupDirectiveClass: | |
| 2602 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskgroupDirectiveClass"); | |
| 2603 | return nullptr; | |
| 2604 | case Stmt::OMPTaskwaitDirectiveClass: | |
| 2605 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskwaitDirectiveClass"); | |
| 2606 | return nullptr; | |
| 2607 | case Stmt::OMPTaskyieldDirectiveClass: | |
| 2608 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskyieldDirectiveClass"); | |
| 2609 | return nullptr; | |
| 2610 | case Stmt::OMPTeamsDirectiveClass: | |
| 2611 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDirectiveClass"); | |
| 2612 | return nullptr; | |
| 2613 | case Stmt::ObjCAtCatchStmtClass: | |
| 2614 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtCatchStmtClass"); | |
| 2615 | return nullptr; | |
| 2616 | case Stmt::ObjCAtFinallyStmtClass: | |
| 2617 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtFinallyStmtClass"); | |
| 2618 | return nullptr; | |
| 2619 | case Stmt::ObjCAtSynchronizedStmtClass: | |
| 2620 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtSynchronizedStmtClass"); | |
| 2621 | return nullptr; | |
| 2622 | case Stmt::ObjCAtThrowStmtClass: | |
| 2623 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtThrowStmtClass"); | |
| 2624 | return nullptr; | |
| 2625 | case Stmt::ObjCAtTryStmtClass: | |
| 2626 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtTryStmtClass"); | |
| 2627 | return nullptr; | |
| 2628 | case Stmt::ObjCAutoreleasePoolStmtClass: | |
| 2629 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAutoreleasePoolStmtClass"); | |
| 2630 | return nullptr; | |
| 2631 | case Stmt::ObjCForCollectionStmtClass: | |
| 2632 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCForCollectionStmtClass"); | |
| 2633 | return nullptr; | |
| 2634 | case Stmt::SEHExceptStmtClass: | |
| 2635 | emit_warning(c, stmt->getLocStart(), "TODO handle C SEHExceptStmtClass"); | |
| 2636 | return nullptr; | |
| 2637 | case Stmt::SEHFinallyStmtClass: | |
| 2638 | emit_warning(c, stmt->getLocStart(), "TODO handle C SEHFinallyStmtClass"); | |
| 2639 | return nullptr; | |
| 2640 | case Stmt::SEHLeaveStmtClass: | |
| 2641 | emit_warning(c, stmt->getLocStart(), "TODO handle C SEHLeaveStmtClass"); | |
| 2642 | return nullptr; | |
| 2643 | case Stmt::SEHTryStmtClass: | |
| 2644 | emit_warning(c, stmt->getLocStart(), "TODO handle C SEHTryStmtClass"); | |
| 2645 | return nullptr; | |
| 2646 | } | |
| 2647 | zig_unreachable(); | |
| 2648 | } | |
| 2649 | ||
| 2650 | static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { | |
| 2651 | Buf *fn_name = buf_create_from_str(decl_name(fn_decl)); | |
| 2652 | ||
| 2653 | if (get_global(c, fn_name)) { | |
| 2654 | // we already saw this function | |
| 2655 | return; | |
| 2656 | } | |
| 2657 | ||
| 2658 | AstNode *proto_node = trans_qual_type(c, fn_decl->getType(), fn_decl->getLocation()); | |
| 2659 | if (proto_node == nullptr) { | |
| 2660 | emit_warning(c, fn_decl->getLocation(), "unable to resolve prototype of function '%s'", buf_ptr(fn_name)); | |
| 2661 | return; | |
| 2662 | } | |
| 2663 | ||
| 2664 | proto_node->data.fn_proto.name = fn_name; | |
| 2665 | proto_node->data.fn_proto.is_extern = !fn_decl->hasBody(); | |
| 2666 | ||
| 2667 | StorageClass sc = fn_decl->getStorageClass(); | |
| 2668 | if (sc == SC_None) { | |
| 2669 | proto_node->data.fn_proto.visib_mod = fn_decl->hasBody() ? c->export_visib_mod : c->visib_mod; | |
| 2670 | } else if (sc == SC_Extern || sc == SC_Static) { | |
| 2671 | proto_node->data.fn_proto.visib_mod = c->visib_mod; | |
| 2672 | } else if (sc == SC_PrivateExtern) { | |
| 2673 | emit_warning(c, fn_decl->getLocation(), "unsupported storage class: private extern"); | |
| 2674 | return; | |
| 2675 | } else { | |
| 2676 | emit_warning(c, fn_decl->getLocation(), "unsupported storage class: unknown"); | |
| 2677 | return; | |
| 2678 | } | |
| 2679 | ||
| 2680 | for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) { | |
| 2681 | AstNode *param_node = proto_node->data.fn_proto.params.at(i); | |
| 2682 | const ParmVarDecl *param = fn_decl->getParamDecl(i); | |
| 2683 | const char *name = decl_name(param); | |
| 2684 | Buf *proto_param_name; | |
| 2685 | if (strlen(name) != 0) { | |
| 2686 | proto_param_name = buf_create_from_str(name); | |
| 2687 | } else { | |
| 2688 | proto_param_name = param_node->data.param_decl.name; | |
| 2689 | if (proto_param_name == nullptr) { | |
| 2690 | proto_param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i); | |
| 2691 | } | |
| 2692 | } | |
| 2693 | param_node->data.param_decl.name = proto_param_name; | |
| 2694 | } | |
| 2695 | ||
| 2696 | if (!fn_decl->hasBody()) { | |
| 2697 | // just a prototype | |
| 2698 | add_top_level_decl(c, proto_node->data.fn_proto.name, proto_node); | |
| 2699 | return; | |
| 2700 | } | |
| 2701 | ||
| 2702 | // actual function definition with body | |
| 2703 | c->ptr_params.clear(); | |
| 2704 | Stmt *body = fn_decl->getBody(); | |
| 2705 | AstNode *actual_body_node = trans_stmt(c, false, nullptr, body, TransRValue); | |
| 2706 | assert(actual_body_node != skip_add_to_block_node); | |
| 2707 | if (actual_body_node == nullptr) { | |
| 2708 | emit_warning(c, fn_decl->getLocation(), "unable to translate function"); | |
| 2709 | return; | |
| 2710 | } | |
| 2711 | ||
| 2712 | // it worked | |
| 2713 | ||
| 2714 | assert(actual_body_node->type == NodeTypeBlock); | |
| 2715 | AstNode *body_node_with_param_inits = trans_create_node(c, NodeTypeBlock); | |
| 2716 | ||
| 2717 | for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) { | |
| 2718 | AstNode *param_node = proto_node->data.fn_proto.params.at(i); | |
| 2719 | Buf *good_name = param_node->data.param_decl.name; | |
| 2720 | ||
| 2721 | if (c->ptr_params.maybe_get(good_name) != nullptr) { | |
| 2722 | // TODO: avoid name collisions | |
| 2723 | Buf *mangled_name = buf_sprintf("_arg_%s", buf_ptr(good_name)); | |
| 2724 | param_node->data.param_decl.name = mangled_name; | |
| 2725 | ||
| 2726 | // var c_name = _mangled_name; | |
| 2727 | AstNode *parameter_init = trans_create_node_var_decl_local(c, false, good_name, nullptr, trans_create_node_symbol(c, mangled_name)); | |
| 2728 | ||
| 2729 | body_node_with_param_inits->data.block.statements.append(parameter_init); | |
| 2730 | } | |
| 2731 | } | |
| 2732 | ||
| 2733 | for (size_t i = 0; i < actual_body_node->data.block.statements.length; i += 1) { | |
| 2734 | body_node_with_param_inits->data.block.statements.append(actual_body_node->data.block.statements.at(i)); | |
| 2735 | } | |
| 2736 | ||
| 2737 | AstNode *fn_def_node = trans_create_node(c, NodeTypeFnDef); | |
| 2738 | fn_def_node->data.fn_def.fn_proto = proto_node; | |
| 2739 | fn_def_node->data.fn_def.body = body_node_with_param_inits; | |
| 2740 | ||
| 2741 | proto_node->data.fn_proto.fn_def_node = fn_def_node; | |
| 2742 | add_top_level_decl(c, fn_def_node->data.fn_def.fn_proto->data.fn_proto.name, fn_def_node); | |
| 2743 | } | |
| 2744 | ||
| 2745 | static AstNode *resolve_typdef_as_builtin(Context *c, const TypedefNameDecl *typedef_decl, const char *primitive_name) { | |
| 2746 | AstNode *node = trans_create_node_symbol_str(c, primitive_name); | |
| 2747 | c->decl_table.put(typedef_decl, node); | |
| 2748 | return node; | |
| 2749 | } | |
| 2750 | ||
| 2751 | static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl) { | |
| 2752 | auto existing_entry = c->decl_table.maybe_get((void*)typedef_decl->getCanonicalDecl()); | |
| 2753 | if (existing_entry) { | |
| 2754 | return existing_entry->value; | |
| 2755 | } | |
| 2756 | QualType child_qt = typedef_decl->getUnderlyingType(); | |
| 2757 | Buf *type_name = buf_create_from_str(decl_name(typedef_decl)); | |
| 2758 | ||
| 2759 | if (buf_eql_str(type_name, "uint8_t")) { | |
| 2760 | return resolve_typdef_as_builtin(c, typedef_decl, "u8"); | |
| 2761 | } else if (buf_eql_str(type_name, "int8_t")) { | |
| 2762 | return resolve_typdef_as_builtin(c, typedef_decl, "i8"); | |
| 2763 | } else if (buf_eql_str(type_name, "uint16_t")) { | |
| 2764 | return resolve_typdef_as_builtin(c, typedef_decl, "u16"); | |
| 2765 | } else if (buf_eql_str(type_name, "int16_t")) { | |
| 2766 | return resolve_typdef_as_builtin(c, typedef_decl, "i16"); | |
| 2767 | } else if (buf_eql_str(type_name, "uint32_t")) { | |
| 2768 | return resolve_typdef_as_builtin(c, typedef_decl, "u32"); | |
| 2769 | } else if (buf_eql_str(type_name, "int32_t")) { | |
| 2770 | return resolve_typdef_as_builtin(c, typedef_decl, "i32"); | |
| 2771 | } else if (buf_eql_str(type_name, "uint64_t")) { | |
| 2772 | return resolve_typdef_as_builtin(c, typedef_decl, "u64"); | |
| 2773 | } else if (buf_eql_str(type_name, "int64_t")) { | |
| 2774 | return resolve_typdef_as_builtin(c, typedef_decl, "i64"); | |
| 2775 | } else if (buf_eql_str(type_name, "intptr_t")) { | |
| 2776 | return resolve_typdef_as_builtin(c, typedef_decl, "isize"); | |
| 2777 | } else if (buf_eql_str(type_name, "uintptr_t")) { | |
| 2778 | return resolve_typdef_as_builtin(c, typedef_decl, "usize"); | |
| 2779 | } else if (buf_eql_str(type_name, "ssize_t")) { | |
| 2780 | return resolve_typdef_as_builtin(c, typedef_decl, "isize"); | |
| 2781 | } else if (buf_eql_str(type_name, "size_t")) { | |
| 2782 | return resolve_typdef_as_builtin(c, typedef_decl, "usize"); | |
| 2783 | } | |
| 2784 | ||
| 2785 | // if the underlying type is anonymous, we can special case it to just | |
| 2786 | // use the name of this typedef | |
| 2787 | // TODO | |
| 2788 | ||
| 2789 | AstNode *type_node = trans_qual_type(c, child_qt, typedef_decl->getLocation()); | |
| 2790 | if (type_node == nullptr) { | |
| 2791 | emit_warning(c, typedef_decl->getLocation(), "typedef %s - unresolved child type", buf_ptr(type_name)); | |
| 2792 | c->decl_table.put(typedef_decl, nullptr); | |
| 2793 | return nullptr; | |
| 2794 | } | |
| 2795 | add_global_var(c, type_name, type_node); | |
| 2796 | ||
| 2797 | AstNode *symbol_node = trans_create_node_symbol(c, type_name); | |
| 2798 | c->decl_table.put(typedef_decl->getCanonicalDecl(), symbol_node); | |
| 2799 | return symbol_node; | |
| 2800 | } | |
| 2801 | ||
| 2802 | struct AstNode *demote_enum_to_opaque(Context *c, const EnumDecl *enum_decl, | |
| 2803 | Buf *full_type_name, Buf *bare_name) | |
| 2804 | { | |
| 2805 | AstNode *opaque_node = trans_create_node_opaque(c); | |
| 2806 | if (full_type_name == nullptr) { | |
| 2807 | c->decl_table.put(enum_decl->getCanonicalDecl(), opaque_node); | |
| 2808 | return opaque_node; | |
| 2809 | } | |
| 2810 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | |
| 2811 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 2812 | add_global_var(c, full_type_name, opaque_node); | |
| 2813 | c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); | |
| 2814 | return symbol_node; | |
| 2815 | } | |
| 2816 | ||
| 2817 | static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { | |
| 2818 | auto existing_entry = c->decl_table.maybe_get((void*)enum_decl->getCanonicalDecl()); | |
| 2819 | if (existing_entry) { | |
| 2820 | return existing_entry->value; | |
| 2821 | } | |
| 2822 | ||
| 2823 | const char *raw_name = decl_name(enum_decl); | |
| 2824 | bool is_anonymous = (raw_name[0] == 0); | |
| 2825 | Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name); | |
| 2826 | Buf *full_type_name = is_anonymous ? nullptr : buf_sprintf("enum_%s", buf_ptr(bare_name)); | |
| 2827 | ||
| 2828 | const EnumDecl *enum_def = enum_decl->getDefinition(); | |
| 2829 | if (!enum_def) { | |
| 2830 | return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name); | |
| 2831 | } | |
| 2832 | ||
| 2833 | bool pure_enum = true; | |
| 2834 | uint32_t field_count = 0; | |
| 2835 | for (auto it = enum_def->enumerator_begin(), | |
| 2836 | it_end = enum_def->enumerator_end(); | |
| 2837 | it != it_end; ++it, field_count += 1) | |
| 2838 | { | |
| 2839 | const EnumConstantDecl *enum_const = *it; | |
| 2840 | if (enum_const->getInitExpr()) { | |
| 2841 | pure_enum = false; | |
| 2842 | } | |
| 2843 | } | |
| 2844 | ||
| 2845 | AstNode *tag_int_type = trans_qual_type(c, enum_decl->getIntegerType(), enum_decl->getLocation()); | |
| 2846 | assert(tag_int_type); | |
| 2847 | ||
| 2848 | if (pure_enum) { | |
| 2849 | AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl); | |
| 2850 | enum_node->data.container_decl.kind = ContainerKindEnum; | |
| 2851 | enum_node->data.container_decl.layout = ContainerLayoutExtern; | |
| 2852 | enum_node->data.container_decl.init_arg_expr = tag_int_type; | |
| 2853 | ||
| 2854 | enum_node->data.container_decl.fields.resize(field_count); | |
| 2855 | uint32_t i = 0; | |
| 2856 | for (auto it = enum_def->enumerator_begin(), | |
| 2857 | it_end = enum_def->enumerator_end(); | |
| 2858 | it != it_end; ++it, i += 1) | |
| 2859 | { | |
| 2860 | const EnumConstantDecl *enum_const = *it; | |
| 2861 | ||
| 2862 | Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); | |
| 2863 | Buf *field_name; | |
| 2864 | if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) { | |
| 2865 | field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name)); | |
| 2866 | } else { | |
| 2867 | field_name = enum_val_name; | |
| 2868 | } | |
| 2869 | ||
| 2870 | AstNode *field_node = trans_create_node(c, NodeTypeStructField); | |
| 2871 | field_node->data.struct_field.name = field_name; | |
| 2872 | field_node->data.struct_field.type = nullptr; | |
| 2873 | enum_node->data.container_decl.fields.items[i] = field_node; | |
| 2874 | ||
| 2875 | // in C each enum value is in the global namespace. so we put them there too. | |
| 2876 | // at this point we can rely on the enum emitting successfully | |
| 2877 | if (is_anonymous) { | |
| 2878 | AstNode *lit_node = trans_create_node_unsigned(c, i); | |
| 2879 | add_global_var(c, enum_val_name, lit_node); | |
| 2880 | } else { | |
| 2881 | AstNode *field_access_node = trans_create_node_field_access(c, | |
| 2882 | trans_create_node_symbol(c, full_type_name), field_name); | |
| 2883 | add_global_var(c, enum_val_name, field_access_node); | |
| 2884 | } | |
| 2885 | } | |
| 2886 | ||
| 2887 | if (is_anonymous) { | |
| 2888 | c->decl_table.put(enum_decl->getCanonicalDecl(), enum_node); | |
| 2889 | return enum_node; | |
| 2890 | } else { | |
| 2891 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | |
| 2892 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 2893 | add_global_var(c, full_type_name, enum_node); | |
| 2894 | c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); | |
| 2895 | return enum_node; | |
| 2896 | } | |
| 2897 | } | |
| 2898 | ||
| 2899 | // TODO after issue #305 is solved, make this be an enum with tag_int_type | |
| 2900 | // as the integer type and set the custom enum values | |
| 2901 | AstNode *enum_node = tag_int_type; | |
| 2902 | ||
| 2903 | ||
| 2904 | // add variables for all the values with enum_node | |
| 2905 | for (auto it = enum_def->enumerator_begin(), | |
| 2906 | it_end = enum_def->enumerator_end(); | |
| 2907 | it != it_end; ++it) | |
| 2908 | { | |
| 2909 | const EnumConstantDecl *enum_const = *it; | |
| 2910 | ||
| 2911 | Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); | |
| 2912 | AstNode *int_node = trans_create_node_apint(c, enum_const->getInitVal()); | |
| 2913 | AstNode *var_node = add_global_var(c, enum_val_name, int_node); | |
| 2914 | var_node->data.variable_declaration.type = tag_int_type; | |
| 2915 | } | |
| 2916 | ||
| 2917 | if (is_anonymous) { | |
| 2918 | c->decl_table.put(enum_decl->getCanonicalDecl(), enum_node); | |
| 2919 | return enum_node; | |
| 2920 | } else { | |
| 2921 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | |
| 2922 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 2923 | add_global_var(c, full_type_name, enum_node); | |
| 2924 | c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); | |
| 2925 | return symbol_node; | |
| 2926 | } | |
| 2927 | } | |
| 2928 | ||
| 2929 | static AstNode *demote_struct_to_opaque(Context *c, const RecordDecl *record_decl, | |
| 2930 | Buf *full_type_name, Buf *bare_name) | |
| 2931 | { | |
| 2932 | AstNode *opaque_node = trans_create_node_opaque(c); | |
| 2933 | if (full_type_name == nullptr) { | |
| 2934 | c->decl_table.put(record_decl->getCanonicalDecl(), opaque_node); | |
| 2935 | return opaque_node; | |
| 2936 | } | |
| 2937 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | |
| 2938 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 2939 | add_global_var(c, full_type_name, opaque_node); | |
| 2940 | c->decl_table.put(record_decl->getCanonicalDecl(), symbol_node); | |
| 2941 | return symbol_node; | |
| 2942 | } | |
| 2943 | ||
| 2944 | static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { | |
| 2945 | auto existing_entry = c->decl_table.maybe_get((void*)record_decl->getCanonicalDecl()); | |
| 2946 | if (existing_entry) { | |
| 2947 | return existing_entry->value; | |
| 2948 | } | |
| 2949 | ||
| 2950 | const char *raw_name = decl_name(record_decl); | |
| 2951 | ||
| 2952 | if (!record_decl->isStruct()) { | |
| 2953 | emit_warning(c, record_decl->getLocation(), "skipping record %s, not a struct", raw_name); | |
| 2954 | c->decl_table.put(record_decl->getCanonicalDecl(), nullptr); | |
| 2955 | return nullptr; | |
| 2956 | } | |
| 2957 | ||
| 2958 | bool is_anonymous = record_decl->isAnonymousStructOrUnion() || raw_name[0] == 0; | |
| 2959 | Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name); | |
| 2960 | Buf *full_type_name = (bare_name == nullptr) ? nullptr : buf_sprintf("struct_%s", buf_ptr(bare_name)); | |
| 2961 | ||
| 2962 | RecordDecl *record_def = record_decl->getDefinition(); | |
| 2963 | if (record_def == nullptr) { | |
| 2964 | return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); | |
| 2965 | } | |
| 2966 | ||
| 2967 | // count fields and validate | |
| 2968 | uint32_t field_count = 0; | |
| 2969 | for (auto it = record_def->field_begin(), | |
| 2970 | it_end = record_def->field_end(); | |
| 2971 | it != it_end; ++it, field_count += 1) | |
| 2972 | { | |
| 2973 | const FieldDecl *field_decl = *it; | |
| 2974 | ||
| 2975 | if (field_decl->isBitField()) { | |
| 2976 | emit_warning(c, field_decl->getLocation(), "struct %s demoted to opaque type - has bitfield", | |
| 2977 | is_anonymous ? "(anon)" : buf_ptr(bare_name)); | |
| 2978 | return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); | |
| 2979 | } | |
| 2980 | } | |
| 2981 | ||
| 2982 | AstNode *struct_node = trans_create_node(c, NodeTypeContainerDecl); | |
| 2983 | struct_node->data.container_decl.kind = ContainerKindStruct; | |
| 2984 | struct_node->data.container_decl.layout = ContainerLayoutExtern; | |
| 2985 | ||
| 2986 | // TODO handle attribute packed | |
| 2987 | ||
| 2988 | struct_node->data.container_decl.fields.resize(field_count); | |
| 2989 | ||
| 2990 | // must be before fields in case a circular reference happens | |
| 2991 | if (is_anonymous) { | |
| 2992 | c->decl_table.put(record_decl->getCanonicalDecl(), struct_node); | |
| 2993 | } else { | |
| 2994 | c->decl_table.put(record_decl->getCanonicalDecl(), trans_create_node_symbol(c, full_type_name)); | |
| 2995 | } | |
| 2996 | ||
| 2997 | uint32_t i = 0; | |
| 2998 | for (auto it = record_def->field_begin(), | |
| 2999 | it_end = record_def->field_end(); | |
| 3000 | it != it_end; ++it, i += 1) | |
| 3001 | { | |
| 3002 | const FieldDecl *field_decl = *it; | |
| 3003 | ||
| 3004 | AstNode *field_node = trans_create_node(c, NodeTypeStructField); | |
| 3005 | field_node->data.struct_field.name = buf_create_from_str(decl_name(field_decl)); | |
| 3006 | field_node->data.struct_field.type = trans_qual_type(c, field_decl->getType(), field_decl->getLocation()); | |
| 3007 | ||
| 3008 | if (field_node->data.struct_field.type == nullptr) { | |
| 3009 | emit_warning(c, field_decl->getLocation(), | |
| 3010 | "struct %s demoted to opaque type - unresolved type", | |
| 3011 | is_anonymous ? "(anon)" : buf_ptr(bare_name)); | |
| 3012 | ||
| 3013 | return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); | |
| 3014 | } | |
| 3015 | ||
| 3016 | struct_node->data.container_decl.fields.items[i] = field_node; | |
| 3017 | } | |
| 3018 | ||
| 3019 | if (is_anonymous) { | |
| 3020 | return struct_node; | |
| 3021 | } else { | |
| 3022 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 3023 | add_global_var(c, full_type_name, struct_node); | |
| 3024 | return trans_create_node_symbol(c, full_type_name); | |
| 3025 | } | |
| 3026 | } | |
| 3027 | ||
| 3028 | static void visit_var_decl(Context *c, const VarDecl *var_decl) { | |
| 3029 | Buf *name = buf_create_from_str(decl_name(var_decl)); | |
| 3030 | ||
| 3031 | switch (var_decl->getTLSKind()) { | |
| 3032 | case VarDecl::TLS_None: | |
| 3033 | break; | |
| 3034 | case VarDecl::TLS_Static: | |
| 3035 | emit_warning(c, var_decl->getLocation(), | |
| 3036 | "ignoring variable '%s' - static thread local storage", buf_ptr(name)); | |
| 3037 | return; | |
| 3038 | case VarDecl::TLS_Dynamic: | |
| 3039 | emit_warning(c, var_decl->getLocation(), | |
| 3040 | "ignoring variable '%s' - dynamic thread local storage", buf_ptr(name)); | |
| 3041 | return; | |
| 3042 | } | |
| 3043 | ||
| 3044 | QualType qt = var_decl->getType(); | |
| 3045 | AstNode *var_type = trans_qual_type(c, qt, var_decl->getLocation()); | |
| 3046 | if (var_type == nullptr) { | |
| 3047 | emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - unresolved type", buf_ptr(name)); | |
| 3048 | return; | |
| 3049 | } | |
| 3050 | ||
| 3051 | bool is_extern = var_decl->hasExternalStorage(); | |
| 3052 | bool is_static = var_decl->isFileVarDecl(); | |
| 3053 | bool is_const = qt.isConstQualified(); | |
| 3054 | ||
| 3055 | if (is_static && !is_extern) { | |
| 3056 | AstNode *init_node; | |
| 3057 | if (var_decl->hasInit()) { | |
| 3058 | APValue *ap_value = var_decl->evaluateValue(); | |
| 3059 | if (ap_value == nullptr) { | |
| 3060 | emit_warning(c, var_decl->getLocation(), | |
| 3061 | "ignoring variable '%s' - unable to evaluate initializer", buf_ptr(name)); | |
| 3062 | return; | |
| 3063 | } | |
| 3064 | switch (ap_value->getKind()) { | |
| 3065 | case APValue::Int: | |
| 3066 | init_node = trans_create_node_apint(c, ap_value->getInt()); | |
| 3067 | break; | |
| 3068 | case APValue::Uninitialized: | |
| 3069 | init_node = trans_create_node(c, NodeTypeUndefinedLiteral); | |
| 3070 | break; | |
| 3071 | case APValue::Float: | |
| 3072 | case APValue::ComplexInt: | |
| 3073 | case APValue::ComplexFloat: | |
| 3074 | case APValue::LValue: | |
| 3075 | case APValue::Vector: | |
| 3076 | case APValue::Array: | |
| 3077 | case APValue::Struct: | |
| 3078 | case APValue::Union: | |
| 3079 | case APValue::MemberPointer: | |
| 3080 | case APValue::AddrLabelDiff: | |
| 3081 | emit_warning(c, var_decl->getLocation(), | |
| 3082 | "ignoring variable '%s' - unrecognized initializer value kind", buf_ptr(name)); | |
| 3083 | return; | |
| 3084 | } | |
| 3085 | } else { | |
| 3086 | init_node = trans_create_node(c, NodeTypeUndefinedLiteral); | |
| 3087 | } | |
| 3088 | ||
| 3089 | AstNode *var_node = trans_create_node_var_decl_global(c, is_const, name, var_type, init_node); | |
| 3090 | add_top_level_decl(c, name, var_node); | |
| 3091 | return; | |
| 3092 | } | |
| 3093 | ||
| 3094 | if (is_extern) { | |
| 3095 | AstNode *var_node = trans_create_node_var_decl_global(c, is_const, name, var_type, nullptr); | |
| 3096 | var_node->data.variable_declaration.is_extern = true; | |
| 3097 | add_top_level_decl(c, name, var_node); | |
| 3098 | return; | |
| 3099 | } | |
| 3100 | ||
| 3101 | emit_warning(c, var_decl->getLocation(), | |
| 3102 | "ignoring variable '%s' - non-extern, non-static variable", buf_ptr(name)); | |
| 3103 | return; | |
| 3104 | } | |
| 3105 | ||
| 3106 | static bool decl_visitor(void *context, const Decl *decl) { | |
| 3107 | Context *c = (Context*)context; | |
| 3108 | ||
| 3109 | switch (decl->getKind()) { | |
| 3110 | case Decl::Function: | |
| 3111 | visit_fn_decl(c, static_cast<const FunctionDecl*>(decl)); | |
| 3112 | break; | |
| 3113 | case Decl::Typedef: | |
| 3114 | resolve_typedef_decl(c, static_cast<const TypedefNameDecl *>(decl)); | |
| 3115 | break; | |
| 3116 | case Decl::Enum: | |
| 3117 | resolve_enum_decl(c, static_cast<const EnumDecl *>(decl)); | |
| 3118 | break; | |
| 3119 | case Decl::Record: | |
| 3120 | resolve_record_decl(c, static_cast<const RecordDecl *>(decl)); | |
| 3121 | break; | |
| 3122 | case Decl::Var: | |
| 3123 | visit_var_decl(c, static_cast<const VarDecl *>(decl)); | |
| 3124 | break; | |
| 3125 | default: | |
| 3126 | emit_warning(c, decl->getLocation(), "ignoring %s decl", decl->getDeclKindName()); | |
| 3127 | } | |
| 3128 | ||
| 3129 | return true; | |
| 3130 | } | |
| 3131 | ||
| 3132 | static bool name_exists(Context *c, Buf *name) { | |
| 3133 | return get_global(c, name) != nullptr; | |
| 3134 | } | |
| 3135 | ||
| 3136 | static void render_aliases(Context *c) { | |
| 3137 | for (size_t i = 0; i < c->aliases.length; i += 1) { | |
| 3138 | Alias *alias = &c->aliases.at(i); | |
| 3139 | if (name_exists(c, alias->new_name)) | |
| 3140 | continue; | |
| 3141 | ||
| 3142 | add_global_var(c, alias->new_name, trans_create_node_symbol(c, alias->canon_name)); | |
| 3143 | } | |
| 3144 | } | |
| 3145 | ||
| 3146 | static void render_macros(Context *c) { | |
| 3147 | auto it = c->macro_table.entry_iterator(); | |
| 3148 | for (;;) { | |
| 3149 | auto *entry = it.next(); | |
| 3150 | if (!entry) | |
| 3151 | break; | |
| 3152 | ||
| 3153 | AstNode *value_node = entry->value; | |
| 3154 | if (value_node->type == NodeTypeFnDef) { | |
| 3155 | add_top_level_decl(c, value_node->data.fn_def.fn_proto->data.fn_proto.name, value_node); | |
| 3156 | } else { | |
| 3157 | add_global_var(c, entry->key, value_node); | |
| 3158 | } | |
| 3159 | } | |
| 3160 | } | |
| 3161 | ||
| 3162 | static AstNode *parse_ctok_num_lit(Context *c, CTokenize *ctok, size_t *tok_i, bool negate) { | |
| 3163 | CTok *tok = &ctok->tokens.at(*tok_i); | |
| 3164 | if (tok->id == CTokIdNumLitInt) { | |
| 3165 | *tok_i += 1; | |
| 3166 | switch (tok->data.num_lit_int.suffix) { | |
| 3167 | case CNumLitSuffixNone: | |
| 3168 | return trans_create_node_unsigned_negative(c, tok->data.num_lit_int.x, negate); | |
| 3169 | case CNumLitSuffixL: | |
| 3170 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_long"); | |
| 3171 | case CNumLitSuffixU: | |
| 3172 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_uint"); | |
| 3173 | case CNumLitSuffixLU: | |
| 3174 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_ulong"); | |
| 3175 | case CNumLitSuffixLL: | |
| 3176 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_longlong"); | |
| 3177 | case CNumLitSuffixLLU: | |
| 3178 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_ulonglong"); | |
| 3179 | } | |
| 3180 | zig_unreachable(); | |
| 3181 | } else if (tok->id == CTokIdNumLitFloat) { | |
| 3182 | *tok_i += 1; | |
| 3183 | double value = negate ? -tok->data.num_lit_float : tok->data.num_lit_float; | |
| 3184 | return trans_create_node_float_lit(c, value); | |
| 3185 | } | |
| 3186 | return nullptr; | |
| 3187 | } | |
| 3188 | ||
| 3189 | static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) { | |
| 3190 | CTok *tok = &ctok->tokens.at(*tok_i); | |
| 3191 | switch (tok->id) { | |
| 3192 | case CTokIdCharLit: | |
| 3193 | *tok_i += 1; | |
| 3194 | return trans_create_node_unsigned(c, tok->data.char_lit); | |
| 3195 | case CTokIdStrLit: | |
| 3196 | *tok_i += 1; | |
| 3197 | return trans_create_node_str_lit_c(c, buf_create_from_buf(&tok->data.str_lit)); | |
| 3198 | case CTokIdMinus: | |
| 3199 | *tok_i += 1; | |
| 3200 | return parse_ctok_num_lit(c, ctok, tok_i, true); | |
| 3201 | case CTokIdNumLitInt: | |
| 3202 | case CTokIdNumLitFloat: | |
| 3203 | return parse_ctok_num_lit(c, ctok, tok_i, false); | |
| 3204 | case CTokIdSymbol: | |
| 3205 | { | |
| 3206 | *tok_i += 1; | |
| 3207 | Buf *symbol_name = buf_create_from_buf(&tok->data.symbol); | |
| 3208 | return trans_create_node_symbol(c, symbol_name); | |
| 3209 | } | |
| 3210 | case CTokIdLParen: | |
| 3211 | { | |
| 3212 | *tok_i += 1; | |
| 3213 | AstNode *inner_node = parse_ctok(c, ctok, tok_i); | |
| 3214 | ||
| 3215 | CTok *next_tok = &ctok->tokens.at(*tok_i); | |
| 3216 | if (next_tok->id != CTokIdRParen) { | |
| 3217 | return nullptr; | |
| 3218 | } | |
| 3219 | *tok_i += 1; | |
| 3220 | return inner_node; | |
| 3221 | } | |
| 3222 | case CTokIdEOF: | |
| 3223 | case CTokIdRParen: | |
| 3224 | // not able to make sense of this | |
| 3225 | return nullptr; | |
| 3226 | } | |
| 3227 | zig_unreachable(); | |
| 3228 | } | |
| 3229 | ||
| 3230 | static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) { | |
| 3231 | tokenize_c_macro(ctok, (const uint8_t *)char_ptr); | |
| 3232 | ||
| 3233 | if (ctok->error) { | |
| 3234 | return; | |
| 3235 | } | |
| 3236 | ||
| 3237 | size_t tok_i = 0; | |
| 3238 | CTok *name_tok = &ctok->tokens.at(tok_i); | |
| 3239 | assert(name_tok->id == CTokIdSymbol && buf_eql_buf(&name_tok->data.symbol, name)); | |
| 3240 | tok_i += 1; | |
| 3241 | ||
| 3242 | AstNode *result_node = parse_ctok(c, ctok, &tok_i); | |
| 3243 | if (result_node == nullptr) { | |
| 3244 | return; | |
| 3245 | } | |
| 3246 | CTok *eof_tok = &ctok->tokens.at(tok_i); | |
| 3247 | if (eof_tok->id != CTokIdEOF) { | |
| 3248 | return; | |
| 3249 | } | |
| 3250 | if (result_node->type == NodeTypeSymbol) { | |
| 3251 | // if it equals itself, ignore. for example, from stdio.h: | |
| 3252 | // #define stdin stdin | |
| 3253 | Buf *symbol_name = result_node->data.symbol_expr.symbol; | |
| 3254 | if (buf_eql_buf(name, symbol_name)) { | |
| 3255 | return; | |
| 3256 | } | |
| 3257 | c->macro_symbols.append({name, symbol_name}); | |
| 3258 | } else { | |
| 3259 | c->macro_table.put(name, result_node); | |
| 3260 | } | |
| 3261 | } | |
| 3262 | ||
| 3263 | static void process_symbol_macros(Context *c) { | |
| 3264 | for (size_t i = 0; i < c->macro_symbols.length; i += 1) { | |
| 3265 | MacroSymbol ms = c->macro_symbols.at(i); | |
| 3266 | ||
| 3267 | // Check if this macro aliases another top level declaration | |
| 3268 | AstNode *existing_node = get_global(c, ms.value); | |
| 3269 | if (!existing_node || name_exists(c, ms.name)) | |
| 3270 | continue; | |
| 3271 | ||
| 3272 | // If a macro aliases a global variable which is a function pointer, we conclude that | |
| 3273 | // the macro is intended to represent a function that assumes the function pointer | |
| 3274 | // variable is non-null and calls it. | |
| 3275 | if (existing_node->type == NodeTypeVariableDeclaration) { | |
| 3276 | AstNode *var_type = existing_node->data.variable_declaration.type; | |
| 3277 | if (var_type != nullptr && var_type->type == NodeTypePrefixOpExpr && | |
| 3278 | var_type->data.prefix_op_expr.prefix_op == PrefixOpMaybe) | |
| 3279 | { | |
| 3280 | AstNode *fn_proto_node = var_type->data.prefix_op_expr.primary_expr; | |
| 3281 | if (fn_proto_node->type == NodeTypeFnProto) { | |
| 3282 | AstNode *inline_fn_node = trans_create_node_inline_fn(c, ms.name, ms.value, fn_proto_node); | |
| 3283 | c->macro_table.put(ms.name, inline_fn_node); | |
| 3284 | continue; | |
| 3285 | } | |
| 3286 | } | |
| 3287 | } | |
| 3288 | ||
| 3289 | add_global_var(c, ms.name, trans_create_node_symbol(c, ms.value)); | |
| 3290 | } | |
| 3291 | } | |
| 3292 | ||
| 3293 | static void process_preprocessor_entities(Context *c, ASTUnit &unit) { | |
| 3294 | CTokenize ctok = {{0}}; | |
| 3295 | ||
| 3296 | // TODO if we see #undef, delete it from the table | |
| 3297 | ||
| 3298 | for (PreprocessedEntity *entity : unit.getLocalPreprocessingEntities()) { | |
| 3299 | switch (entity->getKind()) { | |
| 3300 | case PreprocessedEntity::InvalidKind: | |
| 3301 | case PreprocessedEntity::InclusionDirectiveKind: | |
| 3302 | case PreprocessedEntity::MacroExpansionKind: | |
| 3303 | continue; | |
| 3304 | case PreprocessedEntity::MacroDefinitionKind: | |
| 3305 | { | |
| 3306 | MacroDefinitionRecord *macro = static_cast<MacroDefinitionRecord *>(entity); | |
| 3307 | const char *raw_name = macro->getName()->getNameStart(); | |
| 3308 | SourceRange range = macro->getSourceRange(); | |
| 3309 | SourceLocation begin_loc = range.getBegin(); | |
| 3310 | SourceLocation end_loc = range.getEnd(); | |
| 3311 | ||
| 3312 | if (begin_loc == end_loc) { | |
| 3313 | // this means it is a macro without a value | |
| 3314 | // we don't care about such things | |
| 3315 | continue; | |
| 3316 | } | |
| 3317 | Buf *name = buf_create_from_str(raw_name); | |
| 3318 | if (name_exists(c, name)) { | |
| 3319 | continue; | |
| 3320 | } | |
| 3321 | ||
| 3322 | const char *begin_c = c->source_manager->getCharacterData(begin_loc); | |
| 3323 | process_macro(c, &ctok, name, begin_c); | |
| 3324 | } | |
| 3325 | } | |
| 3326 | } | |
| 3327 | } | |
| 3328 | ||
| 3329 | int parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *source, | |
| 3330 | CodeGen *codegen, AstNode *source_node) | |
| 3331 | { | |
| 3332 | int err; | |
| 3333 | Buf tmp_file_path = BUF_INIT; | |
| 3334 | if ((err = os_buf_to_tmp_file(source, buf_create_from_str(".h"), &tmp_file_path))) { | |
| 3335 | return err; | |
| 3336 | } | |
| 3337 | ||
| 3338 | err = parse_h_file(import, errors, buf_ptr(&tmp_file_path), codegen, source_node); | |
| 3339 | ||
| 3340 | os_delete_file(&tmp_file_path); | |
| 3341 | ||
| 3342 | return err; | |
| 3343 | } | |
| 3344 | ||
| 3345 | int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const char *target_file, | |
| 3346 | CodeGen *codegen, AstNode *source_node) | |
| 3347 | { | |
| 3348 | Context context = {0}; | |
| 3349 | Context *c = &context; | |
| 3350 | c->warnings_on = codegen->verbose_cimport; | |
| 3351 | c->import = import; | |
| 3352 | c->errors = errors; | |
| 3353 | if (buf_ends_with_str(buf_create_from_str(target_file), ".h")) { | |
| 3354 | c->visib_mod = VisibModPub; | |
| 3355 | c->export_visib_mod = VisibModPub; | |
| 3356 | } else { | |
| 3357 | c->visib_mod = VisibModPub; | |
| 3358 | c->export_visib_mod = VisibModExport; | |
| 3359 | } | |
| 3360 | c->decl_table.init(8); | |
| 3361 | c->macro_table.init(8); | |
| 3362 | c->global_table.init(8); | |
| 3363 | c->ptr_params.init(8); | |
| 3364 | c->codegen = codegen; | |
| 3365 | c->source_node = source_node; | |
| 3366 | ||
| 3367 | ZigList<const char *> clang_argv = {0}; | |
| 3368 | ||
| 3369 | clang_argv.append("-x"); | |
| 3370 | clang_argv.append("c"); | |
| 3371 | ||
| 3372 | if (c->codegen->is_native_target) { | |
| 3373 | char *ZIG_PARSEC_CFLAGS = getenv("ZIG_NATIVE_PARSEC_CFLAGS"); | |
| 3374 | if (ZIG_PARSEC_CFLAGS) { | |
| 3375 | Buf tmp_buf = BUF_INIT; | |
| 3376 | char *start = ZIG_PARSEC_CFLAGS; | |
| 3377 | char *space = strstr(start, " "); | |
| 3378 | while (space) { | |
| 3379 | if (space - start > 0) { | |
| 3380 | buf_init_from_mem(&tmp_buf, start, space - start); | |
| 3381 | clang_argv.append(buf_ptr(buf_create_from_buf(&tmp_buf))); | |
| 3382 | } | |
| 3383 | start = space + 1; | |
| 3384 | space = strstr(start, " "); | |
| 3385 | } | |
| 3386 | buf_init_from_str(&tmp_buf, start); | |
| 3387 | clang_argv.append(buf_ptr(buf_create_from_buf(&tmp_buf))); | |
| 3388 | } | |
| 3389 | } | |
| 3390 | ||
| 3391 | clang_argv.append("-isystem"); | |
| 3392 | clang_argv.append(buf_ptr(codegen->zig_c_headers_dir)); | |
| 3393 | ||
| 3394 | clang_argv.append("-isystem"); | |
| 3395 | clang_argv.append(buf_ptr(codegen->libc_include_dir)); | |
| 3396 | ||
| 3397 | // windows c runtime requires -D_DEBUG if using debug libraries | |
| 3398 | if (codegen->build_mode == BuildModeDebug) { | |
| 3399 | clang_argv.append("-D_DEBUG"); | |
| 3400 | } | |
| 3401 | ||
| 3402 | for (size_t i = 0; i < codegen->clang_argv_len; i += 1) { | |
| 3403 | clang_argv.append(codegen->clang_argv[i]); | |
| 3404 | } | |
| 3405 | ||
| 3406 | // we don't need spell checking and it slows things down | |
| 3407 | clang_argv.append("-fno-spell-checking"); | |
| 3408 | ||
| 3409 | // this gives us access to preprocessing entities, presumably at | |
| 3410 | // the cost of performance | |
| 3411 | clang_argv.append("-Xclang"); | |
| 3412 | clang_argv.append("-detailed-preprocessing-record"); | |
| 3413 | ||
| 3414 | if (!c->codegen->is_native_target) { | |
| 3415 | clang_argv.append("-target"); | |
| 3416 | clang_argv.append(buf_ptr(&c->codegen->triple_str)); | |
| 3417 | } | |
| 3418 | ||
| 3419 | clang_argv.append(target_file); | |
| 3420 | ||
| 3421 | // to make the [start...end] argument work | |
| 3422 | clang_argv.append(nullptr); | |
| 3423 | ||
| 3424 | IntrusiveRefCntPtr<DiagnosticsEngine> diags(CompilerInstance::createDiagnostics(new DiagnosticOptions)); | |
| 3425 | ||
| 3426 | std::shared_ptr<PCHContainerOperations> pch_container_ops = std::make_shared<PCHContainerOperations>(); | |
| 3427 | ||
| 3428 | bool skip_function_bodies = false; | |
| 3429 | bool only_local_decls = true; | |
| 3430 | bool capture_diagnostics = true; | |
| 3431 | bool user_files_are_volatile = true; | |
| 3432 | bool allow_pch_with_compiler_errors = false; | |
| 3433 | bool single_file_parse = false; | |
| 3434 | bool for_serialization = false; | |
| 3435 | const char *resources_path = buf_ptr(codegen->zig_c_headers_dir); | |
| 3436 | std::unique_ptr<ASTUnit> err_unit; | |
| 3437 | std::unique_ptr<ASTUnit> ast_unit(ASTUnit::LoadFromCommandLine( | |
| 3438 | &clang_argv.at(0), &clang_argv.last(), | |
| 3439 | pch_container_ops, diags, resources_path, | |
| 3440 | only_local_decls, capture_diagnostics, None, true, 0, TU_Complete, | |
| 3441 | false, false, allow_pch_with_compiler_errors, skip_function_bodies, | |
| 3442 | single_file_parse, user_files_are_volatile, for_serialization, None, &err_unit, | |
| 3443 | nullptr)); | |
| 3444 | ||
| 3445 | // Early failures in LoadFromCommandLine may return with ErrUnit unset. | |
| 3446 | if (!ast_unit && !err_unit) { | |
| 3447 | return ErrorFileSystem; | |
| 3448 | } | |
| 3449 | ||
| 3450 | if (diags->getClient()->getNumErrors() > 0) { | |
| 3451 | if (ast_unit) { | |
| 3452 | err_unit = std::move(ast_unit); | |
| 3453 | } | |
| 3454 | ||
| 3455 | for (ASTUnit::stored_diag_iterator it = err_unit->stored_diag_begin(), | |
| 3456 | it_end = err_unit->stored_diag_end(); | |
| 3457 | it != it_end; ++it) | |
| 3458 | { | |
| 3459 | switch (it->getLevel()) { | |
| 3460 | case DiagnosticsEngine::Ignored: | |
| 3461 | case DiagnosticsEngine::Note: | |
| 3462 | case DiagnosticsEngine::Remark: | |
| 3463 | case DiagnosticsEngine::Warning: | |
| 3464 | continue; | |
| 3465 | case DiagnosticsEngine::Error: | |
| 3466 | case DiagnosticsEngine::Fatal: | |
| 3467 | break; | |
| 3468 | } | |
| 3469 | StringRef msg_str_ref = it->getMessage(); | |
| 3470 | Buf *msg = buf_create_from_str((const char *)msg_str_ref.bytes_begin()); | |
| 3471 | FullSourceLoc fsl = it->getLocation(); | |
| 3472 | if (fsl.hasManager()) { | |
| 3473 | FileID file_id = fsl.getFileID(); | |
| 3474 | StringRef filename = fsl.getManager().getFilename(fsl); | |
| 3475 | unsigned line = fsl.getSpellingLineNumber() - 1; | |
| 3476 | unsigned column = fsl.getSpellingColumnNumber() - 1; | |
| 3477 | unsigned offset = fsl.getManager().getFileOffset(fsl); | |
| 3478 | const char *source = (const char *)fsl.getManager().getBufferData(file_id).bytes_begin(); | |
| 3479 | Buf *path; | |
| 3480 | if (filename.empty()) { | |
| 3481 | path = buf_alloc(); | |
| 3482 | } else { | |
| 3483 | path = buf_create_from_mem((const char *)filename.bytes_begin(), filename.size()); | |
| 3484 | } | |
| 3485 | ||
| 3486 | ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg); | |
| 3487 | ||
| 3488 | c->errors->append(err_msg); | |
| 3489 | } else { | |
| 3490 | // NOTE the only known way this gets triggered right now is if you have a lot of errors | |
| 3491 | // clang emits "too many errors emitted, stopping now" | |
| 3492 | fprintf(stderr, "unexpected error from clang: %s\n", buf_ptr(msg)); | |
| 3493 | } | |
| 3494 | } | |
| 3495 | ||
| 3496 | return 0; | |
| 3497 | } | |
| 3498 | ||
| 3499 | c->ctx = &ast_unit->getASTContext(); | |
| 3500 | c->source_manager = &ast_unit->getSourceManager(); | |
| 3501 | c->root = trans_create_node(c, NodeTypeRoot); | |
| 3502 | ||
| 3503 | ast_unit->visitLocalTopLevelDecls(c, decl_visitor); | |
| 3504 | ||
| 3505 | process_preprocessor_entities(c, *ast_unit); | |
| 3506 | ||
| 3507 | process_symbol_macros(c); | |
| 3508 | render_macros(c); | |
| 3509 | render_aliases(c); | |
| 3510 | ||
| 3511 | import->root = c->root; | |
| 3512 | ||
| 3513 | return 0; | |
| 3514 | } |
src/parsec.hpp deleted-20| ... | ... | @@ -1,20 +0,0 @@ |
| 1 | /* | |
| 2 | * Copyright (c) 2015 Andrew Kelley | |
| 3 | * | |
| 4 | * This file is part of zig, which is MIT licensed. | |
| 5 | * See http://opensource.org/licenses/MIT | |
| 6 | */ | |
| 7 | ||
| 8 | ||
| 9 | #ifndef ZIG_PARSEC_HPP | |
| 10 | #define ZIG_PARSEC_HPP | |
| 11 | ||
| 12 | #include "all_types.hpp" | |
| 13 | ||
| 14 | int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const char *target_file, | |
| 15 | CodeGen *codegen, AstNode *source_node); | |
| 16 | ||
| 17 | int parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *source, | |
| 18 | CodeGen *codegen, AstNode *source_node); | |
| 19 | ||
| 20 | #endif |
src/translate_c.cpp created+4324| ... | ... | @@ -0,0 +1,4324 @@ |
| 1 | /* | |
| 2 | * Copyright (c) 2015 Andrew Kelley | |
| 3 | * | |
| 4 | * This file is part of zig, which is MIT licensed. | |
| 5 | * See http://opensource.org/licenses/MIT | |
| 6 | */ | |
| 7 | ||
| 8 | #include "all_types.hpp" | |
| 9 | #include "analyze.hpp" | |
| 10 | #include "c_tokenizer.hpp" | |
| 11 | #include "error.hpp" | |
| 12 | #include "ir.hpp" | |
| 13 | #include "os.hpp" | |
| 14 | #include "translate_c.hpp" | |
| 15 | #include "parser.hpp" | |
| 16 | ||
| 17 | ||
| 18 | #include <clang/Frontend/ASTUnit.h> | |
| 19 | #include <clang/Frontend/CompilerInstance.h> | |
| 20 | #include <clang/AST/Expr.h> | |
| 21 | ||
| 22 | #include <string.h> | |
| 23 | ||
| 24 | using namespace clang; | |
| 25 | ||
| 26 | struct Alias { | |
| 27 | Buf *new_name; | |
| 28 | Buf *canon_name; | |
| 29 | }; | |
| 30 | ||
| 31 | enum TransScopeId { | |
| 32 | TransScopeIdSwitch, | |
| 33 | TransScopeIdVar, | |
| 34 | TransScopeIdBlock, | |
| 35 | TransScopeIdRoot, | |
| 36 | TransScopeIdWhile, | |
| 37 | }; | |
| 38 | ||
| 39 | struct TransScope { | |
| 40 | TransScopeId id; | |
| 41 | TransScope *parent; | |
| 42 | }; | |
| 43 | ||
| 44 | struct TransScopeSwitch { | |
| 45 | TransScope base; | |
| 46 | AstNode *switch_node; | |
| 47 | uint32_t case_index; | |
| 48 | bool found_default; | |
| 49 | Buf *end_label_name; | |
| 50 | }; | |
| 51 | ||
| 52 | struct TransScopeVar { | |
| 53 | TransScope base; | |
| 54 | Buf *c_name; | |
| 55 | Buf *zig_name; | |
| 56 | }; | |
| 57 | ||
| 58 | struct TransScopeBlock { | |
| 59 | TransScope base; | |
| 60 | AstNode *node; | |
| 61 | }; | |
| 62 | ||
| 63 | struct TransScopeRoot { | |
| 64 | TransScope base; | |
| 65 | }; | |
| 66 | ||
| 67 | struct TransScopeWhile { | |
| 68 | TransScope base; | |
| 69 | AstNode *node; | |
| 70 | }; | |
| 71 | ||
| 72 | struct Context { | |
| 73 | ImportTableEntry *import; | |
| 74 | ZigList<ErrorMsg *> *errors; | |
| 75 | VisibMod visib_mod; | |
| 76 | VisibMod export_visib_mod; | |
| 77 | AstNode *root; | |
| 78 | HashMap<const void *, AstNode *, ptr_hash, ptr_eq> decl_table; | |
| 79 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> macro_table; | |
| 80 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> global_table; | |
| 81 | SourceManager *source_manager; | |
| 82 | ZigList<Alias> aliases; | |
| 83 | AstNode *source_node; | |
| 84 | bool warnings_on; | |
| 85 | ||
| 86 | CodeGen *codegen; | |
| 87 | ASTContext *ctx; | |
| 88 | ||
| 89 | TransScopeRoot *global_scope; | |
| 90 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> ptr_params; | |
| 91 | }; | |
| 92 | ||
| 93 | enum ResultUsed { | |
| 94 | ResultUsedNo, | |
| 95 | ResultUsedYes, | |
| 96 | }; | |
| 97 | ||
| 98 | enum TransLRValue { | |
| 99 | TransLValue, | |
| 100 | TransRValue, | |
| 101 | }; | |
| 102 | ||
| 103 | static TransScopeRoot *trans_scope_root_create(Context *c); | |
| 104 | static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope); | |
| 105 | static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope); | |
| 106 | static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name); | |
| 107 | static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope); | |
| 108 | ||
| 109 | static TransScopeBlock *trans_scope_block_find(TransScope *scope); | |
| 110 | static TransScopeSwitch *trans_scope_switch_find(TransScope *scope); | |
| 111 | ||
| 112 | static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl); | |
| 113 | static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl); | |
| 114 | static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl); | |
| 115 | ||
| 116 | static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt, | |
| 117 | ResultUsed result_used, TransLRValue lrval, | |
| 118 | AstNode **out_node, TransScope **out_child_scope, | |
| 119 | TransScope **out_node_scope); | |
| 120 | static TransScope *trans_stmt(Context *c, TransScope *scope, const Stmt *stmt, AstNode **out_node); | |
| 121 | static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, TransLRValue lrval); | |
| 122 | static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc); | |
| 123 | ||
| 124 | ||
| 125 | ATTRIBUTE_PRINTF(3, 4) | |
| 126 | static void emit_warning(Context *c, const SourceLocation &sl, const char *format, ...) { | |
| 127 | if (!c->warnings_on) { | |
| 128 | return; | |
| 129 | } | |
| 130 | ||
| 131 | va_list ap; | |
| 132 | va_start(ap, format); | |
| 133 | Buf *msg = buf_vprintf(format, ap); | |
| 134 | va_end(ap); | |
| 135 | ||
| 136 | StringRef filename = c->source_manager->getFilename(c->source_manager->getSpellingLoc(sl)); | |
| 137 | const char *filename_bytes = (const char *)filename.bytes_begin(); | |
| 138 | Buf *path; | |
| 139 | if (filename_bytes) { | |
| 140 | path = buf_create_from_str(filename_bytes); | |
| 141 | } else { | |
| 142 | path = buf_sprintf("(no file)"); | |
| 143 | } | |
| 144 | unsigned line = c->source_manager->getSpellingLineNumber(sl); | |
| 145 | unsigned column = c->source_manager->getSpellingColumnNumber(sl); | |
| 146 | fprintf(stderr, "%s:%u:%u: warning: %s\n", buf_ptr(path), line, column, buf_ptr(msg)); | |
| 147 | } | |
| 148 | ||
| 149 | static void add_global_weak_alias(Context *c, Buf *new_name, Buf *canon_name) { | |
| 150 | Alias *alias = c->aliases.add_one(); | |
| 151 | alias->new_name = new_name; | |
| 152 | alias->canon_name = canon_name; | |
| 153 | } | |
| 154 | ||
| 155 | static Buf *trans_lookup_zig_symbol(Context *c, TransScope *scope, Buf *c_symbol_name) { | |
| 156 | while (scope != nullptr) { | |
| 157 | if (scope->id == TransScopeIdVar) { | |
| 158 | TransScopeVar *var_scope = (TransScopeVar *)scope; | |
| 159 | if (buf_eql_buf(var_scope->c_name, c_symbol_name)) { | |
| 160 | return var_scope->zig_name; | |
| 161 | } | |
| 162 | } | |
| 163 | scope = scope->parent; | |
| 164 | } | |
| 165 | return c_symbol_name; | |
| 166 | } | |
| 167 | ||
| 168 | static AstNode * trans_create_node(Context *c, NodeType id) { | |
| 169 | AstNode *node = allocate<AstNode>(1); | |
| 170 | node->type = id; | |
| 171 | node->owner = c->import; | |
| 172 | // TODO line/column. mapping to C file?? | |
| 173 | return node; | |
| 174 | } | |
| 175 | ||
| 176 | static AstNode *trans_create_node_float_lit(Context *c, double value) { | |
| 177 | AstNode *node = trans_create_node(c, NodeTypeFloatLiteral); | |
| 178 | node->data.float_literal.bigfloat = allocate<BigFloat>(1); | |
| 179 | bigfloat_init_64(node->data.float_literal.bigfloat, value); | |
| 180 | return node; | |
| 181 | } | |
| 182 | ||
| 183 | static AstNode *trans_create_node_symbol(Context *c, Buf *name) { | |
| 184 | AstNode *node = trans_create_node(c, NodeTypeSymbol); | |
| 185 | node->data.symbol_expr.symbol = name; | |
| 186 | return node; | |
| 187 | } | |
| 188 | ||
| 189 | static AstNode *trans_create_node_symbol_str(Context *c, const char *name) { | |
| 190 | return trans_create_node_symbol(c, buf_create_from_str(name)); | |
| 191 | } | |
| 192 | ||
| 193 | static AstNode *trans_create_node_builtin_fn_call(Context *c, Buf *name) { | |
| 194 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 195 | node->data.fn_call_expr.fn_ref_expr = trans_create_node_symbol(c, name); | |
| 196 | node->data.fn_call_expr.is_builtin = true; | |
| 197 | return node; | |
| 198 | } | |
| 199 | ||
| 200 | static AstNode *trans_create_node_builtin_fn_call_str(Context *c, const char *name) { | |
| 201 | return trans_create_node_builtin_fn_call(c, buf_create_from_str(name)); | |
| 202 | } | |
| 203 | ||
| 204 | static AstNode *trans_create_node_opaque(Context *c) { | |
| 205 | return trans_create_node_builtin_fn_call_str(c, "OpaqueType"); | |
| 206 | } | |
| 207 | ||
| 208 | static AstNode *trans_create_node_fn_call_1(Context *c, AstNode *fn_ref_expr, AstNode *arg1) { | |
| 209 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 210 | node->data.fn_call_expr.fn_ref_expr = fn_ref_expr; | |
| 211 | node->data.fn_call_expr.params.append(arg1); | |
| 212 | return node; | |
| 213 | } | |
| 214 | ||
| 215 | static AstNode *trans_create_node_field_access(Context *c, AstNode *container, Buf *field_name) { | |
| 216 | AstNode *node = trans_create_node(c, NodeTypeFieldAccessExpr); | |
| 217 | if (container->type == NodeTypeSymbol) { | |
| 218 | assert(container->data.symbol_expr.symbol != nullptr); | |
| 219 | } | |
| 220 | node->data.field_access_expr.struct_expr = container; | |
| 221 | node->data.field_access_expr.field_name = field_name; | |
| 222 | return node; | |
| 223 | } | |
| 224 | ||
| 225 | static AstNode *trans_create_node_field_access_str(Context *c, AstNode *container, const char *field_name) { | |
| 226 | return trans_create_node_field_access(c, container, buf_create_from_str(field_name)); | |
| 227 | } | |
| 228 | ||
| 229 | static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *child_node) { | |
| 230 | AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); | |
| 231 | node->data.prefix_op_expr.prefix_op = op; | |
| 232 | node->data.prefix_op_expr.primary_expr = child_node; | |
| 233 | return node; | |
| 234 | } | |
| 235 | ||
| 236 | static AstNode *trans_create_node_bin_op(Context *c, AstNode *lhs_node, BinOpType op, AstNode *rhs_node) { | |
| 237 | AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); | |
| 238 | node->data.bin_op_expr.op1 = lhs_node; | |
| 239 | node->data.bin_op_expr.bin_op = op; | |
| 240 | node->data.bin_op_expr.op2 = rhs_node; | |
| 241 | return node; | |
| 242 | } | |
| 243 | ||
| 244 | static AstNode *maybe_suppress_result(Context *c, ResultUsed result_used, AstNode *node) { | |
| 245 | if (result_used == ResultUsedYes) return node; | |
| 246 | return trans_create_node_bin_op(c, | |
| 247 | trans_create_node_symbol_str(c, "_"), | |
| 248 | BinOpTypeAssign, | |
| 249 | node); | |
| 250 | } | |
| 251 | ||
| 252 | static AstNode *trans_create_node_addr_of(Context *c, bool is_const, bool is_volatile, AstNode *child_node) { | |
| 253 | AstNode *node = trans_create_node(c, NodeTypeAddrOfExpr); | |
| 254 | node->data.addr_of_expr.is_const = is_const; | |
| 255 | node->data.addr_of_expr.is_volatile = is_volatile; | |
| 256 | node->data.addr_of_expr.op_expr = child_node; | |
| 257 | return node; | |
| 258 | } | |
| 259 | ||
| 260 | static AstNode *trans_create_node_goto(Context *c, Buf *label_name) { | |
| 261 | AstNode *goto_node = trans_create_node(c, NodeTypeGoto); | |
| 262 | goto_node->data.goto_expr.name = label_name; | |
| 263 | return goto_node; | |
| 264 | } | |
| 265 | ||
| 266 | static AstNode *trans_create_node_label(Context *c, Buf *label_name) { | |
| 267 | AstNode *label_node = trans_create_node(c, NodeTypeLabel); | |
| 268 | label_node->data.label.name = label_name; | |
| 269 | return label_node; | |
| 270 | } | |
| 271 | ||
| 272 | static AstNode *trans_create_node_bool(Context *c, bool value) { | |
| 273 | AstNode *bool_node = trans_create_node(c, NodeTypeBoolLiteral); | |
| 274 | bool_node->data.bool_literal.value = value; | |
| 275 | return bool_node; | |
| 276 | } | |
| 277 | ||
| 278 | static AstNode *trans_create_node_str_lit_c(Context *c, Buf *buf) { | |
| 279 | AstNode *node = trans_create_node(c, NodeTypeStringLiteral); | |
| 280 | node->data.string_literal.buf = buf; | |
| 281 | node->data.string_literal.c = true; | |
| 282 | return node; | |
| 283 | } | |
| 284 | ||
| 285 | static AstNode *trans_create_node_str_lit_non_c(Context *c, Buf *buf) { | |
| 286 | AstNode *node = trans_create_node(c, NodeTypeStringLiteral); | |
| 287 | node->data.string_literal.buf = buf; | |
| 288 | node->data.string_literal.c = false; | |
| 289 | return node; | |
| 290 | } | |
| 291 | ||
| 292 | static AstNode *trans_create_node_unsigned_negative(Context *c, uint64_t x, bool is_negative) { | |
| 293 | AstNode *node = trans_create_node(c, NodeTypeIntLiteral); | |
| 294 | node->data.int_literal.bigint = allocate<BigInt>(1); | |
| 295 | bigint_init_data(node->data.int_literal.bigint, &x, 1, is_negative); | |
| 296 | return node; | |
| 297 | } | |
| 298 | ||
| 299 | static AstNode *trans_create_node_unsigned(Context *c, uint64_t x) { | |
| 300 | return trans_create_node_unsigned_negative(c, x, false); | |
| 301 | } | |
| 302 | ||
| 303 | static AstNode *trans_create_node_cast(Context *c, AstNode *dest, AstNode *src) { | |
| 304 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 305 | node->data.fn_call_expr.fn_ref_expr = dest; | |
| 306 | node->data.fn_call_expr.params.resize(1); | |
| 307 | node->data.fn_call_expr.params.items[0] = src; | |
| 308 | return node; | |
| 309 | } | |
| 310 | ||
| 311 | static AstNode *trans_create_node_unsigned_negative_type(Context *c, uint64_t x, bool is_negative, | |
| 312 | const char *type_name) | |
| 313 | { | |
| 314 | AstNode *lit_node = trans_create_node_unsigned_negative(c, x, is_negative); | |
| 315 | return trans_create_node_cast(c, trans_create_node_symbol_str(c, type_name), lit_node); | |
| 316 | } | |
| 317 | ||
| 318 | static AstNode *trans_create_node_array_type(Context *c, AstNode *size_node, AstNode *child_type_node) { | |
| 319 | AstNode *node = trans_create_node(c, NodeTypeArrayType); | |
| 320 | node->data.array_type.size = size_node; | |
| 321 | node->data.array_type.child_type = child_type_node; | |
| 322 | return node; | |
| 323 | } | |
| 324 | ||
| 325 | static AstNode *trans_create_node_var_decl(Context *c, VisibMod visib_mod, bool is_const, Buf *var_name, | |
| 326 | AstNode *type_node, AstNode *init_node) | |
| 327 | { | |
| 328 | AstNode *node = trans_create_node(c, NodeTypeVariableDeclaration); | |
| 329 | node->data.variable_declaration.visib_mod = visib_mod; | |
| 330 | node->data.variable_declaration.symbol = var_name; | |
| 331 | node->data.variable_declaration.is_const = is_const; | |
| 332 | node->data.variable_declaration.type = type_node; | |
| 333 | node->data.variable_declaration.expr = init_node; | |
| 334 | return node; | |
| 335 | } | |
| 336 | ||
| 337 | static AstNode *trans_create_node_var_decl_global(Context *c, bool is_const, Buf *var_name, AstNode *type_node, | |
| 338 | AstNode *init_node) | |
| 339 | { | |
| 340 | return trans_create_node_var_decl(c, c->visib_mod, is_const, var_name, type_node, init_node); | |
| 341 | } | |
| 342 | ||
| 343 | static AstNode *trans_create_node_var_decl_local(Context *c, bool is_const, Buf *var_name, AstNode *type_node, | |
| 344 | AstNode *init_node) | |
| 345 | { | |
| 346 | return trans_create_node_var_decl(c, VisibModPrivate, is_const, var_name, type_node, init_node); | |
| 347 | } | |
| 348 | ||
| 349 | static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *ref_node, AstNode *src_proto_node) { | |
| 350 | AstNode *fn_def = trans_create_node(c, NodeTypeFnDef); | |
| 351 | AstNode *fn_proto = trans_create_node(c, NodeTypeFnProto); | |
| 352 | fn_proto->data.fn_proto.visib_mod = c->visib_mod; | |
| 353 | fn_proto->data.fn_proto.name = fn_name; | |
| 354 | fn_proto->data.fn_proto.is_inline = true; | |
| 355 | fn_proto->data.fn_proto.return_type = src_proto_node->data.fn_proto.return_type; // TODO ok for these to alias? | |
| 356 | ||
| 357 | fn_def->data.fn_def.fn_proto = fn_proto; | |
| 358 | fn_proto->data.fn_proto.fn_def_node = fn_def; | |
| 359 | ||
| 360 | AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, ref_node); | |
| 361 | AstNode *fn_call_node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 362 | fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node; | |
| 363 | ||
| 364 | for (size_t i = 0; i < src_proto_node->data.fn_proto.params.length; i += 1) { | |
| 365 | AstNode *src_param_node = src_proto_node->data.fn_proto.params.at(i); | |
| 366 | Buf *param_name = src_param_node->data.param_decl.name; | |
| 367 | if (!param_name) param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i); | |
| 368 | ||
| 369 | AstNode *dest_param_node = trans_create_node(c, NodeTypeParamDecl); | |
| 370 | dest_param_node->data.param_decl.name = param_name; | |
| 371 | dest_param_node->data.param_decl.type = src_param_node->data.param_decl.type; | |
| 372 | dest_param_node->data.param_decl.is_noalias = src_param_node->data.param_decl.is_noalias; | |
| 373 | fn_proto->data.fn_proto.params.append(dest_param_node); | |
| 374 | ||
| 375 | fn_call_node->data.fn_call_expr.params.append(trans_create_node_symbol(c, param_name)); | |
| 376 | ||
| 377 | } | |
| 378 | ||
| 379 | AstNode *block = trans_create_node(c, NodeTypeBlock); | |
| 380 | block->data.block.statements.resize(1); | |
| 381 | block->data.block.statements.items[0] = fn_call_node; | |
| 382 | block->data.block.last_statement_is_result_expression = true; | |
| 383 | ||
| 384 | fn_def->data.fn_def.body = block; | |
| 385 | return fn_def; | |
| 386 | } | |
| 387 | ||
| 388 | static AstNode *trans_create_node_unwrap_null(Context *c, AstNode *child) { | |
| 389 | return trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, child); | |
| 390 | } | |
| 391 | ||
| 392 | static AstNode *get_global(Context *c, Buf *name) { | |
| 393 | { | |
| 394 | auto entry = c->global_table.maybe_get(name); | |
| 395 | if (entry) { | |
| 396 | return entry->value; | |
| 397 | } | |
| 398 | } | |
| 399 | { | |
| 400 | auto entry = c->macro_table.maybe_get(name); | |
| 401 | if (entry) | |
| 402 | return entry->value; | |
| 403 | } | |
| 404 | if (c->codegen->primitive_type_table.maybe_get(name) != nullptr) { | |
| 405 | return trans_create_node_symbol(c, name); | |
| 406 | } | |
| 407 | return nullptr; | |
| 408 | } | |
| 409 | ||
| 410 | static void add_top_level_decl(Context *c, Buf *name, AstNode *node) { | |
| 411 | c->global_table.put(name, node); | |
| 412 | c->root->data.root.top_level_decls.append(node); | |
| 413 | } | |
| 414 | ||
| 415 | static AstNode *add_global_var(Context *c, Buf *var_name, AstNode *value_node) { | |
| 416 | bool is_const = true; | |
| 417 | AstNode *type_node = nullptr; | |
| 418 | AstNode *node = trans_create_node_var_decl_global(c, is_const, var_name, type_node, value_node); | |
| 419 | add_top_level_decl(c, var_name, node); | |
| 420 | return node; | |
| 421 | } | |
| 422 | ||
| 423 | static Buf *string_ref_to_buf(StringRef string_ref) { | |
| 424 | return buf_create_from_mem((const char *)string_ref.bytes_begin(), string_ref.size()); | |
| 425 | } | |
| 426 | ||
| 427 | static const char *decl_name(const Decl *decl) { | |
| 428 | const NamedDecl *named_decl = static_cast<const NamedDecl *>(decl); | |
| 429 | return (const char *)named_decl->getName().bytes_begin(); | |
| 430 | } | |
| 431 | ||
| 432 | static AstNode *trans_create_node_apint(Context *c, const llvm::APSInt &aps_int) { | |
| 433 | AstNode *node = trans_create_node(c, NodeTypeIntLiteral); | |
| 434 | node->data.int_literal.bigint = allocate<BigInt>(1); | |
| 435 | bigint_init_data(node->data.int_literal.bigint, aps_int.getRawData(), aps_int.getNumWords(), aps_int.isNegative()); | |
| 436 | return node; | |
| 437 | ||
| 438 | } | |
| 439 | ||
| 440 | static const Type *qual_type_canon(QualType qt) { | |
| 441 | return qt.getCanonicalType().getTypePtr(); | |
| 442 | } | |
| 443 | ||
| 444 | static QualType get_expr_qual_type(Context *c, const Expr *expr) { | |
| 445 | // String literals in C are `char *` but they should really be `const char *`. | |
| 446 | if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) { | |
| 447 | const ImplicitCastExpr *cast_expr = static_cast<const ImplicitCastExpr *>(expr); | |
| 448 | if (cast_expr->getCastKind() == CK_ArrayToPointerDecay) { | |
| 449 | const Expr *sub_expr = cast_expr->getSubExpr(); | |
| 450 | if (sub_expr->getStmtClass() == Stmt::StringLiteralClass) { | |
| 451 | QualType array_qt = sub_expr->getType(); | |
| 452 | const ArrayType *array_type = static_cast<const ArrayType *>(array_qt.getTypePtr()); | |
| 453 | QualType pointee_qt = array_type->getElementType(); | |
| 454 | pointee_qt.addConst(); | |
| 455 | return c->ctx->getPointerType(pointee_qt); | |
| 456 | } | |
| 457 | } | |
| 458 | } | |
| 459 | return expr->getType(); | |
| 460 | } | |
| 461 | ||
| 462 | static AstNode *get_expr_type(Context *c, const Expr *expr) { | |
| 463 | return trans_qual_type(c, get_expr_qual_type(c, expr), expr->getLocStart()); | |
| 464 | } | |
| 465 | ||
| 466 | static bool qual_types_equal(QualType t1, QualType t2) { | |
| 467 | if (t1.isConstQualified() != t2.isConstQualified()) { | |
| 468 | return false; | |
| 469 | } | |
| 470 | if (t1.isVolatileQualified() != t2.isVolatileQualified()) { | |
| 471 | return false; | |
| 472 | } | |
| 473 | if (t1.isRestrictQualified() != t2.isRestrictQualified()) { | |
| 474 | return false; | |
| 475 | } | |
| 476 | return t1.getTypePtr() == t2.getTypePtr(); | |
| 477 | } | |
| 478 | ||
| 479 | static bool is_c_void_type(AstNode *node) { | |
| 480 | return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void")); | |
| 481 | } | |
| 482 | ||
| 483 | static bool expr_types_equal(Context *c, const Expr *expr1, const Expr *expr2) { | |
| 484 | QualType t1 = get_expr_qual_type(c, expr1); | |
| 485 | QualType t2 = get_expr_qual_type(c, expr2); | |
| 486 | ||
| 487 | return qual_types_equal(t1, t2); | |
| 488 | } | |
| 489 | ||
| 490 | static bool qual_type_is_ptr(QualType qt) { | |
| 491 | const Type *ty = qual_type_canon(qt); | |
| 492 | return ty->getTypeClass() == Type::Pointer; | |
| 493 | } | |
| 494 | ||
| 495 | static bool qual_type_is_fn_ptr(Context *c, QualType qt) { | |
| 496 | const Type *ty = qual_type_canon(qt); | |
| 497 | if (ty->getTypeClass() != Type::Pointer) { | |
| 498 | return false; | |
| 499 | } | |
| 500 | const PointerType *pointer_ty = static_cast<const PointerType*>(ty); | |
| 501 | QualType child_qt = pointer_ty->getPointeeType(); | |
| 502 | const Type *child_ty = child_qt.getTypePtr(); | |
| 503 | return child_ty->getTypeClass() == Type::FunctionProto; | |
| 504 | } | |
| 505 | ||
| 506 | static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const SourceLocation &source_loc) { | |
| 507 | const Type *ty = qt.getTypePtr(); | |
| 508 | switch (ty->getTypeClass()) { | |
| 509 | case Type::Builtin: | |
| 510 | { | |
| 511 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty); | |
| 512 | switch (builtin_ty->getKind()) { | |
| 513 | case BuiltinType::Char_U: | |
| 514 | case BuiltinType::UChar: | |
| 515 | case BuiltinType::Char_S: | |
| 516 | case BuiltinType::SChar: | |
| 517 | return 8; | |
| 518 | case BuiltinType::UInt128: | |
| 519 | case BuiltinType::Int128: | |
| 520 | return 128; | |
| 521 | default: | |
| 522 | return 0; | |
| 523 | } | |
| 524 | zig_unreachable(); | |
| 525 | } | |
| 526 | case Type::Typedef: | |
| 527 | { | |
| 528 | const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty); | |
| 529 | const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); | |
| 530 | const char *type_name = decl_name(typedef_decl); | |
| 531 | if (strcmp(type_name, "uint8_t") == 0 || strcmp(type_name, "int8_t") == 0) { | |
| 532 | return 8; | |
| 533 | } else if (strcmp(type_name, "uint16_t") == 0 || strcmp(type_name, "int16_t") == 0) { | |
| 534 | return 16; | |
| 535 | } else if (strcmp(type_name, "uint32_t") == 0 || strcmp(type_name, "int32_t") == 0) { | |
| 536 | return 32; | |
| 537 | } else if (strcmp(type_name, "uint64_t") == 0 || strcmp(type_name, "int64_t") == 0) { | |
| 538 | return 64; | |
| 539 | } else { | |
| 540 | return 0; | |
| 541 | } | |
| 542 | } | |
| 543 | default: | |
| 544 | return 0; | |
| 545 | } | |
| 546 | zig_unreachable(); | |
| 547 | } | |
| 548 | ||
| 549 | ||
| 550 | static AstNode *qual_type_to_log2_int_ref(Context *c, const QualType &qt, | |
| 551 | const SourceLocation &source_loc) | |
| 552 | { | |
| 553 | uint32_t int_bit_width = qual_type_int_bit_width(c, qt, source_loc); | |
| 554 | if (int_bit_width != 0) { | |
| 555 | // we can perform the log2 now. | |
| 556 | uint64_t cast_bit_width = log2_u64(int_bit_width); | |
| 557 | return trans_create_node_symbol(c, buf_sprintf("u%" ZIG_PRI_u64, cast_bit_width)); | |
| 558 | } | |
| 559 | ||
| 560 | AstNode *zig_type_node = trans_qual_type(c, qt, source_loc); | |
| 561 | ||
| 562 | // @import("std").math.Log2Int(c_long); | |
| 563 | // | |
| 564 | // FnCall | |
| 565 | // FieldAccess | |
| 566 | // FieldAccess | |
| 567 | // FnCall (.builtin = true) | |
| 568 | // Symbol "import" | |
| 569 | // StringLiteral "std" | |
| 570 | // Symbol "math" | |
| 571 | // Symbol "Log2Int" | |
| 572 | // zig_type_node | |
| 573 | ||
| 574 | AstNode *import_fn_call = trans_create_node_builtin_fn_call_str(c, "import"); | |
| 575 | import_fn_call->data.fn_call_expr.params.append(trans_create_node_str_lit_non_c(c, buf_create_from_str("std"))); | |
| 576 | AstNode *inner_field_access = trans_create_node_field_access_str(c, import_fn_call, "math"); | |
| 577 | AstNode *outer_field_access = trans_create_node_field_access_str(c, inner_field_access, "Log2Int"); | |
| 578 | AstNode *log2int_fn_call = trans_create_node_fn_call_1(c, outer_field_access, zig_type_node); | |
| 579 | ||
| 580 | return log2int_fn_call; | |
| 581 | } | |
| 582 | ||
| 583 | static bool qual_type_child_is_fn_proto(const QualType &qt) { | |
| 584 | if (qt.getTypePtr()->getTypeClass() == Type::Paren) { | |
| 585 | const ParenType *paren_type = static_cast<const ParenType *>(qt.getTypePtr()); | |
| 586 | if (paren_type->getInnerType()->getTypeClass() == Type::FunctionProto) { | |
| 587 | return true; | |
| 588 | } | |
| 589 | } else if (qt.getTypePtr()->getTypeClass() == Type::Attributed) { | |
| 590 | const AttributedType *attr_type = static_cast<const AttributedType *>(qt.getTypePtr()); | |
| 591 | return qual_type_child_is_fn_proto(attr_type->getEquivalentType()); | |
| 592 | } | |
| 593 | return false; | |
| 594 | } | |
| 595 | ||
| 596 | static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location, QualType dest_type, | |
| 597 | QualType src_type, AstNode *expr) | |
| 598 | { | |
| 599 | if (qual_types_equal(dest_type, src_type)) { | |
| 600 | return expr; | |
| 601 | } | |
| 602 | if (qual_type_is_ptr(dest_type) && qual_type_is_ptr(src_type)) { | |
| 603 | AstNode *ptr_cast_node = trans_create_node_builtin_fn_call_str(c, "ptrCast"); | |
| 604 | ptr_cast_node->data.fn_call_expr.params.append(trans_qual_type(c, dest_type, source_location)); | |
| 605 | ptr_cast_node->data.fn_call_expr.params.append(expr); | |
| 606 | return ptr_cast_node; | |
| 607 | } | |
| 608 | // TODO: maybe widen to increase size | |
| 609 | // TODO: maybe bitcast to change sign | |
| 610 | // TODO: maybe truncate to reduce size | |
| 611 | return trans_create_node_fn_call_1(c, trans_qual_type(c, dest_type, source_location), expr); | |
| 612 | } | |
| 613 | ||
| 614 | static bool c_is_signed_integer(Context *c, QualType qt) { | |
| 615 | const Type *c_type = qual_type_canon(qt); | |
| 616 | if (c_type->getTypeClass() != Type::Builtin) | |
| 617 | return false; | |
| 618 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); | |
| 619 | switch (builtin_ty->getKind()) { | |
| 620 | case BuiltinType::SChar: | |
| 621 | case BuiltinType::Short: | |
| 622 | case BuiltinType::Int: | |
| 623 | case BuiltinType::Long: | |
| 624 | case BuiltinType::LongLong: | |
| 625 | case BuiltinType::Int128: | |
| 626 | case BuiltinType::WChar_S: | |
| 627 | return true; | |
| 628 | default: | |
| 629 | return false; | |
| 630 | } | |
| 631 | } | |
| 632 | ||
| 633 | static bool c_is_unsigned_integer(Context *c, QualType qt) { | |
| 634 | const Type *c_type = qual_type_canon(qt); | |
| 635 | if (c_type->getTypeClass() != Type::Builtin) | |
| 636 | return false; | |
| 637 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); | |
| 638 | switch (builtin_ty->getKind()) { | |
| 639 | case BuiltinType::Char_U: | |
| 640 | case BuiltinType::UChar: | |
| 641 | case BuiltinType::Char_S: | |
| 642 | case BuiltinType::UShort: | |
| 643 | case BuiltinType::UInt: | |
| 644 | case BuiltinType::ULong: | |
| 645 | case BuiltinType::ULongLong: | |
| 646 | case BuiltinType::UInt128: | |
| 647 | case BuiltinType::WChar_U: | |
| 648 | return true; | |
| 649 | default: | |
| 650 | return false; | |
| 651 | } | |
| 652 | } | |
| 653 | ||
| 654 | static bool c_is_float(Context *c, QualType qt) { | |
| 655 | const Type *c_type = qt.getTypePtr(); | |
| 656 | if (c_type->getTypeClass() != Type::Builtin) | |
| 657 | return false; | |
| 658 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); | |
| 659 | switch (builtin_ty->getKind()) { | |
| 660 | case BuiltinType::Half: | |
| 661 | case BuiltinType::Float: | |
| 662 | case BuiltinType::Double: | |
| 663 | case BuiltinType::Float128: | |
| 664 | case BuiltinType::LongDouble: | |
| 665 | return true; | |
| 666 | default: | |
| 667 | return false; | |
| 668 | } | |
| 669 | } | |
| 670 | ||
| 671 | static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) { | |
| 672 | if (c_is_signed_integer(c, qt) || c_is_float(c, qt)) { | |
| 673 | // float and signed integer overflow is undefined behavior. | |
| 674 | return false; | |
| 675 | } else { | |
| 676 | // unsigned integer overflow wraps around. | |
| 677 | return true; | |
| 678 | } | |
| 679 | } | |
| 680 | ||
| 681 | static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) { | |
| 682 | switch (ty->getTypeClass()) { | |
| 683 | case Type::Builtin: | |
| 684 | { | |
| 685 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty); | |
| 686 | switch (builtin_ty->getKind()) { | |
| 687 | case BuiltinType::Void: | |
| 688 | return trans_create_node_symbol_str(c, "c_void"); | |
| 689 | case BuiltinType::Bool: | |
| 690 | return trans_create_node_symbol_str(c, "bool"); | |
| 691 | case BuiltinType::Char_U: | |
| 692 | case BuiltinType::UChar: | |
| 693 | case BuiltinType::Char_S: | |
| 694 | return trans_create_node_symbol_str(c, "u8"); | |
| 695 | case BuiltinType::SChar: | |
| 696 | return trans_create_node_symbol_str(c, "i8"); | |
| 697 | case BuiltinType::UShort: | |
| 698 | return trans_create_node_symbol_str(c, "c_ushort"); | |
| 699 | case BuiltinType::UInt: | |
| 700 | return trans_create_node_symbol_str(c, "c_uint"); | |
| 701 | case BuiltinType::ULong: | |
| 702 | return trans_create_node_symbol_str(c, "c_ulong"); | |
| 703 | case BuiltinType::ULongLong: | |
| 704 | return trans_create_node_symbol_str(c, "c_ulonglong"); | |
| 705 | case BuiltinType::Short: | |
| 706 | return trans_create_node_symbol_str(c, "c_short"); | |
| 707 | case BuiltinType::Int: | |
| 708 | return trans_create_node_symbol_str(c, "c_int"); | |
| 709 | case BuiltinType::Long: | |
| 710 | return trans_create_node_symbol_str(c, "c_long"); | |
| 711 | case BuiltinType::LongLong: | |
| 712 | return trans_create_node_symbol_str(c, "c_longlong"); | |
| 713 | case BuiltinType::UInt128: | |
| 714 | return trans_create_node_symbol_str(c, "u128"); | |
| 715 | case BuiltinType::Int128: | |
| 716 | return trans_create_node_symbol_str(c, "i128"); | |
| 717 | case BuiltinType::Float: | |
| 718 | return trans_create_node_symbol_str(c, "f32"); | |
| 719 | case BuiltinType::Double: | |
| 720 | return trans_create_node_symbol_str(c, "f64"); | |
| 721 | case BuiltinType::Float128: | |
| 722 | return trans_create_node_symbol_str(c, "f128"); | |
| 723 | case BuiltinType::Float16: | |
| 724 | return trans_create_node_symbol_str(c, "f16"); | |
| 725 | case BuiltinType::LongDouble: | |
| 726 | return trans_create_node_symbol_str(c, "c_longdouble"); | |
| 727 | case BuiltinType::WChar_U: | |
| 728 | case BuiltinType::Char16: | |
| 729 | case BuiltinType::Char32: | |
| 730 | case BuiltinType::WChar_S: | |
| 731 | case BuiltinType::Half: | |
| 732 | case BuiltinType::NullPtr: | |
| 733 | case BuiltinType::ObjCId: | |
| 734 | case BuiltinType::ObjCClass: | |
| 735 | case BuiltinType::ObjCSel: | |
| 736 | case BuiltinType::OMPArraySection: | |
| 737 | case BuiltinType::Dependent: | |
| 738 | case BuiltinType::Overload: | |
| 739 | case BuiltinType::BoundMember: | |
| 740 | case BuiltinType::PseudoObject: | |
| 741 | case BuiltinType::UnknownAny: | |
| 742 | case BuiltinType::BuiltinFn: | |
| 743 | case BuiltinType::ARCUnbridgedCast: | |
| 744 | ||
| 745 | case BuiltinType::OCLImage1dRO: | |
| 746 | case BuiltinType::OCLImage1dArrayRO: | |
| 747 | case BuiltinType::OCLImage1dBufferRO: | |
| 748 | case BuiltinType::OCLImage2dRO: | |
| 749 | case BuiltinType::OCLImage2dArrayRO: | |
| 750 | case BuiltinType::OCLImage2dDepthRO: | |
| 751 | case BuiltinType::OCLImage2dArrayDepthRO: | |
| 752 | case BuiltinType::OCLImage2dMSAARO: | |
| 753 | case BuiltinType::OCLImage2dArrayMSAARO: | |
| 754 | case BuiltinType::OCLImage2dMSAADepthRO: | |
| 755 | case BuiltinType::OCLImage2dArrayMSAADepthRO: | |
| 756 | case BuiltinType::OCLImage3dRO: | |
| 757 | case BuiltinType::OCLImage1dWO: | |
| 758 | case BuiltinType::OCLImage1dArrayWO: | |
| 759 | case BuiltinType::OCLImage1dBufferWO: | |
| 760 | case BuiltinType::OCLImage2dWO: | |
| 761 | case BuiltinType::OCLImage2dArrayWO: | |
| 762 | case BuiltinType::OCLImage2dDepthWO: | |
| 763 | case BuiltinType::OCLImage2dArrayDepthWO: | |
| 764 | case BuiltinType::OCLImage2dMSAAWO: | |
| 765 | case BuiltinType::OCLImage2dArrayMSAAWO: | |
| 766 | case BuiltinType::OCLImage2dMSAADepthWO: | |
| 767 | case BuiltinType::OCLImage2dArrayMSAADepthWO: | |
| 768 | case BuiltinType::OCLImage3dWO: | |
| 769 | case BuiltinType::OCLImage1dRW: | |
| 770 | case BuiltinType::OCLImage1dArrayRW: | |
| 771 | case BuiltinType::OCLImage1dBufferRW: | |
| 772 | case BuiltinType::OCLImage2dRW: | |
| 773 | case BuiltinType::OCLImage2dArrayRW: | |
| 774 | case BuiltinType::OCLImage2dDepthRW: | |
| 775 | case BuiltinType::OCLImage2dArrayDepthRW: | |
| 776 | case BuiltinType::OCLImage2dMSAARW: | |
| 777 | case BuiltinType::OCLImage2dArrayMSAARW: | |
| 778 | case BuiltinType::OCLImage2dMSAADepthRW: | |
| 779 | case BuiltinType::OCLImage2dArrayMSAADepthRW: | |
| 780 | case BuiltinType::OCLImage3dRW: | |
| 781 | case BuiltinType::OCLSampler: | |
| 782 | case BuiltinType::OCLEvent: | |
| 783 | case BuiltinType::OCLClkEvent: | |
| 784 | case BuiltinType::OCLQueue: | |
| 785 | case BuiltinType::OCLReserveID: | |
| 786 | emit_warning(c, source_loc, "unsupported builtin type"); | |
| 787 | return nullptr; | |
| 788 | } | |
| 789 | break; | |
| 790 | } | |
| 791 | case Type::Pointer: | |
| 792 | { | |
| 793 | const PointerType *pointer_ty = static_cast<const PointerType*>(ty); | |
| 794 | QualType child_qt = pointer_ty->getPointeeType(); | |
| 795 | AstNode *child_node = trans_qual_type(c, child_qt, source_loc); | |
| 796 | if (child_node == nullptr) { | |
| 797 | emit_warning(c, source_loc, "pointer to unsupported type"); | |
| 798 | return nullptr; | |
| 799 | } | |
| 800 | ||
| 801 | if (qual_type_child_is_fn_proto(child_qt)) { | |
| 802 | return trans_create_node_prefix_op(c, PrefixOpMaybe, child_node); | |
| 803 | } | |
| 804 | ||
| 805 | AstNode *pointer_node = trans_create_node_addr_of(c, child_qt.isConstQualified(), | |
| 806 | child_qt.isVolatileQualified(), child_node); | |
| 807 | return trans_create_node_prefix_op(c, PrefixOpMaybe, pointer_node); | |
| 808 | } | |
| 809 | case Type::Typedef: | |
| 810 | { | |
| 811 | const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty); | |
| 812 | const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); | |
| 813 | return resolve_typedef_decl(c, typedef_decl); | |
| 814 | } | |
| 815 | case Type::Elaborated: | |
| 816 | { | |
| 817 | const ElaboratedType *elaborated_ty = static_cast<const ElaboratedType*>(ty); | |
| 818 | switch (elaborated_ty->getKeyword()) { | |
| 819 | case ETK_Struct: | |
| 820 | case ETK_Enum: | |
| 821 | case ETK_Union: | |
| 822 | return trans_qual_type(c, elaborated_ty->getNamedType(), source_loc); | |
| 823 | case ETK_Interface: | |
| 824 | case ETK_Class: | |
| 825 | case ETK_Typename: | |
| 826 | case ETK_None: | |
| 827 | emit_warning(c, source_loc, "unsupported elaborated type"); | |
| 828 | return nullptr; | |
| 829 | } | |
| 830 | } | |
| 831 | case Type::FunctionProto: | |
| 832 | { | |
| 833 | const FunctionProtoType *fn_proto_ty = static_cast<const FunctionProtoType*>(ty); | |
| 834 | ||
| 835 | AstNode *proto_node = trans_create_node(c, NodeTypeFnProto); | |
| 836 | switch (fn_proto_ty->getCallConv()) { | |
| 837 | case CC_C: // __attribute__((cdecl)) | |
| 838 | proto_node->data.fn_proto.cc = CallingConventionC; | |
| 839 | proto_node->data.fn_proto.is_extern = true; | |
| 840 | break; | |
| 841 | case CC_X86StdCall: // __attribute__((stdcall)) | |
| 842 | proto_node->data.fn_proto.cc = CallingConventionStdcall; | |
| 843 | break; | |
| 844 | case CC_X86FastCall: // __attribute__((fastcall)) | |
| 845 | emit_warning(c, source_loc, "unsupported calling convention: x86 fastcall"); | |
| 846 | return nullptr; | |
| 847 | case CC_X86ThisCall: // __attribute__((thiscall)) | |
| 848 | emit_warning(c, source_loc, "unsupported calling convention: x86 thiscall"); | |
| 849 | return nullptr; | |
| 850 | case CC_X86VectorCall: // __attribute__((vectorcall)) | |
| 851 | emit_warning(c, source_loc, "unsupported calling convention: x86 vectorcall"); | |
| 852 | return nullptr; | |
| 853 | case CC_X86Pascal: // __attribute__((pascal)) | |
| 854 | emit_warning(c, source_loc, "unsupported calling convention: x86 pascal"); | |
| 855 | return nullptr; | |
| 856 | case CC_Win64: // __attribute__((ms_abi)) | |
| 857 | emit_warning(c, source_loc, "unsupported calling convention: win64"); | |
| 858 | return nullptr; | |
| 859 | case CC_X86_64SysV: // __attribute__((sysv_abi)) | |
| 860 | emit_warning(c, source_loc, "unsupported calling convention: x86 64sysv"); | |
| 861 | return nullptr; | |
| 862 | case CC_X86RegCall: | |
| 863 | emit_warning(c, source_loc, "unsupported calling convention: x86 reg"); | |
| 864 | return nullptr; | |
| 865 | case CC_AAPCS: // __attribute__((pcs("aapcs"))) | |
| 866 | emit_warning(c, source_loc, "unsupported calling convention: aapcs"); | |
| 867 | return nullptr; | |
| 868 | case CC_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp"))) | |
| 869 | emit_warning(c, source_loc, "unsupported calling convention: aapcs-vfp"); | |
| 870 | return nullptr; | |
| 871 | case CC_IntelOclBicc: // __attribute__((intel_ocl_bicc)) | |
| 872 | emit_warning(c, source_loc, "unsupported calling convention: intel_ocl_bicc"); | |
| 873 | return nullptr; | |
| 874 | case CC_SpirFunction: // default for OpenCL functions on SPIR target | |
| 875 | emit_warning(c, source_loc, "unsupported calling convention: SPIR function"); | |
| 876 | return nullptr; | |
| 877 | case CC_OpenCLKernel: | |
| 878 | emit_warning(c, source_loc, "unsupported calling convention: OpenCLKernel"); | |
| 879 | return nullptr; | |
| 880 | case CC_Swift: | |
| 881 | emit_warning(c, source_loc, "unsupported calling convention: Swift"); | |
| 882 | return nullptr; | |
| 883 | case CC_PreserveMost: | |
| 884 | emit_warning(c, source_loc, "unsupported calling convention: PreserveMost"); | |
| 885 | return nullptr; | |
| 886 | case CC_PreserveAll: | |
| 887 | emit_warning(c, source_loc, "unsupported calling convention: PreserveAll"); | |
| 888 | return nullptr; | |
| 889 | } | |
| 890 | ||
| 891 | proto_node->data.fn_proto.is_var_args = fn_proto_ty->isVariadic(); | |
| 892 | size_t param_count = fn_proto_ty->getNumParams(); | |
| 893 | ||
| 894 | if (fn_proto_ty->getNoReturnAttr()) { | |
| 895 | proto_node->data.fn_proto.return_type = trans_create_node_symbol_str(c, "noreturn"); | |
| 896 | } else { | |
| 897 | proto_node->data.fn_proto.return_type = trans_qual_type(c, fn_proto_ty->getReturnType(), | |
| 898 | source_loc); | |
| 899 | if (proto_node->data.fn_proto.return_type == nullptr) { | |
| 900 | emit_warning(c, source_loc, "unsupported function proto return type"); | |
| 901 | return nullptr; | |
| 902 | } | |
| 903 | // convert c_void to actual void (only for return type) | |
| 904 | // we do want to look at the AstNode instead of QualType, because | |
| 905 | // if they do something like: | |
| 906 | // typedef Foo void; | |
| 907 | // void foo(void) -> Foo; | |
| 908 | // we want to keep the return type AST node. | |
| 909 | if (is_c_void_type(proto_node->data.fn_proto.return_type)) { | |
| 910 | proto_node->data.fn_proto.return_type = nullptr; | |
| 911 | } | |
| 912 | } | |
| 913 | ||
| 914 | //emit_warning(c, source_loc, "TODO figure out fn prototype fn name"); | |
| 915 | const char *fn_name = nullptr; | |
| 916 | if (fn_name != nullptr) { | |
| 917 | proto_node->data.fn_proto.name = buf_create_from_str(fn_name); | |
| 918 | } | |
| 919 | ||
| 920 | for (size_t i = 0; i < param_count; i += 1) { | |
| 921 | QualType qt = fn_proto_ty->getParamType(i); | |
| 922 | AstNode *param_type_node = trans_qual_type(c, qt, source_loc); | |
| 923 | ||
| 924 | if (param_type_node == nullptr) { | |
| 925 | emit_warning(c, source_loc, "unresolved function proto parameter type"); | |
| 926 | return nullptr; | |
| 927 | } | |
| 928 | ||
| 929 | AstNode *param_node = trans_create_node(c, NodeTypeParamDecl); | |
| 930 | //emit_warning(c, source_loc, "TODO figure out fn prototype param name"); | |
| 931 | const char *param_name = nullptr; | |
| 932 | if (param_name != nullptr) { | |
| 933 | param_node->data.param_decl.name = buf_create_from_str(param_name); | |
| 934 | } | |
| 935 | param_node->data.param_decl.is_noalias = qt.isRestrictQualified(); | |
| 936 | param_node->data.param_decl.type = param_type_node; | |
| 937 | proto_node->data.fn_proto.params.append(param_node); | |
| 938 | } | |
| 939 | // TODO check for always_inline attribute | |
| 940 | // TODO check for align attribute | |
| 941 | ||
| 942 | return proto_node; | |
| 943 | } | |
| 944 | case Type::Record: | |
| 945 | { | |
| 946 | const RecordType *record_ty = static_cast<const RecordType*>(ty); | |
| 947 | return resolve_record_decl(c, record_ty->getDecl()); | |
| 948 | } | |
| 949 | case Type::Enum: | |
| 950 | { | |
| 951 | const EnumType *enum_ty = static_cast<const EnumType*>(ty); | |
| 952 | return resolve_enum_decl(c, enum_ty->getDecl()); | |
| 953 | } | |
| 954 | case Type::ConstantArray: | |
| 955 | { | |
| 956 | const ConstantArrayType *const_arr_ty = static_cast<const ConstantArrayType *>(ty); | |
| 957 | AstNode *child_type_node = trans_qual_type(c, const_arr_ty->getElementType(), source_loc); | |
| 958 | if (child_type_node == nullptr) { | |
| 959 | emit_warning(c, source_loc, "unresolved array element type"); | |
| 960 | return nullptr; | |
| 961 | } | |
| 962 | uint64_t size = const_arr_ty->getSize().getLimitedValue(); | |
| 963 | AstNode *size_node = trans_create_node_unsigned(c, size); | |
| 964 | return trans_create_node_array_type(c, size_node, child_type_node); | |
| 965 | } | |
| 966 | case Type::Paren: | |
| 967 | { | |
| 968 | const ParenType *paren_ty = static_cast<const ParenType *>(ty); | |
| 969 | return trans_qual_type(c, paren_ty->getInnerType(), source_loc); | |
| 970 | } | |
| 971 | case Type::Decayed: | |
| 972 | { | |
| 973 | const DecayedType *decayed_ty = static_cast<const DecayedType *>(ty); | |
| 974 | return trans_qual_type(c, decayed_ty->getDecayedType(), source_loc); | |
| 975 | } | |
| 976 | case Type::Attributed: | |
| 977 | { | |
| 978 | const AttributedType *attributed_ty = static_cast<const AttributedType *>(ty); | |
| 979 | return trans_qual_type(c, attributed_ty->getEquivalentType(), source_loc); | |
| 980 | } | |
| 981 | case Type::BlockPointer: | |
| 982 | case Type::LValueReference: | |
| 983 | case Type::RValueReference: | |
| 984 | case Type::MemberPointer: | |
| 985 | case Type::IncompleteArray: | |
| 986 | case Type::VariableArray: | |
| 987 | case Type::DependentSizedArray: | |
| 988 | case Type::DependentSizedExtVector: | |
| 989 | case Type::Vector: | |
| 990 | case Type::ExtVector: | |
| 991 | case Type::FunctionNoProto: | |
| 992 | case Type::UnresolvedUsing: | |
| 993 | case Type::Adjusted: | |
| 994 | case Type::TypeOfExpr: | |
| 995 | case Type::TypeOf: | |
| 996 | case Type::Decltype: | |
| 997 | case Type::UnaryTransform: | |
| 998 | case Type::TemplateTypeParm: | |
| 999 | case Type::SubstTemplateTypeParm: | |
| 1000 | case Type::SubstTemplateTypeParmPack: | |
| 1001 | case Type::TemplateSpecialization: | |
| 1002 | case Type::Auto: | |
| 1003 | case Type::InjectedClassName: | |
| 1004 | case Type::DependentName: | |
| 1005 | case Type::DependentTemplateSpecialization: | |
| 1006 | case Type::PackExpansion: | |
| 1007 | case Type::ObjCObject: | |
| 1008 | case Type::ObjCInterface: | |
| 1009 | case Type::Complex: | |
| 1010 | case Type::ObjCObjectPointer: | |
| 1011 | case Type::Atomic: | |
| 1012 | case Type::Pipe: | |
| 1013 | case Type::ObjCTypeParam: | |
| 1014 | case Type::DeducedTemplateSpecialization: | |
| 1015 | case Type::DependentAddressSpace: | |
| 1016 | emit_warning(c, source_loc, "unsupported type: '%s'", ty->getTypeClassName()); | |
| 1017 | return nullptr; | |
| 1018 | } | |
| 1019 | zig_unreachable(); | |
| 1020 | } | |
| 1021 | ||
| 1022 | static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc) { | |
| 1023 | return trans_type(c, qt.getTypePtr(), source_loc); | |
| 1024 | } | |
| 1025 | ||
| 1026 | static int trans_compound_stmt_inline(Context *c, TransScope *scope, const CompoundStmt *stmt, | |
| 1027 | AstNode *block_node, TransScope **out_node_scope) | |
| 1028 | { | |
| 1029 | assert(block_node->type == NodeTypeBlock); | |
| 1030 | for (CompoundStmt::const_body_iterator it = stmt->body_begin(), end_it = stmt->body_end(); it != end_it; ++it) { | |
| 1031 | AstNode *child_node; | |
| 1032 | scope = trans_stmt(c, scope, *it, &child_node); | |
| 1033 | if (scope == nullptr) | |
| 1034 | return ErrorUnexpected; | |
| 1035 | if (child_node != nullptr) | |
| 1036 | block_node->data.block.statements.append(child_node); | |
| 1037 | } | |
| 1038 | if (out_node_scope != nullptr) { | |
| 1039 | *out_node_scope = scope; | |
| 1040 | } | |
| 1041 | return ErrorNone; | |
| 1042 | } | |
| 1043 | ||
| 1044 | static AstNode *trans_compound_stmt(Context *c, TransScope *scope, const CompoundStmt *stmt, | |
| 1045 | TransScope **out_node_scope) | |
| 1046 | { | |
| 1047 | TransScopeBlock *child_scope_block = trans_scope_block_create(c, scope); | |
| 1048 | if (trans_compound_stmt_inline(c, &child_scope_block->base, stmt, child_scope_block->node, out_node_scope)) | |
| 1049 | return nullptr; | |
| 1050 | return child_scope_block->node; | |
| 1051 | } | |
| 1052 | ||
| 1053 | static AstNode *trans_return_stmt(Context *c, TransScope *scope, const ReturnStmt *stmt) { | |
| 1054 | const Expr *value_expr = stmt->getRetValue(); | |
| 1055 | if (value_expr == nullptr) { | |
| 1056 | return trans_create_node(c, NodeTypeReturnExpr); | |
| 1057 | } else { | |
| 1058 | AstNode *return_node = trans_create_node(c, NodeTypeReturnExpr); | |
| 1059 | return_node->data.return_expr.expr = trans_expr(c, ResultUsedYes, scope, value_expr, TransRValue); | |
| 1060 | if (return_node->data.return_expr.expr == nullptr) | |
| 1061 | return nullptr; | |
| 1062 | return return_node; | |
| 1063 | } | |
| 1064 | } | |
| 1065 | ||
| 1066 | static AstNode *trans_integer_literal(Context *c, const IntegerLiteral *stmt) { | |
| 1067 | llvm::APSInt result; | |
| 1068 | if (!stmt->EvaluateAsInt(result, *c->ctx)) { | |
| 1069 | emit_warning(c, stmt->getLocStart(), "invalid integer literal"); | |
| 1070 | return nullptr; | |
| 1071 | } | |
| 1072 | return trans_create_node_apint(c, result); | |
| 1073 | } | |
| 1074 | ||
| 1075 | static AstNode *trans_conditional_operator(Context *c, ResultUsed result_used, TransScope *scope, | |
| 1076 | const ConditionalOperator *stmt) | |
| 1077 | { | |
| 1078 | AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr); | |
| 1079 | ||
| 1080 | Expr *cond_expr = stmt->getCond(); | |
| 1081 | Expr *true_expr = stmt->getTrueExpr(); | |
| 1082 | Expr *false_expr = stmt->getFalseExpr(); | |
| 1083 | ||
| 1084 | node->data.if_bool_expr.condition = trans_expr(c, ResultUsedYes, scope, cond_expr, TransRValue); | |
| 1085 | if (node->data.if_bool_expr.condition == nullptr) | |
| 1086 | return nullptr; | |
| 1087 | ||
| 1088 | node->data.if_bool_expr.then_block = trans_expr(c, result_used, scope, true_expr, TransRValue); | |
| 1089 | if (node->data.if_bool_expr.then_block == nullptr) | |
| 1090 | return nullptr; | |
| 1091 | ||
| 1092 | node->data.if_bool_expr.else_node = trans_expr(c, result_used, scope, false_expr, TransRValue); | |
| 1093 | if (node->data.if_bool_expr.else_node == nullptr) | |
| 1094 | return nullptr; | |
| 1095 | ||
| 1096 | return maybe_suppress_result(c, result_used, node); | |
| 1097 | } | |
| 1098 | ||
| 1099 | static AstNode *trans_create_bin_op(Context *c, TransScope *scope, Expr *lhs, BinOpType bin_op, Expr *rhs) { | |
| 1100 | AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); | |
| 1101 | node->data.bin_op_expr.bin_op = bin_op; | |
| 1102 | ||
| 1103 | node->data.bin_op_expr.op1 = trans_expr(c, ResultUsedYes, scope, lhs, TransRValue); | |
| 1104 | if (node->data.bin_op_expr.op1 == nullptr) | |
| 1105 | return nullptr; | |
| 1106 | ||
| 1107 | node->data.bin_op_expr.op2 = trans_expr(c, ResultUsedYes, scope, rhs, TransRValue); | |
| 1108 | if (node->data.bin_op_expr.op2 == nullptr) | |
| 1109 | return nullptr; | |
| 1110 | ||
| 1111 | return node; | |
| 1112 | } | |
| 1113 | ||
| 1114 | static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransScope *scope, Expr *lhs, Expr *rhs) { | |
| 1115 | if (result_used == ResultUsedNo) { | |
| 1116 | // common case | |
| 1117 | AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); | |
| 1118 | node->data.bin_op_expr.bin_op = BinOpTypeAssign; | |
| 1119 | ||
| 1120 | node->data.bin_op_expr.op1 = trans_expr(c, ResultUsedYes, scope, lhs, TransLValue); | |
| 1121 | if (node->data.bin_op_expr.op1 == nullptr) | |
| 1122 | return nullptr; | |
| 1123 | ||
| 1124 | node->data.bin_op_expr.op2 = trans_expr(c, ResultUsedYes, scope, rhs, TransRValue); | |
| 1125 | if (node->data.bin_op_expr.op2 == nullptr) | |
| 1126 | return nullptr; | |
| 1127 | ||
| 1128 | return node; | |
| 1129 | } else { | |
| 1130 | // worst case | |
| 1131 | // c: lhs = rhs | |
| 1132 | // zig: { | |
| 1133 | // zig: const _tmp = rhs; | |
| 1134 | // zig: lhs = _tmp; | |
| 1135 | // zig: _tmp | |
| 1136 | // zig: } | |
| 1137 | ||
| 1138 | TransScopeBlock *child_scope = trans_scope_block_create(c, scope); | |
| 1139 | ||
| 1140 | // const _tmp = rhs; | |
| 1141 | AstNode *rhs_node = trans_expr(c, ResultUsedYes, &child_scope->base, rhs, TransRValue); | |
| 1142 | if (rhs_node == nullptr) return nullptr; | |
| 1143 | // TODO: avoid name collisions with generated variable names | |
| 1144 | Buf* tmp_var_name = buf_create_from_str("_tmp"); | |
| 1145 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, rhs_node); | |
| 1146 | child_scope->node->data.block.statements.append(tmp_var_decl); | |
| 1147 | ||
| 1148 | // lhs = _tmp; | |
| 1149 | AstNode *lhs_node = trans_expr(c, ResultUsedYes, &child_scope->base, lhs, TransLValue); | |
| 1150 | if (lhs_node == nullptr) return nullptr; | |
| 1151 | child_scope->node->data.block.statements.append( | |
| 1152 | trans_create_node_bin_op(c, lhs_node, BinOpTypeAssign, | |
| 1153 | trans_create_node_symbol(c, tmp_var_name))); | |
| 1154 | ||
| 1155 | // _tmp | |
| 1156 | child_scope->node->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name)); | |
| 1157 | child_scope->node->data.block.last_statement_is_result_expression = true; | |
| 1158 | ||
| 1159 | return child_scope->node; | |
| 1160 | } | |
| 1161 | } | |
| 1162 | ||
| 1163 | static AstNode *trans_create_shift_op(Context *c, TransScope *scope, QualType result_type, | |
| 1164 | Expr *lhs_expr, BinOpType bin_op, Expr *rhs_expr) | |
| 1165 | { | |
| 1166 | const SourceLocation &rhs_location = rhs_expr->getLocStart(); | |
| 1167 | AstNode *rhs_type = qual_type_to_log2_int_ref(c, result_type, rhs_location); | |
| 1168 | // lhs >> u5(rh) | |
| 1169 | ||
| 1170 | AstNode *lhs = trans_expr(c, ResultUsedYes, scope, lhs_expr, TransLValue); | |
| 1171 | if (lhs == nullptr) return nullptr; | |
| 1172 | ||
| 1173 | AstNode *rhs = trans_expr(c, ResultUsedYes, scope, rhs_expr, TransRValue); | |
| 1174 | if (rhs == nullptr) return nullptr; | |
| 1175 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); | |
| 1176 | ||
| 1177 | return trans_create_node_bin_op(c, lhs, bin_op, coerced_rhs); | |
| 1178 | } | |
| 1179 | ||
| 1180 | static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransScope *scope, const BinaryOperator *stmt) { | |
| 1181 | switch (stmt->getOpcode()) { | |
| 1182 | case BO_PtrMemD: | |
| 1183 | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_PtrMemD"); | |
| 1184 | return nullptr; | |
| 1185 | case BO_PtrMemI: | |
| 1186 | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_PtrMemI"); | |
| 1187 | return nullptr; | |
| 1188 | case BO_Mul: | |
| 1189 | return trans_create_bin_op(c, scope, stmt->getLHS(), | |
| 1190 | qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeMultWrap : BinOpTypeMult, | |
| 1191 | stmt->getRHS()); | |
| 1192 | case BO_Div: | |
| 1193 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) { | |
| 1194 | // unsigned/float division uses the operator | |
| 1195 | return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeDiv, stmt->getRHS()); | |
| 1196 | } else { | |
| 1197 | // signed integer division uses @divTrunc | |
| 1198 | AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "divTrunc"); | |
| 1199 | AstNode *lhs = trans_expr(c, ResultUsedYes, scope, stmt->getLHS(), TransLValue); | |
| 1200 | if (lhs == nullptr) return nullptr; | |
| 1201 | fn_call->data.fn_call_expr.params.append(lhs); | |
| 1202 | AstNode *rhs = trans_expr(c, ResultUsedYes, scope, stmt->getRHS(), TransLValue); | |
| 1203 | if (rhs == nullptr) return nullptr; | |
| 1204 | fn_call->data.fn_call_expr.params.append(rhs); | |
| 1205 | return fn_call; | |
| 1206 | } | |
| 1207 | case BO_Rem: | |
| 1208 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) { | |
| 1209 | // unsigned/float division uses the operator | |
| 1210 | return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeMod, stmt->getRHS()); | |
| 1211 | } else { | |
| 1212 | // signed integer division uses @rem | |
| 1213 | AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "rem"); | |
| 1214 | AstNode *lhs = trans_expr(c, ResultUsedYes, scope, stmt->getLHS(), TransLValue); | |
| 1215 | if (lhs == nullptr) return nullptr; | |
| 1216 | fn_call->data.fn_call_expr.params.append(lhs); | |
| 1217 | AstNode *rhs = trans_expr(c, ResultUsedYes, scope, stmt->getRHS(), TransLValue); | |
| 1218 | if (rhs == nullptr) return nullptr; | |
| 1219 | fn_call->data.fn_call_expr.params.append(rhs); | |
| 1220 | return fn_call; | |
| 1221 | } | |
| 1222 | case BO_Add: | |
| 1223 | return trans_create_bin_op(c, scope, stmt->getLHS(), | |
| 1224 | qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeAddWrap : BinOpTypeAdd, | |
| 1225 | stmt->getRHS()); | |
| 1226 | case BO_Sub: | |
| 1227 | return trans_create_bin_op(c, scope, stmt->getLHS(), | |
| 1228 | qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeSubWrap : BinOpTypeSub, | |
| 1229 | stmt->getRHS()); | |
| 1230 | case BO_Shl: | |
| 1231 | return trans_create_shift_op(c, scope, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftLeft, stmt->getRHS()); | |
| 1232 | case BO_Shr: | |
| 1233 | return trans_create_shift_op(c, scope, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftRight, stmt->getRHS()); | |
| 1234 | case BO_LT: | |
| 1235 | return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpLessThan, stmt->getRHS()); | |
| 1236 | case BO_GT: | |
| 1237 | return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpGreaterThan, stmt->getRHS()); | |
| 1238 | case BO_LE: | |
| 1239 | return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpLessOrEq, stmt->getRHS()); | |
| 1240 | case BO_GE: | |
| 1241 | return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpGreaterOrEq, stmt->getRHS()); | |
| 1242 | case BO_EQ: | |
| 1243 | return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpEq, stmt->getRHS()); | |
| 1244 | case BO_NE: | |
| 1245 | return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpNotEq, stmt->getRHS()); | |
| 1246 | case BO_And: | |
| 1247 | return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinAnd, stmt->getRHS()); | |
| 1248 | case BO_Xor: | |
| 1249 | return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinXor, stmt->getRHS()); | |
| 1250 | case BO_Or: | |
| 1251 | return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinOr, stmt->getRHS()); | |
| 1252 | case BO_LAnd: | |
| 1253 | return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS()); | |
| 1254 | case BO_LOr: | |
| 1255 | // TODO: int vs bool | |
| 1256 | return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS()); | |
| 1257 | case BO_Assign: | |
| 1258 | return trans_create_assign(c, result_used, scope, stmt->getLHS(), stmt->getRHS()); | |
| 1259 | case BO_Comma: | |
| 1260 | { | |
| 1261 | TransScopeBlock *scope_block = trans_scope_block_create(c, scope); | |
| 1262 | AstNode *lhs = trans_expr(c, ResultUsedNo, &scope_block->base, stmt->getLHS(), TransRValue); | |
| 1263 | if (lhs == nullptr) | |
| 1264 | return nullptr; | |
| 1265 | scope_block->node->data.block.statements.append(maybe_suppress_result(c, ResultUsedNo, lhs)); | |
| 1266 | ||
| 1267 | AstNode *rhs = trans_expr(c, result_used, &scope_block->base, stmt->getRHS(), TransRValue); | |
| 1268 | if (rhs == nullptr) | |
| 1269 | return nullptr; | |
| 1270 | scope_block->node->data.block.statements.append(maybe_suppress_result(c, result_used, rhs)); | |
| 1271 | ||
| 1272 | scope_block->node->data.block.last_statement_is_result_expression = true; | |
| 1273 | return scope_block->node; | |
| 1274 | } | |
| 1275 | case BO_MulAssign: | |
| 1276 | case BO_DivAssign: | |
| 1277 | case BO_RemAssign: | |
| 1278 | case BO_AddAssign: | |
| 1279 | case BO_SubAssign: | |
| 1280 | case BO_ShlAssign: | |
| 1281 | case BO_ShrAssign: | |
| 1282 | case BO_AndAssign: | |
| 1283 | case BO_XorAssign: | |
| 1284 | case BO_OrAssign: | |
| 1285 | zig_unreachable(); | |
| 1286 | } | |
| 1287 | ||
| 1288 | zig_unreachable(); | |
| 1289 | } | |
| 1290 | ||
| 1291 | static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result_used, TransScope *scope, | |
| 1292 | const CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) | |
| 1293 | { | |
| 1294 | const SourceLocation &rhs_location = stmt->getRHS()->getLocStart(); | |
| 1295 | AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location); | |
| 1296 | ||
| 1297 | bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr(); | |
| 1298 | if (!use_intermediate_casts && result_used == ResultUsedNo) { | |
| 1299 | // simple common case, where the C and Zig are identical: | |
| 1300 | // lhs >>= rhs | |
| 1301 | AstNode *lhs = trans_expr(c, ResultUsedYes, scope, stmt->getLHS(), TransLValue); | |
| 1302 | if (lhs == nullptr) return nullptr; | |
| 1303 | ||
| 1304 | AstNode *rhs = trans_expr(c, ResultUsedYes, scope, stmt->getRHS(), TransRValue); | |
| 1305 | if (rhs == nullptr) return nullptr; | |
| 1306 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); | |
| 1307 | ||
| 1308 | return trans_create_node_bin_op(c, lhs, assign_op, coerced_rhs); | |
| 1309 | } else { | |
| 1310 | // need more complexity. worst case, this looks like this: | |
| 1311 | // c: lhs >>= rhs | |
| 1312 | // zig: { | |
| 1313 | // zig: const _ref = &lhs; | |
| 1314 | // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs)); | |
| 1315 | // zig: *_ref | |
| 1316 | // zig: } | |
| 1317 | // where u5 is the appropriate type | |
| 1318 | ||
| 1319 | TransScopeBlock *child_scope = trans_scope_block_create(c, scope); | |
| 1320 | ||
| 1321 | // const _ref = &lhs; | |
| 1322 | AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue); | |
| 1323 | if (lhs == nullptr) return nullptr; | |
| 1324 | AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs); | |
| 1325 | // TODO: avoid name collisions with generated variable names | |
| 1326 | Buf* tmp_var_name = buf_create_from_str("_ref"); | |
| 1327 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs); | |
| 1328 | child_scope->node->data.block.statements.append(tmp_var_decl); | |
| 1329 | ||
| 1330 | // *_ref = result_type(operation_type(*_ref) >> u5(rhs)); | |
| 1331 | ||
| 1332 | AstNode *rhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getRHS(), TransRValue); | |
| 1333 | if (rhs == nullptr) return nullptr; | |
| 1334 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); | |
| 1335 | ||
| 1336 | // operation_type(*_ref) | |
| 1337 | AstNode *operation_type_cast = trans_c_cast(c, rhs_location, | |
| 1338 | stmt->getComputationLHSType(), | |
| 1339 | stmt->getLHS()->getType(), | |
| 1340 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1341 | trans_create_node_symbol(c, tmp_var_name))); | |
| 1342 | ||
| 1343 | // result_type(... >> u5(rhs)) | |
| 1344 | AstNode *result_type_cast = trans_c_cast(c, rhs_location, | |
| 1345 | stmt->getComputationResultType(), | |
| 1346 | stmt->getComputationLHSType(), | |
| 1347 | trans_create_node_bin_op(c, | |
| 1348 | operation_type_cast, | |
| 1349 | bin_op, | |
| 1350 | coerced_rhs)); | |
| 1351 | ||
| 1352 | // *_ref = ... | |
| 1353 | AstNode *assign_statement = trans_create_node_bin_op(c, | |
| 1354 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1355 | trans_create_node_symbol(c, tmp_var_name)), | |
| 1356 | BinOpTypeAssign, result_type_cast); | |
| 1357 | ||
| 1358 | child_scope->node->data.block.statements.append(assign_statement); | |
| 1359 | ||
| 1360 | if (result_used == ResultUsedYes) { | |
| 1361 | // *_ref | |
| 1362 | child_scope->node->data.block.statements.append( | |
| 1363 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1364 | trans_create_node_symbol(c, tmp_var_name))); | |
| 1365 | child_scope->node->data.block.last_statement_is_result_expression = true; | |
| 1366 | } | |
| 1367 | ||
| 1368 | return child_scope->node; | |
| 1369 | } | |
| 1370 | } | |
| 1371 | ||
| 1372 | static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used, TransScope *scope, | |
| 1373 | const CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) | |
| 1374 | { | |
| 1375 | if (result_used == ResultUsedNo) { | |
| 1376 | // simple common case, where the C and Zig are identical: | |
| 1377 | // lhs += rhs | |
| 1378 | AstNode *lhs = trans_expr(c, ResultUsedYes, scope, stmt->getLHS(), TransLValue); | |
| 1379 | if (lhs == nullptr) return nullptr; | |
| 1380 | AstNode *rhs = trans_expr(c, ResultUsedYes, scope, stmt->getRHS(), TransRValue); | |
| 1381 | if (rhs == nullptr) return nullptr; | |
| 1382 | return trans_create_node_bin_op(c, lhs, assign_op, rhs); | |
| 1383 | } else { | |
| 1384 | // need more complexity. worst case, this looks like this: | |
| 1385 | // c: lhs += rhs | |
| 1386 | // zig: { | |
| 1387 | // zig: const _ref = &lhs; | |
| 1388 | // zig: *_ref = *_ref + rhs; | |
| 1389 | // zig: *_ref | |
| 1390 | // zig: } | |
| 1391 | ||
| 1392 | TransScopeBlock *child_scope = trans_scope_block_create(c, scope); | |
| 1393 | ||
| 1394 | // const _ref = &lhs; | |
| 1395 | AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue); | |
| 1396 | if (lhs == nullptr) return nullptr; | |
| 1397 | AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs); | |
| 1398 | // TODO: avoid name collisions with generated variable names | |
| 1399 | Buf* tmp_var_name = buf_create_from_str("_ref"); | |
| 1400 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs); | |
| 1401 | child_scope->node->data.block.statements.append(tmp_var_decl); | |
| 1402 | ||
| 1403 | // *_ref = *_ref + rhs; | |
| 1404 | ||
| 1405 | AstNode *rhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getRHS(), TransRValue); | |
| 1406 | if (rhs == nullptr) return nullptr; | |
| 1407 | ||
| 1408 | AstNode *assign_statement = trans_create_node_bin_op(c, | |
| 1409 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1410 | trans_create_node_symbol(c, tmp_var_name)), | |
| 1411 | BinOpTypeAssign, | |
| 1412 | trans_create_node_bin_op(c, | |
| 1413 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1414 | trans_create_node_symbol(c, tmp_var_name)), | |
| 1415 | bin_op, | |
| 1416 | rhs)); | |
| 1417 | child_scope->node->data.block.statements.append(assign_statement); | |
| 1418 | ||
| 1419 | // *_ref | |
| 1420 | child_scope->node->data.block.statements.append( | |
| 1421 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1422 | trans_create_node_symbol(c, tmp_var_name))); | |
| 1423 | child_scope->node->data.block.last_statement_is_result_expression = true; | |
| 1424 | ||
| 1425 | return child_scope->node; | |
| 1426 | } | |
| 1427 | } | |
| 1428 | ||
| 1429 | ||
| 1430 | static AstNode *trans_compound_assign_operator(Context *c, ResultUsed result_used, TransScope *scope, | |
| 1431 | const CompoundAssignOperator *stmt) | |
| 1432 | { | |
| 1433 | switch (stmt->getOpcode()) { | |
| 1434 | case BO_MulAssign: | |
| 1435 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1436 | return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignTimesWrap, BinOpTypeMultWrap); | |
| 1437 | else | |
| 1438 | return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignTimes, BinOpTypeMult); | |
| 1439 | case BO_DivAssign: | |
| 1440 | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_DivAssign"); | |
| 1441 | return nullptr; | |
| 1442 | case BO_RemAssign: | |
| 1443 | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_RemAssign"); | |
| 1444 | return nullptr; | |
| 1445 | case BO_AddAssign: | |
| 1446 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1447 | return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap, BinOpTypeAddWrap); | |
| 1448 | else | |
| 1449 | return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignPlus, BinOpTypeAdd); | |
| 1450 | case BO_SubAssign: | |
| 1451 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1452 | return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap, BinOpTypeSubWrap); | |
| 1453 | else | |
| 1454 | return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignMinus, BinOpTypeSub); | |
| 1455 | case BO_ShlAssign: | |
| 1456 | return trans_create_compound_assign_shift(c, result_used, scope, stmt, BinOpTypeAssignBitShiftLeft, BinOpTypeBitShiftLeft); | |
| 1457 | case BO_ShrAssign: | |
| 1458 | return trans_create_compound_assign_shift(c, result_used, scope, stmt, BinOpTypeAssignBitShiftRight, BinOpTypeBitShiftRight); | |
| 1459 | case BO_AndAssign: | |
| 1460 | return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignBitAnd, BinOpTypeBinAnd); | |
| 1461 | case BO_XorAssign: | |
| 1462 | return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignBitXor, BinOpTypeBinXor); | |
| 1463 | case BO_OrAssign: | |
| 1464 | return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignBitOr, BinOpTypeBinOr); | |
| 1465 | case BO_PtrMemD: | |
| 1466 | case BO_PtrMemI: | |
| 1467 | case BO_Assign: | |
| 1468 | case BO_Mul: | |
| 1469 | case BO_Div: | |
| 1470 | case BO_Rem: | |
| 1471 | case BO_Add: | |
| 1472 | case BO_Sub: | |
| 1473 | case BO_Shl: | |
| 1474 | case BO_Shr: | |
| 1475 | case BO_LT: | |
| 1476 | case BO_GT: | |
| 1477 | case BO_LE: | |
| 1478 | case BO_GE: | |
| 1479 | case BO_EQ: | |
| 1480 | case BO_NE: | |
| 1481 | case BO_And: | |
| 1482 | case BO_Xor: | |
| 1483 | case BO_Or: | |
| 1484 | case BO_LAnd: | |
| 1485 | case BO_LOr: | |
| 1486 | case BO_Comma: | |
| 1487 | zig_unreachable(); | |
| 1488 | } | |
| 1489 | ||
| 1490 | zig_unreachable(); | |
| 1491 | } | |
| 1492 | ||
| 1493 | static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const ImplicitCastExpr *stmt) { | |
| 1494 | switch (stmt->getCastKind()) { | |
| 1495 | case CK_LValueToRValue: | |
| 1496 | return trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue); | |
| 1497 | case CK_IntegralCast: | |
| 1498 | { | |
| 1499 | AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue); | |
| 1500 | if (target_node == nullptr) | |
| 1501 | return nullptr; | |
| 1502 | return trans_c_cast(c, stmt->getExprLoc(), stmt->getType(), | |
| 1503 | stmt->getSubExpr()->getType(), target_node); | |
| 1504 | } | |
| 1505 | case CK_FunctionToPointerDecay: | |
| 1506 | case CK_ArrayToPointerDecay: | |
| 1507 | { | |
| 1508 | AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue); | |
| 1509 | if (target_node == nullptr) | |
| 1510 | return nullptr; | |
| 1511 | return target_node; | |
| 1512 | } | |
| 1513 | case CK_BitCast: | |
| 1514 | { | |
| 1515 | AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue); | |
| 1516 | if (target_node == nullptr) | |
| 1517 | return nullptr; | |
| 1518 | ||
| 1519 | if (expr_types_equal(c, stmt, stmt->getSubExpr())) { | |
| 1520 | return target_node; | |
| 1521 | } | |
| 1522 | ||
| 1523 | AstNode *dest_type_node = get_expr_type(c, stmt); | |
| 1524 | ||
| 1525 | AstNode *node = trans_create_node_builtin_fn_call_str(c, "ptrCast"); | |
| 1526 | node->data.fn_call_expr.params.append(dest_type_node); | |
| 1527 | node->data.fn_call_expr.params.append(target_node); | |
| 1528 | return node; | |
| 1529 | } | |
| 1530 | case CK_NullToPointer: | |
| 1531 | return trans_create_node(c, NodeTypeNullLiteral); | |
| 1532 | case CK_Dependent: | |
| 1533 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent"); | |
| 1534 | return nullptr; | |
| 1535 | case CK_LValueBitCast: | |
| 1536 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_LValueBitCast"); | |
| 1537 | return nullptr; | |
| 1538 | case CK_NoOp: | |
| 1539 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NoOp"); | |
| 1540 | return nullptr; | |
| 1541 | case CK_BaseToDerived: | |
| 1542 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BaseToDerived"); | |
| 1543 | return nullptr; | |
| 1544 | case CK_DerivedToBase: | |
| 1545 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_DerivedToBase"); | |
| 1546 | return nullptr; | |
| 1547 | case CK_UncheckedDerivedToBase: | |
| 1548 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_UncheckedDerivedToBase"); | |
| 1549 | return nullptr; | |
| 1550 | case CK_Dynamic: | |
| 1551 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dynamic"); | |
| 1552 | return nullptr; | |
| 1553 | case CK_ToUnion: | |
| 1554 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ToUnion"); | |
| 1555 | return nullptr; | |
| 1556 | case CK_NullToMemberPointer: | |
| 1557 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NullToMemberPointer"); | |
| 1558 | return nullptr; | |
| 1559 | case CK_BaseToDerivedMemberPointer: | |
| 1560 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BaseToDerivedMemberPointer"); | |
| 1561 | return nullptr; | |
| 1562 | case CK_DerivedToBaseMemberPointer: | |
| 1563 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_DerivedToBaseMemberPointer"); | |
| 1564 | return nullptr; | |
| 1565 | case CK_MemberPointerToBoolean: | |
| 1566 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_MemberPointerToBoolean"); | |
| 1567 | return nullptr; | |
| 1568 | case CK_ReinterpretMemberPointer: | |
| 1569 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ReinterpretMemberPointer"); | |
| 1570 | return nullptr; | |
| 1571 | case CK_UserDefinedConversion: | |
| 1572 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_UserDefinedConversion"); | |
| 1573 | return nullptr; | |
| 1574 | case CK_ConstructorConversion: | |
| 1575 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ConstructorConversion"); | |
| 1576 | return nullptr; | |
| 1577 | case CK_IntegralToPointer: | |
| 1578 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralToPointer"); | |
| 1579 | return nullptr; | |
| 1580 | case CK_PointerToIntegral: | |
| 1581 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_PointerToIntegral"); | |
| 1582 | return nullptr; | |
| 1583 | case CK_PointerToBoolean: | |
| 1584 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_PointerToBoolean"); | |
| 1585 | return nullptr; | |
| 1586 | case CK_ToVoid: | |
| 1587 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ToVoid"); | |
| 1588 | return nullptr; | |
| 1589 | case CK_VectorSplat: | |
| 1590 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_VectorSplat"); | |
| 1591 | return nullptr; | |
| 1592 | case CK_IntegralToBoolean: | |
| 1593 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralToBoolean"); | |
| 1594 | return nullptr; | |
| 1595 | case CK_IntegralToFloating: | |
| 1596 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralToFloating"); | |
| 1597 | return nullptr; | |
| 1598 | case CK_FloatingToIntegral: | |
| 1599 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingToIntegral"); | |
| 1600 | return nullptr; | |
| 1601 | case CK_FloatingToBoolean: | |
| 1602 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingToBoolean"); | |
| 1603 | return nullptr; | |
| 1604 | case CK_BooleanToSignedIntegral: | |
| 1605 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BooleanToSignedIntegral"); | |
| 1606 | return nullptr; | |
| 1607 | case CK_FloatingCast: | |
| 1608 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingCast"); | |
| 1609 | return nullptr; | |
| 1610 | case CK_CPointerToObjCPointerCast: | |
| 1611 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_CPointerToObjCPointerCast"); | |
| 1612 | return nullptr; | |
| 1613 | case CK_BlockPointerToObjCPointerCast: | |
| 1614 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BlockPointerToObjCPointerCast"); | |
| 1615 | return nullptr; | |
| 1616 | case CK_AnyPointerToBlockPointerCast: | |
| 1617 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_AnyPointerToBlockPointerCast"); | |
| 1618 | return nullptr; | |
| 1619 | case CK_ObjCObjectLValueCast: | |
| 1620 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ObjCObjectLValueCast"); | |
| 1621 | return nullptr; | |
| 1622 | case CK_FloatingRealToComplex: | |
| 1623 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingRealToComplex"); | |
| 1624 | return nullptr; | |
| 1625 | case CK_FloatingComplexToReal: | |
| 1626 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexToReal"); | |
| 1627 | return nullptr; | |
| 1628 | case CK_FloatingComplexToBoolean: | |
| 1629 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexToBoolean"); | |
| 1630 | return nullptr; | |
| 1631 | case CK_FloatingComplexCast: | |
| 1632 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexCast"); | |
| 1633 | return nullptr; | |
| 1634 | case CK_FloatingComplexToIntegralComplex: | |
| 1635 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexToIntegralComplex"); | |
| 1636 | return nullptr; | |
| 1637 | case CK_IntegralRealToComplex: | |
| 1638 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralRealToComplex"); | |
| 1639 | return nullptr; | |
| 1640 | case CK_IntegralComplexToReal: | |
| 1641 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexToReal"); | |
| 1642 | return nullptr; | |
| 1643 | case CK_IntegralComplexToBoolean: | |
| 1644 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexToBoolean"); | |
| 1645 | return nullptr; | |
| 1646 | case CK_IntegralComplexCast: | |
| 1647 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexCast"); | |
| 1648 | return nullptr; | |
| 1649 | case CK_IntegralComplexToFloatingComplex: | |
| 1650 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexToFloatingComplex"); | |
| 1651 | return nullptr; | |
| 1652 | case CK_ARCProduceObject: | |
| 1653 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCProduceObject"); | |
| 1654 | return nullptr; | |
| 1655 | case CK_ARCConsumeObject: | |
| 1656 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCConsumeObject"); | |
| 1657 | return nullptr; | |
| 1658 | case CK_ARCReclaimReturnedObject: | |
| 1659 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCReclaimReturnedObject"); | |
| 1660 | return nullptr; | |
| 1661 | case CK_ARCExtendBlockObject: | |
| 1662 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCExtendBlockObject"); | |
| 1663 | return nullptr; | |
| 1664 | case CK_AtomicToNonAtomic: | |
| 1665 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_AtomicToNonAtomic"); | |
| 1666 | return nullptr; | |
| 1667 | case CK_NonAtomicToAtomic: | |
| 1668 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NonAtomicToAtomic"); | |
| 1669 | return nullptr; | |
| 1670 | case CK_CopyAndAutoreleaseBlockObject: | |
| 1671 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_CopyAndAutoreleaseBlockObject"); | |
| 1672 | return nullptr; | |
| 1673 | case CK_BuiltinFnToFnPtr: | |
| 1674 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BuiltinFnToFnPtr"); | |
| 1675 | return nullptr; | |
| 1676 | case CK_ZeroToOCLEvent: | |
| 1677 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ZeroToOCLEvent"); | |
| 1678 | return nullptr; | |
| 1679 | case CK_ZeroToOCLQueue: | |
| 1680 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ZeroToOCLQueue"); | |
| 1681 | return nullptr; | |
| 1682 | case CK_AddressSpaceConversion: | |
| 1683 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_AddressSpaceConversion"); | |
| 1684 | return nullptr; | |
| 1685 | case CK_IntToOCLSampler: | |
| 1686 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntToOCLSampler"); | |
| 1687 | return nullptr; | |
| 1688 | } | |
| 1689 | zig_unreachable(); | |
| 1690 | } | |
| 1691 | ||
| 1692 | static AstNode *trans_decl_ref_expr(Context *c, TransScope *scope, const DeclRefExpr *stmt, TransLRValue lrval) { | |
| 1693 | const ValueDecl *value_decl = stmt->getDecl(); | |
| 1694 | Buf *c_symbol_name = buf_create_from_str(decl_name(value_decl)); | |
| 1695 | Buf *zig_symbol_name = trans_lookup_zig_symbol(c, scope, c_symbol_name); | |
| 1696 | if (lrval == TransLValue) { | |
| 1697 | c->ptr_params.put(zig_symbol_name, true); | |
| 1698 | } | |
| 1699 | return trans_create_node_symbol(c, zig_symbol_name); | |
| 1700 | } | |
| 1701 | ||
| 1702 | static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, TransScope *scope, | |
| 1703 | const UnaryOperator *stmt, BinOpType assign_op) | |
| 1704 | { | |
| 1705 | Expr *op_expr = stmt->getSubExpr(); | |
| 1706 | ||
| 1707 | if (result_used == ResultUsedNo) { | |
| 1708 | // common case | |
| 1709 | // c: expr++ | |
| 1710 | // zig: expr += 1 | |
| 1711 | return trans_create_node_bin_op(c, | |
| 1712 | trans_expr(c, ResultUsedYes, scope, op_expr, TransLValue), | |
| 1713 | assign_op, | |
| 1714 | trans_create_node_unsigned(c, 1)); | |
| 1715 | } | |
| 1716 | // worst case | |
| 1717 | // c: expr++ | |
| 1718 | // zig: { | |
| 1719 | // zig: const _ref = &expr; | |
| 1720 | // zig: const _tmp = *_ref; | |
| 1721 | // zig: *_ref += 1; | |
| 1722 | // zig: _tmp | |
| 1723 | // zig: } | |
| 1724 | TransScopeBlock *child_scope = trans_scope_block_create(c, scope); | |
| 1725 | ||
| 1726 | // const _ref = &expr; | |
| 1727 | AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue); | |
| 1728 | if (expr == nullptr) return nullptr; | |
| 1729 | AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr); | |
| 1730 | // TODO: avoid name collisions with generated variable names | |
| 1731 | Buf* ref_var_name = buf_create_from_str("_ref"); | |
| 1732 | AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr); | |
| 1733 | child_scope->node->data.block.statements.append(ref_var_decl); | |
| 1734 | ||
| 1735 | // const _tmp = *_ref; | |
| 1736 | Buf* tmp_var_name = buf_create_from_str("_tmp"); | |
| 1737 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, | |
| 1738 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1739 | trans_create_node_symbol(c, ref_var_name))); | |
| 1740 | child_scope->node->data.block.statements.append(tmp_var_decl); | |
| 1741 | ||
| 1742 | // *_ref += 1; | |
| 1743 | AstNode *assign_statement = trans_create_node_bin_op(c, | |
| 1744 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1745 | trans_create_node_symbol(c, ref_var_name)), | |
| 1746 | assign_op, | |
| 1747 | trans_create_node_unsigned(c, 1)); | |
| 1748 | child_scope->node->data.block.statements.append(assign_statement); | |
| 1749 | ||
| 1750 | // _tmp | |
| 1751 | child_scope->node->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name)); | |
| 1752 | child_scope->node->data.block.last_statement_is_result_expression = true; | |
| 1753 | ||
| 1754 | return child_scope->node; | |
| 1755 | } | |
| 1756 | ||
| 1757 | static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, TransScope *scope, | |
| 1758 | const UnaryOperator *stmt, BinOpType assign_op) | |
| 1759 | { | |
| 1760 | Expr *op_expr = stmt->getSubExpr(); | |
| 1761 | ||
| 1762 | if (result_used == ResultUsedNo) { | |
| 1763 | // common case | |
| 1764 | // c: ++expr | |
| 1765 | // zig: expr += 1 | |
| 1766 | return trans_create_node_bin_op(c, | |
| 1767 | trans_expr(c, ResultUsedYes, scope, op_expr, TransLValue), | |
| 1768 | assign_op, | |
| 1769 | trans_create_node_unsigned(c, 1)); | |
| 1770 | } | |
| 1771 | // worst case | |
| 1772 | // c: ++expr | |
| 1773 | // zig: { | |
| 1774 | // zig: const _ref = &expr; | |
| 1775 | // zig: *_ref += 1; | |
| 1776 | // zig: *_ref | |
| 1777 | // zig: } | |
| 1778 | TransScopeBlock *child_scope = trans_scope_block_create(c, scope); | |
| 1779 | ||
| 1780 | // const _ref = &expr; | |
| 1781 | AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue); | |
| 1782 | if (expr == nullptr) return nullptr; | |
| 1783 | AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr); | |
| 1784 | // TODO: avoid name collisions with generated variable names | |
| 1785 | Buf* ref_var_name = buf_create_from_str("_ref"); | |
| 1786 | AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr); | |
| 1787 | child_scope->node->data.block.statements.append(ref_var_decl); | |
| 1788 | ||
| 1789 | // *_ref += 1; | |
| 1790 | AstNode *assign_statement = trans_create_node_bin_op(c, | |
| 1791 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1792 | trans_create_node_symbol(c, ref_var_name)), | |
| 1793 | assign_op, | |
| 1794 | trans_create_node_unsigned(c, 1)); | |
| 1795 | child_scope->node->data.block.statements.append(assign_statement); | |
| 1796 | ||
| 1797 | // *_ref | |
| 1798 | AstNode *deref_expr = trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1799 | trans_create_node_symbol(c, ref_var_name)); | |
| 1800 | child_scope->node->data.block.statements.append(deref_expr); | |
| 1801 | child_scope->node->data.block.last_statement_is_result_expression = true; | |
| 1802 | ||
| 1803 | return child_scope->node; | |
| 1804 | } | |
| 1805 | ||
| 1806 | static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransScope *scope, const UnaryOperator *stmt) { | |
| 1807 | switch (stmt->getOpcode()) { | |
| 1808 | case UO_PostInc: | |
| 1809 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1810 | return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap); | |
| 1811 | else | |
| 1812 | return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignPlus); | |
| 1813 | case UO_PostDec: | |
| 1814 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1815 | return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap); | |
| 1816 | else | |
| 1817 | return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignMinus); | |
| 1818 | case UO_PreInc: | |
| 1819 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1820 | return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap); | |
| 1821 | else | |
| 1822 | return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignPlus); | |
| 1823 | case UO_PreDec: | |
| 1824 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1825 | return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap); | |
| 1826 | else | |
| 1827 | return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignMinus); | |
| 1828 | case UO_AddrOf: | |
| 1829 | { | |
| 1830 | AstNode *value_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), TransLValue); | |
| 1831 | if (value_node == nullptr) | |
| 1832 | return value_node; | |
| 1833 | return trans_create_node_addr_of(c, false, false, value_node); | |
| 1834 | } | |
| 1835 | case UO_Deref: | |
| 1836 | { | |
| 1837 | AstNode *value_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), TransRValue); | |
| 1838 | if (value_node == nullptr) | |
| 1839 | return nullptr; | |
| 1840 | bool is_fn_ptr = qual_type_is_fn_ptr(c, stmt->getSubExpr()->getType()); | |
| 1841 | if (is_fn_ptr) | |
| 1842 | return value_node; | |
| 1843 | AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node); | |
| 1844 | return trans_create_node_prefix_op(c, PrefixOpDereference, unwrapped); | |
| 1845 | } | |
| 1846 | case UO_Plus: | |
| 1847 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Plus"); | |
| 1848 | return nullptr; | |
| 1849 | case UO_Minus: | |
| 1850 | { | |
| 1851 | Expr *op_expr = stmt->getSubExpr(); | |
| 1852 | if (!qual_type_has_wrapping_overflow(c, op_expr->getType())) { | |
| 1853 | AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); | |
| 1854 | node->data.prefix_op_expr.prefix_op = PrefixOpNegation; | |
| 1855 | ||
| 1856 | node->data.prefix_op_expr.primary_expr = trans_expr(c, ResultUsedYes, scope, op_expr, TransRValue); | |
| 1857 | if (node->data.prefix_op_expr.primary_expr == nullptr) | |
| 1858 | return nullptr; | |
| 1859 | ||
| 1860 | return node; | |
| 1861 | } else if (c_is_unsigned_integer(c, op_expr->getType())) { | |
| 1862 | // we gotta emit 0 -% x | |
| 1863 | AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); | |
| 1864 | node->data.bin_op_expr.op1 = trans_create_node_unsigned(c, 0); | |
| 1865 | ||
| 1866 | node->data.bin_op_expr.op2 = trans_expr(c, ResultUsedYes, scope, op_expr, TransRValue); | |
| 1867 | if (node->data.bin_op_expr.op2 == nullptr) | |
| 1868 | return nullptr; | |
| 1869 | ||
| 1870 | node->data.bin_op_expr.bin_op = BinOpTypeSubWrap; | |
| 1871 | return node; | |
| 1872 | } else { | |
| 1873 | emit_warning(c, stmt->getLocStart(), "C negation with non float non integer"); | |
| 1874 | return nullptr; | |
| 1875 | } | |
| 1876 | } | |
| 1877 | case UO_Not: | |
| 1878 | { | |
| 1879 | Expr *op_expr = stmt->getSubExpr(); | |
| 1880 | AstNode *sub_node = trans_expr(c, ResultUsedYes, scope, op_expr, TransRValue); | |
| 1881 | if (sub_node == nullptr) | |
| 1882 | return nullptr; | |
| 1883 | return trans_create_node_prefix_op(c, PrefixOpBinNot, sub_node); | |
| 1884 | } | |
| 1885 | case UO_LNot: | |
| 1886 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_LNot"); | |
| 1887 | return nullptr; | |
| 1888 | case UO_Real: | |
| 1889 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Real"); | |
| 1890 | return nullptr; | |
| 1891 | case UO_Imag: | |
| 1892 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Imag"); | |
| 1893 | return nullptr; | |
| 1894 | case UO_Extension: | |
| 1895 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Extension"); | |
| 1896 | return nullptr; | |
| 1897 | case UO_Coawait: | |
| 1898 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Coawait"); | |
| 1899 | return nullptr; | |
| 1900 | } | |
| 1901 | zig_unreachable(); | |
| 1902 | } | |
| 1903 | ||
| 1904 | static int trans_local_declaration(Context *c, TransScope *scope, const DeclStmt *stmt, | |
| 1905 | AstNode **out_node, TransScope **out_scope) | |
| 1906 | { | |
| 1907 | // declarations are added via the scope | |
| 1908 | *out_node = nullptr; | |
| 1909 | ||
| 1910 | TransScopeBlock *scope_block = trans_scope_block_find(scope); | |
| 1911 | assert(scope_block != nullptr); | |
| 1912 | ||
| 1913 | for (auto iter = stmt->decl_begin(); iter != stmt->decl_end(); iter++) { | |
| 1914 | Decl *decl = *iter; | |
| 1915 | switch (decl->getKind()) { | |
| 1916 | case Decl::Var: { | |
| 1917 | VarDecl *var_decl = (VarDecl *)decl; | |
| 1918 | QualType qual_type = var_decl->getTypeSourceInfo()->getType(); | |
| 1919 | AstNode *init_node = nullptr; | |
| 1920 | if (var_decl->hasInit()) { | |
| 1921 | init_node = trans_expr(c, ResultUsedYes, scope, var_decl->getInit(), TransRValue); | |
| 1922 | if (init_node == nullptr) | |
| 1923 | return ErrorUnexpected; | |
| 1924 | ||
| 1925 | } | |
| 1926 | AstNode *type_node = trans_qual_type(c, qual_type, stmt->getLocStart()); | |
| 1927 | if (type_node == nullptr) | |
| 1928 | return ErrorUnexpected; | |
| 1929 | ||
| 1930 | Buf *c_symbol_name = buf_create_from_str(decl_name(var_decl)); | |
| 1931 | ||
| 1932 | TransScopeVar *var_scope = trans_scope_var_create(c, scope, c_symbol_name); | |
| 1933 | scope = &var_scope->base; | |
| 1934 | ||
| 1935 | AstNode *node = trans_create_node_var_decl_local(c, qual_type.isConstQualified(), | |
| 1936 | var_scope->zig_name, type_node, init_node); | |
| 1937 | ||
| 1938 | scope_block->node->data.block.statements.append(node); | |
| 1939 | continue; | |
| 1940 | } | |
| 1941 | case Decl::AccessSpec: | |
| 1942 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind AccessSpec"); | |
| 1943 | return ErrorUnexpected; | |
| 1944 | case Decl::Block: | |
| 1945 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Block"); | |
| 1946 | return ErrorUnexpected; | |
| 1947 | case Decl::Captured: | |
| 1948 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Captured"); | |
| 1949 | return ErrorUnexpected; | |
| 1950 | case Decl::ClassScopeFunctionSpecialization: | |
| 1951 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassScopeFunctionSpecialization"); | |
| 1952 | return ErrorUnexpected; | |
| 1953 | case Decl::Empty: | |
| 1954 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Empty"); | |
| 1955 | return ErrorUnexpected; | |
| 1956 | case Decl::Export: | |
| 1957 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Export"); | |
| 1958 | return ErrorUnexpected; | |
| 1959 | case Decl::ExternCContext: | |
| 1960 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ExternCContext"); | |
| 1961 | return ErrorUnexpected; | |
| 1962 | case Decl::FileScopeAsm: | |
| 1963 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FileScopeAsm"); | |
| 1964 | return ErrorUnexpected; | |
| 1965 | case Decl::Friend: | |
| 1966 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Friend"); | |
| 1967 | return ErrorUnexpected; | |
| 1968 | case Decl::FriendTemplate: | |
| 1969 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FriendTemplate"); | |
| 1970 | return ErrorUnexpected; | |
| 1971 | case Decl::Import: | |
| 1972 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Import"); | |
| 1973 | return ErrorUnexpected; | |
| 1974 | case Decl::LinkageSpec: | |
| 1975 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind LinkageSpec"); | |
| 1976 | return ErrorUnexpected; | |
| 1977 | case Decl::Label: | |
| 1978 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Label"); | |
| 1979 | return ErrorUnexpected; | |
| 1980 | case Decl::Namespace: | |
| 1981 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Namespace"); | |
| 1982 | return ErrorUnexpected; | |
| 1983 | case Decl::NamespaceAlias: | |
| 1984 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind NamespaceAlias"); | |
| 1985 | return ErrorUnexpected; | |
| 1986 | case Decl::ObjCCompatibleAlias: | |
| 1987 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCompatibleAlias"); | |
| 1988 | return ErrorUnexpected; | |
| 1989 | case Decl::ObjCCategory: | |
| 1990 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCategory"); | |
| 1991 | return ErrorUnexpected; | |
| 1992 | case Decl::ObjCCategoryImpl: | |
| 1993 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCategoryImpl"); | |
| 1994 | return ErrorUnexpected; | |
| 1995 | case Decl::ObjCImplementation: | |
| 1996 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCImplementation"); | |
| 1997 | return ErrorUnexpected; | |
| 1998 | case Decl::ObjCInterface: | |
| 1999 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCInterface"); | |
| 2000 | return ErrorUnexpected; | |
| 2001 | case Decl::ObjCProtocol: | |
| 2002 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCProtocol"); | |
| 2003 | return ErrorUnexpected; | |
| 2004 | case Decl::ObjCMethod: | |
| 2005 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCMethod"); | |
| 2006 | return ErrorUnexpected; | |
| 2007 | case Decl::ObjCProperty: | |
| 2008 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCProperty"); | |
| 2009 | return ErrorUnexpected; | |
| 2010 | case Decl::BuiltinTemplate: | |
| 2011 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind BuiltinTemplate"); | |
| 2012 | return ErrorUnexpected; | |
| 2013 | case Decl::ClassTemplate: | |
| 2014 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplate"); | |
| 2015 | return ErrorUnexpected; | |
| 2016 | case Decl::FunctionTemplate: | |
| 2017 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FunctionTemplate"); | |
| 2018 | return ErrorUnexpected; | |
| 2019 | case Decl::TypeAliasTemplate: | |
| 2020 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TypeAliasTemplate"); | |
| 2021 | return ErrorUnexpected; | |
| 2022 | case Decl::VarTemplate: | |
| 2023 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplate"); | |
| 2024 | return ErrorUnexpected; | |
| 2025 | case Decl::TemplateTemplateParm: | |
| 2026 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TemplateTemplateParm"); | |
| 2027 | return ErrorUnexpected; | |
| 2028 | case Decl::Enum: | |
| 2029 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Enum"); | |
| 2030 | return ErrorUnexpected; | |
| 2031 | case Decl::Record: | |
| 2032 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Record"); | |
| 2033 | return ErrorUnexpected; | |
| 2034 | case Decl::CXXRecord: | |
| 2035 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXRecord"); | |
| 2036 | return ErrorUnexpected; | |
| 2037 | case Decl::ClassTemplateSpecialization: | |
| 2038 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplateSpecialization"); | |
| 2039 | return ErrorUnexpected; | |
| 2040 | case Decl::ClassTemplatePartialSpecialization: | |
| 2041 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplatePartialSpecialization"); | |
| 2042 | return ErrorUnexpected; | |
| 2043 | case Decl::TemplateTypeParm: | |
| 2044 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TemplateTypeParm"); | |
| 2045 | return ErrorUnexpected; | |
| 2046 | case Decl::ObjCTypeParam: | |
| 2047 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCTypeParam"); | |
| 2048 | return ErrorUnexpected; | |
| 2049 | case Decl::TypeAlias: | |
| 2050 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TypeAlias"); | |
| 2051 | return ErrorUnexpected; | |
| 2052 | case Decl::Typedef: | |
| 2053 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Typedef"); | |
| 2054 | return ErrorUnexpected; | |
| 2055 | case Decl::UnresolvedUsingTypename: | |
| 2056 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UnresolvedUsingTypename"); | |
| 2057 | return ErrorUnexpected; | |
| 2058 | case Decl::Using: | |
| 2059 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Using"); | |
| 2060 | return ErrorUnexpected; | |
| 2061 | case Decl::UsingDirective: | |
| 2062 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingDirective"); | |
| 2063 | return ErrorUnexpected; | |
| 2064 | case Decl::UsingPack: | |
| 2065 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingPack"); | |
| 2066 | return ErrorUnexpected; | |
| 2067 | case Decl::UsingShadow: | |
| 2068 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingShadow"); | |
| 2069 | return ErrorUnexpected; | |
| 2070 | case Decl::ConstructorUsingShadow: | |
| 2071 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ConstructorUsingShadow"); | |
| 2072 | return ErrorUnexpected; | |
| 2073 | case Decl::Binding: | |
| 2074 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Binding"); | |
| 2075 | return ErrorUnexpected; | |
| 2076 | case Decl::Field: | |
| 2077 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Field"); | |
| 2078 | return ErrorUnexpected; | |
| 2079 | case Decl::ObjCAtDefsField: | |
| 2080 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCAtDefsField"); | |
| 2081 | return ErrorUnexpected; | |
| 2082 | case Decl::ObjCIvar: | |
| 2083 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCIvar"); | |
| 2084 | return ErrorUnexpected; | |
| 2085 | case Decl::Function: | |
| 2086 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Function"); | |
| 2087 | return ErrorUnexpected; | |
| 2088 | case Decl::CXXDeductionGuide: | |
| 2089 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXDeductionGuide"); | |
| 2090 | return ErrorUnexpected; | |
| 2091 | case Decl::CXXMethod: | |
| 2092 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXMethod"); | |
| 2093 | return ErrorUnexpected; | |
| 2094 | case Decl::CXXConstructor: | |
| 2095 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXConstructor"); | |
| 2096 | return ErrorUnexpected; | |
| 2097 | case Decl::CXXConversion: | |
| 2098 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXConversion"); | |
| 2099 | return ErrorUnexpected; | |
| 2100 | case Decl::CXXDestructor: | |
| 2101 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXDestructor"); | |
| 2102 | return ErrorUnexpected; | |
| 2103 | case Decl::MSProperty: | |
| 2104 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind MSProperty"); | |
| 2105 | return ErrorUnexpected; | |
| 2106 | case Decl::NonTypeTemplateParm: | |
| 2107 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind NonTypeTemplateParm"); | |
| 2108 | return ErrorUnexpected; | |
| 2109 | case Decl::Decomposition: | |
| 2110 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Decomposition"); | |
| 2111 | return ErrorUnexpected; | |
| 2112 | case Decl::ImplicitParam: | |
| 2113 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ImplicitParam"); | |
| 2114 | return ErrorUnexpected; | |
| 2115 | case Decl::OMPCapturedExpr: | |
| 2116 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPCapturedExpr"); | |
| 2117 | return ErrorUnexpected; | |
| 2118 | case Decl::ParmVar: | |
| 2119 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ParmVar"); | |
| 2120 | return ErrorUnexpected; | |
| 2121 | case Decl::VarTemplateSpecialization: | |
| 2122 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplateSpecialization"); | |
| 2123 | return ErrorUnexpected; | |
| 2124 | case Decl::VarTemplatePartialSpecialization: | |
| 2125 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplatePartialSpecialization"); | |
| 2126 | return ErrorUnexpected; | |
| 2127 | case Decl::EnumConstant: | |
| 2128 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind EnumConstant"); | |
| 2129 | return ErrorUnexpected; | |
| 2130 | case Decl::IndirectField: | |
| 2131 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind IndirectField"); | |
| 2132 | return ErrorUnexpected; | |
| 2133 | case Decl::OMPDeclareReduction: | |
| 2134 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPDeclareReduction"); | |
| 2135 | return ErrorUnexpected; | |
| 2136 | case Decl::UnresolvedUsingValue: | |
| 2137 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UnresolvedUsingValue"); | |
| 2138 | return ErrorUnexpected; | |
| 2139 | case Decl::OMPThreadPrivate: | |
| 2140 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPThreadPrivate"); | |
| 2141 | return ErrorUnexpected; | |
| 2142 | case Decl::ObjCPropertyImpl: | |
| 2143 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCPropertyImpl"); | |
| 2144 | return ErrorUnexpected; | |
| 2145 | case Decl::PragmaComment: | |
| 2146 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind PragmaComment"); | |
| 2147 | return ErrorUnexpected; | |
| 2148 | case Decl::PragmaDetectMismatch: | |
| 2149 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind PragmaDetectMismatch"); | |
| 2150 | return ErrorUnexpected; | |
| 2151 | case Decl::StaticAssert: | |
| 2152 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind StaticAssert"); | |
| 2153 | return ErrorUnexpected; | |
| 2154 | case Decl::TranslationUnit: | |
| 2155 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TranslationUnit"); | |
| 2156 | return ErrorUnexpected; | |
| 2157 | } | |
| 2158 | zig_unreachable(); | |
| 2159 | } | |
| 2160 | ||
| 2161 | *out_scope = scope; | |
| 2162 | return ErrorNone; | |
| 2163 | } | |
| 2164 | ||
| 2165 | static AstNode *trans_while_loop(Context *c, TransScope *scope, const WhileStmt *stmt) { | |
| 2166 | TransScopeWhile *while_scope = trans_scope_while_create(c, scope); | |
| 2167 | ||
| 2168 | while_scope->node->data.while_expr.condition = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue); | |
| 2169 | if (while_scope->node->data.while_expr.condition == nullptr) | |
| 2170 | return nullptr; | |
| 2171 | ||
| 2172 | TransScope *body_scope = trans_stmt(c, &while_scope->base, stmt->getBody(), | |
| 2173 | &while_scope->node->data.while_expr.body); | |
| 2174 | if (body_scope == nullptr) | |
| 2175 | return nullptr; | |
| 2176 | ||
| 2177 | return while_scope->node; | |
| 2178 | } | |
| 2179 | ||
| 2180 | static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *stmt) { | |
| 2181 | // if (c) t | |
| 2182 | // if (c) t else e | |
| 2183 | AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr); | |
| 2184 | ||
| 2185 | // TODO: condition != 0 | |
| 2186 | AstNode *condition_node = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue); | |
| 2187 | if (condition_node == nullptr) | |
| 2188 | return nullptr; | |
| 2189 | if_node->data.if_bool_expr.condition = condition_node; | |
| 2190 | ||
| 2191 | TransScope *then_scope = trans_stmt(c, scope, stmt->getThen(), &if_node->data.if_bool_expr.then_block); | |
| 2192 | if (then_scope == nullptr) | |
| 2193 | return nullptr; | |
| 2194 | ||
| 2195 | if (stmt->getElse() != nullptr) { | |
| 2196 | TransScope *else_scope = trans_stmt(c, scope, stmt->getElse(), &if_node->data.if_bool_expr.else_node); | |
| 2197 | if (else_scope == nullptr) | |
| 2198 | return nullptr; | |
| 2199 | } | |
| 2200 | ||
| 2201 | return if_node; | |
| 2202 | } | |
| 2203 | ||
| 2204 | static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *scope, const CallExpr *stmt) { | |
| 2205 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 2206 | ||
| 2207 | AstNode *callee_raw_node = trans_expr(c, ResultUsedYes, scope, stmt->getCallee(), TransRValue); | |
| 2208 | if (callee_raw_node == nullptr) | |
| 2209 | return nullptr; | |
| 2210 | ||
| 2211 | AstNode *callee_node = nullptr; | |
| 2212 | if (qual_type_is_fn_ptr(c, stmt->getCallee()->getType())) { | |
| 2213 | if (stmt->getCallee()->getStmtClass() == Stmt::ImplicitCastExprClass) { | |
| 2214 | const ImplicitCastExpr *implicit_cast = static_cast<const ImplicitCastExpr *>(stmt->getCallee()); | |
| 2215 | if (implicit_cast->getCastKind() == CK_FunctionToPointerDecay) { | |
| 2216 | if (implicit_cast->getSubExpr()->getStmtClass() == Stmt::DeclRefExprClass) { | |
| 2217 | const DeclRefExpr *decl_ref = static_cast<const DeclRefExpr *>(implicit_cast->getSubExpr()); | |
| 2218 | const Decl *decl = decl_ref->getFoundDecl(); | |
| 2219 | if (decl->getKind() == Decl::Function) { | |
| 2220 | callee_node = callee_raw_node; | |
| 2221 | } | |
| 2222 | } | |
| 2223 | } | |
| 2224 | } | |
| 2225 | if (callee_node == nullptr) { | |
| 2226 | callee_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, callee_raw_node); | |
| 2227 | } | |
| 2228 | } else { | |
| 2229 | callee_node = callee_raw_node; | |
| 2230 | } | |
| 2231 | ||
| 2232 | node->data.fn_call_expr.fn_ref_expr = callee_node; | |
| 2233 | ||
| 2234 | unsigned num_args = stmt->getNumArgs(); | |
| 2235 | const Expr * const* args = stmt->getArgs(); | |
| 2236 | for (unsigned i = 0; i < num_args; i += 1) { | |
| 2237 | AstNode *arg_node = trans_expr(c, ResultUsedYes, scope, args[i], TransRValue); | |
| 2238 | if (arg_node == nullptr) | |
| 2239 | return nullptr; | |
| 2240 | ||
| 2241 | node->data.fn_call_expr.params.append(arg_node); | |
| 2242 | } | |
| 2243 | ||
| 2244 | return node; | |
| 2245 | } | |
| 2246 | ||
| 2247 | static AstNode *trans_member_expr(Context *c, TransScope *scope, const MemberExpr *stmt) { | |
| 2248 | AstNode *container_node = trans_expr(c, ResultUsedYes, scope, stmt->getBase(), TransRValue); | |
| 2249 | if (container_node == nullptr) | |
| 2250 | return nullptr; | |
| 2251 | ||
| 2252 | if (stmt->isArrow()) { | |
| 2253 | container_node = trans_create_node_unwrap_null(c, container_node); | |
| 2254 | } | |
| 2255 | ||
| 2256 | const char *name = decl_name(stmt->getMemberDecl()); | |
| 2257 | ||
| 2258 | AstNode *node = trans_create_node_field_access_str(c, container_node, name); | |
| 2259 | return node; | |
| 2260 | } | |
| 2261 | ||
| 2262 | static AstNode *trans_array_subscript_expr(Context *c, TransScope *scope, const ArraySubscriptExpr *stmt) { | |
| 2263 | AstNode *container_node = trans_expr(c, ResultUsedYes, scope, stmt->getBase(), TransRValue); | |
| 2264 | if (container_node == nullptr) | |
| 2265 | return nullptr; | |
| 2266 | ||
| 2267 | AstNode *idx_node = trans_expr(c, ResultUsedYes, scope, stmt->getIdx(), TransRValue); | |
| 2268 | if (idx_node == nullptr) | |
| 2269 | return nullptr; | |
| 2270 | ||
| 2271 | ||
| 2272 | AstNode *node = trans_create_node(c, NodeTypeArrayAccessExpr); | |
| 2273 | node->data.array_access_expr.array_ref_expr = container_node; | |
| 2274 | node->data.array_access_expr.subscript = idx_node; | |
| 2275 | return node; | |
| 2276 | } | |
| 2277 | ||
| 2278 | static AstNode *trans_c_style_cast_expr(Context *c, ResultUsed result_used, TransScope *scope, | |
| 2279 | const CStyleCastExpr *stmt, TransLRValue lrvalue) | |
| 2280 | { | |
| 2281 | AstNode *sub_expr_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), lrvalue); | |
| 2282 | if (sub_expr_node == nullptr) | |
| 2283 | return nullptr; | |
| 2284 | ||
| 2285 | return trans_c_cast(c, stmt->getLocStart(), stmt->getType(), stmt->getSubExpr()->getType(), sub_expr_node); | |
| 2286 | } | |
| 2287 | ||
| 2288 | static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, TransScope *scope, | |
| 2289 | const UnaryExprOrTypeTraitExpr *stmt) | |
| 2290 | { | |
| 2291 | AstNode *type_node = trans_qual_type(c, stmt->getTypeOfArgument(), stmt->getLocStart()); | |
| 2292 | if (type_node == nullptr) | |
| 2293 | return nullptr; | |
| 2294 | ||
| 2295 | AstNode *node = trans_create_node_builtin_fn_call_str(c, "sizeOf"); | |
| 2296 | node->data.fn_call_expr.params.append(type_node); | |
| 2297 | return node; | |
| 2298 | } | |
| 2299 | ||
| 2300 | static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const DoStmt *stmt) { | |
| 2301 | TransScopeWhile *while_scope = trans_scope_while_create(c, parent_scope); | |
| 2302 | ||
| 2303 | while_scope->node->data.while_expr.condition = trans_create_node_bool(c, true); | |
| 2304 | ||
| 2305 | AstNode *body_node; | |
| 2306 | TransScope *child_scope; | |
| 2307 | if (stmt->getBody()->getStmtClass() == Stmt::CompoundStmtClass) { | |
| 2308 | // there's already a block in C, so we'll append our condition to it. | |
| 2309 | // c: do { | |
| 2310 | // c: a; | |
| 2311 | // c: b; | |
| 2312 | // c: } while(c); | |
| 2313 | // zig: while (true) { | |
| 2314 | // zig: a; | |
| 2315 | // zig: b; | |
| 2316 | // zig: if (!cond) break; | |
| 2317 | // zig: } | |
| 2318 | ||
| 2319 | // We call the low level function so that we can set child_scope to the scope of the generated block. | |
| 2320 | if (trans_stmt_extra(c, &while_scope->base, stmt->getBody(), ResultUsedNo, TransRValue, &body_node, | |
| 2321 | nullptr, &child_scope)) | |
| 2322 | { | |
| 2323 | return nullptr; | |
| 2324 | } | |
| 2325 | assert(body_node->type == NodeTypeBlock); | |
| 2326 | } else { | |
| 2327 | // the C statement is without a block, so we need to create a block to contain it. | |
| 2328 | // c: do | |
| 2329 | // c: a; | |
| 2330 | // c: while(c); | |
| 2331 | // zig: while (true) { | |
| 2332 | // zig: a; | |
| 2333 | // zig: if (!cond) break; | |
| 2334 | // zig: } | |
| 2335 | TransScopeBlock *child_block_scope = trans_scope_block_create(c, &while_scope->base); | |
| 2336 | body_node = child_block_scope->node; | |
| 2337 | AstNode *child_statement; | |
| 2338 | child_scope = trans_stmt(c, &child_block_scope->base, stmt->getBody(), &child_statement); | |
| 2339 | if (child_scope == nullptr) return nullptr; | |
| 2340 | body_node->data.block.statements.append(child_statement); | |
| 2341 | } | |
| 2342 | ||
| 2343 | // if (!cond) break; | |
| 2344 | AstNode *condition_node = trans_expr(c, ResultUsedYes, child_scope, stmt->getCond(), TransRValue); | |
| 2345 | if (condition_node == nullptr) return nullptr; | |
| 2346 | AstNode *terminator_node = trans_create_node(c, NodeTypeIfBoolExpr); | |
| 2347 | terminator_node->data.if_bool_expr.condition = trans_create_node_prefix_op(c, PrefixOpBoolNot, condition_node); | |
| 2348 | terminator_node->data.if_bool_expr.then_block = trans_create_node(c, NodeTypeBreak); | |
| 2349 | ||
| 2350 | body_node->data.block.statements.append(terminator_node); | |
| 2351 | ||
| 2352 | while_scope->node->data.while_expr.body = body_node; | |
| 2353 | ||
| 2354 | return while_scope->node; | |
| 2355 | } | |
| 2356 | ||
| 2357 | static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const SwitchStmt *stmt) { | |
| 2358 | TransScopeBlock *block_scope = trans_scope_block_create(c, parent_scope); | |
| 2359 | ||
| 2360 | TransScopeSwitch *switch_scope; | |
| 2361 | ||
| 2362 | const DeclStmt *var_decl_stmt = stmt->getConditionVariableDeclStmt(); | |
| 2363 | if (var_decl_stmt == nullptr) { | |
| 2364 | switch_scope = trans_scope_switch_create(c, &block_scope->base); | |
| 2365 | } else { | |
| 2366 | AstNode *vars_node; | |
| 2367 | TransScope *var_scope = trans_stmt(c, &block_scope->base, var_decl_stmt, &vars_node); | |
| 2368 | if (var_scope == nullptr) | |
| 2369 | return nullptr; | |
| 2370 | if (vars_node != nullptr) | |
| 2371 | block_scope->node->data.block.statements.append(vars_node); | |
| 2372 | switch_scope = trans_scope_switch_create(c, var_scope); | |
| 2373 | } | |
| 2374 | block_scope->node->data.block.statements.append(switch_scope->switch_node); | |
| 2375 | ||
| 2376 | // TODO avoid name collisions | |
| 2377 | Buf *end_label_name = buf_create_from_str("end"); | |
| 2378 | switch_scope->end_label_name = end_label_name; | |
| 2379 | ||
| 2380 | const Expr *cond_expr = stmt->getCond(); | |
| 2381 | assert(cond_expr != nullptr); | |
| 2382 | ||
| 2383 | AstNode *expr_node = trans_expr(c, ResultUsedYes, &block_scope->base, cond_expr, TransRValue); | |
| 2384 | if (expr_node == nullptr) | |
| 2385 | return nullptr; | |
| 2386 | switch_scope->switch_node->data.switch_expr.expr = expr_node; | |
| 2387 | ||
| 2388 | AstNode *body_node; | |
| 2389 | const Stmt *body_stmt = stmt->getBody(); | |
| 2390 | if (body_stmt->getStmtClass() == Stmt::CompoundStmtClass) { | |
| 2391 | if (trans_compound_stmt_inline(c, &switch_scope->base, (const CompoundStmt *)body_stmt, | |
| 2392 | block_scope->node, nullptr)) | |
| 2393 | { | |
| 2394 | return nullptr; | |
| 2395 | } | |
| 2396 | } else { | |
| 2397 | TransScope *body_scope = trans_stmt(c, &switch_scope->base, body_stmt, &body_node); | |
| 2398 | if (body_scope == nullptr) | |
| 2399 | return nullptr; | |
| 2400 | if (body_node != nullptr) | |
| 2401 | block_scope->node->data.block.statements.append(body_node); | |
| 2402 | } | |
| 2403 | ||
| 2404 | if (!switch_scope->found_default && !stmt->isAllEnumCasesCovered()) { | |
| 2405 | AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng); | |
| 2406 | prong_node->data.switch_prong.expr = trans_create_node_goto(c, end_label_name); | |
| 2407 | switch_scope->switch_node->data.switch_expr.prongs.append(prong_node); | |
| 2408 | } | |
| 2409 | ||
| 2410 | // This is necessary if the last switch case "falls through" the end of the switch block | |
| 2411 | block_scope->node->data.block.statements.append(trans_create_node_goto(c, end_label_name)); | |
| 2412 | ||
| 2413 | block_scope->node->data.block.statements.append(trans_create_node_label(c, end_label_name)); | |
| 2414 | ||
| 2415 | return block_scope->node; | |
| 2416 | } | |
| 2417 | ||
| 2418 | static int trans_switch_case(Context *c, TransScope *parent_scope, const CaseStmt *stmt, AstNode **out_node, | |
| 2419 | TransScope **out_scope) | |
| 2420 | { | |
| 2421 | *out_node = nullptr; | |
| 2422 | ||
| 2423 | if (stmt->getRHS() != nullptr) { | |
| 2424 | emit_warning(c, stmt->getLocStart(), "TODO support GNU switch case a ... b extension"); | |
| 2425 | return ErrorUnexpected; | |
| 2426 | } | |
| 2427 | ||
| 2428 | TransScopeSwitch *switch_scope = trans_scope_switch_find(parent_scope); | |
| 2429 | assert(switch_scope != nullptr); | |
| 2430 | ||
| 2431 | Buf *label_name = buf_sprintf("case_%" PRIu32, switch_scope->case_index); | |
| 2432 | switch_scope->case_index += 1; | |
| 2433 | ||
| 2434 | { | |
| 2435 | // Add the prong | |
| 2436 | AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng); | |
| 2437 | AstNode *item_node = trans_expr(c, ResultUsedYes, &switch_scope->base, stmt->getLHS(), TransRValue); | |
| 2438 | if (item_node == nullptr) | |
| 2439 | return ErrorUnexpected; | |
| 2440 | prong_node->data.switch_prong.items.append(item_node); | |
| 2441 | ||
| 2442 | prong_node->data.switch_prong.expr = trans_create_node_goto(c, label_name); | |
| 2443 | ||
| 2444 | switch_scope->switch_node->data.switch_expr.prongs.append(prong_node); | |
| 2445 | } | |
| 2446 | ||
| 2447 | TransScopeBlock *scope_block = trans_scope_block_find(parent_scope); | |
| 2448 | scope_block->node->data.block.statements.append(trans_create_node_label(c, label_name)); | |
| 2449 | ||
| 2450 | AstNode *sub_stmt_node; | |
| 2451 | TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node); | |
| 2452 | if (new_scope == nullptr) | |
| 2453 | return ErrorUnexpected; | |
| 2454 | if (sub_stmt_node != nullptr) | |
| 2455 | scope_block->node->data.block.statements.append(sub_stmt_node); | |
| 2456 | ||
| 2457 | *out_scope = new_scope; | |
| 2458 | return ErrorNone; | |
| 2459 | } | |
| 2460 | ||
| 2461 | static int trans_switch_default(Context *c, TransScope *parent_scope, const DefaultStmt *stmt, AstNode **out_node, | |
| 2462 | TransScope **out_scope) | |
| 2463 | { | |
| 2464 | *out_node = nullptr; | |
| 2465 | ||
| 2466 | TransScopeSwitch *switch_scope = trans_scope_switch_find(parent_scope); | |
| 2467 | assert(switch_scope != nullptr); | |
| 2468 | ||
| 2469 | Buf *label_name = buf_sprintf("default"); | |
| 2470 | ||
| 2471 | { | |
| 2472 | // Add the prong | |
| 2473 | AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng); | |
| 2474 | ||
| 2475 | prong_node->data.switch_prong.expr = trans_create_node_goto(c, label_name); | |
| 2476 | ||
| 2477 | switch_scope->switch_node->data.switch_expr.prongs.append(prong_node); | |
| 2478 | switch_scope->found_default = true; | |
| 2479 | } | |
| 2480 | ||
| 2481 | TransScopeBlock *scope_block = trans_scope_block_find(parent_scope); | |
| 2482 | scope_block->node->data.block.statements.append(trans_create_node_label(c, label_name)); | |
| 2483 | ||
| 2484 | ||
| 2485 | AstNode *sub_stmt_node; | |
| 2486 | TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node); | |
| 2487 | if (new_scope == nullptr) | |
| 2488 | return ErrorUnexpected; | |
| 2489 | if (sub_stmt_node != nullptr) | |
| 2490 | scope_block->node->data.block.statements.append(sub_stmt_node); | |
| 2491 | ||
| 2492 | *out_scope = new_scope; | |
| 2493 | return ErrorNone; | |
| 2494 | } | |
| 2495 | ||
| 2496 | static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForStmt *stmt) { | |
| 2497 | AstNode *loop_block_node; | |
| 2498 | TransScopeWhile *while_scope; | |
| 2499 | TransScope *cond_scope; | |
| 2500 | const Stmt *init_stmt = stmt->getInit(); | |
| 2501 | if (init_stmt == nullptr) { | |
| 2502 | while_scope = trans_scope_while_create(c, parent_scope); | |
| 2503 | loop_block_node = while_scope->node; | |
| 2504 | cond_scope = parent_scope; | |
| 2505 | } else { | |
| 2506 | TransScopeBlock *child_scope = trans_scope_block_create(c, parent_scope); | |
| 2507 | loop_block_node = child_scope->node; | |
| 2508 | ||
| 2509 | AstNode *vars_node; | |
| 2510 | cond_scope = trans_stmt(c, &child_scope->base, init_stmt, &vars_node); | |
| 2511 | if (cond_scope == nullptr) | |
| 2512 | return nullptr; | |
| 2513 | if (vars_node != nullptr) | |
| 2514 | child_scope->node->data.block.statements.append(vars_node); | |
| 2515 | ||
| 2516 | while_scope = trans_scope_while_create(c, cond_scope); | |
| 2517 | ||
| 2518 | child_scope->node->data.block.statements.append(while_scope->node); | |
| 2519 | } | |
| 2520 | ||
| 2521 | const Stmt *cond_stmt = stmt->getCond(); | |
| 2522 | if (cond_stmt == nullptr) { | |
| 2523 | while_scope->node->data.while_expr.condition = trans_create_node_bool(c, true); | |
| 2524 | } else { | |
| 2525 | TransScope *end_cond_scope = trans_stmt(c, cond_scope, cond_stmt, | |
| 2526 | &while_scope->node->data.while_expr.condition); | |
| 2527 | if (end_cond_scope == nullptr) | |
| 2528 | return nullptr; | |
| 2529 | } | |
| 2530 | ||
| 2531 | const Stmt *inc_stmt = stmt->getInc(); | |
| 2532 | if (inc_stmt != nullptr) { | |
| 2533 | AstNode *inc_node; | |
| 2534 | TransScope *inc_scope = trans_stmt(c, cond_scope, inc_stmt, &inc_node); | |
| 2535 | if (inc_scope == nullptr) | |
| 2536 | return nullptr; | |
| 2537 | while_scope->node->data.while_expr.continue_expr = inc_node; | |
| 2538 | } | |
| 2539 | ||
| 2540 | AstNode *body_statement; | |
| 2541 | TransScope *body_scope = trans_stmt(c, &while_scope->base, stmt->getBody(), &body_statement); | |
| 2542 | if (body_scope == nullptr) | |
| 2543 | return nullptr; | |
| 2544 | while_scope->node->data.while_expr.body = body_statement; | |
| 2545 | ||
| 2546 | return loop_block_node; | |
| 2547 | } | |
| 2548 | ||
| 2549 | static AstNode *trans_string_literal(Context *c, TransScope *scope, const StringLiteral *stmt) { | |
| 2550 | switch (stmt->getKind()) { | |
| 2551 | case StringLiteral::Ascii: | |
| 2552 | case StringLiteral::UTF8: | |
| 2553 | return trans_create_node_str_lit_c(c, string_ref_to_buf(stmt->getString())); | |
| 2554 | case StringLiteral::UTF16: | |
| 2555 | emit_warning(c, stmt->getLocStart(), "TODO support UTF16 string literals"); | |
| 2556 | return nullptr; | |
| 2557 | case StringLiteral::UTF32: | |
| 2558 | emit_warning(c, stmt->getLocStart(), "TODO support UTF32 string literals"); | |
| 2559 | return nullptr; | |
| 2560 | case StringLiteral::Wide: | |
| 2561 | emit_warning(c, stmt->getLocStart(), "TODO support wide string literals"); | |
| 2562 | return nullptr; | |
| 2563 | } | |
| 2564 | zig_unreachable(); | |
| 2565 | } | |
| 2566 | ||
| 2567 | static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt *stmt) { | |
| 2568 | TransScope *cur_scope = scope; | |
| 2569 | while (cur_scope != nullptr) { | |
| 2570 | if (cur_scope->id == TransScopeIdWhile) { | |
| 2571 | return trans_create_node(c, NodeTypeBreak); | |
| 2572 | } else if (cur_scope->id == TransScopeIdSwitch) { | |
| 2573 | TransScopeSwitch *switch_scope = (TransScopeSwitch *)cur_scope; | |
| 2574 | return trans_create_node_goto(c, switch_scope->end_label_name); | |
| 2575 | } | |
| 2576 | cur_scope = cur_scope->parent; | |
| 2577 | } | |
| 2578 | zig_unreachable(); | |
| 2579 | } | |
| 2580 | ||
| 2581 | static AstNode *trans_continue_stmt(Context *c, TransScope *scope, const ContinueStmt *stmt) { | |
| 2582 | return trans_create_node(c, NodeTypeContinue); | |
| 2583 | } | |
| 2584 | ||
| 2585 | static int wrap_stmt(AstNode **out_node, TransScope **out_scope, TransScope *in_scope, AstNode *result_node) { | |
| 2586 | if (result_node == nullptr) | |
| 2587 | return ErrorUnexpected; | |
| 2588 | *out_node = result_node; | |
| 2589 | if (out_scope != nullptr) | |
| 2590 | *out_scope = in_scope; | |
| 2591 | return ErrorNone; | |
| 2592 | } | |
| 2593 | ||
| 2594 | static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt, | |
| 2595 | ResultUsed result_used, TransLRValue lrvalue, | |
| 2596 | AstNode **out_node, TransScope **out_child_scope, | |
| 2597 | TransScope **out_node_scope) | |
| 2598 | { | |
| 2599 | Stmt::StmtClass sc = stmt->getStmtClass(); | |
| 2600 | switch (sc) { | |
| 2601 | case Stmt::ReturnStmtClass: | |
| 2602 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2603 | trans_return_stmt(c, scope, (const ReturnStmt *)stmt)); | |
| 2604 | case Stmt::CompoundStmtClass: | |
| 2605 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2606 | trans_compound_stmt(c, scope, (const CompoundStmt *)stmt, out_node_scope)); | |
| 2607 | case Stmt::IntegerLiteralClass: | |
| 2608 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2609 | trans_integer_literal(c, (const IntegerLiteral *)stmt)); | |
| 2610 | case Stmt::ConditionalOperatorClass: | |
| 2611 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2612 | trans_conditional_operator(c, result_used, scope, (const ConditionalOperator *)stmt)); | |
| 2613 | case Stmt::BinaryOperatorClass: | |
| 2614 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2615 | trans_binary_operator(c, result_used, scope, (const BinaryOperator *)stmt)); | |
| 2616 | case Stmt::CompoundAssignOperatorClass: | |
| 2617 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2618 | trans_compound_assign_operator(c, result_used, scope, (const CompoundAssignOperator *)stmt)); | |
| 2619 | case Stmt::ImplicitCastExprClass: | |
| 2620 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2621 | trans_implicit_cast_expr(c, scope, (const ImplicitCastExpr *)stmt)); | |
| 2622 | case Stmt::DeclRefExprClass: | |
| 2623 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2624 | trans_decl_ref_expr(c, scope, (const DeclRefExpr *)stmt, lrvalue)); | |
| 2625 | case Stmt::UnaryOperatorClass: | |
| 2626 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2627 | trans_unary_operator(c, result_used, scope, (const UnaryOperator *)stmt)); | |
| 2628 | case Stmt::DeclStmtClass: | |
| 2629 | return trans_local_declaration(c, scope, (const DeclStmt *)stmt, out_node, out_child_scope); | |
| 2630 | case Stmt::WhileStmtClass: | |
| 2631 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2632 | trans_while_loop(c, scope, (const WhileStmt *)stmt)); | |
| 2633 | case Stmt::IfStmtClass: | |
| 2634 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2635 | trans_if_statement(c, scope, (const IfStmt *)stmt)); | |
| 2636 | case Stmt::CallExprClass: | |
| 2637 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2638 | trans_call_expr(c, result_used, scope, (const CallExpr *)stmt)); | |
| 2639 | case Stmt::NullStmtClass: | |
| 2640 | *out_node = nullptr; | |
| 2641 | *out_child_scope = scope; | |
| 2642 | return ErrorNone; | |
| 2643 | case Stmt::MemberExprClass: | |
| 2644 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2645 | trans_member_expr(c, scope, (const MemberExpr *)stmt)); | |
| 2646 | case Stmt::ArraySubscriptExprClass: | |
| 2647 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2648 | trans_array_subscript_expr(c, scope, (const ArraySubscriptExpr *)stmt)); | |
| 2649 | case Stmt::CStyleCastExprClass: | |
| 2650 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2651 | trans_c_style_cast_expr(c, result_used, scope, (const CStyleCastExpr *)stmt, lrvalue)); | |
| 2652 | case Stmt::UnaryExprOrTypeTraitExprClass: | |
| 2653 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2654 | trans_unary_expr_or_type_trait_expr(c, scope, (const UnaryExprOrTypeTraitExpr *)stmt)); | |
| 2655 | case Stmt::DoStmtClass: | |
| 2656 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2657 | trans_do_loop(c, scope, (const DoStmt *)stmt)); | |
| 2658 | case Stmt::ForStmtClass: | |
| 2659 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2660 | trans_for_loop(c, scope, (const ForStmt *)stmt)); | |
| 2661 | case Stmt::StringLiteralClass: | |
| 2662 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2663 | trans_string_literal(c, scope, (const StringLiteral *)stmt)); | |
| 2664 | case Stmt::BreakStmtClass: | |
| 2665 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2666 | trans_break_stmt(c, scope, (const BreakStmt *)stmt)); | |
| 2667 | case Stmt::ContinueStmtClass: | |
| 2668 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2669 | trans_continue_stmt(c, scope, (const ContinueStmt *)stmt)); | |
| 2670 | case Stmt::ParenExprClass: | |
| 2671 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2672 | trans_expr(c, result_used, scope, ((const ParenExpr*)stmt)->getSubExpr(), lrvalue)); | |
| 2673 | case Stmt::SwitchStmtClass: | |
| 2674 | return wrap_stmt(out_node, out_child_scope, scope, | |
| 2675 | trans_switch_stmt(c, scope, (const SwitchStmt *)stmt)); | |
| 2676 | case Stmt::CaseStmtClass: | |
| 2677 | return trans_switch_case(c, scope, (const CaseStmt *)stmt, out_node, out_child_scope); | |
| 2678 | case Stmt::DefaultStmtClass: | |
| 2679 | return trans_switch_default(c, scope, (const DefaultStmt *)stmt, out_node, out_child_scope); | |
| 2680 | case Stmt::NoStmtClass: | |
| 2681 | emit_warning(c, stmt->getLocStart(), "TODO handle C NoStmtClass"); | |
| 2682 | return ErrorUnexpected; | |
| 2683 | case Stmt::GCCAsmStmtClass: | |
| 2684 | emit_warning(c, stmt->getLocStart(), "TODO handle C GCCAsmStmtClass"); | |
| 2685 | return ErrorUnexpected; | |
| 2686 | case Stmt::MSAsmStmtClass: | |
| 2687 | emit_warning(c, stmt->getLocStart(), "TODO handle C MSAsmStmtClass"); | |
| 2688 | return ErrorUnexpected; | |
| 2689 | case Stmt::AttributedStmtClass: | |
| 2690 | emit_warning(c, stmt->getLocStart(), "TODO handle C AttributedStmtClass"); | |
| 2691 | return ErrorUnexpected; | |
| 2692 | case Stmt::CXXCatchStmtClass: | |
| 2693 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXCatchStmtClass"); | |
| 2694 | return ErrorUnexpected; | |
| 2695 | case Stmt::CXXForRangeStmtClass: | |
| 2696 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXForRangeStmtClass"); | |
| 2697 | return ErrorUnexpected; | |
| 2698 | case Stmt::CXXTryStmtClass: | |
| 2699 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTryStmtClass"); | |
| 2700 | return ErrorUnexpected; | |
| 2701 | case Stmt::CapturedStmtClass: | |
| 2702 | emit_warning(c, stmt->getLocStart(), "TODO handle C CapturedStmtClass"); | |
| 2703 | return ErrorUnexpected; | |
| 2704 | case Stmt::CoreturnStmtClass: | |
| 2705 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoreturnStmtClass"); | |
| 2706 | return ErrorUnexpected; | |
| 2707 | case Stmt::CoroutineBodyStmtClass: | |
| 2708 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoroutineBodyStmtClass"); | |
| 2709 | return ErrorUnexpected; | |
| 2710 | case Stmt::BinaryConditionalOperatorClass: | |
| 2711 | emit_warning(c, stmt->getLocStart(), "TODO handle C BinaryConditionalOperatorClass"); | |
| 2712 | return ErrorUnexpected; | |
| 2713 | case Stmt::AddrLabelExprClass: | |
| 2714 | emit_warning(c, stmt->getLocStart(), "TODO handle C AddrLabelExprClass"); | |
| 2715 | return ErrorUnexpected; | |
| 2716 | case Stmt::ArrayInitIndexExprClass: | |
| 2717 | emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayInitIndexExprClass"); | |
| 2718 | return ErrorUnexpected; | |
| 2719 | case Stmt::ArrayInitLoopExprClass: | |
| 2720 | emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayInitLoopExprClass"); | |
| 2721 | return ErrorUnexpected; | |
| 2722 | case Stmt::ArrayTypeTraitExprClass: | |
| 2723 | emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayTypeTraitExprClass"); | |
| 2724 | return ErrorUnexpected; | |
| 2725 | case Stmt::AsTypeExprClass: | |
| 2726 | emit_warning(c, stmt->getLocStart(), "TODO handle C AsTypeExprClass"); | |
| 2727 | return ErrorUnexpected; | |
| 2728 | case Stmt::AtomicExprClass: | |
| 2729 | emit_warning(c, stmt->getLocStart(), "TODO handle C AtomicExprClass"); | |
| 2730 | return ErrorUnexpected; | |
| 2731 | case Stmt::BlockExprClass: | |
| 2732 | emit_warning(c, stmt->getLocStart(), "TODO handle C BlockExprClass"); | |
| 2733 | return ErrorUnexpected; | |
| 2734 | case Stmt::CXXBindTemporaryExprClass: | |
| 2735 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXBindTemporaryExprClass"); | |
| 2736 | return ErrorUnexpected; | |
| 2737 | case Stmt::CXXBoolLiteralExprClass: | |
| 2738 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXBoolLiteralExprClass"); | |
| 2739 | return ErrorUnexpected; | |
| 2740 | case Stmt::CXXConstructExprClass: | |
| 2741 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXConstructExprClass"); | |
| 2742 | return ErrorUnexpected; | |
| 2743 | case Stmt::CXXTemporaryObjectExprClass: | |
| 2744 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTemporaryObjectExprClass"); | |
| 2745 | return ErrorUnexpected; | |
| 2746 | case Stmt::CXXDefaultArgExprClass: | |
| 2747 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDefaultArgExprClass"); | |
| 2748 | return ErrorUnexpected; | |
| 2749 | case Stmt::CXXDefaultInitExprClass: | |
| 2750 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDefaultInitExprClass"); | |
| 2751 | return ErrorUnexpected; | |
| 2752 | case Stmt::CXXDeleteExprClass: | |
| 2753 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDeleteExprClass"); | |
| 2754 | return ErrorUnexpected; | |
| 2755 | case Stmt::CXXDependentScopeMemberExprClass: | |
| 2756 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDependentScopeMemberExprClass"); | |
| 2757 | return ErrorUnexpected; | |
| 2758 | case Stmt::CXXFoldExprClass: | |
| 2759 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXFoldExprClass"); | |
| 2760 | return ErrorUnexpected; | |
| 2761 | case Stmt::CXXInheritedCtorInitExprClass: | |
| 2762 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXInheritedCtorInitExprClass"); | |
| 2763 | return ErrorUnexpected; | |
| 2764 | case Stmt::CXXNewExprClass: | |
| 2765 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNewExprClass"); | |
| 2766 | return ErrorUnexpected; | |
| 2767 | case Stmt::CXXNoexceptExprClass: | |
| 2768 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNoexceptExprClass"); | |
| 2769 | return ErrorUnexpected; | |
| 2770 | case Stmt::CXXNullPtrLiteralExprClass: | |
| 2771 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNullPtrLiteralExprClass"); | |
| 2772 | return ErrorUnexpected; | |
| 2773 | case Stmt::CXXPseudoDestructorExprClass: | |
| 2774 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXPseudoDestructorExprClass"); | |
| 2775 | return ErrorUnexpected; | |
| 2776 | case Stmt::CXXScalarValueInitExprClass: | |
| 2777 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXScalarValueInitExprClass"); | |
| 2778 | return ErrorUnexpected; | |
| 2779 | case Stmt::CXXStdInitializerListExprClass: | |
| 2780 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXStdInitializerListExprClass"); | |
| 2781 | return ErrorUnexpected; | |
| 2782 | case Stmt::CXXThisExprClass: | |
| 2783 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXThisExprClass"); | |
| 2784 | return ErrorUnexpected; | |
| 2785 | case Stmt::CXXThrowExprClass: | |
| 2786 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXThrowExprClass"); | |
| 2787 | return ErrorUnexpected; | |
| 2788 | case Stmt::CXXTypeidExprClass: | |
| 2789 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTypeidExprClass"); | |
| 2790 | return ErrorUnexpected; | |
| 2791 | case Stmt::CXXUnresolvedConstructExprClass: | |
| 2792 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUnresolvedConstructExprClass"); | |
| 2793 | return ErrorUnexpected; | |
| 2794 | case Stmt::CXXUuidofExprClass: | |
| 2795 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUuidofExprClass"); | |
| 2796 | return ErrorUnexpected; | |
| 2797 | case Stmt::CUDAKernelCallExprClass: | |
| 2798 | emit_warning(c, stmt->getLocStart(), "TODO handle C CUDAKernelCallExprClass"); | |
| 2799 | return ErrorUnexpected; | |
| 2800 | case Stmt::CXXMemberCallExprClass: | |
| 2801 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXMemberCallExprClass"); | |
| 2802 | return ErrorUnexpected; | |
| 2803 | case Stmt::CXXOperatorCallExprClass: | |
| 2804 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXOperatorCallExprClass"); | |
| 2805 | return ErrorUnexpected; | |
| 2806 | case Stmt::UserDefinedLiteralClass: | |
| 2807 | emit_warning(c, stmt->getLocStart(), "TODO handle C UserDefinedLiteralClass"); | |
| 2808 | return ErrorUnexpected; | |
| 2809 | case Stmt::CXXFunctionalCastExprClass: | |
| 2810 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXFunctionalCastExprClass"); | |
| 2811 | return ErrorUnexpected; | |
| 2812 | case Stmt::CXXConstCastExprClass: | |
| 2813 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXConstCastExprClass"); | |
| 2814 | return ErrorUnexpected; | |
| 2815 | case Stmt::CXXDynamicCastExprClass: | |
| 2816 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDynamicCastExprClass"); | |
| 2817 | return ErrorUnexpected; | |
| 2818 | case Stmt::CXXReinterpretCastExprClass: | |
| 2819 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXReinterpretCastExprClass"); | |
| 2820 | return ErrorUnexpected; | |
| 2821 | case Stmt::CXXStaticCastExprClass: | |
| 2822 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXStaticCastExprClass"); | |
| 2823 | return ErrorUnexpected; | |
| 2824 | case Stmt::ObjCBridgedCastExprClass: | |
| 2825 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBridgedCastExprClass"); | |
| 2826 | return ErrorUnexpected; | |
| 2827 | case Stmt::CharacterLiteralClass: | |
| 2828 | emit_warning(c, stmt->getLocStart(), "TODO handle C CharacterLiteralClass"); | |
| 2829 | return ErrorUnexpected; | |
| 2830 | case Stmt::ChooseExprClass: | |
| 2831 | emit_warning(c, stmt->getLocStart(), "TODO handle C ChooseExprClass"); | |
| 2832 | return ErrorUnexpected; | |
| 2833 | case Stmt::CompoundLiteralExprClass: | |
| 2834 | emit_warning(c, stmt->getLocStart(), "TODO handle C CompoundLiteralExprClass"); | |
| 2835 | return ErrorUnexpected; | |
| 2836 | case Stmt::ConvertVectorExprClass: | |
| 2837 | emit_warning(c, stmt->getLocStart(), "TODO handle C ConvertVectorExprClass"); | |
| 2838 | return ErrorUnexpected; | |
| 2839 | case Stmt::CoawaitExprClass: | |
| 2840 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoawaitExprClass"); | |
| 2841 | return ErrorUnexpected; | |
| 2842 | case Stmt::CoyieldExprClass: | |
| 2843 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoyieldExprClass"); | |
| 2844 | return ErrorUnexpected; | |
| 2845 | case Stmt::DependentCoawaitExprClass: | |
| 2846 | emit_warning(c, stmt->getLocStart(), "TODO handle C DependentCoawaitExprClass"); | |
| 2847 | return ErrorUnexpected; | |
| 2848 | case Stmt::DependentScopeDeclRefExprClass: | |
| 2849 | emit_warning(c, stmt->getLocStart(), "TODO handle C DependentScopeDeclRefExprClass"); | |
| 2850 | return ErrorUnexpected; | |
| 2851 | case Stmt::DesignatedInitExprClass: | |
| 2852 | emit_warning(c, stmt->getLocStart(), "TODO handle C DesignatedInitExprClass"); | |
| 2853 | return ErrorUnexpected; | |
| 2854 | case Stmt::DesignatedInitUpdateExprClass: | |
| 2855 | emit_warning(c, stmt->getLocStart(), "TODO handle C DesignatedInitUpdateExprClass"); | |
| 2856 | return ErrorUnexpected; | |
| 2857 | case Stmt::ExprWithCleanupsClass: | |
| 2858 | emit_warning(c, stmt->getLocStart(), "TODO handle C ExprWithCleanupsClass"); | |
| 2859 | return ErrorUnexpected; | |
| 2860 | case Stmt::ExpressionTraitExprClass: | |
| 2861 | emit_warning(c, stmt->getLocStart(), "TODO handle C ExpressionTraitExprClass"); | |
| 2862 | return ErrorUnexpected; | |
| 2863 | case Stmt::ExtVectorElementExprClass: | |
| 2864 | emit_warning(c, stmt->getLocStart(), "TODO handle C ExtVectorElementExprClass"); | |
| 2865 | return ErrorUnexpected; | |
| 2866 | case Stmt::FloatingLiteralClass: | |
| 2867 | emit_warning(c, stmt->getLocStart(), "TODO handle C FloatingLiteralClass"); | |
| 2868 | return ErrorUnexpected; | |
| 2869 | case Stmt::FunctionParmPackExprClass: | |
| 2870 | emit_warning(c, stmt->getLocStart(), "TODO handle C FunctionParmPackExprClass"); | |
| 2871 | return ErrorUnexpected; | |
| 2872 | case Stmt::GNUNullExprClass: | |
| 2873 | emit_warning(c, stmt->getLocStart(), "TODO handle C GNUNullExprClass"); | |
| 2874 | return ErrorUnexpected; | |
| 2875 | case Stmt::GenericSelectionExprClass: | |
| 2876 | emit_warning(c, stmt->getLocStart(), "TODO handle C GenericSelectionExprClass"); | |
| 2877 | return ErrorUnexpected; | |
| 2878 | case Stmt::ImaginaryLiteralClass: | |
| 2879 | emit_warning(c, stmt->getLocStart(), "TODO handle C ImaginaryLiteralClass"); | |
| 2880 | return ErrorUnexpected; | |
| 2881 | case Stmt::ImplicitValueInitExprClass: | |
| 2882 | emit_warning(c, stmt->getLocStart(), "TODO handle C ImplicitValueInitExprClass"); | |
| 2883 | return ErrorUnexpected; | |
| 2884 | case Stmt::InitListExprClass: | |
| 2885 | emit_warning(c, stmt->getLocStart(), "TODO handle C InitListExprClass"); | |
| 2886 | return ErrorUnexpected; | |
| 2887 | case Stmt::LambdaExprClass: | |
| 2888 | emit_warning(c, stmt->getLocStart(), "TODO handle C LambdaExprClass"); | |
| 2889 | return ErrorUnexpected; | |
| 2890 | case Stmt::MSPropertyRefExprClass: | |
| 2891 | emit_warning(c, stmt->getLocStart(), "TODO handle C MSPropertyRefExprClass"); | |
| 2892 | return ErrorUnexpected; | |
| 2893 | case Stmt::MSPropertySubscriptExprClass: | |
| 2894 | emit_warning(c, stmt->getLocStart(), "TODO handle C MSPropertySubscriptExprClass"); | |
| 2895 | return ErrorUnexpected; | |
| 2896 | case Stmt::MaterializeTemporaryExprClass: | |
| 2897 | emit_warning(c, stmt->getLocStart(), "TODO handle C MaterializeTemporaryExprClass"); | |
| 2898 | return ErrorUnexpected; | |
| 2899 | case Stmt::NoInitExprClass: | |
| 2900 | emit_warning(c, stmt->getLocStart(), "TODO handle C NoInitExprClass"); | |
| 2901 | return ErrorUnexpected; | |
| 2902 | case Stmt::OMPArraySectionExprClass: | |
| 2903 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPArraySectionExprClass"); | |
| 2904 | return ErrorUnexpected; | |
| 2905 | case Stmt::ObjCArrayLiteralClass: | |
| 2906 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCArrayLiteralClass"); | |
| 2907 | return ErrorUnexpected; | |
| 2908 | case Stmt::ObjCAvailabilityCheckExprClass: | |
| 2909 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAvailabilityCheckExprClass"); | |
| 2910 | return ErrorUnexpected; | |
| 2911 | case Stmt::ObjCBoolLiteralExprClass: | |
| 2912 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBoolLiteralExprClass"); | |
| 2913 | return ErrorUnexpected; | |
| 2914 | case Stmt::ObjCBoxedExprClass: | |
| 2915 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBoxedExprClass"); | |
| 2916 | return ErrorUnexpected; | |
| 2917 | case Stmt::ObjCDictionaryLiteralClass: | |
| 2918 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCDictionaryLiteralClass"); | |
| 2919 | return ErrorUnexpected; | |
| 2920 | case Stmt::ObjCEncodeExprClass: | |
| 2921 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCEncodeExprClass"); | |
| 2922 | return ErrorUnexpected; | |
| 2923 | case Stmt::ObjCIndirectCopyRestoreExprClass: | |
| 2924 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIndirectCopyRestoreExprClass"); | |
| 2925 | return ErrorUnexpected; | |
| 2926 | case Stmt::ObjCIsaExprClass: | |
| 2927 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIsaExprClass"); | |
| 2928 | return ErrorUnexpected; | |
| 2929 | case Stmt::ObjCIvarRefExprClass: | |
| 2930 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIvarRefExprClass"); | |
| 2931 | return ErrorUnexpected; | |
| 2932 | case Stmt::ObjCMessageExprClass: | |
| 2933 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCMessageExprClass"); | |
| 2934 | return ErrorUnexpected; | |
| 2935 | case Stmt::ObjCPropertyRefExprClass: | |
| 2936 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCPropertyRefExprClass"); | |
| 2937 | return ErrorUnexpected; | |
| 2938 | case Stmt::ObjCProtocolExprClass: | |
| 2939 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCProtocolExprClass"); | |
| 2940 | return ErrorUnexpected; | |
| 2941 | case Stmt::ObjCSelectorExprClass: | |
| 2942 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCSelectorExprClass"); | |
| 2943 | return ErrorUnexpected; | |
| 2944 | case Stmt::ObjCStringLiteralClass: | |
| 2945 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCStringLiteralClass"); | |
| 2946 | return ErrorUnexpected; | |
| 2947 | case Stmt::ObjCSubscriptRefExprClass: | |
| 2948 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCSubscriptRefExprClass"); | |
| 2949 | return ErrorUnexpected; | |
| 2950 | case Stmt::OffsetOfExprClass: | |
| 2951 | emit_warning(c, stmt->getLocStart(), "TODO handle C OffsetOfExprClass"); | |
| 2952 | return ErrorUnexpected; | |
| 2953 | case Stmt::OpaqueValueExprClass: | |
| 2954 | emit_warning(c, stmt->getLocStart(), "TODO handle C OpaqueValueExprClass"); | |
| 2955 | return ErrorUnexpected; | |
| 2956 | case Stmt::UnresolvedLookupExprClass: | |
| 2957 | emit_warning(c, stmt->getLocStart(), "TODO handle C UnresolvedLookupExprClass"); | |
| 2958 | return ErrorUnexpected; | |
| 2959 | case Stmt::UnresolvedMemberExprClass: | |
| 2960 | emit_warning(c, stmt->getLocStart(), "TODO handle C UnresolvedMemberExprClass"); | |
| 2961 | return ErrorUnexpected; | |
| 2962 | case Stmt::PackExpansionExprClass: | |
| 2963 | emit_warning(c, stmt->getLocStart(), "TODO handle C PackExpansionExprClass"); | |
| 2964 | return ErrorUnexpected; | |
| 2965 | case Stmt::ParenListExprClass: | |
| 2966 | emit_warning(c, stmt->getLocStart(), "TODO handle C ParenListExprClass"); | |
| 2967 | return ErrorUnexpected; | |
| 2968 | case Stmt::PredefinedExprClass: | |
| 2969 | emit_warning(c, stmt->getLocStart(), "TODO handle C PredefinedExprClass"); | |
| 2970 | return ErrorUnexpected; | |
| 2971 | case Stmt::PseudoObjectExprClass: | |
| 2972 | emit_warning(c, stmt->getLocStart(), "TODO handle C PseudoObjectExprClass"); | |
| 2973 | return ErrorUnexpected; | |
| 2974 | case Stmt::ShuffleVectorExprClass: | |
| 2975 | emit_warning(c, stmt->getLocStart(), "TODO handle C ShuffleVectorExprClass"); | |
| 2976 | return ErrorUnexpected; | |
| 2977 | case Stmt::SizeOfPackExprClass: | |
| 2978 | emit_warning(c, stmt->getLocStart(), "TODO handle C SizeOfPackExprClass"); | |
| 2979 | return ErrorUnexpected; | |
| 2980 | case Stmt::StmtExprClass: | |
| 2981 | emit_warning(c, stmt->getLocStart(), "TODO handle C StmtExprClass"); | |
| 2982 | return ErrorUnexpected; | |
| 2983 | case Stmt::SubstNonTypeTemplateParmExprClass: | |
| 2984 | emit_warning(c, stmt->getLocStart(), "TODO handle C SubstNonTypeTemplateParmExprClass"); | |
| 2985 | return ErrorUnexpected; | |
| 2986 | case Stmt::SubstNonTypeTemplateParmPackExprClass: | |
| 2987 | emit_warning(c, stmt->getLocStart(), "TODO handle C SubstNonTypeTemplateParmPackExprClass"); | |
| 2988 | return ErrorUnexpected; | |
| 2989 | case Stmt::TypeTraitExprClass: | |
| 2990 | emit_warning(c, stmt->getLocStart(), "TODO handle C TypeTraitExprClass"); | |
| 2991 | return ErrorUnexpected; | |
| 2992 | case Stmt::TypoExprClass: | |
| 2993 | emit_warning(c, stmt->getLocStart(), "TODO handle C TypoExprClass"); | |
| 2994 | return ErrorUnexpected; | |
| 2995 | case Stmt::VAArgExprClass: | |
| 2996 | emit_warning(c, stmt->getLocStart(), "TODO handle C VAArgExprClass"); | |
| 2997 | return ErrorUnexpected; | |
| 2998 | case Stmt::GotoStmtClass: | |
| 2999 | emit_warning(c, stmt->getLocStart(), "TODO handle C GotoStmtClass"); | |
| 3000 | return ErrorUnexpected; | |
| 3001 | case Stmt::IndirectGotoStmtClass: | |
| 3002 | emit_warning(c, stmt->getLocStart(), "TODO handle C IndirectGotoStmtClass"); | |
| 3003 | return ErrorUnexpected; | |
| 3004 | case Stmt::LabelStmtClass: | |
| 3005 | emit_warning(c, stmt->getLocStart(), "TODO handle C LabelStmtClass"); | |
| 3006 | return ErrorUnexpected; | |
| 3007 | case Stmt::MSDependentExistsStmtClass: | |
| 3008 | emit_warning(c, stmt->getLocStart(), "TODO handle C MSDependentExistsStmtClass"); | |
| 3009 | return ErrorUnexpected; | |
| 3010 | case Stmt::OMPAtomicDirectiveClass: | |
| 3011 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPAtomicDirectiveClass"); | |
| 3012 | return ErrorUnexpected; | |
| 3013 | case Stmt::OMPBarrierDirectiveClass: | |
| 3014 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPBarrierDirectiveClass"); | |
| 3015 | return ErrorUnexpected; | |
| 3016 | case Stmt::OMPCancelDirectiveClass: | |
| 3017 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCancelDirectiveClass"); | |
| 3018 | return ErrorUnexpected; | |
| 3019 | case Stmt::OMPCancellationPointDirectiveClass: | |
| 3020 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCancellationPointDirectiveClass"); | |
| 3021 | return ErrorUnexpected; | |
| 3022 | case Stmt::OMPCriticalDirectiveClass: | |
| 3023 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCriticalDirectiveClass"); | |
| 3024 | return ErrorUnexpected; | |
| 3025 | case Stmt::OMPFlushDirectiveClass: | |
| 3026 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPFlushDirectiveClass"); | |
| 3027 | return ErrorUnexpected; | |
| 3028 | case Stmt::OMPDistributeDirectiveClass: | |
| 3029 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeDirectiveClass"); | |
| 3030 | return ErrorUnexpected; | |
| 3031 | case Stmt::OMPDistributeParallelForDirectiveClass: | |
| 3032 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeParallelForDirectiveClass"); | |
| 3033 | return ErrorUnexpected; | |
| 3034 | case Stmt::OMPDistributeParallelForSimdDirectiveClass: | |
| 3035 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeParallelForSimdDirectiveClass"); | |
| 3036 | return ErrorUnexpected; | |
| 3037 | case Stmt::OMPDistributeSimdDirectiveClass: | |
| 3038 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeSimdDirectiveClass"); | |
| 3039 | return ErrorUnexpected; | |
| 3040 | case Stmt::OMPForDirectiveClass: | |
| 3041 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPForDirectiveClass"); | |
| 3042 | return ErrorUnexpected; | |
| 3043 | case Stmt::OMPForSimdDirectiveClass: | |
| 3044 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPForSimdDirectiveClass"); | |
| 3045 | return ErrorUnexpected; | |
| 3046 | case Stmt::OMPParallelForDirectiveClass: | |
| 3047 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelForDirectiveClass"); | |
| 3048 | return ErrorUnexpected; | |
| 3049 | case Stmt::OMPParallelForSimdDirectiveClass: | |
| 3050 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelForSimdDirectiveClass"); | |
| 3051 | return ErrorUnexpected; | |
| 3052 | case Stmt::OMPSimdDirectiveClass: | |
| 3053 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSimdDirectiveClass"); | |
| 3054 | return ErrorUnexpected; | |
| 3055 | case Stmt::OMPTargetParallelForSimdDirectiveClass: | |
| 3056 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelForSimdDirectiveClass"); | |
| 3057 | return ErrorUnexpected; | |
| 3058 | case Stmt::OMPTargetSimdDirectiveClass: | |
| 3059 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetSimdDirectiveClass"); | |
| 3060 | return ErrorUnexpected; | |
| 3061 | case Stmt::OMPTargetTeamsDistributeDirectiveClass: | |
| 3062 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeDirectiveClass"); | |
| 3063 | return ErrorUnexpected; | |
| 3064 | case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass: | |
| 3065 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeParallelForDirectiveClass"); | |
| 3066 | return ErrorUnexpected; | |
| 3067 | case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass: | |
| 3068 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeParallelForSimdDirectiveClass"); | |
| 3069 | return ErrorUnexpected; | |
| 3070 | case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: | |
| 3071 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeSimdDirectiveClass"); | |
| 3072 | return ErrorUnexpected; | |
| 3073 | case Stmt::OMPTaskLoopDirectiveClass: | |
| 3074 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskLoopDirectiveClass"); | |
| 3075 | return ErrorUnexpected; | |
| 3076 | case Stmt::OMPTaskLoopSimdDirectiveClass: | |
| 3077 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskLoopSimdDirectiveClass"); | |
| 3078 | return ErrorUnexpected; | |
| 3079 | case Stmt::OMPTeamsDistributeDirectiveClass: | |
| 3080 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeDirectiveClass"); | |
| 3081 | return ErrorUnexpected; | |
| 3082 | case Stmt::OMPTeamsDistributeParallelForDirectiveClass: | |
| 3083 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeParallelForDirectiveClass"); | |
| 3084 | return ErrorUnexpected; | |
| 3085 | case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass: | |
| 3086 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeParallelForSimdDirectiveClass"); | |
| 3087 | return ErrorUnexpected; | |
| 3088 | case Stmt::OMPTeamsDistributeSimdDirectiveClass: | |
| 3089 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeSimdDirectiveClass"); | |
| 3090 | return ErrorUnexpected; | |
| 3091 | case Stmt::OMPMasterDirectiveClass: | |
| 3092 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPMasterDirectiveClass"); | |
| 3093 | return ErrorUnexpected; | |
| 3094 | case Stmt::OMPOrderedDirectiveClass: | |
| 3095 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPOrderedDirectiveClass"); | |
| 3096 | return ErrorUnexpected; | |
| 3097 | case Stmt::OMPParallelDirectiveClass: | |
| 3098 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelDirectiveClass"); | |
| 3099 | return ErrorUnexpected; | |
| 3100 | case Stmt::OMPParallelSectionsDirectiveClass: | |
| 3101 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelSectionsDirectiveClass"); | |
| 3102 | return ErrorUnexpected; | |
| 3103 | case Stmt::OMPSectionDirectiveClass: | |
| 3104 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSectionDirectiveClass"); | |
| 3105 | return ErrorUnexpected; | |
| 3106 | case Stmt::OMPSectionsDirectiveClass: | |
| 3107 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSectionsDirectiveClass"); | |
| 3108 | return ErrorUnexpected; | |
| 3109 | case Stmt::OMPSingleDirectiveClass: | |
| 3110 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSingleDirectiveClass"); | |
| 3111 | return ErrorUnexpected; | |
| 3112 | case Stmt::OMPTargetDataDirectiveClass: | |
| 3113 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetDataDirectiveClass"); | |
| 3114 | return ErrorUnexpected; | |
| 3115 | case Stmt::OMPTargetDirectiveClass: | |
| 3116 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetDirectiveClass"); | |
| 3117 | return ErrorUnexpected; | |
| 3118 | case Stmt::OMPTargetEnterDataDirectiveClass: | |
| 3119 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetEnterDataDirectiveClass"); | |
| 3120 | return ErrorUnexpected; | |
| 3121 | case Stmt::OMPTargetExitDataDirectiveClass: | |
| 3122 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetExitDataDirectiveClass"); | |
| 3123 | return ErrorUnexpected; | |
| 3124 | case Stmt::OMPTargetParallelDirectiveClass: | |
| 3125 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelDirectiveClass"); | |
| 3126 | return ErrorUnexpected; | |
| 3127 | case Stmt::OMPTargetParallelForDirectiveClass: | |
| 3128 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelForDirectiveClass"); | |
| 3129 | return ErrorUnexpected; | |
| 3130 | case Stmt::OMPTargetTeamsDirectiveClass: | |
| 3131 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDirectiveClass"); | |
| 3132 | return ErrorUnexpected; | |
| 3133 | case Stmt::OMPTargetUpdateDirectiveClass: | |
| 3134 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetUpdateDirectiveClass"); | |
| 3135 | return ErrorUnexpected; | |
| 3136 | case Stmt::OMPTaskDirectiveClass: | |
| 3137 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskDirectiveClass"); | |
| 3138 | return ErrorUnexpected; | |
| 3139 | case Stmt::OMPTaskgroupDirectiveClass: | |
| 3140 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskgroupDirectiveClass"); | |
| 3141 | return ErrorUnexpected; | |
| 3142 | case Stmt::OMPTaskwaitDirectiveClass: | |
| 3143 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskwaitDirectiveClass"); | |
| 3144 | return ErrorUnexpected; | |
| 3145 | case Stmt::OMPTaskyieldDirectiveClass: | |
| 3146 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskyieldDirectiveClass"); | |
| 3147 | return ErrorUnexpected; | |
| 3148 | case Stmt::OMPTeamsDirectiveClass: | |
| 3149 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDirectiveClass"); | |
| 3150 | return ErrorUnexpected; | |
| 3151 | case Stmt::ObjCAtCatchStmtClass: | |
| 3152 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtCatchStmtClass"); | |
| 3153 | return ErrorUnexpected; | |
| 3154 | case Stmt::ObjCAtFinallyStmtClass: | |
| 3155 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtFinallyStmtClass"); | |
| 3156 | return ErrorUnexpected; | |
| 3157 | case Stmt::ObjCAtSynchronizedStmtClass: | |
| 3158 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtSynchronizedStmtClass"); | |
| 3159 | return ErrorUnexpected; | |
| 3160 | case Stmt::ObjCAtThrowStmtClass: | |
| 3161 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtThrowStmtClass"); | |
| 3162 | return ErrorUnexpected; | |
| 3163 | case Stmt::ObjCAtTryStmtClass: | |
| 3164 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtTryStmtClass"); | |
| 3165 | return ErrorUnexpected; | |
| 3166 | case Stmt::ObjCAutoreleasePoolStmtClass: | |
| 3167 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAutoreleasePoolStmtClass"); | |
| 3168 | return ErrorUnexpected; | |
| 3169 | case Stmt::ObjCForCollectionStmtClass: | |
| 3170 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCForCollectionStmtClass"); | |
| 3171 | return ErrorUnexpected; | |
| 3172 | case Stmt::SEHExceptStmtClass: | |
| 3173 | emit_warning(c, stmt->getLocStart(), "TODO handle C SEHExceptStmtClass"); | |
| 3174 | return ErrorUnexpected; | |
| 3175 | case Stmt::SEHFinallyStmtClass: | |
| 3176 | emit_warning(c, stmt->getLocStart(), "TODO handle C SEHFinallyStmtClass"); | |
| 3177 | return ErrorUnexpected; | |
| 3178 | case Stmt::SEHLeaveStmtClass: | |
| 3179 | emit_warning(c, stmt->getLocStart(), "TODO handle C SEHLeaveStmtClass"); | |
| 3180 | return ErrorUnexpected; | |
| 3181 | case Stmt::SEHTryStmtClass: | |
| 3182 | emit_warning(c, stmt->getLocStart(), "TODO handle C SEHTryStmtClass"); | |
| 3183 | return ErrorUnexpected; | |
| 3184 | } | |
| 3185 | zig_unreachable(); | |
| 3186 | } | |
| 3187 | ||
| 3188 | // Returns null if there was an error | |
| 3189 | static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, | |
| 3190 | TransLRValue lrval) | |
| 3191 | { | |
| 3192 | AstNode *result_node; | |
| 3193 | TransScope *result_scope; | |
| 3194 | if (trans_stmt_extra(c, scope, expr, result_used, lrval, &result_node, &result_scope, nullptr)) { | |
| 3195 | return nullptr; | |
| 3196 | } | |
| 3197 | return result_node; | |
| 3198 | } | |
| 3199 | ||
| 3200 | // Statements have no result and no concept of L or R value. | |
| 3201 | // Returns child scope, or null if there was an error | |
| 3202 | static TransScope *trans_stmt(Context *c, TransScope *scope, const Stmt *stmt, AstNode **out_node) { | |
| 3203 | TransScope *child_scope; | |
| 3204 | if (trans_stmt_extra(c, scope, stmt, ResultUsedNo, TransRValue, out_node, &child_scope, nullptr)) { | |
| 3205 | return nullptr; | |
| 3206 | } | |
| 3207 | return child_scope; | |
| 3208 | } | |
| 3209 | ||
| 3210 | static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { | |
| 3211 | Buf *fn_name = buf_create_from_str(decl_name(fn_decl)); | |
| 3212 | ||
| 3213 | if (get_global(c, fn_name)) { | |
| 3214 | // we already saw this function | |
| 3215 | return; | |
| 3216 | } | |
| 3217 | ||
| 3218 | AstNode *proto_node = trans_qual_type(c, fn_decl->getType(), fn_decl->getLocation()); | |
| 3219 | if (proto_node == nullptr) { | |
| 3220 | emit_warning(c, fn_decl->getLocation(), "unable to resolve prototype of function '%s'", buf_ptr(fn_name)); | |
| 3221 | return; | |
| 3222 | } | |
| 3223 | ||
| 3224 | proto_node->data.fn_proto.name = fn_name; | |
| 3225 | proto_node->data.fn_proto.is_extern = !fn_decl->hasBody(); | |
| 3226 | ||
| 3227 | StorageClass sc = fn_decl->getStorageClass(); | |
| 3228 | if (sc == SC_None) { | |
| 3229 | proto_node->data.fn_proto.visib_mod = fn_decl->hasBody() ? c->export_visib_mod : c->visib_mod; | |
| 3230 | } else if (sc == SC_Extern || sc == SC_Static) { | |
| 3231 | proto_node->data.fn_proto.visib_mod = c->visib_mod; | |
| 3232 | } else if (sc == SC_PrivateExtern) { | |
| 3233 | emit_warning(c, fn_decl->getLocation(), "unsupported storage class: private extern"); | |
| 3234 | return; | |
| 3235 | } else { | |
| 3236 | emit_warning(c, fn_decl->getLocation(), "unsupported storage class: unknown"); | |
| 3237 | return; | |
| 3238 | } | |
| 3239 | ||
| 3240 | TransScope *scope = &c->global_scope->base; | |
| 3241 | ||
| 3242 | for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) { | |
| 3243 | AstNode *param_node = proto_node->data.fn_proto.params.at(i); | |
| 3244 | const ParmVarDecl *param = fn_decl->getParamDecl(i); | |
| 3245 | const char *name = decl_name(param); | |
| 3246 | ||
| 3247 | Buf *proto_param_name; | |
| 3248 | if (strlen(name) != 0) { | |
| 3249 | proto_param_name = buf_create_from_str(name); | |
| 3250 | } else { | |
| 3251 | proto_param_name = param_node->data.param_decl.name; | |
| 3252 | if (proto_param_name == nullptr) { | |
| 3253 | proto_param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i); | |
| 3254 | } | |
| 3255 | } | |
| 3256 | ||
| 3257 | TransScopeVar *scope_var = trans_scope_var_create(c, scope, proto_param_name); | |
| 3258 | scope = &scope_var->base; | |
| 3259 | ||
| 3260 | param_node->data.param_decl.name = scope_var->zig_name; | |
| 3261 | } | |
| 3262 | ||
| 3263 | if (!fn_decl->hasBody()) { | |
| 3264 | // just a prototype | |
| 3265 | add_top_level_decl(c, proto_node->data.fn_proto.name, proto_node); | |
| 3266 | return; | |
| 3267 | } | |
| 3268 | ||
| 3269 | // actual function definition with body | |
| 3270 | c->ptr_params.clear(); | |
| 3271 | Stmt *body = fn_decl->getBody(); | |
| 3272 | AstNode *actual_body_node; | |
| 3273 | TransScope *result_scope = trans_stmt(c, scope, body, &actual_body_node); | |
| 3274 | if (result_scope == nullptr) { | |
| 3275 | emit_warning(c, fn_decl->getLocation(), "unable to translate function"); | |
| 3276 | return; | |
| 3277 | } | |
| 3278 | assert(actual_body_node != nullptr); | |
| 3279 | assert(actual_body_node->type == NodeTypeBlock); | |
| 3280 | ||
| 3281 | // it worked | |
| 3282 | ||
| 3283 | AstNode *body_node_with_param_inits = trans_create_node(c, NodeTypeBlock); | |
| 3284 | ||
| 3285 | for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) { | |
| 3286 | AstNode *param_node = proto_node->data.fn_proto.params.at(i); | |
| 3287 | Buf *good_name = param_node->data.param_decl.name; | |
| 3288 | ||
| 3289 | if (c->ptr_params.maybe_get(good_name) != nullptr) { | |
| 3290 | // TODO: avoid name collisions | |
| 3291 | Buf *mangled_name = buf_sprintf("_arg_%s", buf_ptr(good_name)); | |
| 3292 | param_node->data.param_decl.name = mangled_name; | |
| 3293 | ||
| 3294 | // var c_name = _mangled_name; | |
| 3295 | AstNode *parameter_init = trans_create_node_var_decl_local(c, false, good_name, nullptr, trans_create_node_symbol(c, mangled_name)); | |
| 3296 | ||
| 3297 | body_node_with_param_inits->data.block.statements.append(parameter_init); | |
| 3298 | } | |
| 3299 | } | |
| 3300 | ||
| 3301 | for (size_t i = 0; i < actual_body_node->data.block.statements.length; i += 1) { | |
| 3302 | body_node_with_param_inits->data.block.statements.append(actual_body_node->data.block.statements.at(i)); | |
| 3303 | } | |
| 3304 | ||
| 3305 | AstNode *fn_def_node = trans_create_node(c, NodeTypeFnDef); | |
| 3306 | fn_def_node->data.fn_def.fn_proto = proto_node; | |
| 3307 | fn_def_node->data.fn_def.body = body_node_with_param_inits; | |
| 3308 | ||
| 3309 | proto_node->data.fn_proto.fn_def_node = fn_def_node; | |
| 3310 | add_top_level_decl(c, fn_def_node->data.fn_def.fn_proto->data.fn_proto.name, fn_def_node); | |
| 3311 | } | |
| 3312 | ||
| 3313 | static AstNode *resolve_typdef_as_builtin(Context *c, const TypedefNameDecl *typedef_decl, const char *primitive_name) { | |
| 3314 | AstNode *node = trans_create_node_symbol_str(c, primitive_name); | |
| 3315 | c->decl_table.put(typedef_decl, node); | |
| 3316 | return node; | |
| 3317 | } | |
| 3318 | ||
| 3319 | static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl) { | |
| 3320 | auto existing_entry = c->decl_table.maybe_get((void*)typedef_decl->getCanonicalDecl()); | |
| 3321 | if (existing_entry) { | |
| 3322 | return existing_entry->value; | |
| 3323 | } | |
| 3324 | QualType child_qt = typedef_decl->getUnderlyingType(); | |
| 3325 | Buf *type_name = buf_create_from_str(decl_name(typedef_decl)); | |
| 3326 | ||
| 3327 | if (buf_eql_str(type_name, "uint8_t")) { | |
| 3328 | return resolve_typdef_as_builtin(c, typedef_decl, "u8"); | |
| 3329 | } else if (buf_eql_str(type_name, "int8_t")) { | |
| 3330 | return resolve_typdef_as_builtin(c, typedef_decl, "i8"); | |
| 3331 | } else if (buf_eql_str(type_name, "uint16_t")) { | |
| 3332 | return resolve_typdef_as_builtin(c, typedef_decl, "u16"); | |
| 3333 | } else if (buf_eql_str(type_name, "int16_t")) { | |
| 3334 | return resolve_typdef_as_builtin(c, typedef_decl, "i16"); | |
| 3335 | } else if (buf_eql_str(type_name, "uint32_t")) { | |
| 3336 | return resolve_typdef_as_builtin(c, typedef_decl, "u32"); | |
| 3337 | } else if (buf_eql_str(type_name, "int32_t")) { | |
| 3338 | return resolve_typdef_as_builtin(c, typedef_decl, "i32"); | |
| 3339 | } else if (buf_eql_str(type_name, "uint64_t")) { | |
| 3340 | return resolve_typdef_as_builtin(c, typedef_decl, "u64"); | |
| 3341 | } else if (buf_eql_str(type_name, "int64_t")) { | |
| 3342 | return resolve_typdef_as_builtin(c, typedef_decl, "i64"); | |
| 3343 | } else if (buf_eql_str(type_name, "intptr_t")) { | |
| 3344 | return resolve_typdef_as_builtin(c, typedef_decl, "isize"); | |
| 3345 | } else if (buf_eql_str(type_name, "uintptr_t")) { | |
| 3346 | return resolve_typdef_as_builtin(c, typedef_decl, "usize"); | |
| 3347 | } else if (buf_eql_str(type_name, "ssize_t")) { | |
| 3348 | return resolve_typdef_as_builtin(c, typedef_decl, "isize"); | |
| 3349 | } else if (buf_eql_str(type_name, "size_t")) { | |
| 3350 | return resolve_typdef_as_builtin(c, typedef_decl, "usize"); | |
| 3351 | } | |
| 3352 | ||
| 3353 | // if the underlying type is anonymous, we can special case it to just | |
| 3354 | // use the name of this typedef | |
| 3355 | // TODO | |
| 3356 | ||
| 3357 | AstNode *type_node = trans_qual_type(c, child_qt, typedef_decl->getLocation()); | |
| 3358 | if (type_node == nullptr) { | |
| 3359 | emit_warning(c, typedef_decl->getLocation(), "typedef %s - unresolved child type", buf_ptr(type_name)); | |
| 3360 | c->decl_table.put(typedef_decl, nullptr); | |
| 3361 | return nullptr; | |
| 3362 | } | |
| 3363 | add_global_var(c, type_name, type_node); | |
| 3364 | ||
| 3365 | AstNode *symbol_node = trans_create_node_symbol(c, type_name); | |
| 3366 | c->decl_table.put(typedef_decl->getCanonicalDecl(), symbol_node); | |
| 3367 | return symbol_node; | |
| 3368 | } | |
| 3369 | ||
| 3370 | struct AstNode *demote_enum_to_opaque(Context *c, const EnumDecl *enum_decl, | |
| 3371 | Buf *full_type_name, Buf *bare_name) | |
| 3372 | { | |
| 3373 | AstNode *opaque_node = trans_create_node_opaque(c); | |
| 3374 | if (full_type_name == nullptr) { | |
| 3375 | c->decl_table.put(enum_decl->getCanonicalDecl(), opaque_node); | |
| 3376 | return opaque_node; | |
| 3377 | } | |
| 3378 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | |
| 3379 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 3380 | add_global_var(c, full_type_name, opaque_node); | |
| 3381 | c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); | |
| 3382 | return symbol_node; | |
| 3383 | } | |
| 3384 | ||
| 3385 | static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { | |
| 3386 | auto existing_entry = c->decl_table.maybe_get((void*)enum_decl->getCanonicalDecl()); | |
| 3387 | if (existing_entry) { | |
| 3388 | return existing_entry->value; | |
| 3389 | } | |
| 3390 | ||
| 3391 | const char *raw_name = decl_name(enum_decl); | |
| 3392 | bool is_anonymous = (raw_name[0] == 0); | |
| 3393 | Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name); | |
| 3394 | Buf *full_type_name = is_anonymous ? nullptr : buf_sprintf("enum_%s", buf_ptr(bare_name)); | |
| 3395 | ||
| 3396 | const EnumDecl *enum_def = enum_decl->getDefinition(); | |
| 3397 | if (!enum_def) { | |
| 3398 | return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name); | |
| 3399 | } | |
| 3400 | ||
| 3401 | bool pure_enum = true; | |
| 3402 | uint32_t field_count = 0; | |
| 3403 | for (auto it = enum_def->enumerator_begin(), | |
| 3404 | it_end = enum_def->enumerator_end(); | |
| 3405 | it != it_end; ++it, field_count += 1) | |
| 3406 | { | |
| 3407 | const EnumConstantDecl *enum_const = *it; | |
| 3408 | if (enum_const->getInitExpr()) { | |
| 3409 | pure_enum = false; | |
| 3410 | } | |
| 3411 | } | |
| 3412 | ||
| 3413 | AstNode *tag_int_type = trans_qual_type(c, enum_decl->getIntegerType(), enum_decl->getLocation()); | |
| 3414 | assert(tag_int_type); | |
| 3415 | ||
| 3416 | if (pure_enum) { | |
| 3417 | AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl); | |
| 3418 | enum_node->data.container_decl.kind = ContainerKindEnum; | |
| 3419 | enum_node->data.container_decl.layout = ContainerLayoutExtern; | |
| 3420 | enum_node->data.container_decl.init_arg_expr = tag_int_type; | |
| 3421 | ||
| 3422 | enum_node->data.container_decl.fields.resize(field_count); | |
| 3423 | uint32_t i = 0; | |
| 3424 | for (auto it = enum_def->enumerator_begin(), | |
| 3425 | it_end = enum_def->enumerator_end(); | |
| 3426 | it != it_end; ++it, i += 1) | |
| 3427 | { | |
| 3428 | const EnumConstantDecl *enum_const = *it; | |
| 3429 | ||
| 3430 | Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); | |
| 3431 | Buf *field_name; | |
| 3432 | if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) { | |
| 3433 | field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name)); | |
| 3434 | } else { | |
| 3435 | field_name = enum_val_name; | |
| 3436 | } | |
| 3437 | ||
| 3438 | AstNode *field_node = trans_create_node(c, NodeTypeStructField); | |
| 3439 | field_node->data.struct_field.name = field_name; | |
| 3440 | field_node->data.struct_field.type = nullptr; | |
| 3441 | enum_node->data.container_decl.fields.items[i] = field_node; | |
| 3442 | ||
| 3443 | // in C each enum value is in the global namespace. so we put them there too. | |
| 3444 | // at this point we can rely on the enum emitting successfully | |
| 3445 | if (is_anonymous) { | |
| 3446 | AstNode *lit_node = trans_create_node_unsigned(c, i); | |
| 3447 | add_global_var(c, enum_val_name, lit_node); | |
| 3448 | } else { | |
| 3449 | AstNode *field_access_node = trans_create_node_field_access(c, | |
| 3450 | trans_create_node_symbol(c, full_type_name), field_name); | |
| 3451 | add_global_var(c, enum_val_name, field_access_node); | |
| 3452 | } | |
| 3453 | } | |
| 3454 | ||
| 3455 | if (is_anonymous) { | |
| 3456 | c->decl_table.put(enum_decl->getCanonicalDecl(), enum_node); | |
| 3457 | return enum_node; | |
| 3458 | } else { | |
| 3459 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | |
| 3460 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 3461 | add_global_var(c, full_type_name, enum_node); | |
| 3462 | c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); | |
| 3463 | return enum_node; | |
| 3464 | } | |
| 3465 | } | |
| 3466 | ||
| 3467 | // TODO after issue #305 is solved, make this be an enum with tag_int_type | |
| 3468 | // as the integer type and set the custom enum values | |
| 3469 | AstNode *enum_node = tag_int_type; | |
| 3470 | ||
| 3471 | ||
| 3472 | // add variables for all the values with enum_node | |
| 3473 | for (auto it = enum_def->enumerator_begin(), | |
| 3474 | it_end = enum_def->enumerator_end(); | |
| 3475 | it != it_end; ++it) | |
| 3476 | { | |
| 3477 | const EnumConstantDecl *enum_const = *it; | |
| 3478 | ||
| 3479 | Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); | |
| 3480 | AstNode *int_node = trans_create_node_apint(c, enum_const->getInitVal()); | |
| 3481 | AstNode *var_node = add_global_var(c, enum_val_name, int_node); | |
| 3482 | var_node->data.variable_declaration.type = tag_int_type; | |
| 3483 | } | |
| 3484 | ||
| 3485 | if (is_anonymous) { | |
| 3486 | c->decl_table.put(enum_decl->getCanonicalDecl(), enum_node); | |
| 3487 | return enum_node; | |
| 3488 | } else { | |
| 3489 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | |
| 3490 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 3491 | add_global_var(c, full_type_name, enum_node); | |
| 3492 | c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); | |
| 3493 | return symbol_node; | |
| 3494 | } | |
| 3495 | } | |
| 3496 | ||
| 3497 | static AstNode *demote_struct_to_opaque(Context *c, const RecordDecl *record_decl, | |
| 3498 | Buf *full_type_name, Buf *bare_name) | |
| 3499 | { | |
| 3500 | AstNode *opaque_node = trans_create_node_opaque(c); | |
| 3501 | if (full_type_name == nullptr) { | |
| 3502 | c->decl_table.put(record_decl->getCanonicalDecl(), opaque_node); | |
| 3503 | return opaque_node; | |
| 3504 | } | |
| 3505 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | |
| 3506 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 3507 | add_global_var(c, full_type_name, opaque_node); | |
| 3508 | c->decl_table.put(record_decl->getCanonicalDecl(), symbol_node); | |
| 3509 | return symbol_node; | |
| 3510 | } | |
| 3511 | ||
| 3512 | static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { | |
| 3513 | auto existing_entry = c->decl_table.maybe_get((void*)record_decl->getCanonicalDecl()); | |
| 3514 | if (existing_entry) { | |
| 3515 | return existing_entry->value; | |
| 3516 | } | |
| 3517 | ||
| 3518 | const char *raw_name = decl_name(record_decl); | |
| 3519 | const char *container_kind_name; | |
| 3520 | ContainerKind container_kind; | |
| 3521 | if (record_decl->isUnion()) { | |
| 3522 | container_kind_name = "union"; | |
| 3523 | container_kind = ContainerKindUnion; | |
| 3524 | } else if (record_decl->isStruct()) { | |
| 3525 | container_kind_name = "struct"; | |
| 3526 | container_kind = ContainerKindStruct; | |
| 3527 | } else { | |
| 3528 | emit_warning(c, record_decl->getLocation(), "skipping record %s, not a struct or union", raw_name); | |
| 3529 | c->decl_table.put(record_decl->getCanonicalDecl(), nullptr); | |
| 3530 | return nullptr; | |
| 3531 | } | |
| 3532 | ||
| 3533 | bool is_anonymous = record_decl->isAnonymousStructOrUnion() || raw_name[0] == 0; | |
| 3534 | Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name); | |
| 3535 | Buf *full_type_name = (bare_name == nullptr) ? | |
| 3536 | nullptr : buf_sprintf("%s_%s", container_kind_name, buf_ptr(bare_name)); | |
| 3537 | ||
| 3538 | RecordDecl *record_def = record_decl->getDefinition(); | |
| 3539 | if (record_def == nullptr) { | |
| 3540 | return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); | |
| 3541 | } | |
| 3542 | ||
| 3543 | // count fields and validate | |
| 3544 | uint32_t field_count = 0; | |
| 3545 | for (auto it = record_def->field_begin(), | |
| 3546 | it_end = record_def->field_end(); | |
| 3547 | it != it_end; ++it, field_count += 1) | |
| 3548 | { | |
| 3549 | const FieldDecl *field_decl = *it; | |
| 3550 | ||
| 3551 | if (field_decl->isBitField()) { | |
| 3552 | emit_warning(c, field_decl->getLocation(), "%s %s demoted to opaque type - has bitfield", | |
| 3553 | container_kind_name, | |
| 3554 | is_anonymous ? "(anon)" : buf_ptr(bare_name)); | |
| 3555 | return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); | |
| 3556 | } | |
| 3557 | } | |
| 3558 | ||
| 3559 | AstNode *struct_node = trans_create_node(c, NodeTypeContainerDecl); | |
| 3560 | struct_node->data.container_decl.kind = container_kind; | |
| 3561 | struct_node->data.container_decl.layout = ContainerLayoutExtern; | |
| 3562 | ||
| 3563 | // TODO handle attribute packed | |
| 3564 | ||
| 3565 | struct_node->data.container_decl.fields.resize(field_count); | |
| 3566 | ||
| 3567 | // must be before fields in case a circular reference happens | |
| 3568 | if (is_anonymous) { | |
| 3569 | c->decl_table.put(record_decl->getCanonicalDecl(), struct_node); | |
| 3570 | } else { | |
| 3571 | c->decl_table.put(record_decl->getCanonicalDecl(), trans_create_node_symbol(c, full_type_name)); | |
| 3572 | } | |
| 3573 | ||
| 3574 | uint32_t i = 0; | |
| 3575 | for (auto it = record_def->field_begin(), | |
| 3576 | it_end = record_def->field_end(); | |
| 3577 | it != it_end; ++it, i += 1) | |
| 3578 | { | |
| 3579 | const FieldDecl *field_decl = *it; | |
| 3580 | ||
| 3581 | AstNode *field_node = trans_create_node(c, NodeTypeStructField); | |
| 3582 | field_node->data.struct_field.name = buf_create_from_str(decl_name(field_decl)); | |
| 3583 | field_node->data.struct_field.type = trans_qual_type(c, field_decl->getType(), field_decl->getLocation()); | |
| 3584 | ||
| 3585 | if (field_node->data.struct_field.type == nullptr) { | |
| 3586 | emit_warning(c, field_decl->getLocation(), | |
| 3587 | "%s %s demoted to opaque type - unresolved type", | |
| 3588 | container_kind_name, | |
| 3589 | is_anonymous ? "(anon)" : buf_ptr(bare_name)); | |
| 3590 | ||
| 3591 | return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); | |
| 3592 | } | |
| 3593 | ||
| 3594 | struct_node->data.container_decl.fields.items[i] = field_node; | |
| 3595 | } | |
| 3596 | ||
| 3597 | if (is_anonymous) { | |
| 3598 | return struct_node; | |
| 3599 | } else { | |
| 3600 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 3601 | add_global_var(c, full_type_name, struct_node); | |
| 3602 | return trans_create_node_symbol(c, full_type_name); | |
| 3603 | } | |
| 3604 | } | |
| 3605 | ||
| 3606 | static AstNode *trans_ap_value(Context *c, APValue *ap_value, QualType qt, const SourceLocation &source_loc) { | |
| 3607 | switch (ap_value->getKind()) { | |
| 3608 | case APValue::Int: | |
| 3609 | return trans_create_node_apint(c, ap_value->getInt()); | |
| 3610 | case APValue::Uninitialized: | |
| 3611 | return trans_create_node(c, NodeTypeUndefinedLiteral); | |
| 3612 | case APValue::Array: { | |
| 3613 | emit_warning(c, source_loc, "TODO add a test case for this code"); | |
| 3614 | ||
| 3615 | unsigned init_count = ap_value->getArrayInitializedElts(); | |
| 3616 | unsigned all_count = ap_value->getArraySize(); | |
| 3617 | unsigned leftover_count = all_count - init_count; | |
| 3618 | AstNode *init_node = trans_create_node(c, NodeTypeContainerInitExpr); | |
| 3619 | AstNode *arr_type_node = trans_qual_type(c, qt, source_loc); | |
| 3620 | init_node->data.container_init_expr.type = arr_type_node; | |
| 3621 | init_node->data.container_init_expr.kind = ContainerInitKindArray; | |
| 3622 | ||
| 3623 | QualType child_qt = qt.getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType(); | |
| 3624 | ||
| 3625 | for (size_t i = 0; i < init_count; i += 1) { | |
| 3626 | APValue &elem_ap_val = ap_value->getArrayInitializedElt(i); | |
| 3627 | AstNode *elem_node = trans_ap_value(c, &elem_ap_val, child_qt, source_loc); | |
| 3628 | if (elem_node == nullptr) | |
| 3629 | return nullptr; | |
| 3630 | init_node->data.container_init_expr.entries.append(elem_node); | |
| 3631 | } | |
| 3632 | if (leftover_count == 0) { | |
| 3633 | return init_node; | |
| 3634 | } | |
| 3635 | ||
| 3636 | APValue &filler_ap_val = ap_value->getArrayFiller(); | |
| 3637 | AstNode *filler_node = trans_ap_value(c, &filler_ap_val, child_qt, source_loc); | |
| 3638 | if (filler_node == nullptr) | |
| 3639 | return nullptr; | |
| 3640 | ||
| 3641 | AstNode *filler_arr_1 = trans_create_node(c, NodeTypeContainerInitExpr); | |
| 3642 | init_node->data.container_init_expr.type = arr_type_node; | |
| 3643 | init_node->data.container_init_expr.kind = ContainerInitKindArray; | |
| 3644 | init_node->data.container_init_expr.entries.append(filler_node); | |
| 3645 | ||
| 3646 | AstNode *rhs_node; | |
| 3647 | if (leftover_count == 1) { | |
| 3648 | rhs_node = filler_arr_1; | |
| 3649 | } else { | |
| 3650 | AstNode *amt_node = trans_create_node_unsigned(c, leftover_count); | |
| 3651 | rhs_node = trans_create_node_bin_op(c, filler_arr_1, BinOpTypeArrayMult, amt_node); | |
| 3652 | } | |
| 3653 | ||
| 3654 | return trans_create_node_bin_op(c, init_node, BinOpTypeArrayCat, rhs_node); | |
| 3655 | } | |
| 3656 | case APValue::LValue: { | |
| 3657 | const APValue::LValueBase lval_base = ap_value->getLValueBase(); | |
| 3658 | if (const Expr *expr = lval_base.dyn_cast<const Expr *>()) { | |
| 3659 | return trans_expr(c, ResultUsedYes, &c->global_scope->base, expr, TransRValue); | |
| 3660 | } | |
| 3661 | //const ValueDecl *value_decl = lval_base.get<const ValueDecl *>(); | |
| 3662 | emit_warning(c, source_loc, "TODO handle initializer LValue ValueDecl"); | |
| 3663 | return nullptr; | |
| 3664 | } | |
| 3665 | case APValue::Float: | |
| 3666 | emit_warning(c, source_loc, "unsupported initializer value kind: Float"); | |
| 3667 | return nullptr; | |
| 3668 | case APValue::ComplexInt: | |
| 3669 | emit_warning(c, source_loc, "unsupported initializer value kind: ComplexInt"); | |
| 3670 | return nullptr; | |
| 3671 | case APValue::ComplexFloat: | |
| 3672 | emit_warning(c, source_loc, "unsupported initializer value kind: ComplexFloat"); | |
| 3673 | return nullptr; | |
| 3674 | case APValue::Vector: | |
| 3675 | emit_warning(c, source_loc, "unsupported initializer value kind: Vector"); | |
| 3676 | return nullptr; | |
| 3677 | case APValue::Struct: | |
| 3678 | emit_warning(c, source_loc, "unsupported initializer value kind: Struct"); | |
| 3679 | return nullptr; | |
| 3680 | case APValue::Union: | |
| 3681 | emit_warning(c, source_loc, "unsupported initializer value kind: Union"); | |
| 3682 | return nullptr; | |
| 3683 | case APValue::MemberPointer: | |
| 3684 | emit_warning(c, source_loc, "unsupported initializer value kind: MemberPointer"); | |
| 3685 | return nullptr; | |
| 3686 | case APValue::AddrLabelDiff: | |
| 3687 | emit_warning(c, source_loc, "unsupported initializer value kind: AddrLabelDiff"); | |
| 3688 | return nullptr; | |
| 3689 | } | |
| 3690 | zig_unreachable(); | |
| 3691 | } | |
| 3692 | ||
| 3693 | static void visit_var_decl(Context *c, const VarDecl *var_decl) { | |
| 3694 | Buf *name = buf_create_from_str(decl_name(var_decl)); | |
| 3695 | ||
| 3696 | switch (var_decl->getTLSKind()) { | |
| 3697 | case VarDecl::TLS_None: | |
| 3698 | break; | |
| 3699 | case VarDecl::TLS_Static: | |
| 3700 | emit_warning(c, var_decl->getLocation(), | |
| 3701 | "ignoring variable '%s' - static thread local storage", buf_ptr(name)); | |
| 3702 | return; | |
| 3703 | case VarDecl::TLS_Dynamic: | |
| 3704 | emit_warning(c, var_decl->getLocation(), | |
| 3705 | "ignoring variable '%s' - dynamic thread local storage", buf_ptr(name)); | |
| 3706 | return; | |
| 3707 | } | |
| 3708 | ||
| 3709 | QualType qt = var_decl->getType(); | |
| 3710 | AstNode *var_type = trans_qual_type(c, qt, var_decl->getLocation()); | |
| 3711 | if (var_type == nullptr) { | |
| 3712 | emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - unresolved type", buf_ptr(name)); | |
| 3713 | return; | |
| 3714 | } | |
| 3715 | ||
| 3716 | bool is_extern = var_decl->hasExternalStorage(); | |
| 3717 | bool is_static = var_decl->isFileVarDecl(); | |
| 3718 | bool is_const = qt.isConstQualified(); | |
| 3719 | ||
| 3720 | if (is_static && !is_extern) { | |
| 3721 | AstNode *init_node; | |
| 3722 | if (var_decl->hasInit()) { | |
| 3723 | APValue *ap_value = var_decl->evaluateValue(); | |
| 3724 | if (ap_value == nullptr) { | |
| 3725 | emit_warning(c, var_decl->getLocation(), | |
| 3726 | "ignoring variable '%s' - unable to evaluate initializer", buf_ptr(name)); | |
| 3727 | return; | |
| 3728 | } | |
| 3729 | init_node = trans_ap_value(c, ap_value, qt, var_decl->getLocation()); | |
| 3730 | if (init_node == nullptr) | |
| 3731 | return; | |
| 3732 | } else { | |
| 3733 | init_node = trans_create_node(c, NodeTypeUndefinedLiteral); | |
| 3734 | } | |
| 3735 | ||
| 3736 | AstNode *var_node = trans_create_node_var_decl_global(c, is_const, name, var_type, init_node); | |
| 3737 | add_top_level_decl(c, name, var_node); | |
| 3738 | return; | |
| 3739 | } | |
| 3740 | ||
| 3741 | if (is_extern) { | |
| 3742 | AstNode *var_node = trans_create_node_var_decl_global(c, is_const, name, var_type, nullptr); | |
| 3743 | var_node->data.variable_declaration.is_extern = true; | |
| 3744 | add_top_level_decl(c, name, var_node); | |
| 3745 | return; | |
| 3746 | } | |
| 3747 | ||
| 3748 | emit_warning(c, var_decl->getLocation(), | |
| 3749 | "ignoring variable '%s' - non-extern, non-static variable", buf_ptr(name)); | |
| 3750 | return; | |
| 3751 | } | |
| 3752 | ||
| 3753 | static bool decl_visitor(void *context, const Decl *decl) { | |
| 3754 | Context *c = (Context*)context; | |
| 3755 | ||
| 3756 | switch (decl->getKind()) { | |
| 3757 | case Decl::Function: | |
| 3758 | visit_fn_decl(c, static_cast<const FunctionDecl*>(decl)); | |
| 3759 | break; | |
| 3760 | case Decl::Typedef: | |
| 3761 | resolve_typedef_decl(c, static_cast<const TypedefNameDecl *>(decl)); | |
| 3762 | break; | |
| 3763 | case Decl::Enum: | |
| 3764 | resolve_enum_decl(c, static_cast<const EnumDecl *>(decl)); | |
| 3765 | break; | |
| 3766 | case Decl::Record: | |
| 3767 | resolve_record_decl(c, static_cast<const RecordDecl *>(decl)); | |
| 3768 | break; | |
| 3769 | case Decl::Var: | |
| 3770 | visit_var_decl(c, static_cast<const VarDecl *>(decl)); | |
| 3771 | break; | |
| 3772 | default: | |
| 3773 | emit_warning(c, decl->getLocation(), "ignoring %s decl", decl->getDeclKindName()); | |
| 3774 | } | |
| 3775 | ||
| 3776 | return true; | |
| 3777 | } | |
| 3778 | ||
| 3779 | static bool name_exists_global(Context *c, Buf *name) { | |
| 3780 | return get_global(c, name) != nullptr; | |
| 3781 | } | |
| 3782 | ||
| 3783 | static bool name_exists_scope(Context *c, Buf *name, TransScope *scope) { | |
| 3784 | while (scope != nullptr) { | |
| 3785 | if (scope->id == TransScopeIdVar) { | |
| 3786 | TransScopeVar *var_scope = (TransScopeVar *)scope; | |
| 3787 | if (buf_eql_buf(name, var_scope->zig_name)) { | |
| 3788 | return true; | |
| 3789 | } | |
| 3790 | } | |
| 3791 | scope = scope->parent; | |
| 3792 | } | |
| 3793 | return name_exists_global(c, name); | |
| 3794 | } | |
| 3795 | ||
| 3796 | static Buf *get_unique_name(Context *c, Buf *name, TransScope *scope) { | |
| 3797 | Buf *proposed_name = name; | |
| 3798 | int count = 0; | |
| 3799 | while (name_exists_scope(c, proposed_name, scope)) { | |
| 3800 | if (proposed_name == name) { | |
| 3801 | proposed_name = buf_alloc(); | |
| 3802 | } | |
| 3803 | buf_resize(proposed_name, 0); | |
| 3804 | buf_appendf(proposed_name, "%s_%d", buf_ptr(name), count); | |
| 3805 | count += 1; | |
| 3806 | } | |
| 3807 | return proposed_name; | |
| 3808 | } | |
| 3809 | ||
| 3810 | static TransScopeRoot *trans_scope_root_create(Context *c) { | |
| 3811 | TransScopeRoot *result = allocate<TransScopeRoot>(1); | |
| 3812 | result->base.id = TransScopeIdRoot; | |
| 3813 | return result; | |
| 3814 | } | |
| 3815 | ||
| 3816 | static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope) { | |
| 3817 | TransScopeWhile *result = allocate<TransScopeWhile>(1); | |
| 3818 | result->base.id = TransScopeIdWhile; | |
| 3819 | result->base.parent = parent_scope; | |
| 3820 | result->node = trans_create_node(c, NodeTypeWhileExpr); | |
| 3821 | return result; | |
| 3822 | } | |
| 3823 | ||
| 3824 | static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope) { | |
| 3825 | TransScopeBlock *result = allocate<TransScopeBlock>(1); | |
| 3826 | result->base.id = TransScopeIdBlock; | |
| 3827 | result->base.parent = parent_scope; | |
| 3828 | result->node = trans_create_node(c, NodeTypeBlock); | |
| 3829 | return result; | |
| 3830 | } | |
| 3831 | ||
| 3832 | static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name) { | |
| 3833 | TransScopeVar *result = allocate<TransScopeVar>(1); | |
| 3834 | result->base.id = TransScopeIdVar; | |
| 3835 | result->base.parent = parent_scope; | |
| 3836 | result->c_name = wanted_name; | |
| 3837 | result->zig_name = get_unique_name(c, wanted_name, parent_scope); | |
| 3838 | return result; | |
| 3839 | } | |
| 3840 | ||
| 3841 | static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope) { | |
| 3842 | TransScopeSwitch *result = allocate<TransScopeSwitch>(1); | |
| 3843 | result->base.id = TransScopeIdSwitch; | |
| 3844 | result->base.parent = parent_scope; | |
| 3845 | result->switch_node = trans_create_node(c, NodeTypeSwitchExpr); | |
| 3846 | return result; | |
| 3847 | } | |
| 3848 | ||
| 3849 | static TransScopeBlock *trans_scope_block_find(TransScope *scope) { | |
| 3850 | while (scope != nullptr) { | |
| 3851 | if (scope->id == TransScopeIdBlock) { | |
| 3852 | return (TransScopeBlock *)scope; | |
| 3853 | } | |
| 3854 | scope = scope->parent; | |
| 3855 | } | |
| 3856 | return nullptr; | |
| 3857 | } | |
| 3858 | ||
| 3859 | static TransScopeSwitch *trans_scope_switch_find(TransScope *scope) { | |
| 3860 | while (scope != nullptr) { | |
| 3861 | if (scope->id == TransScopeIdSwitch) { | |
| 3862 | return (TransScopeSwitch *)scope; | |
| 3863 | } | |
| 3864 | scope = scope->parent; | |
| 3865 | } | |
| 3866 | return nullptr; | |
| 3867 | } | |
| 3868 | ||
| 3869 | static void render_aliases(Context *c) { | |
| 3870 | for (size_t i = 0; i < c->aliases.length; i += 1) { | |
| 3871 | Alias *alias = &c->aliases.at(i); | |
| 3872 | if (name_exists_global(c, alias->new_name)) | |
| 3873 | continue; | |
| 3874 | ||
| 3875 | add_global_var(c, alias->new_name, trans_create_node_symbol(c, alias->canon_name)); | |
| 3876 | } | |
| 3877 | } | |
| 3878 | ||
| 3879 | static AstNode *trans_lookup_ast_container_typeof(Context *c, AstNode *ref_node); | |
| 3880 | ||
| 3881 | static AstNode *trans_lookup_ast_container(Context *c, AstNode *type_node) { | |
| 3882 | if (type_node == nullptr) { | |
| 3883 | return nullptr; | |
| 3884 | } else if (type_node->type == NodeTypeContainerDecl) { | |
| 3885 | return type_node; | |
| 3886 | } else if (type_node->type == NodeTypePrefixOpExpr) { | |
| 3887 | return type_node; | |
| 3888 | } else if (type_node->type == NodeTypeSymbol) { | |
| 3889 | AstNode *existing_node = get_global(c, type_node->data.symbol_expr.symbol); | |
| 3890 | if (existing_node == nullptr) | |
| 3891 | return nullptr; | |
| 3892 | if (existing_node->type != NodeTypeVariableDeclaration) | |
| 3893 | return nullptr; | |
| 3894 | return trans_lookup_ast_container(c, existing_node->data.variable_declaration.expr); | |
| 3895 | } else if (type_node->type == NodeTypeFieldAccessExpr) { | |
| 3896 | AstNode *container_node = trans_lookup_ast_container_typeof(c, type_node->data.field_access_expr.struct_expr); | |
| 3897 | if (container_node == nullptr) | |
| 3898 | return nullptr; | |
| 3899 | if (container_node->type != NodeTypeContainerDecl) | |
| 3900 | return container_node; | |
| 3901 | ||
| 3902 | for (size_t i = 0; i < container_node->data.container_decl.fields.length; i += 1) { | |
| 3903 | AstNode *field_node = container_node->data.container_decl.fields.items[i]; | |
| 3904 | if (buf_eql_buf(field_node->data.struct_field.name, type_node->data.field_access_expr.field_name)) { | |
| 3905 | return trans_lookup_ast_container(c, field_node->data.struct_field.type); | |
| 3906 | } | |
| 3907 | } | |
| 3908 | return nullptr; | |
| 3909 | } else { | |
| 3910 | return nullptr; | |
| 3911 | } | |
| 3912 | } | |
| 3913 | ||
| 3914 | static AstNode *trans_lookup_ast_container_typeof(Context *c, AstNode *ref_node) { | |
| 3915 | if (ref_node->type == NodeTypeSymbol) { | |
| 3916 | AstNode *existing_node = get_global(c, ref_node->data.symbol_expr.symbol); | |
| 3917 | if (existing_node == nullptr) | |
| 3918 | return nullptr; | |
| 3919 | if (existing_node->type != NodeTypeVariableDeclaration) | |
| 3920 | return nullptr; | |
| 3921 | return trans_lookup_ast_container(c, existing_node->data.variable_declaration.type); | |
| 3922 | } else if (ref_node->type == NodeTypeFieldAccessExpr) { | |
| 3923 | AstNode *container_node = trans_lookup_ast_container_typeof(c, ref_node->data.field_access_expr.struct_expr); | |
| 3924 | if (container_node == nullptr) | |
| 3925 | return nullptr; | |
| 3926 | if (container_node->type != NodeTypeContainerDecl) | |
| 3927 | return container_node; | |
| 3928 | for (size_t i = 0; i < container_node->data.container_decl.fields.length; i += 1) { | |
| 3929 | AstNode *field_node = container_node->data.container_decl.fields.items[i]; | |
| 3930 | if (buf_eql_buf(field_node->data.struct_field.name, ref_node->data.field_access_expr.field_name)) { | |
| 3931 | return trans_lookup_ast_container(c, field_node->data.struct_field.type); | |
| 3932 | } | |
| 3933 | } | |
| 3934 | return nullptr; | |
| 3935 | } else { | |
| 3936 | return nullptr; | |
| 3937 | } | |
| 3938 | } | |
| 3939 | ||
| 3940 | static AstNode *trans_lookup_ast_maybe_fn(Context *c, AstNode *ref_node) { | |
| 3941 | AstNode *prefix_node = trans_lookup_ast_container_typeof(c, ref_node); | |
| 3942 | if (prefix_node == nullptr) | |
| 3943 | return nullptr; | |
| 3944 | if (prefix_node->type != NodeTypePrefixOpExpr) | |
| 3945 | return nullptr; | |
| 3946 | if (prefix_node->data.prefix_op_expr.prefix_op != PrefixOpMaybe) | |
| 3947 | return nullptr; | |
| 3948 | ||
| 3949 | AstNode *fn_proto_node = prefix_node->data.prefix_op_expr.primary_expr; | |
| 3950 | if (fn_proto_node->type != NodeTypeFnProto) | |
| 3951 | return nullptr; | |
| 3952 | ||
| 3953 | return fn_proto_node; | |
| 3954 | } | |
| 3955 | ||
| 3956 | static void render_macros(Context *c) { | |
| 3957 | auto it = c->macro_table.entry_iterator(); | |
| 3958 | for (;;) { | |
| 3959 | auto *entry = it.next(); | |
| 3960 | if (!entry) | |
| 3961 | break; | |
| 3962 | ||
| 3963 | AstNode *proto_node; | |
| 3964 | AstNode *value_node = entry->value; | |
| 3965 | if (value_node->type == NodeTypeFnDef) { | |
| 3966 | add_top_level_decl(c, value_node->data.fn_def.fn_proto->data.fn_proto.name, value_node); | |
| 3967 | } else if ((proto_node = trans_lookup_ast_maybe_fn(c, value_node))) { | |
| 3968 | // If a macro aliases a global variable which is a function pointer, we conclude that | |
| 3969 | // the macro is intended to represent a function that assumes the function pointer | |
| 3970 | // variable is non-null and calls it. | |
| 3971 | AstNode *inline_fn_node = trans_create_node_inline_fn(c, entry->key, value_node, proto_node); | |
| 3972 | add_top_level_decl(c, entry->key, inline_fn_node); | |
| 3973 | } else { | |
| 3974 | add_global_var(c, entry->key, value_node); | |
| 3975 | } | |
| 3976 | } | |
| 3977 | } | |
| 3978 | ||
| 3979 | static AstNode *parse_ctok_num_lit(Context *c, CTokenize *ctok, size_t *tok_i, bool negate) { | |
| 3980 | CTok *tok = &ctok->tokens.at(*tok_i); | |
| 3981 | if (tok->id == CTokIdNumLitInt) { | |
| 3982 | *tok_i += 1; | |
| 3983 | switch (tok->data.num_lit_int.suffix) { | |
| 3984 | case CNumLitSuffixNone: | |
| 3985 | return trans_create_node_unsigned_negative(c, tok->data.num_lit_int.x, negate); | |
| 3986 | case CNumLitSuffixL: | |
| 3987 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_long"); | |
| 3988 | case CNumLitSuffixU: | |
| 3989 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_uint"); | |
| 3990 | case CNumLitSuffixLU: | |
| 3991 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_ulong"); | |
| 3992 | case CNumLitSuffixLL: | |
| 3993 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_longlong"); | |
| 3994 | case CNumLitSuffixLLU: | |
| 3995 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_ulonglong"); | |
| 3996 | } | |
| 3997 | zig_unreachable(); | |
| 3998 | } else if (tok->id == CTokIdNumLitFloat) { | |
| 3999 | *tok_i += 1; | |
| 4000 | double value = negate ? -tok->data.num_lit_float : tok->data.num_lit_float; | |
| 4001 | return trans_create_node_float_lit(c, value); | |
| 4002 | } | |
| 4003 | return nullptr; | |
| 4004 | } | |
| 4005 | ||
| 4006 | static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) { | |
| 4007 | CTok *tok = &ctok->tokens.at(*tok_i); | |
| 4008 | switch (tok->id) { | |
| 4009 | case CTokIdCharLit: | |
| 4010 | *tok_i += 1; | |
| 4011 | return trans_create_node_unsigned(c, tok->data.char_lit); | |
| 4012 | case CTokIdStrLit: | |
| 4013 | *tok_i += 1; | |
| 4014 | return trans_create_node_str_lit_c(c, buf_create_from_buf(&tok->data.str_lit)); | |
| 4015 | case CTokIdMinus: | |
| 4016 | *tok_i += 1; | |
| 4017 | return parse_ctok_num_lit(c, ctok, tok_i, true); | |
| 4018 | case CTokIdNumLitInt: | |
| 4019 | case CTokIdNumLitFloat: | |
| 4020 | return parse_ctok_num_lit(c, ctok, tok_i, false); | |
| 4021 | case CTokIdSymbol: | |
| 4022 | { | |
| 4023 | bool need_symbol = false; | |
| 4024 | CTokId curr_id = CTokIdSymbol; | |
| 4025 | Buf *symbol_name = buf_create_from_buf(&tok->data.symbol); | |
| 4026 | AstNode *curr_node = trans_create_node_symbol(c, symbol_name); | |
| 4027 | AstNode *parent_node = curr_node; | |
| 4028 | do { | |
| 4029 | *tok_i += 1; | |
| 4030 | CTok* curr_tok = &ctok->tokens.at(*tok_i); | |
| 4031 | if (need_symbol) { | |
| 4032 | if (curr_tok->id == CTokIdSymbol) { | |
| 4033 | symbol_name = buf_create_from_buf(&curr_tok->data.symbol); | |
| 4034 | curr_node = trans_create_node_field_access(c, parent_node, buf_create_from_buf(symbol_name)); | |
| 4035 | parent_node = curr_node; | |
| 4036 | need_symbol = false; | |
| 4037 | } else { | |
| 4038 | return nullptr; | |
| 4039 | } | |
| 4040 | } else { | |
| 4041 | if (curr_tok->id == CTokIdDot) { | |
| 4042 | need_symbol = true; | |
| 4043 | continue; | |
| 4044 | } else { | |
| 4045 | break; | |
| 4046 | } | |
| 4047 | } | |
| 4048 | } while (curr_id != CTokIdEOF); | |
| 4049 | return curr_node; | |
| 4050 | } | |
| 4051 | case CTokIdLParen: | |
| 4052 | { | |
| 4053 | *tok_i += 1; | |
| 4054 | AstNode *inner_node = parse_ctok(c, ctok, tok_i); | |
| 4055 | ||
| 4056 | CTok *next_tok = &ctok->tokens.at(*tok_i); | |
| 4057 | if (next_tok->id != CTokIdRParen) { | |
| 4058 | return nullptr; | |
| 4059 | } | |
| 4060 | *tok_i += 1; | |
| 4061 | return inner_node; | |
| 4062 | } | |
| 4063 | case CTokIdDot: | |
| 4064 | case CTokIdEOF: | |
| 4065 | case CTokIdRParen: | |
| 4066 | // not able to make sense of this | |
| 4067 | return nullptr; | |
| 4068 | } | |
| 4069 | zig_unreachable(); | |
| 4070 | } | |
| 4071 | ||
| 4072 | static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) { | |
| 4073 | tokenize_c_macro(ctok, (const uint8_t *)char_ptr); | |
| 4074 | ||
| 4075 | if (ctok->error) { | |
| 4076 | return; | |
| 4077 | } | |
| 4078 | ||
| 4079 | size_t tok_i = 0; | |
| 4080 | CTok *name_tok = &ctok->tokens.at(tok_i); | |
| 4081 | assert(name_tok->id == CTokIdSymbol && buf_eql_buf(&name_tok->data.symbol, name)); | |
| 4082 | tok_i += 1; | |
| 4083 | ||
| 4084 | AstNode *result_node = parse_ctok(c, ctok, &tok_i); | |
| 4085 | if (result_node == nullptr) { | |
| 4086 | return; | |
| 4087 | } | |
| 4088 | CTok *eof_tok = &ctok->tokens.at(tok_i); | |
| 4089 | if (eof_tok->id != CTokIdEOF) { | |
| 4090 | return; | |
| 4091 | } | |
| 4092 | if (result_node->type == NodeTypeSymbol) { | |
| 4093 | // if it equals itself, ignore. for example, from stdio.h: | |
| 4094 | // #define stdin stdin | |
| 4095 | Buf *symbol_name = result_node->data.symbol_expr.symbol; | |
| 4096 | if (buf_eql_buf(name, symbol_name)) { | |
| 4097 | return; | |
| 4098 | } | |
| 4099 | } | |
| 4100 | c->macro_table.put(name, result_node); | |
| 4101 | } | |
| 4102 | ||
| 4103 | static void process_preprocessor_entities(Context *c, ASTUnit &unit) { | |
| 4104 | CTokenize ctok = {{0}}; | |
| 4105 | ||
| 4106 | // TODO if we see #undef, delete it from the table | |
| 4107 | ||
| 4108 | for (PreprocessedEntity *entity : unit.getLocalPreprocessingEntities()) { | |
| 4109 | switch (entity->getKind()) { | |
| 4110 | case PreprocessedEntity::InvalidKind: | |
| 4111 | case PreprocessedEntity::InclusionDirectiveKind: | |
| 4112 | case PreprocessedEntity::MacroExpansionKind: | |
| 4113 | continue; | |
| 4114 | case PreprocessedEntity::MacroDefinitionKind: | |
| 4115 | { | |
| 4116 | MacroDefinitionRecord *macro = static_cast<MacroDefinitionRecord *>(entity); | |
| 4117 | const char *raw_name = macro->getName()->getNameStart(); | |
| 4118 | SourceRange range = macro->getSourceRange(); | |
| 4119 | SourceLocation begin_loc = range.getBegin(); | |
| 4120 | SourceLocation end_loc = range.getEnd(); | |
| 4121 | ||
| 4122 | if (begin_loc == end_loc) { | |
| 4123 | // this means it is a macro without a value | |
| 4124 | // we don't care about such things | |
| 4125 | continue; | |
| 4126 | } | |
| 4127 | Buf *name = buf_create_from_str(raw_name); | |
| 4128 | if (name_exists_global(c, name)) { | |
| 4129 | continue; | |
| 4130 | } | |
| 4131 | ||
| 4132 | const char *begin_c = c->source_manager->getCharacterData(begin_loc); | |
| 4133 | process_macro(c, &ctok, name, begin_c); | |
| 4134 | } | |
| 4135 | } | |
| 4136 | } | |
| 4137 | } | |
| 4138 | ||
| 4139 | int parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *source, | |
| 4140 | CodeGen *codegen, AstNode *source_node) | |
| 4141 | { | |
| 4142 | int err; | |
| 4143 | Buf tmp_file_path = BUF_INIT; | |
| 4144 | if ((err = os_buf_to_tmp_file(source, buf_create_from_str(".h"), &tmp_file_path))) { | |
| 4145 | return err; | |
| 4146 | } | |
| 4147 | ||
| 4148 | err = parse_h_file(import, errors, buf_ptr(&tmp_file_path), codegen, source_node); | |
| 4149 | ||
| 4150 | os_delete_file(&tmp_file_path); | |
| 4151 | ||
| 4152 | return err; | |
| 4153 | } | |
| 4154 | ||
| 4155 | int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const char *target_file, | |
| 4156 | CodeGen *codegen, AstNode *source_node) | |
| 4157 | { | |
| 4158 | Context context = {0}; | |
| 4159 | Context *c = &context; | |
| 4160 | c->warnings_on = codegen->verbose_cimport; | |
| 4161 | c->import = import; | |
| 4162 | c->errors = errors; | |
| 4163 | if (buf_ends_with_str(buf_create_from_str(target_file), ".h")) { | |
| 4164 | c->visib_mod = VisibModPub; | |
| 4165 | c->export_visib_mod = VisibModPub; | |
| 4166 | } else { | |
| 4167 | c->visib_mod = VisibModPub; | |
| 4168 | c->export_visib_mod = VisibModExport; | |
| 4169 | } | |
| 4170 | c->decl_table.init(8); | |
| 4171 | c->macro_table.init(8); | |
| 4172 | c->global_table.init(8); | |
| 4173 | c->ptr_params.init(8); | |
| 4174 | c->codegen = codegen; | |
| 4175 | c->source_node = source_node; | |
| 4176 | c->global_scope = trans_scope_root_create(c); | |
| 4177 | ||
| 4178 | ZigList<const char *> clang_argv = {0}; | |
| 4179 | ||
| 4180 | clang_argv.append("-x"); | |
| 4181 | clang_argv.append("c"); | |
| 4182 | ||
| 4183 | if (c->codegen->is_native_target) { | |
| 4184 | char *ZIG_PARSEC_CFLAGS = getenv("ZIG_NATIVE_PARSEC_CFLAGS"); | |
| 4185 | if (ZIG_PARSEC_CFLAGS) { | |
| 4186 | Buf tmp_buf = BUF_INIT; | |
| 4187 | char *start = ZIG_PARSEC_CFLAGS; | |
| 4188 | char *space = strstr(start, " "); | |
| 4189 | while (space) { | |
| 4190 | if (space - start > 0) { | |
| 4191 | buf_init_from_mem(&tmp_buf, start, space - start); | |
| 4192 | clang_argv.append(buf_ptr(buf_create_from_buf(&tmp_buf))); | |
| 4193 | } | |
| 4194 | start = space + 1; | |
| 4195 | space = strstr(start, " "); | |
| 4196 | } | |
| 4197 | buf_init_from_str(&tmp_buf, start); | |
| 4198 | clang_argv.append(buf_ptr(buf_create_from_buf(&tmp_buf))); | |
| 4199 | } | |
| 4200 | } | |
| 4201 | ||
| 4202 | clang_argv.append("-isystem"); | |
| 4203 | clang_argv.append(buf_ptr(codegen->zig_c_headers_dir)); | |
| 4204 | ||
| 4205 | clang_argv.append("-isystem"); | |
| 4206 | clang_argv.append(buf_ptr(codegen->libc_include_dir)); | |
| 4207 | ||
| 4208 | // windows c runtime requires -D_DEBUG if using debug libraries | |
| 4209 | if (codegen->build_mode == BuildModeDebug) { | |
| 4210 | clang_argv.append("-D_DEBUG"); | |
| 4211 | } | |
| 4212 | ||
| 4213 | for (size_t i = 0; i < codegen->clang_argv_len; i += 1) { | |
| 4214 | clang_argv.append(codegen->clang_argv[i]); | |
| 4215 | } | |
| 4216 | ||
| 4217 | // we don't need spell checking and it slows things down | |
| 4218 | clang_argv.append("-fno-spell-checking"); | |
| 4219 | ||
| 4220 | // this gives us access to preprocessing entities, presumably at | |
| 4221 | // the cost of performance | |
| 4222 | clang_argv.append("-Xclang"); | |
| 4223 | clang_argv.append("-detailed-preprocessing-record"); | |
| 4224 | ||
| 4225 | if (!c->codegen->is_native_target) { | |
| 4226 | clang_argv.append("-target"); | |
| 4227 | clang_argv.append(buf_ptr(&c->codegen->triple_str)); | |
| 4228 | } | |
| 4229 | ||
| 4230 | clang_argv.append(target_file); | |
| 4231 | ||
| 4232 | // to make the [start...end] argument work | |
| 4233 | clang_argv.append(nullptr); | |
| 4234 | ||
| 4235 | IntrusiveRefCntPtr<DiagnosticsEngine> diags(CompilerInstance::createDiagnostics(new DiagnosticOptions)); | |
| 4236 | ||
| 4237 | std::shared_ptr<PCHContainerOperations> pch_container_ops = std::make_shared<PCHContainerOperations>(); | |
| 4238 | ||
| 4239 | bool skip_function_bodies = false; | |
| 4240 | bool only_local_decls = true; | |
| 4241 | bool capture_diagnostics = true; | |
| 4242 | bool user_files_are_volatile = true; | |
| 4243 | bool allow_pch_with_compiler_errors = false; | |
| 4244 | bool single_file_parse = false; | |
| 4245 | bool for_serialization = false; | |
| 4246 | const char *resources_path = buf_ptr(codegen->zig_c_headers_dir); | |
| 4247 | std::unique_ptr<ASTUnit> err_unit; | |
| 4248 | std::unique_ptr<ASTUnit> ast_unit(ASTUnit::LoadFromCommandLine( | |
| 4249 | &clang_argv.at(0), &clang_argv.last(), | |
| 4250 | pch_container_ops, diags, resources_path, | |
| 4251 | only_local_decls, capture_diagnostics, None, true, 0, TU_Complete, | |
| 4252 | false, false, allow_pch_with_compiler_errors, skip_function_bodies, | |
| 4253 | single_file_parse, user_files_are_volatile, for_serialization, None, &err_unit, | |
| 4254 | nullptr)); | |
| 4255 | ||
| 4256 | // Early failures in LoadFromCommandLine may return with ErrUnit unset. | |
| 4257 | if (!ast_unit && !err_unit) { | |
| 4258 | return ErrorFileSystem; | |
| 4259 | } | |
| 4260 | ||
| 4261 | if (diags->getClient()->getNumErrors() > 0) { | |
| 4262 | if (ast_unit) { | |
| 4263 | err_unit = std::move(ast_unit); | |
| 4264 | } | |
| 4265 | ||
| 4266 | for (ASTUnit::stored_diag_iterator it = err_unit->stored_diag_begin(), | |
| 4267 | it_end = err_unit->stored_diag_end(); | |
| 4268 | it != it_end; ++it) | |
| 4269 | { | |
| 4270 | switch (it->getLevel()) { | |
| 4271 | case DiagnosticsEngine::Ignored: | |
| 4272 | case DiagnosticsEngine::Note: | |
| 4273 | case DiagnosticsEngine::Remark: | |
| 4274 | case DiagnosticsEngine::Warning: | |
| 4275 | continue; | |
| 4276 | case DiagnosticsEngine::Error: | |
| 4277 | case DiagnosticsEngine::Fatal: | |
| 4278 | break; | |
| 4279 | } | |
| 4280 | StringRef msg_str_ref = it->getMessage(); | |
| 4281 | Buf *msg = string_ref_to_buf(msg_str_ref); | |
| 4282 | FullSourceLoc fsl = it->getLocation(); | |
| 4283 | if (fsl.hasManager()) { | |
| 4284 | FileID file_id = fsl.getFileID(); | |
| 4285 | StringRef filename = fsl.getManager().getFilename(fsl); | |
| 4286 | unsigned line = fsl.getSpellingLineNumber() - 1; | |
| 4287 | unsigned column = fsl.getSpellingColumnNumber() - 1; | |
| 4288 | unsigned offset = fsl.getManager().getFileOffset(fsl); | |
| 4289 | const char *source = (const char *)fsl.getManager().getBufferData(file_id).bytes_begin(); | |
| 4290 | Buf *path; | |
| 4291 | if (filename.empty()) { | |
| 4292 | path = buf_alloc(); | |
| 4293 | } else { | |
| 4294 | path = string_ref_to_buf(filename); | |
| 4295 | } | |
| 4296 | ||
| 4297 | ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg); | |
| 4298 | ||
| 4299 | c->errors->append(err_msg); | |
| 4300 | } else { | |
| 4301 | // NOTE the only known way this gets triggered right now is if you have a lot of errors | |
| 4302 | // clang emits "too many errors emitted, stopping now" | |
| 4303 | fprintf(stderr, "unexpected error from clang: %s\n", buf_ptr(msg)); | |
| 4304 | } | |
| 4305 | } | |
| 4306 | ||
| 4307 | return 0; | |
| 4308 | } | |
| 4309 | ||
| 4310 | c->ctx = &ast_unit->getASTContext(); | |
| 4311 | c->source_manager = &ast_unit->getSourceManager(); | |
| 4312 | c->root = trans_create_node(c, NodeTypeRoot); | |
| 4313 | ||
| 4314 | ast_unit->visitLocalTopLevelDecls(c, decl_visitor); | |
| 4315 | ||
| 4316 | process_preprocessor_entities(c, *ast_unit); | |
| 4317 | ||
| 4318 | render_macros(c); | |
| 4319 | render_aliases(c); | |
| 4320 | ||
| 4321 | import->root = c->root; | |
| 4322 | ||
| 4323 | return 0; | |
| 4324 | } |
src/translate_c.hpp created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | /* | |
| 2 | * Copyright (c) 2015 Andrew Kelley | |
| 3 | * | |
| 4 | * This file is part of zig, which is MIT licensed. | |
| 5 | * See http://opensource.org/licenses/MIT | |
| 6 | */ | |
| 7 | ||
| 8 | ||
| 9 | #ifndef ZIG_PARSEC_HPP | |
| 10 | #define ZIG_PARSEC_HPP | |
| 11 | ||
| 12 | #include "all_types.hpp" | |
| 13 | ||
| 14 | int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const char *target_file, | |
| 15 | CodeGen *codegen, AstNode *source_node); | |
| 16 | ||
| 17 | int parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *source, | |
| 18 | CodeGen *codegen, AstNode *source_node); | |
| 19 | ||
| 20 | #endif |
src/zig_llvm.cpp+4| ... | ... | @@ -403,6 +403,10 @@ unsigned ZigLLVMTag_DW_structure_type(void) { |
| 403 | 403 | return dwarf::DW_TAG_structure_type; |
| 404 | 404 | } |
| 405 | 405 | |
| 406 | unsigned ZigLLVMTag_DW_union_type(void) { | |
| 407 | return dwarf::DW_TAG_union_type; | |
| 408 | } | |
| 409 | ||
| 406 | 410 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) { |
| 407 | 411 | DIBuilder *di_builder = new DIBuilder(*unwrap(module), allow_unresolved); |
| 408 | 412 | return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder); |
src/zig_llvm.hpp+1| ... | ... | @@ -117,6 +117,7 @@ unsigned ZigLLVMEncoding_DW_ATE_signed_char(void); |
| 117 | 117 | unsigned ZigLLVMLang_DW_LANG_C99(void); |
| 118 | 118 | unsigned ZigLLVMTag_DW_variable(void); |
| 119 | 119 | unsigned ZigLLVMTag_DW_structure_type(void); |
| 120 | unsigned ZigLLVMTag_DW_union_type(void); | |
| 120 | 121 | |
| 121 | 122 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved); |
| 122 | 123 | void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module); |
std/base64.zig+432-133| ... | ... | @@ -1,186 +1,485 @@ |
| 1 | 1 | const assert = @import("debug.zig").assert; |
| 2 | 2 | const mem = @import("mem.zig"); |
| 3 | 3 | |
| 4 | pub const standard_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; | |
| 5 | ||
| 6 | pub fn encode(dest: []u8, source: []const u8) -> []u8 { | |
| 7 | return encodeWithAlphabet(dest, source, standard_alphabet); | |
| 8 | } | |
| 9 | ||
| 10 | /// invalid characters in source are allowed, but they cause the value of dest to be undefined. | |
| 11 | pub fn decode(dest: []u8, source: []const u8) -> []u8 { | |
| 12 | return decodeWithAlphabet(dest, source, standard_alphabet); | |
| 13 | } | |
| 14 | ||
| 15 | pub fn encodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8) -> []u8 { | |
| 16 | assert(alphabet.len == 65); | |
| 17 | assert(dest.len >= calcEncodedSize(source.len)); | |
| 18 | ||
| 19 | var i: usize = 0; | |
| 20 | var out_index: usize = 0; | |
| 21 | while (i + 2 < source.len) : (i += 3) { | |
| 22 | dest[out_index] = alphabet[(source[i] >> 2) & 0x3f]; | |
| 23 | out_index += 1; | |
| 24 | ||
| 25 | dest[out_index] = alphabet[((source[i] & 0x3) << 4) | | |
| 26 | ((source[i + 1] & 0xf0) >> 4)]; | |
| 27 | out_index += 1; | |
| 4 | pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
| 5 | pub const standard_pad_char = '='; | |
| 6 | pub const standard_encoder = Base64Encoder.init(standard_alphabet_chars, standard_pad_char); | |
| 7 | ||
| 8 | pub const Base64Encoder = struct { | |
| 9 | alphabet_chars: []const u8, | |
| 10 | pad_char: u8, | |
| 11 | ||
| 12 | /// a bunch of assertions, then simply pass the data right through. | |
| 13 | pub fn init(alphabet_chars: []const u8, pad_char: u8) -> Base64Encoder { | |
| 14 | assert(alphabet_chars.len == 64); | |
| 15 | var char_in_alphabet = []bool{false} ** 256; | |
| 16 | for (alphabet_chars) |c| { | |
| 17 | assert(!char_in_alphabet[c]); | |
| 18 | assert(c != pad_char); | |
| 19 | char_in_alphabet[c] = true; | |
| 20 | } | |
| 28 | 21 | |
| 29 | dest[out_index] = alphabet[((source[i + 1] & 0xf) << 2) | | |
| 30 | ((source[i + 2] & 0xc0) >> 6)]; | |
| 31 | out_index += 1; | |
| 22 | return Base64Encoder{ | |
| 23 | .alphabet_chars = alphabet_chars, | |
| 24 | .pad_char = pad_char, | |
| 25 | }; | |
| 26 | } | |
| 32 | 27 | |
| 33 | dest[out_index] = alphabet[source[i + 2] & 0x3f]; | |
| 34 | out_index += 1; | |
| 28 | /// ceil(source_len * 4/3) | |
| 29 | pub fn calcSize(source_len: usize) -> usize { | |
| 30 | return @divTrunc(source_len + 2, 3) * 4; | |
| 35 | 31 | } |
| 36 | 32 | |
| 37 | if (i < source.len) { | |
| 38 | dest[out_index] = alphabet[(source[i] >> 2) & 0x3f]; | |
| 39 | out_index += 1; | |
| 33 | /// dest.len must be what you get from ::calcSize. | |
| 34 | pub fn encode(encoder: &const Base64Encoder, dest: []u8, source: []const u8) { | |
| 35 | assert(dest.len == Base64Encoder.calcSize(source.len)); | |
| 40 | 36 | |
| 41 | if (i + 1 == source.len) { | |
| 42 | dest[out_index] = alphabet[(source[i] & 0x3) << 4]; | |
| 37 | var i: usize = 0; | |
| 38 | var out_index: usize = 0; | |
| 39 | while (i + 2 < source.len) : (i += 3) { | |
| 40 | dest[out_index] = encoder.alphabet_chars[(source[i] >> 2) & 0x3f]; | |
| 43 | 41 | out_index += 1; |
| 44 | 42 | |
| 45 | dest[out_index] = alphabet[64]; | |
| 46 | out_index += 1; | |
| 47 | } else { | |
| 48 | dest[out_index] = alphabet[((source[i] & 0x3) << 4) | | |
| 43 | dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) | | |
| 49 | 44 | ((source[i + 1] & 0xf0) >> 4)]; |
| 50 | 45 | out_index += 1; |
| 51 | 46 | |
| 52 | dest[out_index] = alphabet[(source[i + 1] & 0xf) << 2]; | |
| 47 | dest[out_index] = encoder.alphabet_chars[((source[i + 1] & 0xf) << 2) | | |
| 48 | ((source[i + 2] & 0xc0) >> 6)]; | |
| 49 | out_index += 1; | |
| 50 | ||
| 51 | dest[out_index] = encoder.alphabet_chars[source[i + 2] & 0x3f]; | |
| 53 | 52 | out_index += 1; |
| 54 | 53 | } |
| 55 | 54 | |
| 56 | dest[out_index] = alphabet[64]; | |
| 57 | out_index += 1; | |
| 58 | } | |
| 55 | if (i < source.len) { | |
| 56 | dest[out_index] = encoder.alphabet_chars[(source[i] >> 2) & 0x3f]; | |
| 57 | out_index += 1; | |
| 59 | 58 | |
| 60 | return dest[0..out_index]; | |
| 61 | } | |
| 59 | if (i + 1 == source.len) { | |
| 60 | dest[out_index] = encoder.alphabet_chars[(source[i] & 0x3) << 4]; | |
| 61 | out_index += 1; | |
| 62 | ||
| 63 | dest[out_index] = encoder.pad_char; | |
| 64 | out_index += 1; | |
| 65 | } else { | |
| 66 | dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) | | |
| 67 | ((source[i + 1] & 0xf0) >> 4)]; | |
| 68 | out_index += 1; | |
| 62 | 69 | |
| 63 | /// invalid characters in source are allowed, but they cause the value of dest to be undefined. | |
| 64 | pub fn decodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8) -> []u8 { | |
| 65 | assert(alphabet.len == 65); | |
| 70 | dest[out_index] = encoder.alphabet_chars[(source[i + 1] & 0xf) << 2]; | |
| 71 | out_index += 1; | |
| 72 | } | |
| 66 | 73 | |
| 67 | var ascii6 = []u8{64} ** 256; | |
| 68 | for (alphabet) |c, i| { | |
| 69 | ascii6[c] = u8(i); | |
| 74 | dest[out_index] = encoder.pad_char; | |
| 75 | out_index += 1; | |
| 76 | } | |
| 70 | 77 | } |
| 78 | }; | |
| 79 | ||
| 80 | pub const standard_decoder = Base64Decoder.init(standard_alphabet_chars, standard_pad_char); | |
| 81 | error InvalidPadding; | |
| 82 | error InvalidCharacter; | |
| 83 | ||
| 84 | pub const Base64Decoder = struct { | |
| 85 | /// e.g. 'A' => 0. | |
| 86 | /// undefined for any value not in the 64 alphabet chars. | |
| 87 | char_to_index: [256]u8, | |
| 88 | /// true only for the 64 chars in the alphabet, not the pad char. | |
| 89 | char_in_alphabet: [256]bool, | |
| 90 | pad_char: u8, | |
| 91 | ||
| 92 | pub fn init(alphabet_chars: []const u8, pad_char: u8) -> Base64Decoder { | |
| 93 | assert(alphabet_chars.len == 64); | |
| 94 | ||
| 95 | var result = Base64Decoder{ | |
| 96 | .char_to_index = undefined, | |
| 97 | .char_in_alphabet = []bool{false} ** 256, | |
| 98 | .pad_char = pad_char, | |
| 99 | }; | |
| 100 | ||
| 101 | for (alphabet_chars) |c, i| { | |
| 102 | assert(!result.char_in_alphabet[c]); | |
| 103 | assert(c != pad_char); | |
| 104 | ||
| 105 | result.char_to_index[c] = u8(i); | |
| 106 | result.char_in_alphabet[c] = true; | |
| 107 | } | |
| 71 | 108 | |
| 72 | return decodeWithAscii6BitMap(dest, source, ascii6[0..], alphabet[64]); | |
| 73 | } | |
| 109 | return result; | |
| 110 | } | |
| 74 | 111 | |
| 75 | pub fn decodeWithAscii6BitMap(dest: []u8, source: []const u8, ascii6: []const u8, pad_char: u8) -> []u8 { | |
| 76 | assert(ascii6.len == 256); | |
| 77 | assert(dest.len >= calcExactDecodedSizeWithPadChar(source, pad_char)); | |
| 112 | /// If the encoded buffer is detected to be invalid, returns error.InvalidPadding. | |
| 113 | pub fn calcSize(decoder: &const Base64Decoder, source: []const u8) -> %usize { | |
| 114 | if (source.len % 4 != 0) return error.InvalidPadding; | |
| 115 | return calcDecodedSizeExactUnsafe(source, decoder.pad_char); | |
| 116 | } | |
| 78 | 117 | |
| 79 | var src_index: usize = 0; | |
| 80 | var dest_index: usize = 0; | |
| 81 | var in_buf_len: usize = source.len; | |
| 118 | /// dest.len must be what you get from ::calcSize. | |
| 119 | /// invalid characters result in error.InvalidCharacter. | |
| 120 | /// invalid padding results in error.InvalidPadding. | |
| 121 | pub fn decode(decoder: &const Base64Decoder, dest: []u8, source: []const u8) -> %void { | |
| 122 | assert(dest.len == %%decoder.calcSize(source)); | |
| 123 | assert(source.len % 4 == 0); | |
| 124 | ||
| 125 | var src_cursor: usize = 0; | |
| 126 | var dest_cursor: usize = 0; | |
| 127 | ||
| 128 | while (src_cursor < source.len) : (src_cursor += 4) { | |
| 129 | if (!decoder.char_in_alphabet[source[src_cursor + 0]]) return error.InvalidCharacter; | |
| 130 | if (!decoder.char_in_alphabet[source[src_cursor + 1]]) return error.InvalidCharacter; | |
| 131 | if (src_cursor < source.len - 4 or source[src_cursor + 3] != decoder.pad_char) { | |
| 132 | // common case | |
| 133 | if (!decoder.char_in_alphabet[source[src_cursor + 2]]) return error.InvalidCharacter; | |
| 134 | if (!decoder.char_in_alphabet[source[src_cursor + 3]]) return error.InvalidCharacter; | |
| 135 | dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 | | |
| 136 | decoder.char_to_index[source[src_cursor + 1]] >> 4; | |
| 137 | dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 | | |
| 138 | decoder.char_to_index[source[src_cursor + 2]] >> 2; | |
| 139 | dest[dest_cursor + 2] = decoder.char_to_index[source[src_cursor + 2]] << 6 | | |
| 140 | decoder.char_to_index[source[src_cursor + 3]]; | |
| 141 | dest_cursor += 3; | |
| 142 | } else if (source[src_cursor + 2] != decoder.pad_char) { | |
| 143 | // one pad char | |
| 144 | if (!decoder.char_in_alphabet[source[src_cursor + 2]]) return error.InvalidCharacter; | |
| 145 | dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 | | |
| 146 | decoder.char_to_index[source[src_cursor + 1]] >> 4; | |
| 147 | dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 | | |
| 148 | decoder.char_to_index[source[src_cursor + 2]] >> 2; | |
| 149 | if (decoder.char_to_index[source[src_cursor + 2]] << 6 != 0) return error.InvalidPadding; | |
| 150 | dest_cursor += 2; | |
| 151 | } else { | |
| 152 | // two pad chars | |
| 153 | dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 | | |
| 154 | decoder.char_to_index[source[src_cursor + 1]] >> 4; | |
| 155 | if (decoder.char_to_index[source[src_cursor + 1]] << 4 != 0) return error.InvalidPadding; | |
| 156 | dest_cursor += 1; | |
| 157 | } | |
| 158 | } | |
| 82 | 159 | |
| 83 | while (in_buf_len > 0 and source[in_buf_len - 1] == pad_char) { | |
| 84 | in_buf_len -= 1; | |
| 160 | assert(src_cursor == source.len); | |
| 161 | assert(dest_cursor == dest.len); | |
| 85 | 162 | } |
| 163 | }; | |
| 164 | ||
| 165 | error OutputTooSmall; | |
| 166 | ||
| 167 | pub const Base64DecoderWithIgnore = struct { | |
| 168 | decoder: Base64Decoder, | |
| 169 | char_is_ignored: [256]bool, | |
| 170 | pub fn init(alphabet_chars: []const u8, pad_char: u8, ignore_chars: []const u8) -> Base64DecoderWithIgnore { | |
| 171 | var result = Base64DecoderWithIgnore { | |
| 172 | .decoder = Base64Decoder.init(alphabet_chars, pad_char), | |
| 173 | .char_is_ignored = []bool{false} ** 256, | |
| 174 | }; | |
| 175 | ||
| 176 | for (ignore_chars) |c| { | |
| 177 | assert(!result.decoder.char_in_alphabet[c]); | |
| 178 | assert(!result.char_is_ignored[c]); | |
| 179 | assert(result.decoder.pad_char != c); | |
| 180 | result.char_is_ignored[c] = true; | |
| 181 | } | |
| 86 | 182 | |
| 87 | while (in_buf_len > 4) { | |
| 88 | dest[dest_index] = ascii6[source[src_index + 0]] << 2 | | |
| 89 | ascii6[source[src_index + 1]] >> 4; | |
| 90 | dest_index += 1; | |
| 183 | return result; | |
| 184 | } | |
| 91 | 185 | |
| 92 | dest[dest_index] = ascii6[source[src_index + 1]] << 4 | | |
| 93 | ascii6[source[src_index + 2]] >> 2; | |
| 94 | dest_index += 1; | |
| 186 | /// If no characters end up being ignored or padding, this will be the exact decoded size. | |
| 187 | pub fn calcSizeUpperBound(encoded_len: usize) -> %usize { | |
| 188 | return @divTrunc(encoded_len, 4) * 3; | |
| 189 | } | |
| 95 | 190 | |
| 96 | dest[dest_index] = ascii6[source[src_index + 2]] << 6 | | |
| 97 | ascii6[source[src_index + 3]]; | |
| 98 | dest_index += 1; | |
| 191 | /// Invalid characters that are not ignored result in error.InvalidCharacter. | |
| 192 | /// Invalid padding results in error.InvalidPadding. | |
| 193 | /// Decoding more data than can fit in dest results in error.OutputTooSmall. See also ::calcSizeUpperBound. | |
| 194 | /// Returns the number of bytes writen to dest. | |
| 195 | pub fn decode(decoder_with_ignore: &const Base64DecoderWithIgnore, dest: []u8, source: []const u8) -> %usize { | |
| 196 | const decoder = &const decoder_with_ignore.decoder; | |
| 197 | ||
| 198 | var src_cursor: usize = 0; | |
| 199 | var dest_cursor: usize = 0; | |
| 200 | ||
| 201 | while (true) { | |
| 202 | // get the next 4 chars, if available | |
| 203 | var next_4_chars: [4]u8 = undefined; | |
| 204 | var available_chars: usize = 0; | |
| 205 | var pad_char_count: usize = 0; | |
| 206 | while (available_chars < 4 and src_cursor < source.len) { | |
| 207 | var c = source[src_cursor]; | |
| 208 | src_cursor += 1; | |
| 209 | ||
| 210 | if (decoder.char_in_alphabet[c]) { | |
| 211 | // normal char | |
| 212 | next_4_chars[available_chars] = c; | |
| 213 | available_chars += 1; | |
| 214 | } else if (decoder_with_ignore.char_is_ignored[c]) { | |
| 215 | // we're told to skip this one | |
| 216 | continue; | |
| 217 | } else if (c == decoder.pad_char) { | |
| 218 | // the padding has begun. count the pad chars. | |
| 219 | pad_char_count += 1; | |
| 220 | while (src_cursor < source.len) { | |
| 221 | c = source[src_cursor]; | |
| 222 | src_cursor += 1; | |
| 223 | if (c == decoder.pad_char) { | |
| 224 | pad_char_count += 1; | |
| 225 | if (pad_char_count > 2) return error.InvalidCharacter; | |
| 226 | } else if (decoder_with_ignore.char_is_ignored[c]) { | |
| 227 | // we can even ignore chars during the padding | |
| 228 | continue; | |
| 229 | } else return error.InvalidCharacter; | |
| 230 | } | |
| 231 | break; | |
| 232 | } else return error.InvalidCharacter; | |
| 233 | } | |
| 234 | ||
| 235 | switch (available_chars) { | |
| 236 | 4 => { | |
| 237 | // common case | |
| 238 | if (dest_cursor + 3 > dest.len) return error.OutputTooSmall; | |
| 239 | assert(pad_char_count == 0); | |
| 240 | dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 | | |
| 241 | decoder.char_to_index[next_4_chars[1]] >> 4; | |
| 242 | dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 | | |
| 243 | decoder.char_to_index[next_4_chars[2]] >> 2; | |
| 244 | dest[dest_cursor + 2] = decoder.char_to_index[next_4_chars[2]] << 6 | | |
| 245 | decoder.char_to_index[next_4_chars[3]]; | |
| 246 | dest_cursor += 3; | |
| 247 | continue; | |
| 248 | }, | |
| 249 | 3 => { | |
| 250 | if (dest_cursor + 2 > dest.len) return error.OutputTooSmall; | |
| 251 | if (pad_char_count != 1) return error.InvalidPadding; | |
| 252 | dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 | | |
| 253 | decoder.char_to_index[next_4_chars[1]] >> 4; | |
| 254 | dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 | | |
| 255 | decoder.char_to_index[next_4_chars[2]] >> 2; | |
| 256 | if (decoder.char_to_index[next_4_chars[2]] << 6 != 0) return error.InvalidPadding; | |
| 257 | dest_cursor += 2; | |
| 258 | break; | |
| 259 | }, | |
| 260 | 2 => { | |
| 261 | if (dest_cursor + 1 > dest.len) return error.OutputTooSmall; | |
| 262 | if (pad_char_count != 2) return error.InvalidPadding; | |
| 263 | dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 | | |
| 264 | decoder.char_to_index[next_4_chars[1]] >> 4; | |
| 265 | if (decoder.char_to_index[next_4_chars[1]] << 4 != 0) return error.InvalidPadding; | |
| 266 | dest_cursor += 1; | |
| 267 | break; | |
| 268 | }, | |
| 269 | 1 => { | |
| 270 | return error.InvalidPadding; | |
| 271 | }, | |
| 272 | 0 => { | |
| 273 | if (pad_char_count != 0) return error.InvalidPadding; | |
| 274 | break; | |
| 275 | }, | |
| 276 | else => unreachable, | |
| 277 | } | |
| 278 | } | |
| 99 | 279 | |
| 100 | src_index += 4; | |
| 101 | in_buf_len -= 4; | |
| 102 | } | |
| 280 | assert(src_cursor == source.len); | |
| 103 | 281 | |
| 104 | if (in_buf_len > 1) { | |
| 105 | dest[dest_index] = ascii6[source[src_index + 0]] << 2 | | |
| 106 | ascii6[source[src_index + 1]] >> 4; | |
| 107 | dest_index += 1; | |
| 282 | return dest_cursor; | |
| 108 | 283 | } |
| 109 | if (in_buf_len > 2) { | |
| 110 | dest[dest_index] = ascii6[source[src_index + 1]] << 4 | | |
| 111 | ascii6[source[src_index + 2]] >> 2; | |
| 112 | dest_index += 1; | |
| 284 | }; | |
| 285 | ||
| 286 | ||
| 287 | pub const standard_decoder_unsafe = Base64DecoderUnsafe.init(standard_alphabet_chars, standard_pad_char); | |
| 288 | ||
| 289 | pub const Base64DecoderUnsafe = struct { | |
| 290 | /// e.g. 'A' => 0. | |
| 291 | /// undefined for any value not in the 64 alphabet chars. | |
| 292 | char_to_index: [256]u8, | |
| 293 | pad_char: u8, | |
| 294 | ||
| 295 | pub fn init(alphabet_chars: []const u8, pad_char: u8) -> Base64DecoderUnsafe { | |
| 296 | assert(alphabet_chars.len == 64); | |
| 297 | var result = Base64DecoderUnsafe { | |
| 298 | .char_to_index = undefined, | |
| 299 | .pad_char = pad_char, | |
| 300 | }; | |
| 301 | for (alphabet_chars) |c, i| { | |
| 302 | assert(c != pad_char); | |
| 303 | result.char_to_index[c] = u8(i); | |
| 304 | } | |
| 305 | return result; | |
| 113 | 306 | } |
| 114 | if (in_buf_len > 3) { | |
| 115 | dest[dest_index] = ascii6[source[src_index + 2]] << 6 | | |
| 116 | ascii6[source[src_index + 3]]; | |
| 117 | dest_index += 1; | |
| 307 | ||
| 308 | /// The source buffer must be valid. | |
| 309 | pub fn calcSize(decoder: &const Base64DecoderUnsafe, source: []const u8) -> usize { | |
| 310 | return calcDecodedSizeExactUnsafe(source, decoder.pad_char); | |
| 118 | 311 | } |
| 119 | 312 | |
| 120 | return dest[0..dest_index]; | |
| 121 | } | |
| 313 | /// dest.len must be what you get from ::calcDecodedSizeExactUnsafe. | |
| 314 | /// invalid characters or padding will result in undefined values. | |
| 315 | pub fn decode(decoder: &const Base64DecoderUnsafe, dest: []u8, source: []const u8) { | |
| 316 | assert(dest.len == decoder.calcSize(source)); | |
| 122 | 317 | |
| 123 | pub fn calcEncodedSize(source_len: usize) -> usize { | |
| 124 | return (((source_len * 4) / 3 + 3) / 4) * 4; | |
| 125 | } | |
| 318 | var src_index: usize = 0; | |
| 319 | var dest_index: usize = 0; | |
| 320 | var in_buf_len: usize = source.len; | |
| 126 | 321 | |
| 127 | /// Computes the upper bound of the decoded size based only on the encoded length. | |
| 128 | /// To compute the exact decoded size, see ::calcExactDecodedSize | |
| 129 | pub fn calcMaxDecodedSize(encoded_len: usize) -> usize { | |
| 130 | return @divExact(encoded_len * 3, 4); | |
| 131 | } | |
| 322 | while (in_buf_len > 0 and source[in_buf_len - 1] == decoder.pad_char) { | |
| 323 | in_buf_len -= 1; | |
| 324 | } | |
| 132 | 325 | |
| 133 | /// Computes the number of decoded bytes there will be. This function must | |
| 134 | /// be given the encoded buffer because there might be padding | |
| 135 | /// bytes at the end ('=' in the standard alphabet) | |
| 136 | pub fn calcExactDecodedSize(encoded: []const u8) -> usize { | |
| 137 | return calcExactDecodedSizeWithAlphabet(encoded, standard_alphabet); | |
| 138 | } | |
| 326 | while (in_buf_len > 4) { | |
| 327 | dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 | | |
| 328 | decoder.char_to_index[source[src_index + 1]] >> 4; | |
| 329 | dest_index += 1; | |
| 139 | 330 | |
| 140 | pub fn calcExactDecodedSizeWithAlphabet(encoded: []const u8, alphabet: []const u8) -> usize { | |
| 141 | assert(alphabet.len == 65); | |
| 142 | return calcExactDecodedSizeWithPadChar(encoded, alphabet[64]); | |
| 143 | } | |
| 331 | dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 | | |
| 332 | decoder.char_to_index[source[src_index + 2]] >> 2; | |
| 333 | dest_index += 1; | |
| 144 | 334 | |
| 145 | pub fn calcExactDecodedSizeWithPadChar(encoded: []const u8, pad_char: u8) -> usize { | |
| 146 | var buf_len = encoded.len; | |
| 335 | dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 | | |
| 336 | decoder.char_to_index[source[src_index + 3]]; | |
| 337 | dest_index += 1; | |
| 147 | 338 | |
| 148 | while (buf_len > 0 and encoded[buf_len - 1] == pad_char) { | |
| 149 | buf_len -= 1; | |
| 150 | } | |
| 339 | src_index += 4; | |
| 340 | in_buf_len -= 4; | |
| 341 | } | |
| 151 | 342 | |
| 152 | return (buf_len * 3) / 4; | |
| 343 | if (in_buf_len > 1) { | |
| 344 | dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 | | |
| 345 | decoder.char_to_index[source[src_index + 1]] >> 4; | |
| 346 | dest_index += 1; | |
| 347 | } | |
| 348 | if (in_buf_len > 2) { | |
| 349 | dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 | | |
| 350 | decoder.char_to_index[source[src_index + 2]] >> 2; | |
| 351 | dest_index += 1; | |
| 352 | } | |
| 353 | if (in_buf_len > 3) { | |
| 354 | dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 | | |
| 355 | decoder.char_to_index[source[src_index + 3]]; | |
| 356 | dest_index += 1; | |
| 357 | } | |
| 358 | } | |
| 359 | }; | |
| 360 | ||
| 361 | fn calcDecodedSizeExactUnsafe(source: []const u8, pad_char: u8) -> usize { | |
| 362 | if (source.len == 0) return 0; | |
| 363 | var result = @divExact(source.len, 4) * 3; | |
| 364 | if (source[source.len - 1] == pad_char) { | |
| 365 | result -= 1; | |
| 366 | if (source[source.len - 2] == pad_char) { | |
| 367 | result -= 1; | |
| 368 | } | |
| 369 | } | |
| 370 | return result; | |
| 153 | 371 | } |
| 154 | 372 | |
| 373 | ||
| 155 | 374 | test "base64" { |
| 156 | testBase64(); | |
| 157 | comptime testBase64(); | |
| 375 | @setEvalBranchQuota(5000); | |
| 376 | %%testBase64(); | |
| 377 | comptime %%testBase64(); | |
| 158 | 378 | } |
| 159 | 379 | |
| 160 | fn testBase64() { | |
| 161 | testBase64Case("", ""); | |
| 162 | testBase64Case("f", "Zg=="); | |
| 163 | testBase64Case("fo", "Zm8="); | |
| 164 | testBase64Case("foo", "Zm9v"); | |
| 165 | testBase64Case("foob", "Zm9vYg=="); | |
| 166 | testBase64Case("fooba", "Zm9vYmE="); | |
| 167 | testBase64Case("foobar", "Zm9vYmFy"); | |
| 380 | fn testBase64() -> %void { | |
| 381 | %return testAllApis("", ""); | |
| 382 | %return testAllApis("f", "Zg=="); | |
| 383 | %return testAllApis("fo", "Zm8="); | |
| 384 | %return testAllApis("foo", "Zm9v"); | |
| 385 | %return testAllApis("foob", "Zm9vYg=="); | |
| 386 | %return testAllApis("fooba", "Zm9vYmE="); | |
| 387 | %return testAllApis("foobar", "Zm9vYmFy"); | |
| 388 | ||
| 389 | %return testDecodeIgnoreSpace("", " "); | |
| 390 | %return testDecodeIgnoreSpace("f", "Z g= ="); | |
| 391 | %return testDecodeIgnoreSpace("fo", " Zm8="); | |
| 392 | %return testDecodeIgnoreSpace("foo", "Zm9v "); | |
| 393 | %return testDecodeIgnoreSpace("foob", "Zm9vYg = = "); | |
| 394 | %return testDecodeIgnoreSpace("fooba", "Zm9v YmE="); | |
| 395 | %return testDecodeIgnoreSpace("foobar", " Z m 9 v Y m F y "); | |
| 396 | ||
| 397 | // test getting some api errors | |
| 398 | %return testError("A", error.InvalidPadding); | |
| 399 | %return testError("AA", error.InvalidPadding); | |
| 400 | %return testError("AAA", error.InvalidPadding); | |
| 401 | %return testError("A..A", error.InvalidCharacter); | |
| 402 | %return testError("AA=A", error.InvalidCharacter); | |
| 403 | %return testError("AA/=", error.InvalidPadding); | |
| 404 | %return testError("A/==", error.InvalidPadding); | |
| 405 | %return testError("A===", error.InvalidCharacter); | |
| 406 | %return testError("====", error.InvalidCharacter); | |
| 407 | ||
| 408 | %return testOutputTooSmallError("AA=="); | |
| 409 | %return testOutputTooSmallError("AAA="); | |
| 410 | %return testOutputTooSmallError("AAAA"); | |
| 411 | %return testOutputTooSmallError("AAAAAA=="); | |
| 168 | 412 | } |
| 169 | 413 | |
| 170 | fn testBase64Case(expected_decoded: []const u8, expected_encoded: []const u8) { | |
| 171 | const calculated_decoded_len = calcExactDecodedSize(expected_encoded); | |
| 172 | assert(calculated_decoded_len == expected_decoded.len); | |
| 414 | fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) -> %void { | |
| 415 | // Base64Encoder | |
| 416 | { | |
| 417 | var buffer: [0x100]u8 = undefined; | |
| 418 | var encoded = buffer[0..Base64Encoder.calcSize(expected_decoded.len)]; | |
| 419 | standard_encoder.encode(encoded, expected_decoded); | |
| 420 | assert(mem.eql(u8, encoded, expected_encoded)); | |
| 421 | } | |
| 173 | 422 | |
| 174 | const calculated_encoded_len = calcEncodedSize(expected_decoded.len); | |
| 175 | assert(calculated_encoded_len == expected_encoded.len); | |
| 423 | // Base64Decoder | |
| 424 | { | |
| 425 | var buffer: [0x100]u8 = undefined; | |
| 426 | var decoded = buffer[0..%return standard_decoder.calcSize(expected_encoded)]; | |
| 427 | %return standard_decoder.decode(decoded, expected_encoded); | |
| 428 | assert(mem.eql(u8, decoded, expected_decoded)); | |
| 429 | } | |
| 176 | 430 | |
| 177 | var buf: [100]u8 = undefined; | |
| 431 | // Base64DecoderWithIgnore | |
| 432 | { | |
| 433 | const standard_decoder_ignore_nothing = Base64DecoderWithIgnore.init( | |
| 434 | standard_alphabet_chars, standard_pad_char, ""); | |
| 435 | var buffer: [0x100]u8 = undefined; | |
| 436 | var decoded = buffer[0..%return Base64DecoderWithIgnore.calcSizeUpperBound(expected_encoded.len)]; | |
| 437 | var written = %return standard_decoder_ignore_nothing.decode(decoded, expected_encoded); | |
| 438 | assert(written <= decoded.len); | |
| 439 | assert(mem.eql(u8, decoded[0..written], expected_decoded)); | |
| 440 | } | |
| 178 | 441 | |
| 179 | const actual_decoded = decode(buf[0..], expected_encoded); | |
| 180 | assert(actual_decoded.len == expected_decoded.len); | |
| 181 | assert(mem.eql(u8, expected_decoded, actual_decoded)); | |
| 442 | // Base64DecoderUnsafe | |
| 443 | { | |
| 444 | var buffer: [0x100]u8 = undefined; | |
| 445 | var decoded = buffer[0..standard_decoder_unsafe.calcSize(expected_encoded)]; | |
| 446 | standard_decoder_unsafe.decode(decoded, expected_encoded); | |
| 447 | assert(mem.eql(u8, decoded, expected_decoded)); | |
| 448 | } | |
| 449 | } | |
| 450 | ||
| 451 | fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) -> %void { | |
| 452 | const standard_decoder_ignore_space = Base64DecoderWithIgnore.init( | |
| 453 | standard_alphabet_chars, standard_pad_char, " "); | |
| 454 | var buffer: [0x100]u8 = undefined; | |
| 455 | var decoded = buffer[0..%return Base64DecoderWithIgnore.calcSizeUpperBound(encoded.len)]; | |
| 456 | var written = %return standard_decoder_ignore_space.decode(decoded, encoded); | |
| 457 | assert(mem.eql(u8, decoded[0..written], expected_decoded)); | |
| 458 | } | |
| 459 | ||
| 460 | error ExpectedError; | |
| 461 | fn testError(encoded: []const u8, expected_err: error) -> %void { | |
| 462 | const standard_decoder_ignore_space = Base64DecoderWithIgnore.init( | |
| 463 | standard_alphabet_chars, standard_pad_char, " "); | |
| 464 | var buffer: [0x100]u8 = undefined; | |
| 465 | if (standard_decoder.calcSize(encoded)) |decoded_size| { | |
| 466 | var decoded = buffer[0..decoded_size]; | |
| 467 | if (standard_decoder.decode(decoded, encoded)) |_| { | |
| 468 | return error.ExpectedError; | |
| 469 | } else |err| if (err != expected_err) return err; | |
| 470 | } else |err| if (err != expected_err) return err; | |
| 471 | ||
| 472 | if (standard_decoder_ignore_space.decode(buffer[0..], encoded)) |_| { | |
| 473 | return error.ExpectedError; | |
| 474 | } else |err| if (err != expected_err) return err; | |
| 475 | } | |
| 182 | 476 | |
| 183 | const actual_encoded = encode(buf[0..], expected_decoded); | |
| 184 | assert(actual_encoded.len == expected_encoded.len); | |
| 185 | assert(mem.eql(u8, expected_encoded, actual_encoded)); | |
| 477 | fn testOutputTooSmallError(encoded: []const u8) -> %void { | |
| 478 | const standard_decoder_ignore_space = Base64DecoderWithIgnore.init( | |
| 479 | standard_alphabet_chars, standard_pad_char, " "); | |
| 480 | var buffer: [0x100]u8 = undefined; | |
| 481 | var decoded = buffer[0..calcDecodedSizeExactUnsafe(encoded, standard_pad_char) - 1]; | |
| 482 | if (standard_decoder_ignore_space.decode(decoded, encoded)) |_| { | |
| 483 | return error.ExpectedError; | |
| 484 | } else |err| if (err != error.OutputTooSmall) return err; | |
| 186 | 485 | } |
std/os/index.zig+9-5| ... | ... | @@ -31,6 +31,8 @@ pub const windowsWaitSingle = windows_util.windowsWaitSingle; |
| 31 | 31 | pub const windowsWrite = windows_util.windowsWrite; |
| 32 | 32 | pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty; |
| 33 | 33 | pub const windowsOpen = windows_util.windowsOpen; |
| 34 | pub const windowsLoadDll = windows_util.windowsLoadDll; | |
| 35 | pub const windowsUnloadDll = windows_util.windowsUnloadDll; | |
| 34 | 36 | pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock; |
| 35 | 37 | |
| 36 | 38 | pub const FileHandle = if (is_windows) windows.HANDLE else i32; |
| ... | ... | @@ -620,7 +622,9 @@ pub fn symLinkPosix(allocator: &Allocator, existing_path: []const u8, new_path: |
| 620 | 622 | } |
| 621 | 623 | |
| 622 | 624 | // here we replace the standard +/ with -_ so that it can be used in a file name |
| 623 | const b64_fs_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="; | |
| 625 | const b64_fs_encoder = base64.Base64Encoder.init( | |
| 626 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", | |
| 627 | base64.standard_pad_char); | |
| 624 | 628 | |
| 625 | 629 | pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) -> %void { |
| 626 | 630 | if (symLink(allocator, existing_path, new_path)) { |
| ... | ... | @@ -632,12 +636,12 @@ pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: |
| 632 | 636 | } |
| 633 | 637 | |
| 634 | 638 | var rand_buf: [12]u8 = undefined; |
| 635 | const tmp_path = %return allocator.alloc(u8, new_path.len + base64.calcEncodedSize(rand_buf.len)); | |
| 639 | const tmp_path = %return allocator.alloc(u8, new_path.len + base64.Base64Encoder.calcSize(rand_buf.len)); | |
| 636 | 640 | defer allocator.free(tmp_path); |
| 637 | 641 | mem.copy(u8, tmp_path[0..], new_path); |
| 638 | 642 | while (true) { |
| 639 | 643 | %return getRandomBytes(rand_buf[0..]); |
| 640 | _ = base64.encodeWithAlphabet(tmp_path[new_path.len..], rand_buf, b64_fs_alphabet); | |
| 644 | b64_fs_encoder.encode(tmp_path[new_path.len..], rand_buf); | |
| 641 | 645 | if (symLink(allocator, existing_path, tmp_path)) { |
| 642 | 646 | return rename(allocator, tmp_path, new_path); |
| 643 | 647 | } else |err| { |
| ... | ... | @@ -715,11 +719,11 @@ pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []con |
| 715 | 719 | /// Guaranteed to be atomic. |
| 716 | 720 | pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: []const u8, mode: usize) -> %void { |
| 717 | 721 | var rand_buf: [12]u8 = undefined; |
| 718 | const tmp_path = %return allocator.alloc(u8, dest_path.len + base64.calcEncodedSize(rand_buf.len)); | |
| 722 | const tmp_path = %return allocator.alloc(u8, dest_path.len + base64.Base64Encoder.calcSize(rand_buf.len)); | |
| 719 | 723 | defer allocator.free(tmp_path); |
| 720 | 724 | mem.copy(u8, tmp_path[0..], dest_path); |
| 721 | 725 | %return getRandomBytes(rand_buf[0..]); |
| 722 | _ = base64.encodeWithAlphabet(tmp_path[dest_path.len..], rand_buf, b64_fs_alphabet); | |
| 726 | b64_fs_encoder.encode(tmp_path[dest_path.len..], rand_buf); | |
| 723 | 727 | |
| 724 | 728 | var out_file = %return io.File.openWriteMode(tmp_path, mode, allocator); |
| 725 | 729 | defer out_file.close(); |
std/os/windows/index.zig+6| ... | ... | @@ -84,6 +84,11 @@ pub extern "kernel32" stdcallcc fn WriteFile(in_hFile: HANDLE, in_lpBuffer: &con |
| 84 | 84 | in_nNumberOfBytesToWrite: DWORD, out_lpNumberOfBytesWritten: ?&DWORD, |
| 85 | 85 | in_out_lpOverlapped: ?&OVERLAPPED) -> BOOL; |
| 86 | 86 | |
| 87 | //TODO: call unicode versions instead of relying on ANSI code page | |
| 88 | pub extern "kernel32" stdcallcc fn LoadLibraryA(lpLibFileName: LPCSTR) -> ?HMODULE; | |
| 89 | ||
| 90 | pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) -> BOOL; | |
| 91 | ||
| 87 | 92 | pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) -> c_int; |
| 88 | 93 | |
| 89 | 94 | pub const PROV_RSA_FULL = 1; |
| ... | ... | @@ -97,6 +102,7 @@ pub const FLOAT = f32; |
| 97 | 102 | pub const HANDLE = &c_void; |
| 98 | 103 | pub const HCRYPTPROV = ULONG_PTR; |
| 99 | 104 | pub const HINSTANCE = &@OpaqueType(); |
| 105 | pub const HMODULE = &@OpaqueType(); | |
| 100 | 106 | pub const INT = c_int; |
| 101 | 107 | pub const LPBYTE = &BYTE; |
| 102 | 108 | pub const LPCH = &CHAR; |
std/os/windows/util.zig+23| ... | ... | @@ -4,6 +4,7 @@ const windows = std.os.windows; |
| 4 | 4 | const assert = std.debug.assert; |
| 5 | 5 | const mem = std.mem; |
| 6 | 6 | const BufMap = std.BufMap; |
| 7 | const cstr = std.cstr; | |
| 7 | 8 | |
| 8 | 9 | error WaitAbandoned; |
| 9 | 10 | error WaitTimeOut; |
| ... | ... | @@ -149,3 +150,25 @@ pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) |
| 149 | 150 | result[i] = 0; |
| 150 | 151 | return result; |
| 151 | 152 | } |
| 153 | ||
| 154 | error DllNotFound; | |
| 155 | pub fn windowsLoadDll(allocator: &mem.Allocator, dll_path: []const u8) -> %windows.HMODULE { | |
| 156 | const padded_buff = %return cstr.addNullByte(allocator, dll_path); | |
| 157 | defer allocator.free(padded_buff); | |
| 158 | return windows.LoadLibraryA(padded_buff.ptr) ?? error.DllNotFound; | |
| 159 | } | |
| 160 | ||
| 161 | pub fn windowsUnloadDll(hModule: windows.HMODULE) { | |
| 162 | assert(windows.FreeLibrary(hModule)!= 0); | |
| 163 | } | |
| 164 | ||
| 165 | ||
| 166 | test "InvalidDll" { | |
| 167 | const DllName = "asdf.dll"; | |
| 168 | const allocator = std.debug.global_allocator; | |
| 169 | const handle = os.windowsLoadDll(allocator, DllName) %% |err| { | |
| 170 | assert(err == error.DllNotFound); | |
| 171 | return; | |
| 172 | }; | |
| 173 | } | |
| 174 |
test/cases/union.zig+44| ... | ... | @@ -31,3 +31,47 @@ test "unions embedded in aggregate types" { |
| 31 | 31 | else => unreachable, |
| 32 | 32 | } |
| 33 | 33 | } |
| 34 | ||
| 35 | ||
| 36 | const Foo = union { | |
| 37 | float: f64, | |
| 38 | int: i32, | |
| 39 | }; | |
| 40 | ||
| 41 | test "basic unions" { | |
| 42 | var foo = Foo { .int = 1 }; | |
| 43 | assert(foo.int == 1); | |
| 44 | foo = Foo {.float = 12.34}; | |
| 45 | assert(foo.float == 12.34); | |
| 46 | } | |
| 47 | ||
| 48 | test "init union with runtime value" { | |
| 49 | var foo: Foo = undefined; | |
| 50 | ||
| 51 | setFloat(&foo, 12.34); | |
| 52 | assert(foo.float == 12.34); | |
| 53 | ||
| 54 | setInt(&foo, 42); | |
| 55 | assert(foo.int == 42); | |
| 56 | } | |
| 57 | ||
| 58 | fn setFloat(foo: &Foo, x: f64) { | |
| 59 | *foo = Foo { .float = x }; | |
| 60 | } | |
| 61 | ||
| 62 | fn setInt(foo: &Foo, x: i32) { | |
| 63 | *foo = Foo { .int = x }; | |
| 64 | } | |
| 65 | ||
| 66 | const FooExtern = extern union { | |
| 67 | float: f64, | |
| 68 | int: i32, | |
| 69 | }; | |
| 70 | ||
| 71 | test "basic extern unions" { | |
| 72 | var foo = FooExtern { .int = 1 }; | |
| 73 | assert(foo.int == 1); | |
| 74 | foo.float = 12.34; | |
| 75 | assert(foo.float == 12.34); | |
| 76 | } | |
| 77 |
test/compile_errors.zig+22-3| ... | ... | @@ -389,8 +389,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 389 | 389 | \\ const y = a.bar; |
| 390 | 390 | \\} |
| 391 | 391 | , |
| 392 | ".tmp_source.zig:4:6: error: no member named 'foo' in 'A'", | |
| 393 | ".tmp_source.zig:5:16: error: no member named 'bar' in 'A'"); | |
| 392 | ".tmp_source.zig:4:6: error: no member named 'foo' in struct 'A'", | |
| 393 | ".tmp_source.zig:5:16: error: no member named 'bar' in struct 'A'"); | |
| 394 | 394 | |
| 395 | 395 | cases.add("redefinition of struct", |
| 396 | 396 | \\const A = struct { x : i32, }; |
| ... | ... | @@ -454,7 +454,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 454 | 454 | \\ .foo = 42, |
| 455 | 455 | \\ }; |
| 456 | 456 | \\} |
| 457 | , ".tmp_source.zig:10:9: error: no member named 'foo' in 'A'"); | |
| 457 | , ".tmp_source.zig:10:9: error: no member named 'foo' in struct 'A'"); | |
| 458 | 458 | |
| 459 | 459 | cases.add("invalid break expression", |
| 460 | 460 | \\export fn f() { |
| ... | ... | @@ -2343,4 +2343,23 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2343 | 2343 | \\pub extern fn foo(format: &const u8, ...); |
| 2344 | 2344 | , |
| 2345 | 2345 | ".tmp_source.zig:2:9: error: expected type '&const u8', found '[5]u8'"); |
| 2346 | ||
| 2347 | cases.add("constant inside comptime function has compile error", | |
| 2348 | \\const ContextAllocator = MemoryPool(usize); | |
| 2349 | \\ | |
| 2350 | \\pub fn MemoryPool(comptime T: type) -> type { | |
| 2351 | \\ const free_list_t = @compileError("aoeu"); | |
| 2352 | \\ | |
| 2353 | \\ struct { | |
| 2354 | \\ free_list: free_list_t, | |
| 2355 | \\ } | |
| 2356 | \\} | |
| 2357 | \\ | |
| 2358 | \\export fn entry() { | |
| 2359 | \\ var allocator: ContextAllocator = undefined; | |
| 2360 | \\} | |
| 2361 | , | |
| 2362 | ".tmp_source.zig:4:25: error: aoeu", | |
| 2363 | ".tmp_source.zig:1:36: note: called from here", | |
| 2364 | ".tmp_source.zig:12:20: note: referenced here"); | |
| 2346 | 2365 | } |
test/debug_safety.zig+20| ... | ... | @@ -260,4 +260,24 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 260 | 260 | \\ return int_slice[0]; |
| 261 | 261 | \\} |
| 262 | 262 | ); |
| 263 | ||
| 264 | cases.addDebugSafety("bad union field access", | |
| 265 | \\pub fn panic(message: []const u8) -> noreturn { | |
| 266 | \\ @import("std").os.exit(126); | |
| 267 | \\} | |
| 268 | \\ | |
| 269 | \\const Foo = union { | |
| 270 | \\ float: f32, | |
| 271 | \\ int: u32, | |
| 272 | \\}; | |
| 273 | \\ | |
| 274 | \\pub fn main() -> %void { | |
| 275 | \\ var f = Foo { .int = 42 }; | |
| 276 | \\ bar(&f); | |
| 277 | \\} | |
| 278 | \\ | |
| 279 | \\fn bar(f: &Foo) { | |
| 280 | \\ f.float = 12.34; | |
| 281 | \\} | |
| 282 | ); | |
| 263 | 283 | } |
test/parsec.zig deleted-871| ... | ... | @@ -1,871 +0,0 @@ |
| 1 | const tests = @import("tests.zig"); | |
| 2 | ||
| 3 | pub fn addCases(cases: &tests.ParseCContext) { | |
| 4 | cases.addAllowWarnings("simple data types", | |
| 5 | \\#include <stdint.h> | |
| 6 | \\int foo(char a, unsigned char b, signed char c); | |
| 7 | \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype | |
| 8 | \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d); | |
| 9 | \\void baz(int8_t a, int16_t b, int32_t c, int64_t d); | |
| 10 | , | |
| 11 | \\pub extern fn foo(a: u8, b: u8, c: i8) -> c_int; | |
| 12 | , | |
| 13 | \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64); | |
| 14 | , | |
| 15 | \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64); | |
| 16 | ); | |
| 17 | ||
| 18 | cases.add("noreturn attribute", | |
| 19 | \\void foo(void) __attribute__((noreturn)); | |
| 20 | , | |
| 21 | \\pub extern fn foo() -> noreturn; | |
| 22 | ); | |
| 23 | ||
| 24 | cases.addC("simple function", | |
| 25 | \\int abs(int a) { | |
| 26 | \\ return a < 0 ? -a : a; | |
| 27 | \\} | |
| 28 | , | |
| 29 | \\export fn abs(a: c_int) -> c_int { | |
| 30 | \\ return if (a < 0) -a else a; | |
| 31 | \\} | |
| 32 | ); | |
| 33 | ||
| 34 | cases.add("enums", | |
| 35 | \\enum Foo { | |
| 36 | \\ FooA, | |
| 37 | \\ FooB, | |
| 38 | \\ Foo1, | |
| 39 | \\}; | |
| 40 | , | |
| 41 | \\pub const enum_Foo = extern enum { | |
| 42 | \\ A, | |
| 43 | \\ B, | |
| 44 | \\ @"1", | |
| 45 | \\}; | |
| 46 | , | |
| 47 | \\pub const FooA = enum_Foo.A; | |
| 48 | , | |
| 49 | \\pub const FooB = enum_Foo.B; | |
| 50 | , | |
| 51 | \\pub const Foo1 = enum_Foo.@"1"; | |
| 52 | , | |
| 53 | \\pub const Foo = enum_Foo; | |
| 54 | ); | |
| 55 | ||
| 56 | cases.add("restrict -> noalias", | |
| 57 | \\void foo(void *restrict bar, void *restrict); | |
| 58 | , | |
| 59 | \\pub extern fn foo(noalias bar: ?&c_void, noalias arg1: ?&c_void); | |
| 60 | ); | |
| 61 | ||
| 62 | cases.add("simple struct", | |
| 63 | \\struct Foo { | |
| 64 | \\ int x; | |
| 65 | \\ char *y; | |
| 66 | \\}; | |
| 67 | , | |
| 68 | \\const struct_Foo = extern struct { | |
| 69 | \\ x: c_int, | |
| 70 | \\ y: ?&u8, | |
| 71 | \\}; | |
| 72 | , | |
| 73 | \\pub const Foo = struct_Foo; | |
| 74 | ); | |
| 75 | ||
| 76 | cases.add("qualified struct and enum", | |
| 77 | \\struct Foo { | |
| 78 | \\ int x; | |
| 79 | \\ int y; | |
| 80 | \\}; | |
| 81 | \\enum Bar { | |
| 82 | \\ BarA, | |
| 83 | \\ BarB, | |
| 84 | \\}; | |
| 85 | \\void func(struct Foo *a, enum Bar **b); | |
| 86 | , | |
| 87 | \\pub const struct_Foo = extern struct { | |
| 88 | \\ x: c_int, | |
| 89 | \\ y: c_int, | |
| 90 | \\}; | |
| 91 | , | |
| 92 | \\pub const enum_Bar = extern enum { | |
| 93 | \\ A, | |
| 94 | \\ B, | |
| 95 | \\}; | |
| 96 | , | |
| 97 | \\pub const BarA = enum_Bar.A; | |
| 98 | , | |
| 99 | \\pub const BarB = enum_Bar.B; | |
| 100 | , | |
| 101 | \\pub extern fn func(a: ?&struct_Foo, b: ?&(?&enum_Bar)); | |
| 102 | , | |
| 103 | \\pub const Foo = struct_Foo; | |
| 104 | , | |
| 105 | \\pub const Bar = enum_Bar; | |
| 106 | ); | |
| 107 | ||
| 108 | cases.add("constant size array", | |
| 109 | \\void func(int array[20]); | |
| 110 | , | |
| 111 | \\pub extern fn func(array: ?&c_int); | |
| 112 | ); | |
| 113 | ||
| 114 | cases.add("self referential struct with function pointer", | |
| 115 | \\struct Foo { | |
| 116 | \\ void (*derp)(struct Foo *foo); | |
| 117 | \\}; | |
| 118 | , | |
| 119 | \\pub const struct_Foo = extern struct { | |
| 120 | \\ derp: ?extern fn(?&struct_Foo), | |
| 121 | \\}; | |
| 122 | , | |
| 123 | \\pub const Foo = struct_Foo; | |
| 124 | ); | |
| 125 | ||
| 126 | cases.add("struct prototype used in func", | |
| 127 | \\struct Foo; | |
| 128 | \\struct Foo *some_func(struct Foo *foo, int x); | |
| 129 | , | |
| 130 | \\pub const struct_Foo = @OpaqueType(); | |
| 131 | , | |
| 132 | \\pub extern fn some_func(foo: ?&struct_Foo, x: c_int) -> ?&struct_Foo; | |
| 133 | , | |
| 134 | \\pub const Foo = struct_Foo; | |
| 135 | ); | |
| 136 | ||
| 137 | cases.add("#define a char literal", | |
| 138 | \\#define A_CHAR 'a' | |
| 139 | , | |
| 140 | \\pub const A_CHAR = 97; | |
| 141 | ); | |
| 142 | ||
| 143 | cases.add("#define an unsigned integer literal", | |
| 144 | \\#define CHANNEL_COUNT 24 | |
| 145 | , | |
| 146 | \\pub const CHANNEL_COUNT = 24; | |
| 147 | ); | |
| 148 | ||
| 149 | cases.add("#define referencing another #define", | |
| 150 | \\#define THING2 THING1 | |
| 151 | \\#define THING1 1234 | |
| 152 | , | |
| 153 | \\pub const THING1 = 1234; | |
| 154 | , | |
| 155 | \\pub const THING2 = THING1; | |
| 156 | ); | |
| 157 | ||
| 158 | cases.add("variables", | |
| 159 | \\extern int extern_var; | |
| 160 | \\static const int int_var = 13; | |
| 161 | , | |
| 162 | \\pub extern var extern_var: c_int; | |
| 163 | , | |
| 164 | \\pub const int_var: c_int = 13; | |
| 165 | ); | |
| 166 | ||
| 167 | cases.add("circular struct definitions", | |
| 168 | \\struct Bar; | |
| 169 | \\ | |
| 170 | \\struct Foo { | |
| 171 | \\ struct Bar *next; | |
| 172 | \\}; | |
| 173 | \\ | |
| 174 | \\struct Bar { | |
| 175 | \\ struct Foo *next; | |
| 176 | \\}; | |
| 177 | , | |
| 178 | \\pub const struct_Bar = extern struct { | |
| 179 | \\ next: ?&struct_Foo, | |
| 180 | \\}; | |
| 181 | , | |
| 182 | \\pub const struct_Foo = extern struct { | |
| 183 | \\ next: ?&struct_Bar, | |
| 184 | \\}; | |
| 185 | ); | |
| 186 | ||
| 187 | cases.add("typedef void", | |
| 188 | \\typedef void Foo; | |
| 189 | \\Foo fun(Foo *a); | |
| 190 | , | |
| 191 | \\pub const Foo = c_void; | |
| 192 | , | |
| 193 | \\pub extern fn fun(a: ?&Foo) -> Foo; | |
| 194 | ); | |
| 195 | ||
| 196 | cases.add("generate inline func for #define global extern fn", | |
| 197 | \\extern void (*fn_ptr)(void); | |
| 198 | \\#define foo fn_ptr | |
| 199 | \\ | |
| 200 | \\extern char (*fn_ptr2)(int, float); | |
| 201 | \\#define bar fn_ptr2 | |
| 202 | , | |
| 203 | \\pub extern var fn_ptr: ?extern fn(); | |
| 204 | , | |
| 205 | \\pub inline fn foo() { | |
| 206 | \\ (??fn_ptr)() | |
| 207 | \\} | |
| 208 | , | |
| 209 | \\pub extern var fn_ptr2: ?extern fn(c_int, f32) -> u8; | |
| 210 | , | |
| 211 | \\pub inline fn bar(arg0: c_int, arg1: f32) -> u8 { | |
| 212 | \\ (??fn_ptr2)(arg0, arg1) | |
| 213 | \\} | |
| 214 | ); | |
| 215 | ||
| 216 | cases.add("#define string", | |
| 217 | \\#define foo "a string" | |
| 218 | , | |
| 219 | \\pub const foo = c"a string"; | |
| 220 | ); | |
| 221 | ||
| 222 | cases.add("__cdecl doesn't mess up function pointers", | |
| 223 | \\void foo(void (__cdecl *fn_ptr)(void)); | |
| 224 | , | |
| 225 | \\pub extern fn foo(fn_ptr: ?extern fn()); | |
| 226 | ); | |
| 227 | ||
| 228 | cases.add("comment after integer literal", | |
| 229 | \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 230 | , | |
| 231 | \\pub const SDL_INIT_VIDEO = 32; | |
| 232 | ); | |
| 233 | ||
| 234 | cases.add("u integer suffix after hex literal", | |
| 235 | \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 236 | , | |
| 237 | \\pub const SDL_INIT_VIDEO = c_uint(32); | |
| 238 | ); | |
| 239 | ||
| 240 | cases.add("l integer suffix after hex literal", | |
| 241 | \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 242 | , | |
| 243 | \\pub const SDL_INIT_VIDEO = c_long(32); | |
| 244 | ); | |
| 245 | ||
| 246 | cases.add("ul integer suffix after hex literal", | |
| 247 | \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 248 | , | |
| 249 | \\pub const SDL_INIT_VIDEO = c_ulong(32); | |
| 250 | ); | |
| 251 | ||
| 252 | cases.add("lu integer suffix after hex literal", | |
| 253 | \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 254 | , | |
| 255 | \\pub const SDL_INIT_VIDEO = c_ulong(32); | |
| 256 | ); | |
| 257 | ||
| 258 | cases.add("ll integer suffix after hex literal", | |
| 259 | \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 260 | , | |
| 261 | \\pub const SDL_INIT_VIDEO = c_longlong(32); | |
| 262 | ); | |
| 263 | ||
| 264 | cases.add("ull integer suffix after hex literal", | |
| 265 | \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 266 | , | |
| 267 | \\pub const SDL_INIT_VIDEO = c_ulonglong(32); | |
| 268 | ); | |
| 269 | ||
| 270 | cases.add("llu integer suffix after hex literal", | |
| 271 | \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 272 | , | |
| 273 | \\pub const SDL_INIT_VIDEO = c_ulonglong(32); | |
| 274 | ); | |
| 275 | ||
| 276 | cases.add("zig keywords in C code", | |
| 277 | \\struct comptime { | |
| 278 | \\ int defer; | |
| 279 | \\}; | |
| 280 | , | |
| 281 | \\pub const struct_comptime = extern struct { | |
| 282 | \\ @"defer": c_int, | |
| 283 | \\}; | |
| 284 | , | |
| 285 | \\pub const @"comptime" = struct_comptime; | |
| 286 | ); | |
| 287 | ||
| 288 | cases.add("macro defines string literal with hex", | |
| 289 | \\#define FOO "aoeu\xab derp" | |
| 290 | \\#define FOO2 "aoeu\x0007a derp" | |
| 291 | \\#define FOO_CHAR '\xfF' | |
| 292 | , | |
| 293 | \\pub const FOO = c"aoeu\xab derp"; | |
| 294 | , | |
| 295 | \\pub const FOO2 = c"aoeuz derp"; | |
| 296 | , | |
| 297 | \\pub const FOO_CHAR = 255; | |
| 298 | ); | |
| 299 | ||
| 300 | cases.add("macro defines string literal with octal", | |
| 301 | \\#define FOO "aoeu\023 derp" | |
| 302 | \\#define FOO2 "aoeu\0234 derp" | |
| 303 | \\#define FOO_CHAR '\077' | |
| 304 | , | |
| 305 | \\pub const FOO = c"aoeu\x13 derp"; | |
| 306 | , | |
| 307 | \\pub const FOO2 = c"aoeu\x134 derp"; | |
| 308 | , | |
| 309 | \\pub const FOO_CHAR = 63; | |
| 310 | ); | |
| 311 | ||
| 312 | cases.add("macro with parens around negative number", | |
| 313 | \\#define LUA_GLOBALSINDEX (-10002) | |
| 314 | , | |
| 315 | \\pub const LUA_GLOBALSINDEX = -10002; | |
| 316 | ); | |
| 317 | ||
| 318 | cases.addC("post increment", | |
| 319 | \\unsigned foo1(unsigned a) { | |
| 320 | \\ a++; | |
| 321 | \\ return a; | |
| 322 | \\} | |
| 323 | \\int foo2(int a) { | |
| 324 | \\ a++; | |
| 325 | \\ return a; | |
| 326 | \\} | |
| 327 | , | |
| 328 | \\export fn foo1(_arg_a: c_uint) -> c_uint { | |
| 329 | \\ var a = _arg_a; | |
| 330 | \\ a +%= 1; | |
| 331 | \\ return a; | |
| 332 | \\} | |
| 333 | \\export fn foo2(_arg_a: c_int) -> c_int { | |
| 334 | \\ var a = _arg_a; | |
| 335 | \\ a += 1; | |
| 336 | \\ return a; | |
| 337 | \\} | |
| 338 | ); | |
| 339 | ||
| 340 | cases.addC("shift right assign", | |
| 341 | \\int log2(unsigned a) { | |
| 342 | \\ int i = 0; | |
| 343 | \\ while (a > 0) { | |
| 344 | \\ a >>= 1; | |
| 345 | \\ } | |
| 346 | \\ return i; | |
| 347 | \\} | |
| 348 | , | |
| 349 | \\export fn log2(_arg_a: c_uint) -> c_int { | |
| 350 | \\ var a = _arg_a; | |
| 351 | \\ var i: c_int = 0; | |
| 352 | \\ while (a > c_uint(0)) { | |
| 353 | \\ a >>= @import("std").math.Log2Int(c_uint)(1); | |
| 354 | \\ }; | |
| 355 | \\ return i; | |
| 356 | \\} | |
| 357 | ); | |
| 358 | ||
| 359 | cases.addC("if statement", | |
| 360 | \\int max(int a, int b) { | |
| 361 | \\ if (a < b) | |
| 362 | \\ return b; | |
| 363 | \\ | |
| 364 | \\ if (a < b) | |
| 365 | \\ return b; | |
| 366 | \\ else | |
| 367 | \\ return a; | |
| 368 | \\} | |
| 369 | , | |
| 370 | \\export fn max(a: c_int, b: c_int) -> c_int { | |
| 371 | \\ if (a < b) return b; | |
| 372 | \\ if (a < b) return b else return a; | |
| 373 | \\} | |
| 374 | ); | |
| 375 | ||
| 376 | cases.addC("==, !=", | |
| 377 | \\int max(int a, int b) { | |
| 378 | \\ if (a == b) | |
| 379 | \\ return a; | |
| 380 | \\ if (a != b) | |
| 381 | \\ return b; | |
| 382 | \\ return a; | |
| 383 | \\} | |
| 384 | , | |
| 385 | \\export fn max(a: c_int, b: c_int) -> c_int { | |
| 386 | \\ if (a == b) return a; | |
| 387 | \\ if (a != b) return b; | |
| 388 | \\ return a; | |
| 389 | \\} | |
| 390 | ); | |
| 391 | ||
| 392 | cases.addC("add, sub, mul, div, rem", | |
| 393 | \\int s(int a, int b) { | |
| 394 | \\ int c; | |
| 395 | \\ c = a + b; | |
| 396 | \\ c = a - b; | |
| 397 | \\ c = a * b; | |
| 398 | \\ c = a / b; | |
| 399 | \\ c = a % b; | |
| 400 | \\} | |
| 401 | \\unsigned u(unsigned a, unsigned b) { | |
| 402 | \\ unsigned c; | |
| 403 | \\ c = a + b; | |
| 404 | \\ c = a - b; | |
| 405 | \\ c = a * b; | |
| 406 | \\ c = a / b; | |
| 407 | \\ c = a % b; | |
| 408 | \\} | |
| 409 | , | |
| 410 | \\export fn s(a: c_int, b: c_int) -> c_int { | |
| 411 | \\ var c: c_int; | |
| 412 | \\ c = (a + b); | |
| 413 | \\ c = (a - b); | |
| 414 | \\ c = (a * b); | |
| 415 | \\ c = @divTrunc(a, b); | |
| 416 | \\ c = @rem(a, b); | |
| 417 | \\} | |
| 418 | \\export fn u(a: c_uint, b: c_uint) -> c_uint { | |
| 419 | \\ var c: c_uint; | |
| 420 | \\ c = (a +% b); | |
| 421 | \\ c = (a -% b); | |
| 422 | \\ c = (a *% b); | |
| 423 | \\ c = (a / b); | |
| 424 | \\ c = (a % b); | |
| 425 | \\} | |
| 426 | ); | |
| 427 | ||
| 428 | cases.addC("bitwise binary operators", | |
| 429 | \\int max(int a, int b) { | |
| 430 | \\ return (a & b) ^ (a | b); | |
| 431 | \\} | |
| 432 | , | |
| 433 | \\export fn max(a: c_int, b: c_int) -> c_int { | |
| 434 | \\ return (a & b) ^ (a | b); | |
| 435 | \\} | |
| 436 | ); | |
| 437 | ||
| 438 | cases.addC("logical and, logical or", | |
| 439 | \\int max(int a, int b) { | |
| 440 | \\ if (a < b || a == b) | |
| 441 | \\ return b; | |
| 442 | \\ if (a >= b && a == b) | |
| 443 | \\ return a; | |
| 444 | \\ return a; | |
| 445 | \\} | |
| 446 | , | |
| 447 | \\export fn max(a: c_int, b: c_int) -> c_int { | |
| 448 | \\ if ((a < b) or (a == b)) return b; | |
| 449 | \\ if ((a >= b) and (a == b)) return a; | |
| 450 | \\ return a; | |
| 451 | \\} | |
| 452 | ); | |
| 453 | ||
| 454 | cases.addC("assign", | |
| 455 | \\int max(int a) { | |
| 456 | \\ int tmp; | |
| 457 | \\ tmp = a; | |
| 458 | \\ a = tmp; | |
| 459 | \\} | |
| 460 | , | |
| 461 | \\export fn max(_arg_a: c_int) -> c_int { | |
| 462 | \\ var a = _arg_a; | |
| 463 | \\ var tmp: c_int; | |
| 464 | \\ tmp = a; | |
| 465 | \\ a = tmp; | |
| 466 | \\} | |
| 467 | ); | |
| 468 | ||
| 469 | cases.addC("chaining assign", | |
| 470 | \\void max(int a) { | |
| 471 | \\ int b, c; | |
| 472 | \\ c = b = a; | |
| 473 | \\} | |
| 474 | , | |
| 475 | \\export fn max(a: c_int) { | |
| 476 | \\ var b: c_int; | |
| 477 | \\ var c: c_int; | |
| 478 | \\ c = { | |
| 479 | \\ const _tmp = a; | |
| 480 | \\ b = _tmp; | |
| 481 | \\ _tmp | |
| 482 | \\ }; | |
| 483 | \\} | |
| 484 | ); | |
| 485 | ||
| 486 | cases.addC("shift right assign with a fixed size type", | |
| 487 | \\#include <stdint.h> | |
| 488 | \\int log2(uint32_t a) { | |
| 489 | \\ int i = 0; | |
| 490 | \\ while (a > 0) { | |
| 491 | \\ a >>= 1; | |
| 492 | \\ } | |
| 493 | \\ return i; | |
| 494 | \\} | |
| 495 | , | |
| 496 | \\export fn log2(_arg_a: u32) -> c_int { | |
| 497 | \\ var a = _arg_a; | |
| 498 | \\ var i: c_int = 0; | |
| 499 | \\ while (a > c_uint(0)) { | |
| 500 | \\ a >>= u5(1); | |
| 501 | \\ }; | |
| 502 | \\ return i; | |
| 503 | \\} | |
| 504 | ); | |
| 505 | ||
| 506 | cases.add("anonymous enum", | |
| 507 | \\enum { | |
| 508 | \\ One, | |
| 509 | \\ Two, | |
| 510 | \\}; | |
| 511 | , | |
| 512 | \\pub const One = 0; | |
| 513 | \\pub const Two = 1; | |
| 514 | ); | |
| 515 | ||
| 516 | cases.addC("function call", | |
| 517 | \\static void bar(void) { } | |
| 518 | \\void foo(void) { bar(); } | |
| 519 | , | |
| 520 | \\pub fn bar() {} | |
| 521 | \\export fn foo() { | |
| 522 | \\ bar(); | |
| 523 | \\} | |
| 524 | ); | |
| 525 | ||
| 526 | cases.addC("field access expression", | |
| 527 | \\struct Foo { | |
| 528 | \\ int field; | |
| 529 | \\}; | |
| 530 | \\int read_field(struct Foo *foo) { | |
| 531 | \\ return foo->field; | |
| 532 | \\} | |
| 533 | , | |
| 534 | \\pub const struct_Foo = extern struct { | |
| 535 | \\ field: c_int, | |
| 536 | \\}; | |
| 537 | \\export fn read_field(foo: ?&struct_Foo) -> c_int { | |
| 538 | \\ return (??foo).field; | |
| 539 | \\} | |
| 540 | ); | |
| 541 | ||
| 542 | cases.addC("null statements", | |
| 543 | \\void foo(void) { | |
| 544 | \\ ;;;;; | |
| 545 | \\} | |
| 546 | , | |
| 547 | \\export fn foo() {} | |
| 548 | ); | |
| 549 | ||
| 550 | cases.add("undefined array global", | |
| 551 | \\int array[100]; | |
| 552 | , | |
| 553 | \\pub var array: [100]c_int = undefined; | |
| 554 | ); | |
| 555 | ||
| 556 | cases.addC("array access", | |
| 557 | \\int array[100]; | |
| 558 | \\int foo(int index) { | |
| 559 | \\ return array[index]; | |
| 560 | \\} | |
| 561 | , | |
| 562 | \\pub var array: [100]c_int = undefined; | |
| 563 | \\export fn foo(index: c_int) -> c_int { | |
| 564 | \\ return array[index]; | |
| 565 | \\} | |
| 566 | ); | |
| 567 | ||
| 568 | ||
| 569 | cases.addC("c style cast", | |
| 570 | \\int float_to_int(float a) { | |
| 571 | \\ return (int)a; | |
| 572 | \\} | |
| 573 | , | |
| 574 | \\export fn float_to_int(a: f32) -> c_int { | |
| 575 | \\ return c_int(a); | |
| 576 | \\} | |
| 577 | ); | |
| 578 | ||
| 579 | cases.addC("implicit cast to void *", | |
| 580 | \\void *foo(unsigned short *x) { | |
| 581 | \\ return x; | |
| 582 | \\} | |
| 583 | , | |
| 584 | \\export fn foo(x: ?&c_ushort) -> ?&c_void { | |
| 585 | \\ return @ptrCast(?&c_void, x); | |
| 586 | \\} | |
| 587 | ); | |
| 588 | ||
| 589 | cases.addC("sizeof", | |
| 590 | \\#include <stddef.h> | |
| 591 | \\size_t size_of(void) { | |
| 592 | \\ return sizeof(int); | |
| 593 | \\} | |
| 594 | , | |
| 595 | \\export fn size_of() -> usize { | |
| 596 | \\ return @sizeOf(c_int); | |
| 597 | \\} | |
| 598 | ); | |
| 599 | ||
| 600 | cases.addC("null pointer implicit cast", | |
| 601 | \\int* foo(void) { | |
| 602 | \\ return 0; | |
| 603 | \\} | |
| 604 | , | |
| 605 | \\export fn foo() -> ?&c_int { | |
| 606 | \\ return null; | |
| 607 | \\} | |
| 608 | ); | |
| 609 | ||
| 610 | cases.addC("comma operator", | |
| 611 | \\int foo(void) { | |
| 612 | \\ return 1, 2; | |
| 613 | \\} | |
| 614 | , | |
| 615 | \\export fn foo() -> c_int { | |
| 616 | \\ return { | |
| 617 | \\ _ = 1; | |
| 618 | \\ 2 | |
| 619 | \\ }; | |
| 620 | \\} | |
| 621 | ); | |
| 622 | ||
| 623 | cases.addC("bitshift", | |
| 624 | \\int foo(void) { | |
| 625 | \\ return (1 << 2) >> 1; | |
| 626 | \\} | |
| 627 | , | |
| 628 | \\export fn foo() -> c_int { | |
| 629 | \\ return (1 << @import("std").math.Log2Int(c_int)(2)) >> @import("std").math.Log2Int(c_int)(1); | |
| 630 | \\} | |
| 631 | ); | |
| 632 | ||
| 633 | cases.addC("compound assignment operators", | |
| 634 | \\void foo(void) { | |
| 635 | \\ int a = 0; | |
| 636 | \\ a += (a += 1); | |
| 637 | \\ a -= (a -= 1); | |
| 638 | \\ a *= (a *= 1); | |
| 639 | \\ a &= (a &= 1); | |
| 640 | \\ a |= (a |= 1); | |
| 641 | \\ a ^= (a ^= 1); | |
| 642 | \\ a >>= (a >>= 1); | |
| 643 | \\ a <<= (a <<= 1); | |
| 644 | \\} | |
| 645 | , | |
| 646 | \\export fn foo() { | |
| 647 | \\ var a: c_int = 0; | |
| 648 | \\ a += { | |
| 649 | \\ const _ref = &a; | |
| 650 | \\ (*_ref) = ((*_ref) + 1); | |
| 651 | \\ *_ref | |
| 652 | \\ }; | |
| 653 | \\ a -= { | |
| 654 | \\ const _ref = &a; | |
| 655 | \\ (*_ref) = ((*_ref) - 1); | |
| 656 | \\ *_ref | |
| 657 | \\ }; | |
| 658 | \\ a *= { | |
| 659 | \\ const _ref = &a; | |
| 660 | \\ (*_ref) = ((*_ref) * 1); | |
| 661 | \\ *_ref | |
| 662 | \\ }; | |
| 663 | \\ a &= { | |
| 664 | \\ const _ref = &a; | |
| 665 | \\ (*_ref) = ((*_ref) & 1); | |
| 666 | \\ *_ref | |
| 667 | \\ }; | |
| 668 | \\ a |= { | |
| 669 | \\ const _ref = &a; | |
| 670 | \\ (*_ref) = ((*_ref) | 1); | |
| 671 | \\ *_ref | |
| 672 | \\ }; | |
| 673 | \\ a ^= { | |
| 674 | \\ const _ref = &a; | |
| 675 | \\ (*_ref) = ((*_ref) ^ 1); | |
| 676 | \\ *_ref | |
| 677 | \\ }; | |
| 678 | \\ a >>= @import("std").math.Log2Int(c_int)({ | |
| 679 | \\ const _ref = &a; | |
| 680 | \\ (*_ref) = c_int(c_int(*_ref) >> @import("std").math.Log2Int(c_int)(1)); | |
| 681 | \\ *_ref | |
| 682 | \\ }); | |
| 683 | \\ a <<= @import("std").math.Log2Int(c_int)({ | |
| 684 | \\ const _ref = &a; | |
| 685 | \\ (*_ref) = c_int(c_int(*_ref) << @import("std").math.Log2Int(c_int)(1)); | |
| 686 | \\ *_ref | |
| 687 | \\ }); | |
| 688 | \\} | |
| 689 | ); | |
| 690 | ||
| 691 | cases.addC("compound assignment operators unsigned", | |
| 692 | \\void foo(void) { | |
| 693 | \\ unsigned a = 0; | |
| 694 | \\ a += (a += 1); | |
| 695 | \\ a -= (a -= 1); | |
| 696 | \\ a *= (a *= 1); | |
| 697 | \\ a &= (a &= 1); | |
| 698 | \\ a |= (a |= 1); | |
| 699 | \\ a ^= (a ^= 1); | |
| 700 | \\ a >>= (a >>= 1); | |
| 701 | \\ a <<= (a <<= 1); | |
| 702 | \\} | |
| 703 | , | |
| 704 | \\export fn foo() { | |
| 705 | \\ var a: c_uint = c_uint(0); | |
| 706 | \\ a +%= { | |
| 707 | \\ const _ref = &a; | |
| 708 | \\ (*_ref) = ((*_ref) +% c_uint(1)); | |
| 709 | \\ *_ref | |
| 710 | \\ }; | |
| 711 | \\ a -%= { | |
| 712 | \\ const _ref = &a; | |
| 713 | \\ (*_ref) = ((*_ref) -% c_uint(1)); | |
| 714 | \\ *_ref | |
| 715 | \\ }; | |
| 716 | \\ a *%= { | |
| 717 | \\ const _ref = &a; | |
| 718 | \\ (*_ref) = ((*_ref) *% c_uint(1)); | |
| 719 | \\ *_ref | |
| 720 | \\ }; | |
| 721 | \\ a &= { | |
| 722 | \\ const _ref = &a; | |
| 723 | \\ (*_ref) = ((*_ref) & c_uint(1)); | |
| 724 | \\ *_ref | |
| 725 | \\ }; | |
| 726 | \\ a |= { | |
| 727 | \\ const _ref = &a; | |
| 728 | \\ (*_ref) = ((*_ref) | c_uint(1)); | |
| 729 | \\ *_ref | |
| 730 | \\ }; | |
| 731 | \\ a ^= { | |
| 732 | \\ const _ref = &a; | |
| 733 | \\ (*_ref) = ((*_ref) ^ c_uint(1)); | |
| 734 | \\ *_ref | |
| 735 | \\ }; | |
| 736 | \\ a >>= @import("std").math.Log2Int(c_uint)({ | |
| 737 | \\ const _ref = &a; | |
| 738 | \\ (*_ref) = c_uint(c_uint(*_ref) >> @import("std").math.Log2Int(c_uint)(1)); | |
| 739 | \\ *_ref | |
| 740 | \\ }); | |
| 741 | \\ a <<= @import("std").math.Log2Int(c_uint)({ | |
| 742 | \\ const _ref = &a; | |
| 743 | \\ (*_ref) = c_uint(c_uint(*_ref) << @import("std").math.Log2Int(c_uint)(1)); | |
| 744 | \\ *_ref | |
| 745 | \\ }); | |
| 746 | \\} | |
| 747 | ); | |
| 748 | ||
| 749 | cases.addC("duplicate typedef", | |
| 750 | \\typedef long foo; | |
| 751 | \\typedef int bar; | |
| 752 | \\typedef long foo; | |
| 753 | \\typedef int baz; | |
| 754 | , | |
| 755 | \\pub const foo = c_long; | |
| 756 | \\pub const bar = c_int; | |
| 757 | \\pub const baz = c_int; | |
| 758 | ); | |
| 759 | ||
| 760 | cases.addC("post increment/decrement", | |
| 761 | \\void foo(void) { | |
| 762 | \\ int i = 0; | |
| 763 | \\ unsigned u = 0; | |
| 764 | \\ i++; | |
| 765 | \\ i--; | |
| 766 | \\ u++; | |
| 767 | \\ u--; | |
| 768 | \\ i = i++; | |
| 769 | \\ i = i--; | |
| 770 | \\ u = u++; | |
| 771 | \\ u = u--; | |
| 772 | \\} | |
| 773 | , | |
| 774 | \\export fn foo() { | |
| 775 | \\ var i: c_int = 0; | |
| 776 | \\ var u: c_uint = c_uint(0); | |
| 777 | \\ i += 1; | |
| 778 | \\ i -= 1; | |
| 779 | \\ u +%= 1; | |
| 780 | \\ u -%= 1; | |
| 781 | \\ i = { | |
| 782 | \\ const _ref = &i; | |
| 783 | \\ const _tmp = *_ref; | |
| 784 | \\ (*_ref) += 1; | |
| 785 | \\ _tmp | |
| 786 | \\ }; | |
| 787 | \\ i = { | |
| 788 | \\ const _ref = &i; | |
| 789 | \\ const _tmp = *_ref; | |
| 790 | \\ (*_ref) -= 1; | |
| 791 | \\ _tmp | |
| 792 | \\ }; | |
| 793 | \\ u = { | |
| 794 | \\ const _ref = &u; | |
| 795 | \\ const _tmp = *_ref; | |
| 796 | \\ (*_ref) +%= 1; | |
| 797 | \\ _tmp | |
| 798 | \\ }; | |
| 799 | \\ u = { | |
| 800 | \\ const _ref = &u; | |
| 801 | \\ const _tmp = *_ref; | |
| 802 | \\ (*_ref) -%= 1; | |
| 803 | \\ _tmp | |
| 804 | \\ }; | |
| 805 | \\} | |
| 806 | ); | |
| 807 | ||
| 808 | cases.addC("do loop", | |
| 809 | \\void foo(void) { | |
| 810 | \\ int a = 2; | |
| 811 | \\ do { | |
| 812 | \\ a--; | |
| 813 | \\ } while (a != 0); | |
| 814 | \\ | |
| 815 | \\ int b = 2; | |
| 816 | \\ do | |
| 817 | \\ b--; | |
| 818 | \\ while (b != 0); | |
| 819 | \\} | |
| 820 | , | |
| 821 | \\export fn foo() { | |
| 822 | \\ var a: c_int = 2; | |
| 823 | \\ while (true) { | |
| 824 | \\ a -= 1; | |
| 825 | \\ if (!(a != 0)) break; | |
| 826 | \\ }; | |
| 827 | \\ var b: c_int = 2; | |
| 828 | \\ while (true) { | |
| 829 | \\ b -= 1; | |
| 830 | \\ if (!(b != 0)) break; | |
| 831 | \\ }; | |
| 832 | \\} | |
| 833 | ); | |
| 834 | ||
| 835 | cases.addC("deref function pointer", | |
| 836 | \\void foo(void) {} | |
| 837 | \\void bar(void) { | |
| 838 | \\ void(*f)(void) = foo; | |
| 839 | \\ f(); | |
| 840 | \\ (*(f))(); | |
| 841 | \\} | |
| 842 | , | |
| 843 | \\export fn foo() {} | |
| 844 | \\export fn bar() { | |
| 845 | \\ var f: ?extern fn() = foo; | |
| 846 | \\ (??f)(); | |
| 847 | \\ (??f)(); | |
| 848 | \\} | |
| 849 | ); | |
| 850 | ||
| 851 | cases.addC("normal deref", | |
| 852 | \\void foo(int *x) { | |
| 853 | \\ *x = 1; | |
| 854 | \\} | |
| 855 | , | |
| 856 | \\export fn foo(x: ?&c_int) { | |
| 857 | \\ (*(??x)) = 1; | |
| 858 | \\} | |
| 859 | ); | |
| 860 | } | |
| 861 | ||
| 862 | ||
| 863 | ||
| 864 | // TODO | |
| 865 | //float *ptrcast(int *a) { | |
| 866 | // return (float *)a; | |
| 867 | //} | |
| 868 | // should translate to | |
| 869 | // fn ptrcast(a: ?&c_int) -> ?&f32 { | |
| 870 | // return @ptrCast(?&f32, a); | |
| 871 | // } |
test/tests.zig+24-24| ... | ... | @@ -18,7 +18,7 @@ const build_examples = @import("build_examples.zig"); |
| 18 | 18 | const compile_errors = @import("compile_errors.zig"); |
| 19 | 19 | const assemble_and_link = @import("assemble_and_link.zig"); |
| 20 | 20 | const debug_safety = @import("debug_safety.zig"); |
| 21 | const parsec = @import("parsec.zig"); | |
| 21 | const translate_c = @import("translate_c.zig"); | |
| 22 | 22 | |
| 23 | 23 | const TestTarget = struct { |
| 24 | 24 | os: builtin.Os, |
| ... | ... | @@ -123,16 +123,16 @@ pub fn addAssembleAndLinkTests(b: &build.Builder, test_filter: ?[]const u8) -> & |
| 123 | 123 | return cases.step; |
| 124 | 124 | } |
| 125 | 125 | |
| 126 | pub fn addParseCTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step { | |
| 127 | const cases = %%b.allocator.create(ParseCContext); | |
| 128 | *cases = ParseCContext { | |
| 126 | pub fn addTranslateCTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step { | |
| 127 | const cases = %%b.allocator.create(TranslateCContext); | |
| 128 | *cases = TranslateCContext { | |
| 129 | 129 | .b = b, |
| 130 | .step = b.step("test-parsec", "Run the C header file parsing tests"), | |
| 130 | .step = b.step("test-translate-c", "Run the C header file parsing tests"), | |
| 131 | 131 | .test_index = 0, |
| 132 | 132 | .test_filter = test_filter, |
| 133 | 133 | }; |
| 134 | 134 | |
| 135 | parsec.addCases(cases); | |
| 135 | translate_c.addCases(cases); | |
| 136 | 136 | |
| 137 | 137 | return cases.step; |
| 138 | 138 | } |
| ... | ... | @@ -770,7 +770,7 @@ pub const BuildExamplesContext = struct { |
| 770 | 770 | } |
| 771 | 771 | }; |
| 772 | 772 | |
| 773 | pub const ParseCContext = struct { | |
| 773 | pub const TranslateCContext = struct { | |
| 774 | 774 | b: &build.Builder, |
| 775 | 775 | step: &build.Step, |
| 776 | 776 | test_index: usize, |
| ... | ... | @@ -799,17 +799,17 @@ pub const ParseCContext = struct { |
| 799 | 799 | } |
| 800 | 800 | }; |
| 801 | 801 | |
| 802 | const ParseCCmpOutputStep = struct { | |
| 802 | const TranslateCCmpOutputStep = struct { | |
| 803 | 803 | step: build.Step, |
| 804 | context: &ParseCContext, | |
| 804 | context: &TranslateCContext, | |
| 805 | 805 | name: []const u8, |
| 806 | 806 | test_index: usize, |
| 807 | 807 | case: &const TestCase, |
| 808 | 808 | |
| 809 | pub fn create(context: &ParseCContext, name: []const u8, case: &const TestCase) -> &ParseCCmpOutputStep { | |
| 809 | pub fn create(context: &TranslateCContext, name: []const u8, case: &const TestCase) -> &TranslateCCmpOutputStep { | |
| 810 | 810 | const allocator = context.b.allocator; |
| 811 | const ptr = %%allocator.create(ParseCCmpOutputStep); | |
| 812 | *ptr = ParseCCmpOutputStep { | |
| 811 | const ptr = %%allocator.create(TranslateCCmpOutputStep); | |
| 812 | *ptr = TranslateCCmpOutputStep { | |
| 813 | 813 | .step = build.Step.init("ParseCCmpOutput", allocator, make), |
| 814 | 814 | .context = context, |
| 815 | 815 | .name = name, |
| ... | ... | @@ -821,7 +821,7 @@ pub const ParseCContext = struct { |
| 821 | 821 | } |
| 822 | 822 | |
| 823 | 823 | fn make(step: &build.Step) -> %void { |
| 824 | const self = @fieldParentPtr(ParseCCmpOutputStep, "step", step); | |
| 824 | const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step); | |
| 825 | 825 | const b = self.context.b; |
| 826 | 826 | |
| 827 | 827 | const root_src = %%os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename); |
| ... | ... | @@ -829,7 +829,7 @@ pub const ParseCContext = struct { |
| 829 | 829 | var zig_args = ArrayList([]const u8).init(b.allocator); |
| 830 | 830 | %%zig_args.append(b.zig_exe); |
| 831 | 831 | |
| 832 | %%zig_args.append("parsec"); | |
| 832 | %%zig_args.append("translate-c"); | |
| 833 | 833 | %%zig_args.append(b.pathFromRoot(root_src)); |
| 834 | 834 | |
| 835 | 835 | warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name); |
| ... | ... | @@ -882,7 +882,7 @@ pub const ParseCContext = struct { |
| 882 | 882 | |
| 883 | 883 | if (stderr.len != 0 and !self.case.allow_warnings) { |
| 884 | 884 | warn( |
| 885 | \\====== parsec emitted warnings: ============ | |
| 885 | \\====== translate-c emitted warnings: ======= | |
| 886 | 886 | \\{} |
| 887 | 887 | \\============================================ |
| 888 | 888 | \\ |
| ... | ... | @@ -914,7 +914,7 @@ pub const ParseCContext = struct { |
| 914 | 914 | warn("\n"); |
| 915 | 915 | } |
| 916 | 916 | |
| 917 | pub fn create(self: &ParseCContext, allow_warnings: bool, filename: []const u8, name: []const u8, | |
| 917 | pub fn create(self: &TranslateCContext, allow_warnings: bool, filename: []const u8, name: []const u8, | |
| 918 | 918 | source: []const u8, expected_lines: ...) -> &TestCase |
| 919 | 919 | { |
| 920 | 920 | const tc = %%self.b.allocator.create(TestCase); |
| ... | ... | @@ -932,37 +932,37 @@ pub const ParseCContext = struct { |
| 932 | 932 | return tc; |
| 933 | 933 | } |
| 934 | 934 | |
| 935 | pub fn add(self: &ParseCContext, name: []const u8, source: []const u8, expected_lines: ...) { | |
| 935 | pub fn add(self: &TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) { | |
| 936 | 936 | const tc = self.create(false, "source.h", name, source, expected_lines); |
| 937 | 937 | self.addCase(tc); |
| 938 | 938 | } |
| 939 | 939 | |
| 940 | pub fn addC(self: &ParseCContext, name: []const u8, source: []const u8, expected_lines: ...) { | |
| 940 | pub fn addC(self: &TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) { | |
| 941 | 941 | const tc = self.create(false, "source.c", name, source, expected_lines); |
| 942 | 942 | self.addCase(tc); |
| 943 | 943 | } |
| 944 | 944 | |
| 945 | pub fn addAllowWarnings(self: &ParseCContext, name: []const u8, source: []const u8, expected_lines: ...) { | |
| 945 | pub fn addAllowWarnings(self: &TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) { | |
| 946 | 946 | const tc = self.create(true, "source.h", name, source, expected_lines); |
| 947 | 947 | self.addCase(tc); |
| 948 | 948 | } |
| 949 | 949 | |
| 950 | pub fn addCase(self: &ParseCContext, case: &const TestCase) { | |
| 950 | pub fn addCase(self: &TranslateCContext, case: &const TestCase) { | |
| 951 | 951 | const b = self.b; |
| 952 | 952 | |
| 953 | const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "parsec {}", case.name); | |
| 953 | const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "translate-c {}", case.name); | |
| 954 | 954 | if (self.test_filter) |filter| { |
| 955 | 955 | if (mem.indexOf(u8, annotated_case_name, filter) == null) |
| 956 | 956 | return; |
| 957 | 957 | } |
| 958 | 958 | |
| 959 | const parsec_and_cmp = ParseCCmpOutputStep.create(self, annotated_case_name, case); | |
| 960 | self.step.dependOn(&parsec_and_cmp.step); | |
| 959 | const translate_c_and_cmp = TranslateCCmpOutputStep.create(self, annotated_case_name, case); | |
| 960 | self.step.dependOn(&translate_c_and_cmp.step); | |
| 961 | 961 | |
| 962 | 962 | for (case.sources.toSliceConst()) |src_file| { |
| 963 | 963 | const expanded_src_path = %%os.path.join(b.allocator, b.cache_root, src_file.filename); |
| 964 | 964 | const write_src = b.addWriteFile(expanded_src_path, src_file.source); |
| 965 | parsec_and_cmp.step.dependOn(&write_src.step); | |
| 965 | translate_c_and_cmp.step.dependOn(&write_src.step); | |
| 966 | 966 | } |
| 967 | 967 | } |
| 968 | 968 | }; |
test/translate_c.zig created+1181| ... | ... | @@ -0,0 +1,1181 @@ |
| 1 | const tests = @import("tests.zig"); | |
| 2 | ||
| 3 | pub fn addCases(cases: &tests.TranslateCContext) { | |
| 4 | cases.addAllowWarnings("simple data types", | |
| 5 | \\#include <stdint.h> | |
| 6 | \\int foo(char a, unsigned char b, signed char c); | |
| 7 | \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype | |
| 8 | \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d); | |
| 9 | \\void baz(int8_t a, int16_t b, int32_t c, int64_t d); | |
| 10 | , | |
| 11 | \\pub extern fn foo(a: u8, b: u8, c: i8) -> c_int; | |
| 12 | , | |
| 13 | \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64); | |
| 14 | , | |
| 15 | \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64); | |
| 16 | ); | |
| 17 | ||
| 18 | cases.add("noreturn attribute", | |
| 19 | \\void foo(void) __attribute__((noreturn)); | |
| 20 | , | |
| 21 | \\pub extern fn foo() -> noreturn; | |
| 22 | ); | |
| 23 | ||
| 24 | cases.addC("simple function", | |
| 25 | \\int abs(int a) { | |
| 26 | \\ return a < 0 ? -a : a; | |
| 27 | \\} | |
| 28 | , | |
| 29 | \\export fn abs(a: c_int) -> c_int { | |
| 30 | \\ return if (a < 0) -a else a; | |
| 31 | \\} | |
| 32 | ); | |
| 33 | ||
| 34 | cases.add("enums", | |
| 35 | \\enum Foo { | |
| 36 | \\ FooA, | |
| 37 | \\ FooB, | |
| 38 | \\ Foo1, | |
| 39 | \\}; | |
| 40 | , | |
| 41 | \\pub const enum_Foo = extern enum { | |
| 42 | \\ A, | |
| 43 | \\ B, | |
| 44 | \\ @"1", | |
| 45 | \\}; | |
| 46 | , | |
| 47 | \\pub const FooA = enum_Foo.A; | |
| 48 | , | |
| 49 | \\pub const FooB = enum_Foo.B; | |
| 50 | , | |
| 51 | \\pub const Foo1 = enum_Foo.@"1"; | |
| 52 | , | |
| 53 | \\pub const Foo = enum_Foo; | |
| 54 | ); | |
| 55 | ||
| 56 | cases.add("restrict -> noalias", | |
| 57 | \\void foo(void *restrict bar, void *restrict); | |
| 58 | , | |
| 59 | \\pub extern fn foo(noalias bar: ?&c_void, noalias arg1: ?&c_void); | |
| 60 | ); | |
| 61 | ||
| 62 | cases.add("simple struct", | |
| 63 | \\struct Foo { | |
| 64 | \\ int x; | |
| 65 | \\ char *y; | |
| 66 | \\}; | |
| 67 | , | |
| 68 | \\const struct_Foo = extern struct { | |
| 69 | \\ x: c_int, | |
| 70 | \\ y: ?&u8, | |
| 71 | \\}; | |
| 72 | , | |
| 73 | \\pub const Foo = struct_Foo; | |
| 74 | ); | |
| 75 | ||
| 76 | cases.add("qualified struct and enum", | |
| 77 | \\struct Foo { | |
| 78 | \\ int x; | |
| 79 | \\ int y; | |
| 80 | \\}; | |
| 81 | \\enum Bar { | |
| 82 | \\ BarA, | |
| 83 | \\ BarB, | |
| 84 | \\}; | |
| 85 | \\void func(struct Foo *a, enum Bar **b); | |
| 86 | , | |
| 87 | \\pub const struct_Foo = extern struct { | |
| 88 | \\ x: c_int, | |
| 89 | \\ y: c_int, | |
| 90 | \\}; | |
| 91 | , | |
| 92 | \\pub const enum_Bar = extern enum { | |
| 93 | \\ A, | |
| 94 | \\ B, | |
| 95 | \\}; | |
| 96 | , | |
| 97 | \\pub const BarA = enum_Bar.A; | |
| 98 | , | |
| 99 | \\pub const BarB = enum_Bar.B; | |
| 100 | , | |
| 101 | \\pub extern fn func(a: ?&struct_Foo, b: ?&(?&enum_Bar)); | |
| 102 | , | |
| 103 | \\pub const Foo = struct_Foo; | |
| 104 | , | |
| 105 | \\pub const Bar = enum_Bar; | |
| 106 | ); | |
| 107 | ||
| 108 | cases.add("constant size array", | |
| 109 | \\void func(int array[20]); | |
| 110 | , | |
| 111 | \\pub extern fn func(array: ?&c_int); | |
| 112 | ); | |
| 113 | ||
| 114 | cases.add("self referential struct with function pointer", | |
| 115 | \\struct Foo { | |
| 116 | \\ void (*derp)(struct Foo *foo); | |
| 117 | \\}; | |
| 118 | , | |
| 119 | \\pub const struct_Foo = extern struct { | |
| 120 | \\ derp: ?extern fn(?&struct_Foo), | |
| 121 | \\}; | |
| 122 | , | |
| 123 | \\pub const Foo = struct_Foo; | |
| 124 | ); | |
| 125 | ||
| 126 | cases.add("struct prototype used in func", | |
| 127 | \\struct Foo; | |
| 128 | \\struct Foo *some_func(struct Foo *foo, int x); | |
| 129 | , | |
| 130 | \\pub const struct_Foo = @OpaqueType(); | |
| 131 | , | |
| 132 | \\pub extern fn some_func(foo: ?&struct_Foo, x: c_int) -> ?&struct_Foo; | |
| 133 | , | |
| 134 | \\pub const Foo = struct_Foo; | |
| 135 | ); | |
| 136 | ||
| 137 | cases.add("#define a char literal", | |
| 138 | \\#define A_CHAR 'a' | |
| 139 | , | |
| 140 | \\pub const A_CHAR = 97; | |
| 141 | ); | |
| 142 | ||
| 143 | cases.add("#define an unsigned integer literal", | |
| 144 | \\#define CHANNEL_COUNT 24 | |
| 145 | , | |
| 146 | \\pub const CHANNEL_COUNT = 24; | |
| 147 | ); | |
| 148 | ||
| 149 | cases.add("#define referencing another #define", | |
| 150 | \\#define THING2 THING1 | |
| 151 | \\#define THING1 1234 | |
| 152 | , | |
| 153 | \\pub const THING1 = 1234; | |
| 154 | , | |
| 155 | \\pub const THING2 = THING1; | |
| 156 | ); | |
| 157 | ||
| 158 | cases.add("variables", | |
| 159 | \\extern int extern_var; | |
| 160 | \\static const int int_var = 13; | |
| 161 | , | |
| 162 | \\pub extern var extern_var: c_int; | |
| 163 | , | |
| 164 | \\pub const int_var: c_int = 13; | |
| 165 | ); | |
| 166 | ||
| 167 | cases.add("circular struct definitions", | |
| 168 | \\struct Bar; | |
| 169 | \\ | |
| 170 | \\struct Foo { | |
| 171 | \\ struct Bar *next; | |
| 172 | \\}; | |
| 173 | \\ | |
| 174 | \\struct Bar { | |
| 175 | \\ struct Foo *next; | |
| 176 | \\}; | |
| 177 | , | |
| 178 | \\pub const struct_Bar = extern struct { | |
| 179 | \\ next: ?&struct_Foo, | |
| 180 | \\}; | |
| 181 | , | |
| 182 | \\pub const struct_Foo = extern struct { | |
| 183 | \\ next: ?&struct_Bar, | |
| 184 | \\}; | |
| 185 | ); | |
| 186 | ||
| 187 | cases.add("typedef void", | |
| 188 | \\typedef void Foo; | |
| 189 | \\Foo fun(Foo *a); | |
| 190 | , | |
| 191 | \\pub const Foo = c_void; | |
| 192 | , | |
| 193 | \\pub extern fn fun(a: ?&Foo) -> Foo; | |
| 194 | ); | |
| 195 | ||
| 196 | cases.add("generate inline func for #define global extern fn", | |
| 197 | \\extern void (*fn_ptr)(void); | |
| 198 | \\#define foo fn_ptr | |
| 199 | \\ | |
| 200 | \\extern char (*fn_ptr2)(int, float); | |
| 201 | \\#define bar fn_ptr2 | |
| 202 | , | |
| 203 | \\pub extern var fn_ptr: ?extern fn(); | |
| 204 | , | |
| 205 | \\pub inline fn foo() { | |
| 206 | \\ (??fn_ptr)() | |
| 207 | \\} | |
| 208 | , | |
| 209 | \\pub extern var fn_ptr2: ?extern fn(c_int, f32) -> u8; | |
| 210 | , | |
| 211 | \\pub inline fn bar(arg0: c_int, arg1: f32) -> u8 { | |
| 212 | \\ (??fn_ptr2)(arg0, arg1) | |
| 213 | \\} | |
| 214 | ); | |
| 215 | ||
| 216 | cases.add("#define string", | |
| 217 | \\#define foo "a string" | |
| 218 | , | |
| 219 | \\pub const foo = c"a string"; | |
| 220 | ); | |
| 221 | ||
| 222 | cases.add("__cdecl doesn't mess up function pointers", | |
| 223 | \\void foo(void (__cdecl *fn_ptr)(void)); | |
| 224 | , | |
| 225 | \\pub extern fn foo(fn_ptr: ?extern fn()); | |
| 226 | ); | |
| 227 | ||
| 228 | cases.add("comment after integer literal", | |
| 229 | \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 230 | , | |
| 231 | \\pub const SDL_INIT_VIDEO = 32; | |
| 232 | ); | |
| 233 | ||
| 234 | cases.add("u integer suffix after hex literal", | |
| 235 | \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 236 | , | |
| 237 | \\pub const SDL_INIT_VIDEO = c_uint(32); | |
| 238 | ); | |
| 239 | ||
| 240 | cases.add("l integer suffix after hex literal", | |
| 241 | \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 242 | , | |
| 243 | \\pub const SDL_INIT_VIDEO = c_long(32); | |
| 244 | ); | |
| 245 | ||
| 246 | cases.add("ul integer suffix after hex literal", | |
| 247 | \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 248 | , | |
| 249 | \\pub const SDL_INIT_VIDEO = c_ulong(32); | |
| 250 | ); | |
| 251 | ||
| 252 | cases.add("lu integer suffix after hex literal", | |
| 253 | \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 254 | , | |
| 255 | \\pub const SDL_INIT_VIDEO = c_ulong(32); | |
| 256 | ); | |
| 257 | ||
| 258 | cases.add("ll integer suffix after hex literal", | |
| 259 | \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 260 | , | |
| 261 | \\pub const SDL_INIT_VIDEO = c_longlong(32); | |
| 262 | ); | |
| 263 | ||
| 264 | cases.add("ull integer suffix after hex literal", | |
| 265 | \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 266 | , | |
| 267 | \\pub const SDL_INIT_VIDEO = c_ulonglong(32); | |
| 268 | ); | |
| 269 | ||
| 270 | cases.add("llu integer suffix after hex literal", | |
| 271 | \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 272 | , | |
| 273 | \\pub const SDL_INIT_VIDEO = c_ulonglong(32); | |
| 274 | ); | |
| 275 | ||
| 276 | cases.add("zig keywords in C code", | |
| 277 | \\struct comptime { | |
| 278 | \\ int defer; | |
| 279 | \\}; | |
| 280 | , | |
| 281 | \\pub const struct_comptime = extern struct { | |
| 282 | \\ @"defer": c_int, | |
| 283 | \\}; | |
| 284 | , | |
| 285 | \\pub const @"comptime" = struct_comptime; | |
| 286 | ); | |
| 287 | ||
| 288 | cases.add("macro defines string literal with hex", | |
| 289 | \\#define FOO "aoeu\xab derp" | |
| 290 | \\#define FOO2 "aoeu\x0007a derp" | |
| 291 | \\#define FOO_CHAR '\xfF' | |
| 292 | , | |
| 293 | \\pub const FOO = c"aoeu\xab derp"; | |
| 294 | , | |
| 295 | \\pub const FOO2 = c"aoeuz derp"; | |
| 296 | , | |
| 297 | \\pub const FOO_CHAR = 255; | |
| 298 | ); | |
| 299 | ||
| 300 | cases.add("macro defines string literal with octal", | |
| 301 | \\#define FOO "aoeu\023 derp" | |
| 302 | \\#define FOO2 "aoeu\0234 derp" | |
| 303 | \\#define FOO_CHAR '\077' | |
| 304 | , | |
| 305 | \\pub const FOO = c"aoeu\x13 derp"; | |
| 306 | , | |
| 307 | \\pub const FOO2 = c"aoeu\x134 derp"; | |
| 308 | , | |
| 309 | \\pub const FOO_CHAR = 63; | |
| 310 | ); | |
| 311 | ||
| 312 | cases.add("macro with parens around negative number", | |
| 313 | \\#define LUA_GLOBALSINDEX (-10002) | |
| 314 | , | |
| 315 | \\pub const LUA_GLOBALSINDEX = -10002; | |
| 316 | ); | |
| 317 | ||
| 318 | cases.addC("post increment", | |
| 319 | \\unsigned foo1(unsigned a) { | |
| 320 | \\ a++; | |
| 321 | \\ return a; | |
| 322 | \\} | |
| 323 | \\int foo2(int a) { | |
| 324 | \\ a++; | |
| 325 | \\ return a; | |
| 326 | \\} | |
| 327 | , | |
| 328 | \\export fn foo1(_arg_a: c_uint) -> c_uint { | |
| 329 | \\ var a = _arg_a; | |
| 330 | \\ a +%= 1; | |
| 331 | \\ return a; | |
| 332 | \\} | |
| 333 | \\export fn foo2(_arg_a: c_int) -> c_int { | |
| 334 | \\ var a = _arg_a; | |
| 335 | \\ a += 1; | |
| 336 | \\ return a; | |
| 337 | \\} | |
| 338 | ); | |
| 339 | ||
| 340 | cases.addC("shift right assign", | |
| 341 | \\int log2(unsigned a) { | |
| 342 | \\ int i = 0; | |
| 343 | \\ while (a > 0) { | |
| 344 | \\ a >>= 1; | |
| 345 | \\ } | |
| 346 | \\ return i; | |
| 347 | \\} | |
| 348 | , | |
| 349 | \\export fn log2(_arg_a: c_uint) -> c_int { | |
| 350 | \\ var a = _arg_a; | |
| 351 | \\ var i: c_int = 0; | |
| 352 | \\ while (a > c_uint(0)) { | |
| 353 | \\ a >>= @import("std").math.Log2Int(c_uint)(1); | |
| 354 | \\ }; | |
| 355 | \\ return i; | |
| 356 | \\} | |
| 357 | ); | |
| 358 | ||
| 359 | cases.addC("if statement", | |
| 360 | \\int max(int a, int b) { | |
| 361 | \\ if (a < b) | |
| 362 | \\ return b; | |
| 363 | \\ | |
| 364 | \\ if (a < b) | |
| 365 | \\ return b; | |
| 366 | \\ else | |
| 367 | \\ return a; | |
| 368 | \\} | |
| 369 | , | |
| 370 | \\export fn max(a: c_int, b: c_int) -> c_int { | |
| 371 | \\ if (a < b) return b; | |
| 372 | \\ if (a < b) return b else return a; | |
| 373 | \\} | |
| 374 | ); | |
| 375 | ||
| 376 | cases.addC("==, !=", | |
| 377 | \\int max(int a, int b) { | |
| 378 | \\ if (a == b) | |
| 379 | \\ return a; | |
| 380 | \\ if (a != b) | |
| 381 | \\ return b; | |
| 382 | \\ return a; | |
| 383 | \\} | |
| 384 | , | |
| 385 | \\export fn max(a: c_int, b: c_int) -> c_int { | |
| 386 | \\ if (a == b) return a; | |
| 387 | \\ if (a != b) return b; | |
| 388 | \\ return a; | |
| 389 | \\} | |
| 390 | ); | |
| 391 | ||
| 392 | cases.addC("add, sub, mul, div, rem", | |
| 393 | \\int s(int a, int b) { | |
| 394 | \\ int c; | |
| 395 | \\ c = a + b; | |
| 396 | \\ c = a - b; | |
| 397 | \\ c = a * b; | |
| 398 | \\ c = a / b; | |
| 399 | \\ c = a % b; | |
| 400 | \\} | |
| 401 | \\unsigned u(unsigned a, unsigned b) { | |
| 402 | \\ unsigned c; | |
| 403 | \\ c = a + b; | |
| 404 | \\ c = a - b; | |
| 405 | \\ c = a * b; | |
| 406 | \\ c = a / b; | |
| 407 | \\ c = a % b; | |
| 408 | \\} | |
| 409 | , | |
| 410 | \\export fn s(a: c_int, b: c_int) -> c_int { | |
| 411 | \\ var c: c_int; | |
| 412 | \\ c = (a + b); | |
| 413 | \\ c = (a - b); | |
| 414 | \\ c = (a * b); | |
| 415 | \\ c = @divTrunc(a, b); | |
| 416 | \\ c = @rem(a, b); | |
| 417 | \\} | |
| 418 | \\export fn u(a: c_uint, b: c_uint) -> c_uint { | |
| 419 | \\ var c: c_uint; | |
| 420 | \\ c = (a +% b); | |
| 421 | \\ c = (a -% b); | |
| 422 | \\ c = (a *% b); | |
| 423 | \\ c = (a / b); | |
| 424 | \\ c = (a % b); | |
| 425 | \\} | |
| 426 | ); | |
| 427 | ||
| 428 | cases.addC("bitwise binary operators", | |
| 429 | \\int max(int a, int b) { | |
| 430 | \\ return (a & b) ^ (a | b); | |
| 431 | \\} | |
| 432 | , | |
| 433 | \\export fn max(a: c_int, b: c_int) -> c_int { | |
| 434 | \\ return (a & b) ^ (a | b); | |
| 435 | \\} | |
| 436 | ); | |
| 437 | ||
| 438 | cases.addC("logical and, logical or", | |
| 439 | \\int max(int a, int b) { | |
| 440 | \\ if (a < b || a == b) | |
| 441 | \\ return b; | |
| 442 | \\ if (a >= b && a == b) | |
| 443 | \\ return a; | |
| 444 | \\ return a; | |
| 445 | \\} | |
| 446 | , | |
| 447 | \\export fn max(a: c_int, b: c_int) -> c_int { | |
| 448 | \\ if ((a < b) or (a == b)) return b; | |
| 449 | \\ if ((a >= b) and (a == b)) return a; | |
| 450 | \\ return a; | |
| 451 | \\} | |
| 452 | ); | |
| 453 | ||
| 454 | cases.addC("assign", | |
| 455 | \\int max(int a) { | |
| 456 | \\ int tmp; | |
| 457 | \\ tmp = a; | |
| 458 | \\ a = tmp; | |
| 459 | \\} | |
| 460 | , | |
| 461 | \\export fn max(_arg_a: c_int) -> c_int { | |
| 462 | \\ var a = _arg_a; | |
| 463 | \\ var tmp: c_int; | |
| 464 | \\ tmp = a; | |
| 465 | \\ a = tmp; | |
| 466 | \\} | |
| 467 | ); | |
| 468 | ||
| 469 | cases.addC("chaining assign", | |
| 470 | \\void max(int a) { | |
| 471 | \\ int b, c; | |
| 472 | \\ c = b = a; | |
| 473 | \\} | |
| 474 | , | |
| 475 | \\export fn max(a: c_int) { | |
| 476 | \\ var b: c_int; | |
| 477 | \\ var c: c_int; | |
| 478 | \\ c = { | |
| 479 | \\ const _tmp = a; | |
| 480 | \\ b = _tmp; | |
| 481 | \\ _tmp | |
| 482 | \\ }; | |
| 483 | \\} | |
| 484 | ); | |
| 485 | ||
| 486 | cases.addC("shift right assign with a fixed size type", | |
| 487 | \\#include <stdint.h> | |
| 488 | \\int log2(uint32_t a) { | |
| 489 | \\ int i = 0; | |
| 490 | \\ while (a > 0) { | |
| 491 | \\ a >>= 1; | |
| 492 | \\ } | |
| 493 | \\ return i; | |
| 494 | \\} | |
| 495 | , | |
| 496 | \\export fn log2(_arg_a: u32) -> c_int { | |
| 497 | \\ var a = _arg_a; | |
| 498 | \\ var i: c_int = 0; | |
| 499 | \\ while (a > c_uint(0)) { | |
| 500 | \\ a >>= u5(1); | |
| 501 | \\ }; | |
| 502 | \\ return i; | |
| 503 | \\} | |
| 504 | ); | |
| 505 | ||
| 506 | cases.add("anonymous enum", | |
| 507 | \\enum { | |
| 508 | \\ One, | |
| 509 | \\ Two, | |
| 510 | \\}; | |
| 511 | , | |
| 512 | \\pub const One = 0; | |
| 513 | \\pub const Two = 1; | |
| 514 | ); | |
| 515 | ||
| 516 | cases.addC("function call", | |
| 517 | \\static void bar(void) { } | |
| 518 | \\void foo(void) { bar(); } | |
| 519 | , | |
| 520 | \\pub fn bar() {} | |
| 521 | \\export fn foo() { | |
| 522 | \\ bar(); | |
| 523 | \\} | |
| 524 | ); | |
| 525 | ||
| 526 | cases.addC("field access expression", | |
| 527 | \\struct Foo { | |
| 528 | \\ int field; | |
| 529 | \\}; | |
| 530 | \\int read_field(struct Foo *foo) { | |
| 531 | \\ return foo->field; | |
| 532 | \\} | |
| 533 | , | |
| 534 | \\pub const struct_Foo = extern struct { | |
| 535 | \\ field: c_int, | |
| 536 | \\}; | |
| 537 | \\export fn read_field(foo: ?&struct_Foo) -> c_int { | |
| 538 | \\ return (??foo).field; | |
| 539 | \\} | |
| 540 | ); | |
| 541 | ||
| 542 | cases.addC("null statements", | |
| 543 | \\void foo(void) { | |
| 544 | \\ ;;;;; | |
| 545 | \\} | |
| 546 | , | |
| 547 | \\export fn foo() {} | |
| 548 | ); | |
| 549 | ||
| 550 | cases.add("undefined array global", | |
| 551 | \\int array[100]; | |
| 552 | , | |
| 553 | \\pub var array: [100]c_int = undefined; | |
| 554 | ); | |
| 555 | ||
| 556 | cases.addC("array access", | |
| 557 | \\int array[100]; | |
| 558 | \\int foo(int index) { | |
| 559 | \\ return array[index]; | |
| 560 | \\} | |
| 561 | , | |
| 562 | \\pub var array: [100]c_int = undefined; | |
| 563 | \\export fn foo(index: c_int) -> c_int { | |
| 564 | \\ return array[index]; | |
| 565 | \\} | |
| 566 | ); | |
| 567 | ||
| 568 | ||
| 569 | cases.addC("c style cast", | |
| 570 | \\int float_to_int(float a) { | |
| 571 | \\ return (int)a; | |
| 572 | \\} | |
| 573 | , | |
| 574 | \\export fn float_to_int(a: f32) -> c_int { | |
| 575 | \\ return c_int(a); | |
| 576 | \\} | |
| 577 | ); | |
| 578 | ||
| 579 | cases.addC("implicit cast to void *", | |
| 580 | \\void *foo(unsigned short *x) { | |
| 581 | \\ return x; | |
| 582 | \\} | |
| 583 | , | |
| 584 | \\export fn foo(x: ?&c_ushort) -> ?&c_void { | |
| 585 | \\ return @ptrCast(?&c_void, x); | |
| 586 | \\} | |
| 587 | ); | |
| 588 | ||
| 589 | cases.addC("sizeof", | |
| 590 | \\#include <stddef.h> | |
| 591 | \\size_t size_of(void) { | |
| 592 | \\ return sizeof(int); | |
| 593 | \\} | |
| 594 | , | |
| 595 | \\export fn size_of() -> usize { | |
| 596 | \\ return @sizeOf(c_int); | |
| 597 | \\} | |
| 598 | ); | |
| 599 | ||
| 600 | cases.addC("null pointer implicit cast", | |
| 601 | \\int* foo(void) { | |
| 602 | \\ return 0; | |
| 603 | \\} | |
| 604 | , | |
| 605 | \\export fn foo() -> ?&c_int { | |
| 606 | \\ return null; | |
| 607 | \\} | |
| 608 | ); | |
| 609 | ||
| 610 | cases.addC("comma operator", | |
| 611 | \\int foo(void) { | |
| 612 | \\ return 1, 2; | |
| 613 | \\} | |
| 614 | , | |
| 615 | \\export fn foo() -> c_int { | |
| 616 | \\ return { | |
| 617 | \\ _ = 1; | |
| 618 | \\ 2 | |
| 619 | \\ }; | |
| 620 | \\} | |
| 621 | ); | |
| 622 | ||
| 623 | cases.addC("bitshift", | |
| 624 | \\int foo(void) { | |
| 625 | \\ return (1 << 2) >> 1; | |
| 626 | \\} | |
| 627 | , | |
| 628 | \\export fn foo() -> c_int { | |
| 629 | \\ return (1 << @import("std").math.Log2Int(c_int)(2)) >> @import("std").math.Log2Int(c_int)(1); | |
| 630 | \\} | |
| 631 | ); | |
| 632 | ||
| 633 | cases.addC("compound assignment operators", | |
| 634 | \\void foo(void) { | |
| 635 | \\ int a = 0; | |
| 636 | \\ a += (a += 1); | |
| 637 | \\ a -= (a -= 1); | |
| 638 | \\ a *= (a *= 1); | |
| 639 | \\ a &= (a &= 1); | |
| 640 | \\ a |= (a |= 1); | |
| 641 | \\ a ^= (a ^= 1); | |
| 642 | \\ a >>= (a >>= 1); | |
| 643 | \\ a <<= (a <<= 1); | |
| 644 | \\} | |
| 645 | , | |
| 646 | \\export fn foo() { | |
| 647 | \\ var a: c_int = 0; | |
| 648 | \\ a += { | |
| 649 | \\ const _ref = &a; | |
| 650 | \\ (*_ref) = ((*_ref) + 1); | |
| 651 | \\ *_ref | |
| 652 | \\ }; | |
| 653 | \\ a -= { | |
| 654 | \\ const _ref = &a; | |
| 655 | \\ (*_ref) = ((*_ref) - 1); | |
| 656 | \\ *_ref | |
| 657 | \\ }; | |
| 658 | \\ a *= { | |
| 659 | \\ const _ref = &a; | |
| 660 | \\ (*_ref) = ((*_ref) * 1); | |
| 661 | \\ *_ref | |
| 662 | \\ }; | |
| 663 | \\ a &= { | |
| 664 | \\ const _ref = &a; | |
| 665 | \\ (*_ref) = ((*_ref) & 1); | |
| 666 | \\ *_ref | |
| 667 | \\ }; | |
| 668 | \\ a |= { | |
| 669 | \\ const _ref = &a; | |
| 670 | \\ (*_ref) = ((*_ref) | 1); | |
| 671 | \\ *_ref | |
| 672 | \\ }; | |
| 673 | \\ a ^= { | |
| 674 | \\ const _ref = &a; | |
| 675 | \\ (*_ref) = ((*_ref) ^ 1); | |
| 676 | \\ *_ref | |
| 677 | \\ }; | |
| 678 | \\ a >>= @import("std").math.Log2Int(c_int)({ | |
| 679 | \\ const _ref = &a; | |
| 680 | \\ (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_int)(1)); | |
| 681 | \\ *_ref | |
| 682 | \\ }); | |
| 683 | \\ a <<= @import("std").math.Log2Int(c_int)({ | |
| 684 | \\ const _ref = &a; | |
| 685 | \\ (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_int)(1)); | |
| 686 | \\ *_ref | |
| 687 | \\ }); | |
| 688 | \\} | |
| 689 | ); | |
| 690 | ||
| 691 | cases.addC("compound assignment operators unsigned", | |
| 692 | \\void foo(void) { | |
| 693 | \\ unsigned a = 0; | |
| 694 | \\ a += (a += 1); | |
| 695 | \\ a -= (a -= 1); | |
| 696 | \\ a *= (a *= 1); | |
| 697 | \\ a &= (a &= 1); | |
| 698 | \\ a |= (a |= 1); | |
| 699 | \\ a ^= (a ^= 1); | |
| 700 | \\ a >>= (a >>= 1); | |
| 701 | \\ a <<= (a <<= 1); | |
| 702 | \\} | |
| 703 | , | |
| 704 | \\export fn foo() { | |
| 705 | \\ var a: c_uint = c_uint(0); | |
| 706 | \\ a +%= { | |
| 707 | \\ const _ref = &a; | |
| 708 | \\ (*_ref) = ((*_ref) +% c_uint(1)); | |
| 709 | \\ *_ref | |
| 710 | \\ }; | |
| 711 | \\ a -%= { | |
| 712 | \\ const _ref = &a; | |
| 713 | \\ (*_ref) = ((*_ref) -% c_uint(1)); | |
| 714 | \\ *_ref | |
| 715 | \\ }; | |
| 716 | \\ a *%= { | |
| 717 | \\ const _ref = &a; | |
| 718 | \\ (*_ref) = ((*_ref) *% c_uint(1)); | |
| 719 | \\ *_ref | |
| 720 | \\ }; | |
| 721 | \\ a &= { | |
| 722 | \\ const _ref = &a; | |
| 723 | \\ (*_ref) = ((*_ref) & c_uint(1)); | |
| 724 | \\ *_ref | |
| 725 | \\ }; | |
| 726 | \\ a |= { | |
| 727 | \\ const _ref = &a; | |
| 728 | \\ (*_ref) = ((*_ref) | c_uint(1)); | |
| 729 | \\ *_ref | |
| 730 | \\ }; | |
| 731 | \\ a ^= { | |
| 732 | \\ const _ref = &a; | |
| 733 | \\ (*_ref) = ((*_ref) ^ c_uint(1)); | |
| 734 | \\ *_ref | |
| 735 | \\ }; | |
| 736 | \\ a >>= @import("std").math.Log2Int(c_uint)({ | |
| 737 | \\ const _ref = &a; | |
| 738 | \\ (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_uint)(1)); | |
| 739 | \\ *_ref | |
| 740 | \\ }); | |
| 741 | \\ a <<= @import("std").math.Log2Int(c_uint)({ | |
| 742 | \\ const _ref = &a; | |
| 743 | \\ (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_uint)(1)); | |
| 744 | \\ *_ref | |
| 745 | \\ }); | |
| 746 | \\} | |
| 747 | ); | |
| 748 | ||
| 749 | cases.addC("duplicate typedef", | |
| 750 | \\typedef long foo; | |
| 751 | \\typedef int bar; | |
| 752 | \\typedef long foo; | |
| 753 | \\typedef int baz; | |
| 754 | , | |
| 755 | \\pub const foo = c_long; | |
| 756 | \\pub const bar = c_int; | |
| 757 | \\pub const baz = c_int; | |
| 758 | ); | |
| 759 | ||
| 760 | cases.addC("post increment/decrement", | |
| 761 | \\void foo(void) { | |
| 762 | \\ int i = 0; | |
| 763 | \\ unsigned u = 0; | |
| 764 | \\ i++; | |
| 765 | \\ i--; | |
| 766 | \\ u++; | |
| 767 | \\ u--; | |
| 768 | \\ i = i++; | |
| 769 | \\ i = i--; | |
| 770 | \\ u = u++; | |
| 771 | \\ u = u--; | |
| 772 | \\} | |
| 773 | , | |
| 774 | \\export fn foo() { | |
| 775 | \\ var i: c_int = 0; | |
| 776 | \\ var u: c_uint = c_uint(0); | |
| 777 | \\ i += 1; | |
| 778 | \\ i -= 1; | |
| 779 | \\ u +%= 1; | |
| 780 | \\ u -%= 1; | |
| 781 | \\ i = { | |
| 782 | \\ const _ref = &i; | |
| 783 | \\ const _tmp = *_ref; | |
| 784 | \\ (*_ref) += 1; | |
| 785 | \\ _tmp | |
| 786 | \\ }; | |
| 787 | \\ i = { | |
| 788 | \\ const _ref = &i; | |
| 789 | \\ const _tmp = *_ref; | |
| 790 | \\ (*_ref) -= 1; | |
| 791 | \\ _tmp | |
| 792 | \\ }; | |
| 793 | \\ u = { | |
| 794 | \\ const _ref = &u; | |
| 795 | \\ const _tmp = *_ref; | |
| 796 | \\ (*_ref) +%= 1; | |
| 797 | \\ _tmp | |
| 798 | \\ }; | |
| 799 | \\ u = { | |
| 800 | \\ const _ref = &u; | |
| 801 | \\ const _tmp = *_ref; | |
| 802 | \\ (*_ref) -%= 1; | |
| 803 | \\ _tmp | |
| 804 | \\ }; | |
| 805 | \\} | |
| 806 | ); | |
| 807 | ||
| 808 | cases.addC("pre increment/decrement", | |
| 809 | \\void foo(void) { | |
| 810 | \\ int i = 0; | |
| 811 | \\ unsigned u = 0; | |
| 812 | \\ ++i; | |
| 813 | \\ --i; | |
| 814 | \\ ++u; | |
| 815 | \\ --u; | |
| 816 | \\ i = ++i; | |
| 817 | \\ i = --i; | |
| 818 | \\ u = ++u; | |
| 819 | \\ u = --u; | |
| 820 | \\} | |
| 821 | , | |
| 822 | \\export fn foo() { | |
| 823 | \\ var i: c_int = 0; | |
| 824 | \\ var u: c_uint = c_uint(0); | |
| 825 | \\ i += 1; | |
| 826 | \\ i -= 1; | |
| 827 | \\ u +%= 1; | |
| 828 | \\ u -%= 1; | |
| 829 | \\ i = { | |
| 830 | \\ const _ref = &i; | |
| 831 | \\ (*_ref) += 1; | |
| 832 | \\ *_ref | |
| 833 | \\ }; | |
| 834 | \\ i = { | |
| 835 | \\ const _ref = &i; | |
| 836 | \\ (*_ref) -= 1; | |
| 837 | \\ *_ref | |
| 838 | \\ }; | |
| 839 | \\ u = { | |
| 840 | \\ const _ref = &u; | |
| 841 | \\ (*_ref) +%= 1; | |
| 842 | \\ *_ref | |
| 843 | \\ }; | |
| 844 | \\ u = { | |
| 845 | \\ const _ref = &u; | |
| 846 | \\ (*_ref) -%= 1; | |
| 847 | \\ *_ref | |
| 848 | \\ }; | |
| 849 | \\} | |
| 850 | ); | |
| 851 | ||
| 852 | cases.addC("do loop", | |
| 853 | \\void foo(void) { | |
| 854 | \\ int a = 2; | |
| 855 | \\ do { | |
| 856 | \\ a--; | |
| 857 | \\ } while (a != 0); | |
| 858 | \\ | |
| 859 | \\ int b = 2; | |
| 860 | \\ do | |
| 861 | \\ b--; | |
| 862 | \\ while (b != 0); | |
| 863 | \\} | |
| 864 | , | |
| 865 | \\export fn foo() { | |
| 866 | \\ var a: c_int = 2; | |
| 867 | \\ while (true) { | |
| 868 | \\ a -= 1; | |
| 869 | \\ if (!(a != 0)) break; | |
| 870 | \\ }; | |
| 871 | \\ var b: c_int = 2; | |
| 872 | \\ while (true) { | |
| 873 | \\ b -= 1; | |
| 874 | \\ if (!(b != 0)) break; | |
| 875 | \\ }; | |
| 876 | \\} | |
| 877 | ); | |
| 878 | ||
| 879 | cases.addC("deref function pointer", | |
| 880 | \\void foo(void) {} | |
| 881 | \\void baz(void) {} | |
| 882 | \\void bar(void) { | |
| 883 | \\ void(*f)(void) = foo; | |
| 884 | \\ f(); | |
| 885 | \\ (*(f))(); | |
| 886 | \\ baz(); | |
| 887 | \\} | |
| 888 | , | |
| 889 | \\export fn foo() {} | |
| 890 | \\export fn baz() {} | |
| 891 | \\export fn bar() { | |
| 892 | \\ var f: ?extern fn() = foo; | |
| 893 | \\ (??f)(); | |
| 894 | \\ (??f)(); | |
| 895 | \\ baz(); | |
| 896 | \\} | |
| 897 | ); | |
| 898 | ||
| 899 | cases.addC("normal deref", | |
| 900 | \\void foo(int *x) { | |
| 901 | \\ *x = 1; | |
| 902 | \\} | |
| 903 | , | |
| 904 | \\export fn foo(x: ?&c_int) { | |
| 905 | \\ (*(??x)) = 1; | |
| 906 | \\} | |
| 907 | ); | |
| 908 | ||
| 909 | cases.add("simple union", | |
| 910 | \\union Foo { | |
| 911 | \\ int x; | |
| 912 | \\ double y; | |
| 913 | \\}; | |
| 914 | , | |
| 915 | \\pub const union_Foo = extern union { | |
| 916 | \\ x: c_int, | |
| 917 | \\ y: f64, | |
| 918 | \\}; | |
| 919 | , | |
| 920 | \\pub const Foo = union_Foo; | |
| 921 | ); | |
| 922 | ||
| 923 | cases.add("address of operator", | |
| 924 | \\int foo(void) { | |
| 925 | \\ int x = 1234; | |
| 926 | \\ int *ptr = &x; | |
| 927 | \\ return *ptr; | |
| 928 | \\} | |
| 929 | , | |
| 930 | \\pub fn foo() -> c_int { | |
| 931 | \\ var x: c_int = 1234; | |
| 932 | \\ var ptr: ?&c_int = &x; | |
| 933 | \\ return *(??ptr); | |
| 934 | \\} | |
| 935 | ); | |
| 936 | ||
| 937 | cases.add("string literal", | |
| 938 | \\const char *foo(void) { | |
| 939 | \\ return "bar"; | |
| 940 | \\} | |
| 941 | , | |
| 942 | \\pub fn foo() -> ?&const u8 { | |
| 943 | \\ return c"bar"; | |
| 944 | \\} | |
| 945 | ); | |
| 946 | ||
| 947 | cases.add("return void", | |
| 948 | \\void foo(void) { | |
| 949 | \\ return; | |
| 950 | \\} | |
| 951 | , | |
| 952 | \\pub fn foo() { | |
| 953 | \\ return; | |
| 954 | \\} | |
| 955 | ); | |
| 956 | ||
| 957 | cases.add("for loop", | |
| 958 | \\void foo(void) { | |
| 959 | \\ for (int i = 0; i < 10; i += 1) { } | |
| 960 | \\} | |
| 961 | , | |
| 962 | \\pub fn foo() { | |
| 963 | \\ { | |
| 964 | \\ var i: c_int = 0; | |
| 965 | \\ while (i < 10) : (i += 1) {}; | |
| 966 | \\ }; | |
| 967 | \\} | |
| 968 | ); | |
| 969 | ||
| 970 | cases.add("empty for loop", | |
| 971 | \\void foo(void) { | |
| 972 | \\ for (;;) { } | |
| 973 | \\} | |
| 974 | , | |
| 975 | \\pub fn foo() { | |
| 976 | \\ while (true) {}; | |
| 977 | \\} | |
| 978 | ); | |
| 979 | ||
| 980 | cases.add("break statement", | |
| 981 | \\void foo(void) { | |
| 982 | \\ for (;;) { | |
| 983 | \\ break; | |
| 984 | \\ } | |
| 985 | \\} | |
| 986 | , | |
| 987 | \\pub fn foo() { | |
| 988 | \\ while (true) { | |
| 989 | \\ break; | |
| 990 | \\ }; | |
| 991 | \\} | |
| 992 | ); | |
| 993 | ||
| 994 | cases.add("continue statement", | |
| 995 | \\void foo(void) { | |
| 996 | \\ for (;;) { | |
| 997 | \\ continue; | |
| 998 | \\ } | |
| 999 | \\} | |
| 1000 | , | |
| 1001 | \\pub fn foo() { | |
| 1002 | \\ while (true) { | |
| 1003 | \\ continue; | |
| 1004 | \\ }; | |
| 1005 | \\} | |
| 1006 | ); | |
| 1007 | ||
| 1008 | cases.add("switch statement", | |
| 1009 | \\int foo(int x) { | |
| 1010 | \\ switch (x) { | |
| 1011 | \\ case 1: | |
| 1012 | \\ x += 1; | |
| 1013 | \\ case 2: | |
| 1014 | \\ break; | |
| 1015 | \\ case 3: | |
| 1016 | \\ case 4: | |
| 1017 | \\ return x + 1; | |
| 1018 | \\ default: | |
| 1019 | \\ return 10; | |
| 1020 | \\ } | |
| 1021 | \\ return x + 13; | |
| 1022 | \\} | |
| 1023 | , | |
| 1024 | \\fn foo(_arg_x: c_int) -> c_int { | |
| 1025 | \\ var x = _arg_x; | |
| 1026 | \\ { | |
| 1027 | \\ switch (x) { | |
| 1028 | \\ 1 => goto case_0, | |
| 1029 | \\ 2 => goto case_1, | |
| 1030 | \\ 3 => goto case_2, | |
| 1031 | \\ 4 => goto case_3, | |
| 1032 | \\ else => goto default, | |
| 1033 | \\ }; | |
| 1034 | \\ case_0: | |
| 1035 | \\ x += 1; | |
| 1036 | \\ case_1: | |
| 1037 | \\ goto end; | |
| 1038 | \\ case_2: | |
| 1039 | \\ case_3: | |
| 1040 | \\ return x + 1; | |
| 1041 | \\ default: | |
| 1042 | \\ return 10; | |
| 1043 | \\ goto end; | |
| 1044 | \\ end: | |
| 1045 | \\ }; | |
| 1046 | \\ return x + 13; | |
| 1047 | \\} | |
| 1048 | ); | |
| 1049 | ||
| 1050 | cases.add("macros with field targets", | |
| 1051 | \\typedef unsigned int GLbitfield; | |
| 1052 | \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask); | |
| 1053 | \\typedef void(*OpenGLProc)(void); | |
| 1054 | \\union OpenGLProcs { | |
| 1055 | \\ OpenGLProc ptr[1]; | |
| 1056 | \\ struct { | |
| 1057 | \\ PFNGLCLEARPROC Clear; | |
| 1058 | \\ } gl; | |
| 1059 | \\}; | |
| 1060 | \\extern union OpenGLProcs glProcs; | |
| 1061 | \\#define glClearUnion glProcs.gl.Clear | |
| 1062 | \\#define glClearPFN PFNGLCLEARPROC | |
| 1063 | , | |
| 1064 | \\pub const GLbitfield = c_uint; | |
| 1065 | , | |
| 1066 | \\pub const PFNGLCLEARPROC = ?extern fn(GLbitfield); | |
| 1067 | , | |
| 1068 | \\pub const OpenGLProc = ?extern fn(); | |
| 1069 | , | |
| 1070 | \\pub const union_OpenGLProcs = extern union { | |
| 1071 | \\ ptr: [1]OpenGLProc, | |
| 1072 | \\ gl: extern struct { | |
| 1073 | \\ Clear: PFNGLCLEARPROC, | |
| 1074 | \\ }, | |
| 1075 | \\}; | |
| 1076 | , | |
| 1077 | \\pub extern var glProcs: union_OpenGLProcs; | |
| 1078 | , | |
| 1079 | \\pub const glClearPFN = PFNGLCLEARPROC; | |
| 1080 | , | |
| 1081 | \\pub inline fn glClearUnion(arg0: GLbitfield) { | |
| 1082 | \\ (??glProcs.gl.Clear)(arg0) | |
| 1083 | \\} | |
| 1084 | , | |
| 1085 | \\pub const OpenGLProcs = union_OpenGLProcs; | |
| 1086 | ); | |
| 1087 | ||
| 1088 | cases.add("switch statement with no default", | |
| 1089 | \\int foo(int x) { | |
| 1090 | \\ switch (x) { | |
| 1091 | \\ case 1: | |
| 1092 | \\ x += 1; | |
| 1093 | \\ case 2: | |
| 1094 | \\ break; | |
| 1095 | \\ case 3: | |
| 1096 | \\ case 4: | |
| 1097 | \\ return x + 1; | |
| 1098 | \\ } | |
| 1099 | \\ return x + 13; | |
| 1100 | \\} | |
| 1101 | , | |
| 1102 | \\fn foo(_arg_x: c_int) -> c_int { | |
| 1103 | \\ var x = _arg_x; | |
| 1104 | \\ { | |
| 1105 | \\ switch (x) { | |
| 1106 | \\ 1 => goto case_0, | |
| 1107 | \\ 2 => goto case_1, | |
| 1108 | \\ 3 => goto case_2, | |
| 1109 | \\ 4 => goto case_3, | |
| 1110 | \\ else => goto end, | |
| 1111 | \\ }; | |
| 1112 | \\ case_0: | |
| 1113 | \\ x += 1; | |
| 1114 | \\ case_1: | |
| 1115 | \\ goto end; | |
| 1116 | \\ case_2: | |
| 1117 | \\ case_3: | |
| 1118 | \\ return x + 1; | |
| 1119 | \\ goto end; | |
| 1120 | \\ end: | |
| 1121 | \\ }; | |
| 1122 | \\ return x + 13; | |
| 1123 | \\} | |
| 1124 | ); | |
| 1125 | ||
| 1126 | cases.add("variable name shadowing", | |
| 1127 | \\int foo(void) { | |
| 1128 | \\ int x = 1; | |
| 1129 | \\ { | |
| 1130 | \\ int x = 2; | |
| 1131 | \\ x += 1; | |
| 1132 | \\ } | |
| 1133 | \\ return x; | |
| 1134 | \\} | |
| 1135 | , | |
| 1136 | \\pub fn foo() -> c_int { | |
| 1137 | \\ var x: c_int = 1; | |
| 1138 | \\ { | |
| 1139 | \\ var x_0: c_int = 2; | |
| 1140 | \\ x_0 += 1; | |
| 1141 | \\ }; | |
| 1142 | \\ return x; | |
| 1143 | \\} | |
| 1144 | ); | |
| 1145 | ||
| 1146 | cases.add("pointer casting", | |
| 1147 | \\float *ptrcast(int *a) { | |
| 1148 | \\ return (float *)a; | |
| 1149 | \\} | |
| 1150 | , | |
| 1151 | \\fn ptrcast(a: ?&c_int) -> ?&f32 { | |
| 1152 | \\ return @ptrCast(?&f32, a); | |
| 1153 | \\} | |
| 1154 | ); | |
| 1155 | ||
| 1156 | cases.add("bin not", | |
| 1157 | \\int foo(int x) { | |
| 1158 | \\ return ~x; | |
| 1159 | \\} | |
| 1160 | , | |
| 1161 | \\pub fn foo(x: c_int) -> c_int { | |
| 1162 | \\ return ~x; | |
| 1163 | \\} | |
| 1164 | ); | |
| 1165 | ||
| 1166 | cases.add("primitive types included in defined symbols", | |
| 1167 | \\int foo(int u32) { | |
| 1168 | \\ return u32; | |
| 1169 | \\} | |
| 1170 | , | |
| 1171 | \\pub fn foo(u32_0: c_int) -> c_int { | |
| 1172 | \\ return u32_0; | |
| 1173 | \\} | |
| 1174 | ); | |
| 1175 | ||
| 1176 | cases.add("const ptr initializer", | |
| 1177 | \\static const char *v0 = "0.0.0"; | |
| 1178 | , | |
| 1179 | \\pub var v0: ?&const u8 = c"0.0.0"; | |
| 1180 | ); | |
| 1181 | } |