| 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,7 +339,7 @@ set(ZIG_SOURCES |
| 339 | "${CMAKE_SOURCE_DIR}/src/target.cpp" | 339 | "${CMAKE_SOURCE_DIR}/src/target.cpp" |
| 340 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" | 340 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" |
| 341 | "${CMAKE_SOURCE_DIR}/src/util.cpp" | 341 | "${CMAKE_SOURCE_DIR}/src/util.cpp" |
| 342 | "${CMAKE_SOURCE_DIR}/src/parsec.cpp" | 342 | "${CMAKE_SOURCE_DIR}/src/translate_c.cpp" |
| 343 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" | 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,5 +58,5 @@ pub fn build(b: &Builder) { |
| 58 | test_step.dependOn(tests.addCompileErrorTests(b, test_filter)); | 58 | test_step.dependOn(tests.addCompileErrorTests(b, test_filter)); |
| 59 | test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter)); | 59 | test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter)); |
| 60 | test_step.dependOn(tests.addDebugSafetyTests(b, test_filter)); | 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,4 +22,4 @@ make install |
| 22 | ./zig build --build-file ../build.zig test-compile-errors --verbose | 22 | ./zig build --build-file ../build.zig test-compile-errors --verbose |
| 23 | ./zig build --build-file ../build.zig test-asm-link --verbose | 23 | ./zig build --build-file ../build.zig test-asm-link --verbose |
| 24 | ./zig build --build-file ../build.zig test-debug-safety --verbose | 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,10 +70,14 @@ |
| 70 | <li><a href="#mersenne">Mersenne Twister Random Number Generator</a></li> | 70 | <li><a href="#mersenne">Mersenne Twister Random Number Generator</a></li> |
| 71 | </ul> | 71 | </ul> |
| 72 | <h3 id="hello">Hello World</h3> | 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 | pub fn main() -&gt; %void { | 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 | }</code></pre> | 81 | }</code></pre> |
| 78 | <p>Build this with:</p> | 82 | <p>Build this with:</p> |
| 79 | <pre>zig build-exe hello.zig</pre> | 83 | <pre>zig build-exe hello.zig</pre> |
doc/langref.html.in+15-4| ... | @@ -75,6 +75,7 @@ | ... | @@ -75,6 +75,7 @@ |
| 75 | <li><a href="#slices">Slices</a></li> | 75 | <li><a href="#slices">Slices</a></li> |
| 76 | <li><a href="#struct">struct</a></li> | 76 | <li><a href="#struct">struct</a></li> |
| 77 | <li><a href="#enum">enum</a></li> | 77 | <li><a href="#enum">enum</a></li> |
| 78 | <li><a href="#union">union</a></li> | ||
| 78 | <li><a href="#switch">switch</a></li> | 79 | <li><a href="#switch">switch</a></li> |
| 79 | <li><a href="#while">while</a></li> | 80 | <li><a href="#while">while</a></li> |
| 80 | <li><a href="#for">for</a></li> | 81 | <li><a href="#for">for</a></li> |
| ... | @@ -209,6 +210,7 @@ | ... | @@ -209,6 +210,7 @@ |
| 209 | <li><a href="#undef-invalid-error-code">Invalid Error Code</a></li> | 210 | <li><a href="#undef-invalid-error-code">Invalid Error Code</a></li> |
| 210 | <li><a href="#undef-invalid-enum-cast">Invalid Enum Cast</a></li> | 211 | <li><a href="#undef-invalid-enum-cast">Invalid Enum Cast</a></li> |
| 211 | <li><a href="#undef-incorrect-pointer-alignment">Incorrect Pointer Alignment</a></li> | 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 | </ul> | 214 | </ul> |
| 213 | </li> | 215 | </li> |
| 214 | <li><a href="#memory">Memory</a></li> | 216 | <li><a href="#memory">Memory</a></li> |
| ... | @@ -2189,6 +2191,8 @@ Test 4/4 enum builtins...OK</code></pre> | ... | @@ -2189,6 +2191,8 @@ Test 4/4 enum builtins...OK</code></pre> |
| 2189 | <li><a href="#builtin-enumTagName">@enumTagName</a></li> | 2191 | <li><a href="#builtin-enumTagName">@enumTagName</a></li> |
| 2190 | <li><a href="#builtin-memberCount">@memberCount</a></li> | 2192 | <li><a href="#builtin-memberCount">@memberCount</a></li> |
| 2191 | </ul> | 2193 | </ul> |
| 2194 | <h2 id="union">union</h2> | ||
| 2195 | <p>TODO union documentation</p> | ||
| 2192 | <h2 id="switch">switch</h2> | 2196 | <h2 id="switch">switch</h2> |
| 2193 | <pre><code class="zig">const assert = @import("std").debug.assert; | 2197 | <pre><code class="zig">const assert = @import("std").debug.assert; |
| 2194 | const builtin = @import("builtin"); | 2198 | const builtin = @import("builtin"); |
| ... | @@ -5117,6 +5121,9 @@ comptime { | ... | @@ -5117,6 +5121,9 @@ comptime { |
| 5117 | <h3 id="undef-incorrect-pointer-alignment">Incorrect Pointer Alignment</h3> | 5121 | <h3 id="undef-incorrect-pointer-alignment">Incorrect Pointer Alignment</h3> |
| 5118 | <p>TODO</p> | 5122 | <p>TODO</p> |
| 5119 | 5123 | ||
| 5124 | <h3 id="undef-bad-union-field">Wrong Union Field Access</h3> | ||
| 5125 | <p>TODO</p> | ||
| 5126 | |||
| 5120 | <h2 id="memory">Memory</h2> | 5127 | <h2 id="memory">Memory</h2> |
| 5121 | <p>TODO: explain no default allocator in zig</p> | 5128 | <p>TODO: explain no default allocator in zig</p> |
| 5122 | <p>TODO: show how to use the allocator interface</p> | 5129 | <p>TODO: show how to use the allocator interface</p> |
| ... | @@ -5405,10 +5412,14 @@ const c = @cImport({ | ... | @@ -5405,10 +5412,14 @@ const c = @cImport({ |
| 5405 | export fn decode_base_64(dest_ptr: &amp;u8, dest_len: usize, | 5412 | export fn decode_base_64(dest_ptr: &amp;u8, dest_len: usize, |
| 5406 | source_ptr: &amp;const u8, source_len: usize) -&gt; usize | 5413 | source_ptr: &amp;const u8, source_len: usize) -&gt; usize |
| 5407 | { | 5414 | { |
| 5408 | const src = source_ptr[0...source_len]; | 5415 | const src = source_ptr[0..source_len]; |
| 5409 | const dest = dest_ptr[0...dest_len]; | 5416 | const dest = dest_ptr[0..dest_len]; |
| 5410 | return base64.decode(dest, src).len; | 5417 | const base64_decoder = base64.standard_decoder_unsafe; |
| 5411 | }</code></pre> | 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 | <h4>test.c</h4> | 5423 | <h4>test.c</h4> |
| 5413 | <pre><code class="c">// This header is generated by zig from base64.zig | 5424 | <pre><code class="c">// This header is generated by zig from base64.zig |
| 5414 | #include "base64.h" | 5425 | #include "base64.h" |
example/mix_o_files/base64.zig+4-1| ... | @@ -3,5 +3,8 @@ const base64 = @import("std").base64; | ... | @@ -3,5 +3,8 @@ const base64 = @import("std").base64; |
| 3 | export fn decode_base_64(dest_ptr: &u8, dest_len: usize, source_ptr: &const u8, source_len: usize) -> usize { | 3 | export fn decode_base_64(dest_ptr: &u8, dest_len: usize, source_ptr: &const u8, source_len: usize) -> usize { |
| 4 | const src = source_ptr[0..source_len]; | 4 | const src = source_ptr[0..source_len]; |
| 5 | const dest = dest_ptr[0..dest_len]; | 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,7 +208,7 @@ fn printUsage(outstream: &io.OutStream) -> %void { |
| 208 | \\ build-exe [source] create executable from source or object files | 208 | \\ build-exe [source] create executable from source or object files |
| 209 | \\ build-lib [source] create library from source or object files | 209 | \\ build-lib [source] create library from source or object files |
| 210 | \\ build-obj [source] create object from source or assembly | 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 | \\ targets list available compilation targets | 212 | \\ targets list available compilation targets |
| 213 | \\ test [source] create and run a test build | 213 | \\ test [source] create and run a test build |
| 214 | \\ version print version number and exit | 214 | \\ version print version number and exit |
src/all_types.hpp+55-2| ... | @@ -36,6 +36,7 @@ struct IrInstructionCast; | ... | @@ -36,6 +36,7 @@ struct IrInstructionCast; |
| 36 | struct IrBasicBlock; | 36 | struct IrBasicBlock; |
| 37 | struct ScopeDecls; | 37 | struct ScopeDecls; |
| 38 | struct ZigWindowsSDK; | 38 | struct ZigWindowsSDK; |
| 39 | struct Tld; | ||
| 39 | 40 | ||
| 40 | struct IrGotoItem { | 41 | struct IrGotoItem { |
| 41 | AstNode *source_node; | 42 | AstNode *source_node; |
| ... | @@ -59,7 +60,9 @@ struct IrExecutable { | ... | @@ -59,7 +60,9 @@ struct IrExecutable { |
| 59 | Buf *c_import_buf; | 60 | Buf *c_import_buf; |
| 60 | AstNode *source_node; | 61 | AstNode *source_node; |
| 61 | IrExecutable *parent_exec; | 62 | IrExecutable *parent_exec; |
| 63 | IrExecutable *source_exec; | ||
| 62 | Scope *begin_scope; | 64 | Scope *begin_scope; |
| 65 | ZigList<Tld *> tld_list; | ||
| 63 | }; | 66 | }; |
| 64 | 67 | ||
| 65 | enum OutType { | 68 | enum OutType { |
| ... | @@ -73,6 +76,7 @@ enum ConstParentId { | ... | @@ -73,6 +76,7 @@ enum ConstParentId { |
| 73 | ConstParentIdNone, | 76 | ConstParentIdNone, |
| 74 | ConstParentIdStruct, | 77 | ConstParentIdStruct, |
| 75 | ConstParentIdArray, | 78 | ConstParentIdArray, |
| 79 | ConstParentIdUnion, | ||
| 76 | }; | 80 | }; |
| 77 | 81 | ||
| 78 | struct ConstParent { | 82 | struct ConstParent { |
| ... | @@ -87,6 +91,9 @@ struct ConstParent { | ... | @@ -87,6 +91,9 @@ struct ConstParent { |
| 87 | ConstExprValue *struct_val; | 91 | ConstExprValue *struct_val; |
| 88 | size_t field_index; | 92 | size_t field_index; |
| 89 | } p_struct; | 93 | } p_struct; |
| 94 | struct { | ||
| 95 | ConstExprValue *union_val; | ||
| 96 | } p_union; | ||
| 90 | } data; | 97 | } data; |
| 91 | }; | 98 | }; |
| 92 | 99 | ||
| ... | @@ -100,6 +107,12 @@ struct ConstStructValue { | ... | @@ -100,6 +107,12 @@ struct ConstStructValue { |
| 100 | ConstParent parent; | 107 | ConstParent parent; |
| 101 | }; | 108 | }; |
| 102 | 109 | ||
| 110 | struct ConstUnionValue { | ||
| 111 | uint64_t tag; | ||
| 112 | ConstExprValue *payload; | ||
| 113 | ConstParent parent; | ||
| 114 | }; | ||
| 115 | |||
| 103 | enum ConstArraySpecial { | 116 | enum ConstArraySpecial { |
| 104 | ConstArraySpecialNone, | 117 | ConstArraySpecialNone, |
| 105 | ConstArraySpecialUndef, | 118 | ConstArraySpecialUndef, |
| ... | @@ -238,6 +251,7 @@ struct ConstExprValue { | ... | @@ -238,6 +251,7 @@ struct ConstExprValue { |
| 238 | ErrorTableEntry *x_pure_err; | 251 | ErrorTableEntry *x_pure_err; |
| 239 | ConstEnumValue x_enum; | 252 | ConstEnumValue x_enum; |
| 240 | ConstStructValue x_struct; | 253 | ConstStructValue x_struct; |
| 254 | ConstUnionValue x_union; | ||
| 241 | ConstArrayValue x_array; | 255 | ConstArrayValue x_array; |
| 242 | ConstPtrValue x_ptr; | 256 | ConstPtrValue x_ptr; |
| 243 | ImportTableEntry *x_import; | 257 | ImportTableEntry *x_import; |
| ... | @@ -336,6 +350,13 @@ struct TypeEnumField { | ... | @@ -336,6 +350,13 @@ struct TypeEnumField { |
| 336 | uint32_t gen_index; | 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 | enum NodeType { | 360 | enum NodeType { |
| 340 | NodeTypeRoot, | 361 | NodeTypeRoot, |
| 341 | NodeTypeFnProto, | 362 | NodeTypeFnProto, |
| ... | @@ -1021,14 +1042,19 @@ struct TypeTableEntryEnumTag { | ... | @@ -1021,14 +1042,19 @@ struct TypeTableEntryEnumTag { |
| 1021 | LLVMValueRef name_table; | 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 | struct TypeTableEntryUnion { | 1048 | struct TypeTableEntryUnion { |
| 1025 | AstNode *decl_node; | 1049 | AstNode *decl_node; |
| 1026 | ContainerLayout layout; | 1050 | ContainerLayout layout; |
| 1027 | uint32_t src_field_count; | 1051 | uint32_t src_field_count; |
| 1028 | uint32_t gen_field_count; | 1052 | uint32_t gen_field_count; |
| 1029 | TypeStructField *fields; | 1053 | TypeUnionField *fields; |
| 1030 | uint64_t size_bytes; | ||
| 1031 | bool is_invalid; // true if any fields are invalid | 1054 | bool is_invalid; // true if any fields are invalid |
| 1055 | TypeTableEntry *tag_type; | ||
| 1056 | LLVMTypeRef union_type_ref; | ||
| 1057 | |||
| 1032 | ScopeDecls *decls_scope; | 1058 | ScopeDecls *decls_scope; |
| 1033 | 1059 | ||
| 1034 | // set this flag temporarily to detect infinite loops | 1060 | // set this flag temporarily to detect infinite loops |
| ... | @@ -1039,6 +1065,13 @@ struct TypeTableEntryUnion { | ... | @@ -1039,6 +1065,13 @@ struct TypeTableEntryUnion { |
| 1039 | 1065 | ||
| 1040 | bool zero_bits_loop_flag; | 1066 | bool zero_bits_loop_flag; |
| 1041 | bool zero_bits_known; | 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 | struct FnGenParamInfo { | 1077 | struct FnGenParamInfo { |
| ... | @@ -1287,6 +1320,7 @@ enum PanicMsgId { | ... | @@ -1287,6 +1320,7 @@ enum PanicMsgId { |
| 1287 | PanicMsgIdUnwrapMaybeFail, | 1320 | PanicMsgIdUnwrapMaybeFail, |
| 1288 | PanicMsgIdInvalidErrorCode, | 1321 | PanicMsgIdInvalidErrorCode, |
| 1289 | PanicMsgIdIncorrectAlignment, | 1322 | PanicMsgIdIncorrectAlignment, |
| 1323 | PanicMsgIdBadUnionField, | ||
| 1290 | 1324 | ||
| 1291 | PanicMsgIdCount, | 1325 | PanicMsgIdCount, |
| 1292 | }; | 1326 | }; |
| ... | @@ -1796,6 +1830,7 @@ enum IrInstructionId { | ... | @@ -1796,6 +1830,7 @@ enum IrInstructionId { |
| 1796 | IrInstructionIdFieldPtr, | 1830 | IrInstructionIdFieldPtr, |
| 1797 | IrInstructionIdStructFieldPtr, | 1831 | IrInstructionIdStructFieldPtr, |
| 1798 | IrInstructionIdEnumFieldPtr, | 1832 | IrInstructionIdEnumFieldPtr, |
| 1833 | IrInstructionIdUnionFieldPtr, | ||
| 1799 | IrInstructionIdElemPtr, | 1834 | IrInstructionIdElemPtr, |
| 1800 | IrInstructionIdVarPtr, | 1835 | IrInstructionIdVarPtr, |
| 1801 | IrInstructionIdCall, | 1836 | IrInstructionIdCall, |
| ... | @@ -1805,6 +1840,7 @@ enum IrInstructionId { | ... | @@ -1805,6 +1840,7 @@ enum IrInstructionId { |
| 1805 | IrInstructionIdContainerInitList, | 1840 | IrInstructionIdContainerInitList, |
| 1806 | IrInstructionIdContainerInitFields, | 1841 | IrInstructionIdContainerInitFields, |
| 1807 | IrInstructionIdStructInit, | 1842 | IrInstructionIdStructInit, |
| 1843 | IrInstructionIdUnionInit, | ||
| 1808 | IrInstructionIdUnreachable, | 1844 | IrInstructionIdUnreachable, |
| 1809 | IrInstructionIdTypeOf, | 1845 | IrInstructionIdTypeOf, |
| 1810 | IrInstructionIdToPtrType, | 1846 | IrInstructionIdToPtrType, |
| ... | @@ -2060,6 +2096,14 @@ struct IrInstructionEnumFieldPtr { | ... | @@ -2060,6 +2096,14 @@ struct IrInstructionEnumFieldPtr { |
| 2060 | bool is_const; | 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 | struct IrInstructionElemPtr { | 2107 | struct IrInstructionElemPtr { |
| 2064 | IrInstruction base; | 2108 | IrInstruction base; |
| 2065 | 2109 | ||
| ... | @@ -2150,6 +2194,15 @@ struct IrInstructionStructInit { | ... | @@ -2150,6 +2194,15 @@ struct IrInstructionStructInit { |
| 2150 | LLVMValueRef tmp_ptr; | 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 | struct IrInstructionUnreachable { | 2206 | struct IrInstructionUnreachable { |
| 2154 | IrInstruction base; | 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,7 +28,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type); |
| 28 | 28 | ||
| 29 | ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { | 29 | ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { |
| 30 | if (node->owner->c_import_node != nullptr) { | 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 | // failed semantic analysis, which isn't supposed to happen | 32 | // failed semantic analysis, which isn't supposed to happen |
| 33 | ErrorMsg *err = add_node_error(g, node->owner->c_import_node, | 33 | ErrorMsg *err = add_node_error(g, node->owner->c_import_node, |
| 34 | buf_sprintf("compiler bug: @cImport generated invalid zig code")); | 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,7 +48,7 @@ ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { |
| 48 | 48 | ||
| 49 | ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) { | 49 | ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) { |
| 50 | if (node->owner->c_import_node != nullptr) { | 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 | // failed semantic analysis, which isn't supposed to happen | 52 | // failed semantic analysis, which isn't supposed to happen |
| 53 | 53 | ||
| 54 | Buf *note_path = buf_create_from_str("?.c"); | 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,7 +338,7 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) { |
| 338 | TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const, | 338 | TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const, |
| 339 | bool is_volatile, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count) | 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 | TypeId type_id = {}; | 343 | TypeId type_id = {}; |
| 344 | TypeTableEntry **parent_pointer = nullptr; | 344 | TypeTableEntry **parent_pointer = nullptr; |
| ... | @@ -1008,11 +1008,12 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi | ... | @@ -1008,11 +1008,12 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi |
| 1008 | } | 1008 | } |
| 1009 | 1009 | ||
| 1010 | size_t line = decl_node ? decl_node->line : 0; | 1010 | size_t line = decl_node ? decl_node->line : 0; |
| 1011 | unsigned dwarf_kind = ZigLLVMTag_DW_structure_type(); | ||
| 1011 | 1012 | ||
| 1012 | ImportTableEntry *import = get_scope_import(scope); | 1013 | ImportTableEntry *import = get_scope_import(scope); |
| 1013 | entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name); | 1014 | entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name); |
| 1014 | entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, | 1015 | entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, |
| 1015 | ZigLLVMTag_DW_structure_type(), name, | 1016 | dwarf_kind, name, |
| 1016 | ZigLLVMFileToScope(import->di_file), import->di_file, (unsigned)(line + 1)); | 1017 | ZigLLVMFileToScope(import->di_file), import->di_file, (unsigned)(line + 1)); |
| 1017 | 1018 | ||
| 1018 | buf_init_from_str(&entry->name, name); | 1019 | buf_init_from_str(&entry->name, name); |
| ... | @@ -1285,7 +1286,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { | ... | @@ -1285,7 +1286,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1285 | return; | 1286 | return; |
| 1286 | 1287 | ||
| 1287 | resolve_enum_zero_bits(g, enum_type); | 1288 | resolve_enum_zero_bits(g, enum_type); |
| 1288 | if (enum_type->data.enumeration.is_invalid) | 1289 | if (type_is_invalid(enum_type)) |
| 1289 | return; | 1290 | return; |
| 1290 | 1291 | ||
| 1291 | AstNode *decl_node = enum_type->data.enumeration.decl_node; | 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,7 +1835,246 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 1834 | } | 1835 | } |
| 1835 | 1836 | ||
| 1836 | static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { | 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 | static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { | 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,7 +2113,7 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { |
| 1873 | type_enum_field->value = i; | 2113 | type_enum_field->value = i; |
| 1874 | 2114 | ||
| 1875 | type_ensure_zero_bits_known(g, field_type); | 2115 | type_ensure_zero_bits_known(g, field_type); |
| 1876 | if (field_type->id == TypeTableEntryIdInvalid) { | 2116 | if (type_is_invalid(field_type)) { |
| 1877 | enum_type->data.enumeration.is_invalid = true; | 2117 | enum_type->data.enumeration.is_invalid = true; |
| 1878 | continue; | 2118 | continue; |
| 1879 | } | 2119 | } |
| ... | @@ -1980,7 +2220,69 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { | ... | @@ -1980,7 +2220,69 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { |
| 1980 | } | 2220 | } |
| 1981 | 2221 | ||
| 1982 | static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { | 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 | static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) { | 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,6 +3153,18 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) { |
| 2851 | return nullptr; | 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 | static bool is_container(TypeTableEntry *type_entry) { | 3168 | static bool is_container(TypeTableEntry *type_entry) { |
| 2855 | switch (type_entry->id) { | 3169 | switch (type_entry->id) { |
| 2856 | case TypeTableEntryIdInvalid: | 3170 | case TypeTableEntryIdInvalid: |
| ... | @@ -4703,6 +5017,8 @@ ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { | ... | @@ -4703,6 +5017,8 @@ ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { |
| 4703 | return &value->data.x_array.s_none.parent; | 5017 | return &value->data.x_array.s_none.parent; |
| 4704 | } else if (type_entry->id == TypeTableEntryIdStruct) { | 5018 | } else if (type_entry->id == TypeTableEntryIdStruct) { |
| 4705 | return &value->data.x_struct.parent; | 5019 | return &value->data.x_struct.parent; |
| 5020 | } else if (type_entry->id == TypeTableEntryIdUnion) { | ||
| 5021 | return &value->data.x_union.parent; | ||
| 4706 | } | 5022 | } |
| 4707 | return nullptr; | 5023 | return nullptr; |
| 4708 | } | 5024 | } |
| ... | @@ -4914,7 +5230,8 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) { | ... | @@ -4914,7 +5230,8 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) { |
| 4914 | assert(type_entry->data.enumeration.abi_alignment != 0); | 5230 | assert(type_entry->data.enumeration.abi_alignment != 0); |
| 4915 | return type_entry->data.enumeration.abi_alignment; | 5231 | return type_entry->data.enumeration.abi_alignment; |
| 4916 | } else if (type_entry->id == TypeTableEntryIdUnion) { | 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 | } else if (type_entry->id == TypeTableEntryIdOpaque) { | 5235 | } else if (type_entry->id == TypeTableEntryIdOpaque) { |
| 4919 | return 1; | 5236 | return 1; |
| 4920 | } else { | 5237 | } else { |
| ... | @@ -4929,3 +5246,11 @@ TypeTableEntry *get_align_amt_type(CodeGen *g) { | ... | @@ -4929,3 +5246,11 @@ TypeTableEntry *get_align_amt_type(CodeGen *g) { |
| 4929 | } | 5246 | } |
| 4930 | return g->align_amt_type; | 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,6 +63,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry); |
| 63 | TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name); | 63 | TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name); |
| 64 | ScopeDecls *get_container_scope(TypeTableEntry *type_entry); | 64 | ScopeDecls *get_container_scope(TypeTableEntry *type_entry); |
| 65 | TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name); | 65 | TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name); |
| 66 | TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name); | ||
| 66 | bool is_container_ref(TypeTableEntry *type_entry); | 67 | bool is_container_ref(TypeTableEntry *type_entry); |
| 67 | void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); | 68 | void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); |
| 68 | void scan_import(CodeGen *g, ImportTableEntry *import); | 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,6 +120,7 @@ static void begin_token(CTokenize *ctok, CTokId id) { |
| 120 | case CTokIdLParen: | 120 | case CTokIdLParen: |
| 121 | case CTokIdRParen: | 121 | case CTokIdRParen: |
| 122 | case CTokIdEOF: | 122 | case CTokIdEOF: |
| 123 | case CTokIdDot: | ||
| 123 | break; | 124 | break; |
| 124 | } | 125 | } |
| 125 | } | 126 | } |
| ... | @@ -216,9 +217,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { | ... | @@ -216,9 +217,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { |
| 216 | buf_append_char(&ctok->buf, '0'); | 217 | buf_append_char(&ctok->buf, '0'); |
| 217 | break; | 218 | break; |
| 218 | case '.': | 219 | case '.': |
| 219 | begin_token(ctok, CTokIdNumLitFloat); | 220 | begin_token(ctok, CTokIdDot); |
| 220 | ctok->state = CTokStateFloat; | 221 | end_token(ctok); |
| 221 | buf_init_from_str(&ctok->buf, "0."); | ||
| 222 | break; | 222 | break; |
| 223 | case '(': | 223 | case '(': |
| 224 | begin_token(ctok, CTokIdLParen); | 224 | begin_token(ctok, CTokIdLParen); |
| ... | @@ -238,6 +238,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { | ... | @@ -238,6 +238,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { |
| 238 | break; | 238 | break; |
| 239 | case CTokStateFloat: | 239 | case CTokStateFloat: |
| 240 | switch (*c) { | 240 | switch (*c) { |
| 241 | case '.': | ||
| 242 | break; | ||
| 241 | case 'e': | 243 | case 'e': |
| 242 | case 'E': | 244 | case 'E': |
| 243 | buf_append_char(&ctok->buf, 'e'); | 245 | buf_append_char(&ctok->buf, 'e'); |
src/c_tokenizer.hpp+1| ... | @@ -21,6 +21,7 @@ enum CTokId { | ... | @@ -21,6 +21,7 @@ enum CTokId { |
| 21 | CTokIdLParen, | 21 | CTokIdLParen, |
| 22 | CTokIdRParen, | 22 | CTokIdRParen, |
| 23 | CTokIdEOF, | 23 | CTokIdEOF, |
| 24 | CTokIdDot, | ||
| 24 | }; | 25 | }; |
| 25 | 26 | ||
| 26 | enum CNumLitSuffix { | 27 | enum CNumLitSuffix { |
src/codegen.cpp+155-6| ... | @@ -15,7 +15,7 @@ | ... | @@ -15,7 +15,7 @@ |
| 15 | #include "ir.hpp" | 15 | #include "ir.hpp" |
| 16 | #include "link.hpp" | 16 | #include "link.hpp" |
| 17 | #include "os.hpp" | 17 | #include "os.hpp" |
| 18 | #include "parsec.hpp" | 18 | #include "translate_c.hpp" |
| 19 | #include "target.hpp" | 19 | #include "target.hpp" |
| 20 | #include "zig_llvm.hpp" | 20 | #include "zig_llvm.hpp" |
| 21 | 21 | ||
| ... | @@ -810,6 +810,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { | ... | @@ -810,6 +810,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { |
| 810 | return buf_create_from_str("invalid error code"); | 810 | return buf_create_from_str("invalid error code"); |
| 811 | case PanicMsgIdIncorrectAlignment: | 811 | case PanicMsgIdIncorrectAlignment: |
| 812 | return buf_create_from_str("incorrect alignment"); | 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 | zig_unreachable(); | 816 | zig_unreachable(); |
| 815 | } | 817 | } |
| ... | @@ -2393,6 +2395,50 @@ static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executabl | ... | @@ -2393,6 +2395,50 @@ static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executabl |
| 2393 | return bitcasted_union_field_ptr; | 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 | static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) { | 2442 | static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) { |
| 2397 | const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2; | 2443 | const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2; |
| 2398 | size_t len = tok->end - tok->start - 2; | 2444 | size_t len = tok->end - tok->start - 2; |
| ... | @@ -3365,6 +3411,42 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, | ... | @@ -3365,6 +3411,42 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, |
| 3365 | return instruction->tmp_ptr; | 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 | static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable, | 3450 | static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable, |
| 3369 | IrInstructionContainerInitList *instruction) | 3451 | IrInstructionContainerInitList *instruction) |
| 3370 | { | 3452 | { |
| ... | @@ -3486,6 +3568,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -3486,6 +3568,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3486 | return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction); | 3568 | return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction); |
| 3487 | case IrInstructionIdEnumFieldPtr: | 3569 | case IrInstructionIdEnumFieldPtr: |
| 3488 | return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction); | 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 | case IrInstructionIdAsm: | 3573 | case IrInstructionIdAsm: |
| 3490 | return ir_render_asm(g, executable, (IrInstructionAsm *)instruction); | 3574 | return ir_render_asm(g, executable, (IrInstructionAsm *)instruction); |
| 3491 | case IrInstructionIdTestNonNull: | 3575 | case IrInstructionIdTestNonNull: |
| ... | @@ -3544,6 +3628,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -3544,6 +3628,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3544 | return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction); | 3628 | return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction); |
| 3545 | case IrInstructionIdStructInit: | 3629 | case IrInstructionIdStructInit: |
| 3546 | return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); | 3630 | return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); |
| 3631 | case IrInstructionIdUnionInit: | ||
| 3632 | return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); | ||
| 3547 | case IrInstructionIdPtrCast: | 3633 | case IrInstructionIdPtrCast: |
| 3548 | return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction); | 3634 | return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction); |
| 3549 | case IrInstructionIdBitCast: | 3635 | case IrInstructionIdBitCast: |
| ... | @@ -3595,6 +3681,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) { | ... | @@ -3595,6 +3681,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) { |
| 3595 | 3681 | ||
| 3596 | static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index); | 3682 | static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index); |
| 3597 | static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index); | 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 | static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) { | 3686 | static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) { |
| 3600 | switch (parent->id) { | 3687 | switch (parent->id) { |
| ... | @@ -3608,6 +3695,8 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent | ... | @@ -3608,6 +3695,8 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent |
| 3608 | case ConstParentIdArray: | 3695 | case ConstParentIdArray: |
| 3609 | return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val, | 3696 | return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val, |
| 3610 | parent->data.p_array.elem_index); | 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 | zig_unreachable(); | 3701 | zig_unreachable(); |
| 3613 | } | 3702 | } |
| ... | @@ -3637,6 +3726,18 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s | ... | @@ -3637,6 +3726,18 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s |
| 3637 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); | 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 | static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) { | 3741 | static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) { |
| 3641 | switch (const_val->special) { | 3742 | switch (const_val->special) { |
| 3642 | case ConstValSpecialRuntime: | 3743 | case ConstValSpecialRuntime: |
| ... | @@ -3872,10 +3973,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -3872,10 +3973,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3872 | return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count); | 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 | case TypeTableEntryIdArray: | 3976 | case TypeTableEntryIdArray: |
| 3880 | { | 3977 | { |
| 3881 | uint64_t len = type_entry->data.array.len; | 3978 | uint64_t len = type_entry->data.array.len; |
| ... | @@ -3898,6 +3995,55 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -3898,6 +3995,55 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3898 | return LLVMConstArray(element_type_ref, values, (unsigned)len); | 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 | case TypeTableEntryIdEnum: | 4047 | case TypeTableEntryIdEnum: |
| 3902 | { | 4048 | { |
| 3903 | LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref; | 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,6 +4522,9 @@ static void do_code_gen(CodeGen *g) { |
| 4376 | } else if (instruction->id == IrInstructionIdStructInit) { | 4522 | } else if (instruction->id == IrInstructionIdStructInit) { |
| 4377 | IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction; | 4523 | IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction; |
| 4378 | slot = &struct_init_instruction->tmp_ptr; | 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 | } else if (instruction->id == IrInstructionIdCall) { | 4528 | } else if (instruction->id == IrInstructionIdCall) { |
| 4380 | IrInstructionCall *call_instruction = (IrInstructionCall *)instruction; | 4529 | IrInstructionCall *call_instruction = (IrInstructionCall *)instruction; |
| 4381 | slot = &call_instruction->tmp_ptr; | 4530 | slot = &call_instruction->tmp_ptr; |
| ... | @@ -5204,7 +5353,7 @@ static void init(CodeGen *g) { | ... | @@ -5204,7 +5353,7 @@ static void init(CodeGen *g) { |
| 5204 | define_builtin_compile_vars(g); | 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 | find_libc_include_path(g); | 5357 | find_libc_include_path(g); |
| 5209 | 5358 | ||
| 5210 | Buf *src_basename = buf_alloc(); | 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,7 +56,7 @@ PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, |
| 56 | void codegen_add_assembly(CodeGen *g, Buf *path); | 56 | void codegen_add_assembly(CodeGen *g, Buf *path); |
| 57 | void codegen_add_object(CodeGen *g, Buf *object_path); | 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 | #endif | 62 | #endif |
src/ir.cpp+221-38| ... | @@ -11,7 +11,7 @@ | ... | @@ -11,7 +11,7 @@ |
| 11 | #include "ir.hpp" | 11 | #include "ir.hpp" |
| 12 | #include "ir_print.hpp" | 12 | #include "ir_print.hpp" |
| 13 | #include "os.hpp" | 13 | #include "os.hpp" |
| 14 | #include "parsec.hpp" | 14 | #include "translate_c.hpp" |
| 15 | #include "range_set.hpp" | 15 | #include "range_set.hpp" |
| 16 | #include "softfloat.hpp" | 16 | #include "softfloat.hpp" |
| 17 | 17 | ||
| ... | @@ -227,6 +227,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumFieldPtr *) | ... | @@ -227,6 +227,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumFieldPtr *) |
| 227 | return IrInstructionIdEnumFieldPtr; | 227 | return IrInstructionIdEnumFieldPtr; |
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionFieldPtr *) { | ||
| 231 | return IrInstructionIdUnionFieldPtr; | ||
| 232 | } | ||
| 233 | |||
| 230 | static constexpr IrInstructionId ir_instruction_id(IrInstructionElemPtr *) { | 234 | static constexpr IrInstructionId ir_instruction_id(IrInstructionElemPtr *) { |
| 231 | return IrInstructionIdElemPtr; | 235 | return IrInstructionIdElemPtr; |
| 232 | } | 236 | } |
| ... | @@ -351,6 +355,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) { | ... | @@ -351,6 +355,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) { |
| 351 | return IrInstructionIdStructInit; | 355 | return IrInstructionIdStructInit; |
| 352 | } | 356 | } |
| 353 | 357 | ||
| 358 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit *) { | ||
| 359 | return IrInstructionIdUnionInit; | ||
| 360 | } | ||
| 361 | |||
| 354 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMinValue *) { | 362 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMinValue *) { |
| 355 | return IrInstructionIdMinValue; | 363 | return IrInstructionIdMinValue; |
| 356 | } | 364 | } |
| ... | @@ -922,6 +930,27 @@ static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction | ... | @@ -922,6 +930,27 @@ static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction |
| 922 | return new_instruction; | 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 | static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, | 954 | static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 926 | FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, | 955 | FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 927 | bool is_comptime, bool is_inline) | 956 | bool is_comptime, bool is_inline) |
| ... | @@ -1112,6 +1141,28 @@ static IrInstruction *ir_build_struct_init_from(IrBuilder *irb, IrInstruction *o | ... | @@ -1112,6 +1141,28 @@ static IrInstruction *ir_build_struct_init_from(IrBuilder *irb, IrInstruction *o |
| 1112 | return new_instruction; | 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 | static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) { | 1166 | static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 1116 | IrInstructionUnreachable *unreachable_instruction = | 1167 | IrInstructionUnreachable *unreachable_instruction = |
| 1117 | ir_build_instruction<IrInstructionUnreachable>(irb, scope, source_node); | 1168 | ir_build_instruction<IrInstructionUnreachable>(irb, scope, source_node); |
| ... | @@ -2422,6 +2473,13 @@ static IrInstruction *ir_instruction_enumfieldptr_get_dep(IrInstructionEnumField | ... | @@ -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 | static IrInstruction *ir_instruction_elemptr_get_dep(IrInstructionElemPtr *instruction, size_t index) { | 2483 | static IrInstruction *ir_instruction_elemptr_get_dep(IrInstructionElemPtr *instruction, size_t index) { |
| 2426 | switch (index) { | 2484 | switch (index) { |
| 2427 | case 0: return instruction->array_ptr; | 2485 | case 0: return instruction->array_ptr; |
| ... | @@ -2485,6 +2543,13 @@ static IrInstruction *ir_instruction_structinit_get_dep(IrInstructionStructInit | ... | @@ -2485,6 +2543,13 @@ static IrInstruction *ir_instruction_structinit_get_dep(IrInstructionStructInit |
| 2485 | return nullptr; | 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 | static IrInstruction *ir_instruction_unreachable_get_dep(IrInstructionUnreachable *instruction, size_t index) { | 2553 | static IrInstruction *ir_instruction_unreachable_get_dep(IrInstructionUnreachable *instruction, size_t index) { |
| 2489 | return nullptr; | 2554 | return nullptr; |
| 2490 | } | 2555 | } |
| ... | @@ -3099,6 +3164,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t | ... | @@ -3099,6 +3164,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3099 | return ir_instruction_structfieldptr_get_dep((IrInstructionStructFieldPtr *) instruction, index); | 3164 | return ir_instruction_structfieldptr_get_dep((IrInstructionStructFieldPtr *) instruction, index); |
| 3100 | case IrInstructionIdEnumFieldPtr: | 3165 | case IrInstructionIdEnumFieldPtr: |
| 3101 | return ir_instruction_enumfieldptr_get_dep((IrInstructionEnumFieldPtr *) instruction, index); | 3166 | return ir_instruction_enumfieldptr_get_dep((IrInstructionEnumFieldPtr *) instruction, index); |
| 3167 | case IrInstructionIdUnionFieldPtr: | ||
| 3168 | return ir_instruction_unionfieldptr_get_dep((IrInstructionUnionFieldPtr *) instruction, index); | ||
| 3102 | case IrInstructionIdElemPtr: | 3169 | case IrInstructionIdElemPtr: |
| 3103 | return ir_instruction_elemptr_get_dep((IrInstructionElemPtr *) instruction, index); | 3170 | return ir_instruction_elemptr_get_dep((IrInstructionElemPtr *) instruction, index); |
| 3104 | case IrInstructionIdVarPtr: | 3171 | case IrInstructionIdVarPtr: |
| ... | @@ -3117,6 +3184,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t | ... | @@ -3117,6 +3184,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3117 | return ir_instruction_containerinitfields_get_dep((IrInstructionContainerInitFields *) instruction, index); | 3184 | return ir_instruction_containerinitfields_get_dep((IrInstructionContainerInitFields *) instruction, index); |
| 3118 | case IrInstructionIdStructInit: | 3185 | case IrInstructionIdStructInit: |
| 3119 | return ir_instruction_structinit_get_dep((IrInstructionStructInit *) instruction, index); | 3186 | return ir_instruction_structinit_get_dep((IrInstructionStructInit *) instruction, index); |
| 3187 | case IrInstructionIdUnionInit: | ||
| 3188 | return ir_instruction_unioninit_get_dep((IrInstructionUnionInit *) instruction, index); | ||
| 3120 | case IrInstructionIdUnreachable: | 3189 | case IrInstructionIdUnreachable: |
| 3121 | return ir_instruction_unreachable_get_dep((IrInstructionUnreachable *) instruction, index); | 3190 | return ir_instruction_unreachable_get_dep((IrInstructionUnreachable *) instruction, index); |
| 3122 | case IrInstructionIdTypeOf: | 3191 | case IrInstructionIdTypeOf: |
| ... | @@ -6233,8 +6302,9 @@ static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char | ... | @@ -6233,8 +6302,9 @@ static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char |
| 6233 | buf_appendf(name, ")"); | 6302 | buf_appendf(name, ")"); |
| 6234 | return name; | 6303 | return name; |
| 6235 | } else { | 6304 | } else { |
| 6305 | //Note: C-imports do not have valid location information | ||
| 6236 | return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name, | 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,6 +6333,9 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope, |
| 6263 | } | 6333 | } |
| 6264 | irb->codegen->resolve_queue.append(&tld_container->base); | 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 | return ir_build_const_type(irb, parent_scope, node, container_type); | 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,6 +6558,20 @@ static bool ir_goto_pass2(IrBuilder *irb) { |
| 6485 | return true; | 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 | bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_executable) { | 6575 | bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_executable) { |
| 6489 | assert(node->owner); | 6576 | assert(node->owner); |
| 6490 | 6577 | ||
| ... | @@ -6508,7 +6595,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -6508,7 +6595,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 6508 | } | 6595 | } |
| 6509 | 6596 | ||
| 6510 | if (!ir_goto_pass2(irb)) { | 6597 | if (!ir_goto_pass2(irb)) { |
| 6511 | irb->exec->invalid = true; | 6598 | invalidate_exec(ir_executable); |
| 6512 | return false; | 6599 | return false; |
| 6513 | } | 6600 | } |
| 6514 | 6601 | ||
| ... | @@ -6534,7 +6621,7 @@ static void add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, ErrorMsg | ... | @@ -6534,7 +6621,7 @@ static void add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, ErrorMsg |
| 6534 | } | 6621 | } |
| 6535 | 6622 | ||
| 6536 | static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) { | 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 | ErrorMsg *err_msg = add_node_error(codegen, source_node, msg); | 6625 | ErrorMsg *err_msg = add_node_error(codegen, source_node, msg); |
| 6539 | if (exec->parent_exec) { | 6626 | if (exec->parent_exec) { |
| 6540 | add_call_stack_errors(codegen, exec, err_msg, 10); | 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,6 +7984,9 @@ static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instructio |
| 7897 | ConstExprValue *const_val = &const_instr->value; | 7984 | ConstExprValue *const_val = &const_instr->value; |
| 7898 | const_val->type = pointee_type; | 7985 | const_val->type = pointee_type; |
| 7899 | type_ensure_zero_bits_known(ira->codegen, type_entry); | 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 | const_val->data.x_type = get_pointer_to_type_extra(ira->codegen, type_entry, | 7990 | const_val->data.x_type = get_pointer_to_type_extra(ira->codegen, type_entry, |
| 7901 | ptr_is_const, ptr_is_volatile, get_abi_alignment(ira->codegen, type_entry), 0, 0); | 7991 | ptr_is_const, ptr_is_volatile, get_abi_alignment(ira->codegen, type_entry), 0, 0); |
| 7902 | return const_instr; | 7992 | return const_instr; |
| ... | @@ -7984,6 +8074,7 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node | ... | @@ -7984,6 +8074,7 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node |
| 7984 | IrExecutable analyzed_executable = {0}; | 8074 | IrExecutable analyzed_executable = {0}; |
| 7985 | analyzed_executable.source_node = source_node; | 8075 | analyzed_executable.source_node = source_node; |
| 7986 | analyzed_executable.parent_exec = parent_exec; | 8076 | analyzed_executable.parent_exec = parent_exec; |
| 8077 | analyzed_executable.source_exec = &ir_executable; | ||
| 7987 | analyzed_executable.name = exec_name; | 8078 | analyzed_executable.name = exec_name; |
| 7988 | analyzed_executable.is_inline = true; | 8079 | analyzed_executable.is_inline = true; |
| 7989 | analyzed_executable.fn_entry = fn_entry; | 8080 | analyzed_executable.fn_entry = fn_entry; |
| ... | @@ -10279,30 +10370,40 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, | ... | @@ -10279,30 +10370,40 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 10279 | 10370 | ||
| 10280 | bool is_const = (var->value->type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const; | 10371 | bool is_const = (var->value->type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const; |
| 10281 | bool is_volatile = (var->value->type->id == TypeTableEntryIdMetaType) ? is_volatile_ptr : false; | 10372 | bool is_volatile = (var->value->type->id == TypeTableEntryIdMetaType) ? is_volatile_ptr : false; |
| 10282 | if (mem_slot && mem_slot->special != ConstValSpecialRuntime) { | 10373 | if (mem_slot != nullptr) { |
| 10283 | ConstPtrMut ptr_mut; | 10374 | switch (mem_slot->special) { |
| 10284 | if (comptime_var_mem) { | 10375 | case ConstValSpecialRuntime: |
| 10285 | ptr_mut = ConstPtrMutComptimeVar; | 10376 | goto no_mem_slot; |
| 10286 | } else if (var->gen_is_const) { | 10377 | case ConstValSpecialStatic: // fallthrough |
| 10287 | ptr_mut = ConstPtrMutComptimeConst; | 10378 | case ConstValSpecialUndef: { |
| 10288 | } else { | 10379 | ConstPtrMut ptr_mut; |
| 10289 | assert(!comptime_var_mem); | 10380 | if (comptime_var_mem) { |
| 10290 | ptr_mut = ConstPtrMutRuntimeVar; | 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, | 10392 | zig_unreachable(); |
| 10293 | ptr_mut, is_const, is_volatile, var->align_bytes); | 10393 | } |
| 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); | ||
| 10300 | 10394 | ||
| 10301 | bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); | 10395 | no_mem_slot: |
| 10302 | var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack; | ||
| 10303 | 10396 | ||
| 10304 | return var_ptr_instruction; | 10397 | IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb, |
| 10305 | } | 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 | static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, | 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,10 +10509,11 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 10408 | result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type, | 10509 | result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type, |
| 10409 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, | 10510 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, |
| 10410 | nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec); | 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 | ira->codegen->memoized_fn_eval_table.put(exec_scope, result); | 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 | ConstExprValue *out_val = ir_build_const_from(ira, &call_instruction->base); | 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,8 +11519,20 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira, |
| 11417 | return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value, true, false); | 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 | ir_add_error_node(ira, field_ptr_instruction->base.source_node, | 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 | return ira->codegen->builtin_types.entry_invalid; | 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,14 +11542,13 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field |
| 11428 | { | 11542 | { |
| 11429 | TypeTableEntry *bare_type = container_ref_type(container_type); | 11543 | TypeTableEntry *bare_type = container_ref_type(container_type); |
| 11430 | ensure_complete_type(ira->codegen, bare_type); | 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 | assert(container_ptr->value.type->id == TypeTableEntryIdPointer); | 11548 | assert(container_ptr->value.type->id == TypeTableEntryIdPointer); |
| 11433 | bool is_const = container_ptr->value.type->data.pointer.is_const; | 11549 | bool is_const = container_ptr->value.type->data.pointer.is_const; |
| 11434 | bool is_volatile = container_ptr->value.type->data.pointer.is_volatile; | 11550 | bool is_volatile = container_ptr->value.type->data.pointer.is_volatile; |
| 11435 | if (bare_type->id == TypeTableEntryIdStruct) { | 11551 | if (bare_type->id == TypeTableEntryIdStruct) { |
| 11436 | if (bare_type->data.structure.is_invalid) | ||
| 11437 | return ira->codegen->builtin_types.entry_invalid; | ||
| 11438 | |||
| 11439 | TypeStructField *field = find_struct_type_field(bare_type, field_name); | 11552 | TypeStructField *field = find_struct_type_field(bare_type, field_name); |
| 11440 | if (field) { | 11553 | if (field) { |
| 11441 | bool is_packed = (bare_type->data.structure.layout == ContainerLayoutPacked); | 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,9 +11589,6 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field |
| 11476 | field_ptr_instruction, container_ptr, container_type); | 11589 | field_ptr_instruction, container_ptr, container_type); |
| 11477 | } | 11590 | } |
| 11478 | } else if (bare_type->id == TypeTableEntryIdEnum) { | 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 | TypeEnumField *field = find_enum_type_field(bare_type, field_name); | 11592 | TypeEnumField *field = find_enum_type_field(bare_type, field_name); |
| 11483 | if (field) { | 11593 | if (field) { |
| 11484 | ir_build_enum_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field); | 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,7 +11599,15 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field |
| 11489 | field_ptr_instruction, container_ptr, container_type); | 11599 | field_ptr_instruction, container_ptr, container_type); |
| 11490 | } | 11600 | } |
| 11491 | } else if (bare_type->id == TypeTableEntryIdUnion) { | 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 | } else { | 11611 | } else { |
| 11494 | zig_unreachable(); | 11612 | zig_unreachable(); |
| 11495 | } | 11613 | } |
| ... | @@ -13033,9 +13151,71 @@ static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionR | ... | @@ -13033,9 +13151,71 @@ static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionR |
| 13033 | return ir_analyze_ref(ira, &ref_instruction->base, value, ref_instruction->is_const, ref_instruction->is_volatile); | 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 | static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction, | 13213 | static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction, |
| 13037 | TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields) | 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 | if (container_type->id != TypeTableEntryIdStruct || is_slice(container_type)) { | 13219 | if (container_type->id != TypeTableEntryIdStruct || is_slice(container_type)) { |
| 13040 | ir_add_error(ira, instruction, | 13220 | ir_add_error(ira, instruction, |
| 13041 | buf_sprintf("type '%s' does not support struct initialization syntax", | 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,8 +13223,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru |
| 13043 | return ira->codegen->builtin_types.entry_invalid; | 13223 | return ira->codegen->builtin_types.entry_invalid; |
| 13044 | } | 13224 | } |
| 13045 | 13225 | ||
| 13046 | if (!type_is_complete(container_type)) | 13226 | ensure_complete_type(ira->codegen, container_type); |
| 13047 | resolve_container_type(ira->codegen, container_type); | ||
| 13048 | 13227 | ||
| 13049 | size_t actual_field_count = container_type->data.structure.src_field_count; | 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,7 +13249,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru |
| 13070 | TypeStructField *type_field = find_struct_type_field(container_type, field->name); | 13249 | TypeStructField *type_field = find_struct_type_field(container_type, field->name); |
| 13071 | if (!type_field) { | 13250 | if (!type_field) { |
| 13072 | ir_add_error_node(ira, field->source_node, | 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 | buf_ptr(field->name), buf_ptr(&container_type->name))); | 13253 | buf_ptr(field->name), buf_ptr(&container_type->name))); |
| 13075 | return ira->codegen->builtin_types.entry_invalid; | 13254 | return ira->codegen->builtin_types.entry_invalid; |
| 13076 | } | 13255 | } |
| ... | @@ -15657,8 +15836,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -15657,8 +15836,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 15657 | case IrInstructionIdIntToErr: | 15836 | case IrInstructionIdIntToErr: |
| 15658 | case IrInstructionIdErrToInt: | 15837 | case IrInstructionIdErrToInt: |
| 15659 | case IrInstructionIdStructInit: | 15838 | case IrInstructionIdStructInit: |
| 15839 | case IrInstructionIdUnionInit: | ||
| 15660 | case IrInstructionIdStructFieldPtr: | 15840 | case IrInstructionIdStructFieldPtr: |
| 15661 | case IrInstructionIdEnumFieldPtr: | 15841 | case IrInstructionIdEnumFieldPtr: |
| 15842 | case IrInstructionIdUnionFieldPtr: | ||
| 15662 | case IrInstructionIdInitEnum: | 15843 | case IrInstructionIdInitEnum: |
| 15663 | case IrInstructionIdMaybeWrap: | 15844 | case IrInstructionIdMaybeWrap: |
| 15664 | case IrInstructionIdErrWrapCode: | 15845 | case IrInstructionIdErrWrapCode: |
| ... | @@ -15968,6 +16149,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -15968,6 +16149,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 15968 | case IrInstructionIdContainerInitList: | 16149 | case IrInstructionIdContainerInitList: |
| 15969 | case IrInstructionIdContainerInitFields: | 16150 | case IrInstructionIdContainerInitFields: |
| 15970 | case IrInstructionIdStructInit: | 16151 | case IrInstructionIdStructInit: |
| 16152 | case IrInstructionIdUnionInit: | ||
| 15971 | case IrInstructionIdFieldPtr: | 16153 | case IrInstructionIdFieldPtr: |
| 15972 | case IrInstructionIdElemPtr: | 16154 | case IrInstructionIdElemPtr: |
| 15973 | case IrInstructionIdVarPtr: | 16155 | case IrInstructionIdVarPtr: |
| ... | @@ -15977,6 +16159,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -15977,6 +16159,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 15977 | case IrInstructionIdArrayLen: | 16159 | case IrInstructionIdArrayLen: |
| 15978 | case IrInstructionIdStructFieldPtr: | 16160 | case IrInstructionIdStructFieldPtr: |
| 15979 | case IrInstructionIdEnumFieldPtr: | 16161 | case IrInstructionIdEnumFieldPtr: |
| 16162 | case IrInstructionIdUnionFieldPtr: | ||
| 15980 | case IrInstructionIdArrayType: | 16163 | case IrInstructionIdArrayType: |
| 15981 | case IrInstructionIdSliceType: | 16164 | case IrInstructionIdSliceType: |
| 15982 | case IrInstructionIdSizeOf: | 16165 | case IrInstructionIdSizeOf: |
src/ir_print.cpp+22| ... | @@ -290,6 +290,15 @@ static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruct | ... | @@ -290,6 +290,15 @@ static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruct |
| 290 | fprintf(irp->f, "} // struct init"); | 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 | static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) { | 302 | static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) { |
| 294 | fprintf(irp->f, "unreachable"); | 303 | fprintf(irp->f, "unreachable"); |
| 295 | } | 304 | } |
| ... | @@ -359,6 +368,13 @@ static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *ins | ... | @@ -359,6 +368,13 @@ static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *ins |
| 359 | fprintf(irp->f, ")"); | 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 | static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety *instruction) { | 378 | static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety *instruction) { |
| 363 | fprintf(irp->f, "@setDebugSafety("); | 379 | fprintf(irp->f, "@setDebugSafety("); |
| 364 | ir_print_other_instruction(irp, instruction->scope_value); | 380 | ir_print_other_instruction(irp, instruction->scope_value); |
| ... | @@ -1023,6 +1039,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1023,6 +1039,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1023 | case IrInstructionIdStructInit: | 1039 | case IrInstructionIdStructInit: |
| 1024 | ir_print_struct_init(irp, (IrInstructionStructInit *)instruction); | 1040 | ir_print_struct_init(irp, (IrInstructionStructInit *)instruction); |
| 1025 | break; | 1041 | break; |
| 1042 | case IrInstructionIdUnionInit: | ||
| 1043 | ir_print_union_init(irp, (IrInstructionUnionInit *)instruction); | ||
| 1044 | break; | ||
| 1026 | case IrInstructionIdUnreachable: | 1045 | case IrInstructionIdUnreachable: |
| 1027 | ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction); | 1046 | ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction); |
| 1028 | break; | 1047 | break; |
| ... | @@ -1056,6 +1075,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1056,6 +1075,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1056 | case IrInstructionIdEnumFieldPtr: | 1075 | case IrInstructionIdEnumFieldPtr: |
| 1057 | ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction); | 1076 | ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction); |
| 1058 | break; | 1077 | break; |
| 1078 | case IrInstructionIdUnionFieldPtr: | ||
| 1079 | ir_print_union_field_ptr(irp, (IrInstructionUnionFieldPtr *)instruction); | ||
| 1080 | break; | ||
| 1059 | case IrInstructionIdSetDebugSafety: | 1081 | case IrInstructionIdSetDebugSafety: |
| 1060 | ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction); | 1082 | ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction); |
| 1061 | break; | 1083 | break; |
src/main.cpp+11-11| ... | @@ -23,7 +23,7 @@ static int usage(const char *arg0) { | ... | @@ -23,7 +23,7 @@ static int usage(const char *arg0) { |
| 23 | " build-exe [source] create executable from source or object files\n" | 23 | " build-exe [source] create executable from source or object files\n" |
| 24 | " build-lib [source] create library from source or object files\n" | 24 | " build-lib [source] create library from source or object files\n" |
| 25 | " build-obj [source] create object from source or assembly\n" | 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 | " targets list available compilation targets\n" | 27 | " targets list available compilation targets\n" |
| 28 | " test [source] create and run a test build\n" | 28 | " test [source] create and run a test build\n" |
| 29 | " version print version number and exit\n" | 29 | " version print version number and exit\n" |
| ... | @@ -229,7 +229,7 @@ enum Cmd { | ... | @@ -229,7 +229,7 @@ enum Cmd { |
| 229 | CmdTest, | 229 | CmdTest, |
| 230 | CmdVersion, | 230 | CmdVersion, |
| 231 | CmdZen, | 231 | CmdZen, |
| 232 | CmdParseC, | 232 | CmdTranslateC, |
| 233 | CmdTargets, | 233 | CmdTargets, |
| 234 | }; | 234 | }; |
| 235 | 235 | ||
| ... | @@ -632,8 +632,8 @@ int main(int argc, char **argv) { | ... | @@ -632,8 +632,8 @@ int main(int argc, char **argv) { |
| 632 | cmd = CmdVersion; | 632 | cmd = CmdVersion; |
| 633 | } else if (strcmp(arg, "zen") == 0) { | 633 | } else if (strcmp(arg, "zen") == 0) { |
| 634 | cmd = CmdZen; | 634 | cmd = CmdZen; |
| 635 | } else if (strcmp(arg, "parsec") == 0) { | 635 | } else if (strcmp(arg, "translate-c") == 0) { |
| 636 | cmd = CmdParseC; | 636 | cmd = CmdTranslateC; |
| 637 | } else if (strcmp(arg, "test") == 0) { | 637 | } else if (strcmp(arg, "test") == 0) { |
| 638 | cmd = CmdTest; | 638 | cmd = CmdTest; |
| 639 | out_type = OutTypeExe; | 639 | out_type = OutTypeExe; |
| ... | @@ -646,7 +646,7 @@ int main(int argc, char **argv) { | ... | @@ -646,7 +646,7 @@ int main(int argc, char **argv) { |
| 646 | } else { | 646 | } else { |
| 647 | switch (cmd) { | 647 | switch (cmd) { |
| 648 | case CmdBuild: | 648 | case CmdBuild: |
| 649 | case CmdParseC: | 649 | case CmdTranslateC: |
| 650 | case CmdTest: | 650 | case CmdTest: |
| 651 | if (!in_file) { | 651 | if (!in_file) { |
| 652 | in_file = arg; | 652 | in_file = arg; |
| ... | @@ -703,13 +703,13 @@ int main(int argc, char **argv) { | ... | @@ -703,13 +703,13 @@ int main(int argc, char **argv) { |
| 703 | 703 | ||
| 704 | switch (cmd) { | 704 | switch (cmd) { |
| 705 | case CmdBuild: | 705 | case CmdBuild: |
| 706 | case CmdParseC: | 706 | case CmdTranslateC: |
| 707 | case CmdTest: | 707 | case CmdTest: |
| 708 | { | 708 | { |
| 709 | if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) { | 709 | if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) { |
| 710 | fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n"); | 710 | fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n"); |
| 711 | return usage(arg0); | 711 | return usage(arg0); |
| 712 | } else if ((cmd == CmdParseC || cmd == CmdTest) && !in_file) { | 712 | } else if ((cmd == CmdTranslateC || cmd == CmdTest) && !in_file) { |
| 713 | fprintf(stderr, "Expected source file argument.\n"); | 713 | fprintf(stderr, "Expected source file argument.\n"); |
| 714 | return usage(arg0); | 714 | return usage(arg0); |
| 715 | } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) { | 715 | } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) { |
| ... | @@ -719,7 +719,7 @@ int main(int argc, char **argv) { | ... | @@ -719,7 +719,7 @@ int main(int argc, char **argv) { |
| 719 | 719 | ||
| 720 | assert(cmd != CmdBuild || out_type != OutTypeUnknown); | 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 | Buf *in_file_buf = nullptr; | 724 | Buf *in_file_buf = nullptr; |
| 725 | 725 | ||
| ... | @@ -742,7 +742,7 @@ int main(int argc, char **argv) { | ... | @@ -742,7 +742,7 @@ int main(int argc, char **argv) { |
| 742 | return usage(arg0); | 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 | Buf *full_cache_dir = buf_alloc(); | 747 | Buf *full_cache_dir = buf_alloc(); |
| 748 | os_path_resolve(buf_create_from_str("."), | 748 | os_path_resolve(buf_create_from_str("."), |
| ... | @@ -841,8 +841,8 @@ int main(int argc, char **argv) { | ... | @@ -841,8 +841,8 @@ int main(int argc, char **argv) { |
| 841 | if (timing_info) | 841 | if (timing_info) |
| 842 | codegen_print_timing_report(g, stdout); | 842 | codegen_print_timing_report(g, stdout); |
| 843 | return EXIT_SUCCESS; | 843 | return EXIT_SUCCESS; |
| 844 | } else if (cmd == CmdParseC) { | 844 | } else if (cmd == CmdTranslateC) { |
| 845 | codegen_parsec(g, in_file_buf); | 845 | codegen_translate_c(g, in_file_buf); |
| 846 | ast_render(g, stdout, g->root_import->root, 4); | 846 | ast_render(g, stdout, g->root_import->root, 4); |
| 847 | if (timing_info) | 847 | if (timing_info) |
| 848 | codegen_print_timing_report(g, stdout); | 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,6 +403,10 @@ unsigned ZigLLVMTag_DW_structure_type(void) { |
| 403 | return dwarf::DW_TAG_structure_type; | 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 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) { | 410 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) { |
| 407 | DIBuilder *di_builder = new DIBuilder(*unwrap(module), allow_unresolved); | 411 | DIBuilder *di_builder = new DIBuilder(*unwrap(module), allow_unresolved); |
| 408 | return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder); | 412 | return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder); |
src/zig_llvm.hpp+1| ... | @@ -117,6 +117,7 @@ unsigned ZigLLVMEncoding_DW_ATE_signed_char(void); | ... | @@ -117,6 +117,7 @@ unsigned ZigLLVMEncoding_DW_ATE_signed_char(void); |
| 117 | unsigned ZigLLVMLang_DW_LANG_C99(void); | 117 | unsigned ZigLLVMLang_DW_LANG_C99(void); |
| 118 | unsigned ZigLLVMTag_DW_variable(void); | 118 | unsigned ZigLLVMTag_DW_variable(void); |
| 119 | unsigned ZigLLVMTag_DW_structure_type(void); | 119 | unsigned ZigLLVMTag_DW_structure_type(void); |
| 120 | unsigned ZigLLVMTag_DW_union_type(void); | ||
| 120 | 121 | ||
| 121 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved); | 122 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved); |
| 122 | void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module); | 123 | void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module); |
std/base64.zig+432-133| ... | @@ -1,186 +1,485 @@ | ... | @@ -1,186 +1,485 @@ |
| 1 | const assert = @import("debug.zig").assert; | 1 | const assert = @import("debug.zig").assert; |
| 2 | const mem = @import("mem.zig"); | 2 | const mem = @import("mem.zig"); |
| 3 | 3 | ||
| 4 | pub const standard_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; | 4 | pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
| 5 | 5 | pub const standard_pad_char = '='; | |
| 6 | pub fn encode(dest: []u8, source: []const u8) -> []u8 { | 6 | pub const standard_encoder = Base64Encoder.init(standard_alphabet_chars, standard_pad_char); |
| 7 | return encodeWithAlphabet(dest, source, standard_alphabet); | 7 | |
| 8 | } | 8 | pub const Base64Encoder = struct { |
| 9 | 9 | alphabet_chars: []const u8, | |
| 10 | /// invalid characters in source are allowed, but they cause the value of dest to be undefined. | 10 | pad_char: u8, |
| 11 | pub fn decode(dest: []u8, source: []const u8) -> []u8 { | 11 | |
| 12 | return decodeWithAlphabet(dest, source, standard_alphabet); | 12 | /// a bunch of assertions, then simply pass the data right through. |
| 13 | } | 13 | pub fn init(alphabet_chars: []const u8, pad_char: u8) -> Base64Encoder { |
| 14 | 14 | assert(alphabet_chars.len == 64); | |
| 15 | pub fn encodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8) -> []u8 { | 15 | var char_in_alphabet = []bool{false} ** 256; |
| 16 | assert(alphabet.len == 65); | 16 | for (alphabet_chars) |c| { |
| 17 | assert(dest.len >= calcEncodedSize(source.len)); | 17 | assert(!char_in_alphabet[c]); |
| 18 | 18 | assert(c != pad_char); | |
| 19 | var i: usize = 0; | 19 | char_in_alphabet[c] = true; |
| 20 | var out_index: usize = 0; | 20 | } |
| 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; | ||
| 28 | 21 | ||
| 29 | dest[out_index] = alphabet[((source[i + 1] & 0xf) << 2) | | 22 | return Base64Encoder{ |
| 30 | ((source[i + 2] & 0xc0) >> 6)]; | 23 | .alphabet_chars = alphabet_chars, |
| 31 | out_index += 1; | 24 | .pad_char = pad_char, |
| 25 | }; | ||
| 26 | } | ||
| 32 | 27 | ||
| 33 | dest[out_index] = alphabet[source[i + 2] & 0x3f]; | 28 | /// ceil(source_len * 4/3) |
| 34 | out_index += 1; | 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) { | 33 | /// dest.len must be what you get from ::calcSize. |
| 38 | dest[out_index] = alphabet[(source[i] >> 2) & 0x3f]; | 34 | pub fn encode(encoder: &const Base64Encoder, dest: []u8, source: []const u8) { |
| 39 | out_index += 1; | 35 | assert(dest.len == Base64Encoder.calcSize(source.len)); |
| 40 | 36 | ||
| 41 | if (i + 1 == source.len) { | 37 | var i: usize = 0; |
| 42 | dest[out_index] = alphabet[(source[i] & 0x3) << 4]; | 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 | out_index += 1; | 41 | out_index += 1; |
| 44 | 42 | ||
| 45 | dest[out_index] = alphabet[64]; | 43 | dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) | |
| 46 | out_index += 1; | ||
| 47 | } else { | ||
| 48 | dest[out_index] = alphabet[((source[i] & 0x3) << 4) | | ||
| 49 | ((source[i + 1] & 0xf0) >> 4)]; | 44 | ((source[i + 1] & 0xf0) >> 4)]; |
| 50 | out_index += 1; | 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 | out_index += 1; | 52 | out_index += 1; |
| 54 | } | 53 | } |
| 55 | 54 | ||
| 56 | dest[out_index] = alphabet[64]; | 55 | if (i < source.len) { |
| 57 | out_index += 1; | 56 | dest[out_index] = encoder.alphabet_chars[(source[i] >> 2) & 0x3f]; |
| 58 | } | 57 | out_index += 1; |
| 59 | 58 | ||
| 60 | return dest[0..out_index]; | 59 | if (i + 1 == source.len) { |
| 61 | } | 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. | 70 | dest[out_index] = encoder.alphabet_chars[(source[i + 1] & 0xf) << 2]; |
| 64 | pub fn decodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8) -> []u8 { | 71 | out_index += 1; |
| 65 | assert(alphabet.len == 65); | 72 | } |
| 66 | 73 | ||
| 67 | var ascii6 = []u8{64} ** 256; | 74 | dest[out_index] = encoder.pad_char; |
| 68 | for (alphabet) |c, i| { | 75 | out_index += 1; |
| 69 | ascii6[c] = u8(i); | 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]); | 109 | return result; |
| 73 | } | 110 | } |
| 74 | 111 | ||
| 75 | pub fn decodeWithAscii6BitMap(dest: []u8, source: []const u8, ascii6: []const u8, pad_char: u8) -> []u8 { | 112 | /// If the encoded buffer is detected to be invalid, returns error.InvalidPadding. |
| 76 | assert(ascii6.len == 256); | 113 | pub fn calcSize(decoder: &const Base64Decoder, source: []const u8) -> %usize { |
| 77 | assert(dest.len >= calcExactDecodedSizeWithPadChar(source, pad_char)); | 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; | 118 | /// dest.len must be what you get from ::calcSize. |
| 80 | var dest_index: usize = 0; | 119 | /// invalid characters result in error.InvalidCharacter. |
| 81 | var in_buf_len: usize = source.len; | 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) { | 160 | assert(src_cursor == source.len); |
| 84 | in_buf_len -= 1; | 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) { | 183 | return result; |
| 88 | dest[dest_index] = ascii6[source[src_index + 0]] << 2 | | 184 | } |
| 89 | ascii6[source[src_index + 1]] >> 4; | ||
| 90 | dest_index += 1; | ||
| 91 | 185 | ||
| 92 | dest[dest_index] = ascii6[source[src_index + 1]] << 4 | | 186 | /// If no characters end up being ignored or padding, this will be the exact decoded size. |
| 93 | ascii6[source[src_index + 2]] >> 2; | 187 | pub fn calcSizeUpperBound(encoded_len: usize) -> %usize { |
| 94 | dest_index += 1; | 188 | return @divTrunc(encoded_len, 4) * 3; |
| 189 | } | ||
| 95 | 190 | ||
| 96 | dest[dest_index] = ascii6[source[src_index + 2]] << 6 | | 191 | /// Invalid characters that are not ignored result in error.InvalidCharacter. |
| 97 | ascii6[source[src_index + 3]]; | 192 | /// Invalid padding results in error.InvalidPadding. |
| 98 | dest_index += 1; | 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; | 280 | assert(src_cursor == source.len); |
| 101 | in_buf_len -= 4; | ||
| 102 | } | ||
| 103 | 281 | ||
| 104 | if (in_buf_len > 1) { | 282 | return dest_cursor; |
| 105 | dest[dest_index] = ascii6[source[src_index + 0]] << 2 | | ||
| 106 | ascii6[source[src_index + 1]] >> 4; | ||
| 107 | dest_index += 1; | ||
| 108 | } | 283 | } |
| 109 | if (in_buf_len > 2) { | 284 | }; |
| 110 | dest[dest_index] = ascii6[source[src_index + 1]] << 4 | | 285 | |
| 111 | ascii6[source[src_index + 2]] >> 2; | 286 | |
| 112 | dest_index += 1; | 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) { | 307 | |
| 115 | dest[dest_index] = ascii6[source[src_index + 2]] << 6 | | 308 | /// The source buffer must be valid. |
| 116 | ascii6[source[src_index + 3]]; | 309 | pub fn calcSize(decoder: &const Base64DecoderUnsafe, source: []const u8) -> usize { |
| 117 | dest_index += 1; | 310 | return calcDecodedSizeExactUnsafe(source, decoder.pad_char); |
| 118 | } | 311 | } |
| 119 | 312 | ||
| 120 | return dest[0..dest_index]; | 313 | /// dest.len must be what you get from ::calcDecodedSizeExactUnsafe. |
| 121 | } | 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 { | 318 | var src_index: usize = 0; |
| 124 | return (((source_len * 4) / 3 + 3) / 4) * 4; | 319 | var dest_index: usize = 0; |
| 125 | } | 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. | 322 | while (in_buf_len > 0 and source[in_buf_len - 1] == decoder.pad_char) { |
| 128 | /// To compute the exact decoded size, see ::calcExactDecodedSize | 323 | in_buf_len -= 1; |
| 129 | pub fn calcMaxDecodedSize(encoded_len: usize) -> usize { | 324 | } |
| 130 | return @divExact(encoded_len * 3, 4); | ||
| 131 | } | ||
| 132 | 325 | ||
| 133 | /// Computes the number of decoded bytes there will be. This function must | 326 | while (in_buf_len > 4) { |
| 134 | /// be given the encoded buffer because there might be padding | 327 | dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 | |
| 135 | /// bytes at the end ('=' in the standard alphabet) | 328 | decoder.char_to_index[source[src_index + 1]] >> 4; |
| 136 | pub fn calcExactDecodedSize(encoded: []const u8) -> usize { | 329 | dest_index += 1; |
| 137 | return calcExactDecodedSizeWithAlphabet(encoded, standard_alphabet); | ||
| 138 | } | ||
| 139 | 330 | ||
| 140 | pub fn calcExactDecodedSizeWithAlphabet(encoded: []const u8, alphabet: []const u8) -> usize { | 331 | dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 | |
| 141 | assert(alphabet.len == 65); | 332 | decoder.char_to_index[source[src_index + 2]] >> 2; |
| 142 | return calcExactDecodedSizeWithPadChar(encoded, alphabet[64]); | 333 | dest_index += 1; |
| 143 | } | ||
| 144 | 334 | ||
| 145 | pub fn calcExactDecodedSizeWithPadChar(encoded: []const u8, pad_char: u8) -> usize { | 335 | dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 | |
| 146 | var buf_len = encoded.len; | 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) { | 339 | src_index += 4; |
| 149 | buf_len -= 1; | 340 | in_buf_len -= 4; |
| 150 | } | 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 | test "base64" { | 374 | test "base64" { |
| 156 | testBase64(); | 375 | @setEvalBranchQuota(5000); |
| 157 | comptime testBase64(); | 376 | %%testBase64(); |
| 377 | comptime %%testBase64(); | ||
| 158 | } | 378 | } |
| 159 | 379 | ||
| 160 | fn testBase64() { | 380 | fn testBase64() -> %void { |
| 161 | testBase64Case("", ""); | 381 | %return testAllApis("", ""); |
| 162 | testBase64Case("f", "Zg=="); | 382 | %return testAllApis("f", "Zg=="); |
| 163 | testBase64Case("fo", "Zm8="); | 383 | %return testAllApis("fo", "Zm8="); |
| 164 | testBase64Case("foo", "Zm9v"); | 384 | %return testAllApis("foo", "Zm9v"); |
| 165 | testBase64Case("foob", "Zm9vYg=="); | 385 | %return testAllApis("foob", "Zm9vYg=="); |
| 166 | testBase64Case("fooba", "Zm9vYmE="); | 386 | %return testAllApis("fooba", "Zm9vYmE="); |
| 167 | testBase64Case("foobar", "Zm9vYmFy"); | 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) { | 414 | fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) -> %void { |
| 171 | const calculated_decoded_len = calcExactDecodedSize(expected_encoded); | 415 | // Base64Encoder |
| 172 | assert(calculated_decoded_len == expected_decoded.len); | 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); | 423 | // Base64Decoder |
| 175 | assert(calculated_encoded_len == expected_encoded.len); | 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); | 442 | // Base64DecoderUnsafe |
| 180 | assert(actual_decoded.len == expected_decoded.len); | 443 | { |
| 181 | assert(mem.eql(u8, expected_decoded, actual_decoded)); | 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); | 477 | fn testOutputTooSmallError(encoded: []const u8) -> %void { |
| 184 | assert(actual_encoded.len == expected_encoded.len); | 478 | const standard_decoder_ignore_space = Base64DecoderWithIgnore.init( |
| 185 | assert(mem.eql(u8, expected_encoded, actual_encoded)); | 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,6 +31,8 @@ pub const windowsWaitSingle = windows_util.windowsWaitSingle; |
| 31 | pub const windowsWrite = windows_util.windowsWrite; | 31 | pub const windowsWrite = windows_util.windowsWrite; |
| 32 | pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty; | 32 | pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty; |
| 33 | pub const windowsOpen = windows_util.windowsOpen; | 33 | pub const windowsOpen = windows_util.windowsOpen; |
| 34 | pub const windowsLoadDll = windows_util.windowsLoadDll; | ||
| 35 | pub const windowsUnloadDll = windows_util.windowsUnloadDll; | ||
| 34 | pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock; | 36 | pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock; |
| 35 | 37 | ||
| 36 | pub const FileHandle = if (is_windows) windows.HANDLE else i32; | 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,7 +622,9 @@ pub fn symLinkPosix(allocator: &Allocator, existing_path: []const u8, new_path: |
| 620 | } | 622 | } |
| 621 | 623 | ||
| 622 | // here we replace the standard +/ with -_ so that it can be used in a file name | 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 | pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) -> %void { | 629 | pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) -> %void { |
| 626 | if (symLink(allocator, existing_path, new_path)) { | 630 | if (symLink(allocator, existing_path, new_path)) { |
| ... | @@ -632,12 +636,12 @@ pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: | ... | @@ -632,12 +636,12 @@ pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: |
| 632 | } | 636 | } |
| 633 | 637 | ||
| 634 | var rand_buf: [12]u8 = undefined; | 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 | defer allocator.free(tmp_path); | 640 | defer allocator.free(tmp_path); |
| 637 | mem.copy(u8, tmp_path[0..], new_path); | 641 | mem.copy(u8, tmp_path[0..], new_path); |
| 638 | while (true) { | 642 | while (true) { |
| 639 | %return getRandomBytes(rand_buf[0..]); | 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 | if (symLink(allocator, existing_path, tmp_path)) { | 645 | if (symLink(allocator, existing_path, tmp_path)) { |
| 642 | return rename(allocator, tmp_path, new_path); | 646 | return rename(allocator, tmp_path, new_path); |
| 643 | } else |err| { | 647 | } else |err| { |
| ... | @@ -715,11 +719,11 @@ pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []con | ... | @@ -715,11 +719,11 @@ pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []con |
| 715 | /// Guaranteed to be atomic. | 719 | /// Guaranteed to be atomic. |
| 716 | pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: []const u8, mode: usize) -> %void { | 720 | pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: []const u8, mode: usize) -> %void { |
| 717 | var rand_buf: [12]u8 = undefined; | 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 | defer allocator.free(tmp_path); | 723 | defer allocator.free(tmp_path); |
| 720 | mem.copy(u8, tmp_path[0..], dest_path); | 724 | mem.copy(u8, tmp_path[0..], dest_path); |
| 721 | %return getRandomBytes(rand_buf[0..]); | 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 | var out_file = %return io.File.openWriteMode(tmp_path, mode, allocator); | 728 | var out_file = %return io.File.openWriteMode(tmp_path, mode, allocator); |
| 725 | defer out_file.close(); | 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,6 +84,11 @@ pub extern "kernel32" stdcallcc fn WriteFile(in_hFile: HANDLE, in_lpBuffer: &con |
| 84 | in_nNumberOfBytesToWrite: DWORD, out_lpNumberOfBytesWritten: ?&DWORD, | 84 | in_nNumberOfBytesToWrite: DWORD, out_lpNumberOfBytesWritten: ?&DWORD, |
| 85 | in_out_lpOverlapped: ?&OVERLAPPED) -> BOOL; | 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 | pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) -> c_int; | 92 | pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) -> c_int; |
| 88 | 93 | ||
| 89 | pub const PROV_RSA_FULL = 1; | 94 | pub const PROV_RSA_FULL = 1; |
| ... | @@ -97,6 +102,7 @@ pub const FLOAT = f32; | ... | @@ -97,6 +102,7 @@ pub const FLOAT = f32; |
| 97 | pub const HANDLE = &c_void; | 102 | pub const HANDLE = &c_void; |
| 98 | pub const HCRYPTPROV = ULONG_PTR; | 103 | pub const HCRYPTPROV = ULONG_PTR; |
| 99 | pub const HINSTANCE = &@OpaqueType(); | 104 | pub const HINSTANCE = &@OpaqueType(); |
| 105 | pub const HMODULE = &@OpaqueType(); | ||
| 100 | pub const INT = c_int; | 106 | pub const INT = c_int; |
| 101 | pub const LPBYTE = &BYTE; | 107 | pub const LPBYTE = &BYTE; |
| 102 | pub const LPCH = &CHAR; | 108 | pub const LPCH = &CHAR; |
std/os/windows/util.zig+23| ... | @@ -4,6 +4,7 @@ const windows = std.os.windows; | ... | @@ -4,6 +4,7 @@ const windows = std.os.windows; |
| 4 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 5 | const mem = std.mem; | 5 | const mem = std.mem; |
| 6 | const BufMap = std.BufMap; | 6 | const BufMap = std.BufMap; |
| 7 | const cstr = std.cstr; | ||
| 7 | 8 | ||
| 8 | error WaitAbandoned; | 9 | error WaitAbandoned; |
| 9 | error WaitTimeOut; | 10 | error WaitTimeOut; |
| ... | @@ -149,3 +150,25 @@ pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) | ... | @@ -149,3 +150,25 @@ pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap) |
| 149 | result[i] = 0; | 150 | result[i] = 0; |
| 150 | return result; | 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,3 +31,47 @@ test "unions embedded in aggregate types" { |
| 31 | else => unreachable, | 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,8 +389,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 389 | \\ const y = a.bar; | 389 | \\ const y = a.bar; |
| 390 | \\} | 390 | \\} |
| 391 | , | 391 | , |
| 392 | ".tmp_source.zig:4:6: error: no member named 'foo' 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 'A'"); | 393 | ".tmp_source.zig:5:16: error: no member named 'bar' in struct 'A'"); |
| 394 | 394 | ||
| 395 | cases.add("redefinition of struct", | 395 | cases.add("redefinition of struct", |
| 396 | \\const A = struct { x : i32, }; | 396 | \\const A = struct { x : i32, }; |
| ... | @@ -454,7 +454,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -454,7 +454,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 454 | \\ .foo = 42, | 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 | cases.add("invalid break expression", | 459 | cases.add("invalid break expression", |
| 460 | \\export fn f() { | 460 | \\export fn f() { |
| ... | @@ -2343,4 +2343,23 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -2343,4 +2343,23 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2343 | \\pub extern fn foo(format: &const u8, ...); | 2343 | \\pub extern fn foo(format: &const u8, ...); |
| 2344 | , | 2344 | , |
| 2345 | ".tmp_source.zig:2:9: error: expected type '&const u8', found '[5]u8'"); | 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,4 +260,24 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 260 | \\ return int_slice[0]; | 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,7 +18,7 @@ const build_examples = @import("build_examples.zig"); |
| 18 | const compile_errors = @import("compile_errors.zig"); | 18 | const compile_errors = @import("compile_errors.zig"); |
| 19 | const assemble_and_link = @import("assemble_and_link.zig"); | 19 | const assemble_and_link = @import("assemble_and_link.zig"); |
| 20 | const debug_safety = @import("debug_safety.zig"); | 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 | const TestTarget = struct { | 23 | const TestTarget = struct { |
| 24 | os: builtin.Os, | 24 | os: builtin.Os, |
| ... | @@ -123,16 +123,16 @@ pub fn addAssembleAndLinkTests(b: &build.Builder, test_filter: ?[]const u8) -> & | ... | @@ -123,16 +123,16 @@ pub fn addAssembleAndLinkTests(b: &build.Builder, test_filter: ?[]const u8) -> & |
| 123 | return cases.step; | 123 | return cases.step; |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | pub fn addParseCTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step { | 126 | pub fn addTranslateCTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step { |
| 127 | const cases = %%b.allocator.create(ParseCContext); | 127 | const cases = %%b.allocator.create(TranslateCContext); |
| 128 | *cases = ParseCContext { | 128 | *cases = TranslateCContext { |
| 129 | .b = b, | 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 | .test_index = 0, | 131 | .test_index = 0, |
| 132 | .test_filter = test_filter, | 132 | .test_filter = test_filter, |
| 133 | }; | 133 | }; |
| 134 | 134 | ||
| 135 | parsec.addCases(cases); | 135 | translate_c.addCases(cases); |
| 136 | 136 | ||
| 137 | return cases.step; | 137 | return cases.step; |
| 138 | } | 138 | } |
| ... | @@ -770,7 +770,7 @@ pub const BuildExamplesContext = struct { | ... | @@ -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 | b: &build.Builder, | 774 | b: &build.Builder, |
| 775 | step: &build.Step, | 775 | step: &build.Step, |
| 776 | test_index: usize, | 776 | test_index: usize, |
| ... | @@ -799,17 +799,17 @@ pub const ParseCContext = struct { | ... | @@ -799,17 +799,17 @@ pub const ParseCContext = struct { |
| 799 | } | 799 | } |
| 800 | }; | 800 | }; |
| 801 | 801 | ||
| 802 | const ParseCCmpOutputStep = struct { | 802 | const TranslateCCmpOutputStep = struct { |
| 803 | step: build.Step, | 803 | step: build.Step, |
| 804 | context: &ParseCContext, | 804 | context: &TranslateCContext, |
| 805 | name: []const u8, | 805 | name: []const u8, |
| 806 | test_index: usize, | 806 | test_index: usize, |
| 807 | case: &const TestCase, | 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 | const allocator = context.b.allocator; | 810 | const allocator = context.b.allocator; |
| 811 | const ptr = %%allocator.create(ParseCCmpOutputStep); | 811 | const ptr = %%allocator.create(TranslateCCmpOutputStep); |
| 812 | *ptr = ParseCCmpOutputStep { | 812 | *ptr = TranslateCCmpOutputStep { |
| 813 | .step = build.Step.init("ParseCCmpOutput", allocator, make), | 813 | .step = build.Step.init("ParseCCmpOutput", allocator, make), |
| 814 | .context = context, | 814 | .context = context, |
| 815 | .name = name, | 815 | .name = name, |
| ... | @@ -821,7 +821,7 @@ pub const ParseCContext = struct { | ... | @@ -821,7 +821,7 @@ pub const ParseCContext = struct { |
| 821 | } | 821 | } |
| 822 | 822 | ||
| 823 | fn make(step: &build.Step) -> %void { | 823 | fn make(step: &build.Step) -> %void { |
| 824 | const self = @fieldParentPtr(ParseCCmpOutputStep, "step", step); | 824 | const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step); |
| 825 | const b = self.context.b; | 825 | const b = self.context.b; |
| 826 | 826 | ||
| 827 | const root_src = %%os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename); | 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,7 +829,7 @@ pub const ParseCContext = struct { |
| 829 | var zig_args = ArrayList([]const u8).init(b.allocator); | 829 | var zig_args = ArrayList([]const u8).init(b.allocator); |
| 830 | %%zig_args.append(b.zig_exe); | 830 | %%zig_args.append(b.zig_exe); |
| 831 | 831 | ||
| 832 | %%zig_args.append("parsec"); | 832 | %%zig_args.append("translate-c"); |
| 833 | %%zig_args.append(b.pathFromRoot(root_src)); | 833 | %%zig_args.append(b.pathFromRoot(root_src)); |
| 834 | 834 | ||
| 835 | warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name); | 835 | warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name); |
| ... | @@ -882,7 +882,7 @@ pub const ParseCContext = struct { | ... | @@ -882,7 +882,7 @@ pub const ParseCContext = struct { |
| 882 | 882 | ||
| 883 | if (stderr.len != 0 and !self.case.allow_warnings) { | 883 | if (stderr.len != 0 and !self.case.allow_warnings) { |
| 884 | warn( | 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,7 +914,7 @@ pub const ParseCContext = struct { |
| 914 | warn("\n"); | 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 | source: []const u8, expected_lines: ...) -> &TestCase | 918 | source: []const u8, expected_lines: ...) -> &TestCase |
| 919 | { | 919 | { |
| 920 | const tc = %%self.b.allocator.create(TestCase); | 920 | const tc = %%self.b.allocator.create(TestCase); |
| ... | @@ -932,37 +932,37 @@ pub const ParseCContext = struct { | ... | @@ -932,37 +932,37 @@ pub const ParseCContext = struct { |
| 932 | return tc; | 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 | const tc = self.create(false, "source.h", name, source, expected_lines); | 936 | const tc = self.create(false, "source.h", name, source, expected_lines); |
| 937 | self.addCase(tc); | 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 | const tc = self.create(false, "source.c", name, source, expected_lines); | 941 | const tc = self.create(false, "source.c", name, source, expected_lines); |
| 942 | self.addCase(tc); | 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 | const tc = self.create(true, "source.h", name, source, expected_lines); | 946 | const tc = self.create(true, "source.h", name, source, expected_lines); |
| 947 | self.addCase(tc); | 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 | const b = self.b; | 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 | if (self.test_filter) |filter| { | 954 | if (self.test_filter) |filter| { |
| 955 | if (mem.indexOf(u8, annotated_case_name, filter) == null) | 955 | if (mem.indexOf(u8, annotated_case_name, filter) == null) |
| 956 | return; | 956 | return; |
| 957 | } | 957 | } |
| 958 | 958 | ||
| 959 | const parsec_and_cmp = ParseCCmpOutputStep.create(self, annotated_case_name, case); | 959 | const translate_c_and_cmp = TranslateCCmpOutputStep.create(self, annotated_case_name, case); |
| 960 | self.step.dependOn(&parsec_and_cmp.step); | 960 | self.step.dependOn(&translate_c_and_cmp.step); |
| 961 | 961 | ||
| 962 | for (case.sources.toSliceConst()) |src_file| { | 962 | for (case.sources.toSliceConst()) |src_file| { |
| 963 | const expanded_src_path = %%os.path.join(b.allocator, b.cache_root, src_file.filename); | 963 | const expanded_src_path = %%os.path.join(b.allocator, b.cache_root, src_file.filename); |
| 964 | const write_src = b.addWriteFile(expanded_src_path, src_file.source); | 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 | } | ||