authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-29 16:34:50-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-29 16:34:50-05:00
log91ef68f9b1121d2a08f175a81f88321664c90a61
tree73e2c9cf0b1f24b9855095757e65c4ac981517ef
parent9a4da6c8d8d55f47609b8e900e9a4bb1ac34d5e7
parent70662830044418fc2d637c166fc100fe72d60fcf

Merge remote-tracking branch 'origin/master' into llvm6


33 files changed, 6945 insertions(+), 4651 deletions(-)

CMakeLists.txt+1-1
......@@ -339,7 +339,7 @@ set(ZIG_SOURCES
339339 "${CMAKE_SOURCE_DIR}/src/target.cpp"
340340 "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp"
341341 "${CMAKE_SOURCE_DIR}/src/util.cpp"
342 "${CMAKE_SOURCE_DIR}/src/parsec.cpp"
342 "${CMAKE_SOURCE_DIR}/src/translate_c.cpp"
343343 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
344344)
345345
build.zig+1-1
......@@ -58,5 +58,5 @@ pub fn build(b: &Builder) {
5858 test_step.dependOn(tests.addCompileErrorTests(b, test_filter));
5959 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter));
6060 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));
6262}
ci/travis_osx_script+1-1
......@@ -22,4 +22,4 @@ make install
2222./zig build --build-file ../build.zig test-compile-errors --verbose
2323./zig build --build-file ../build.zig test-asm-link --verbose
2424./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 @@
7070 <li><a href="#mersenne">Mersenne Twister Random Number Generator</a></li>
7171 </ul>
7272 <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");
7474
7575pub 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");
7781}</code></pre>
7882 <p>Build this with:</p>
7983 <pre>zig build-exe hello.zig</pre>
doc/langref.html.in+15-4
......@@ -75,6 +75,7 @@
7575 <li><a href="#slices">Slices</a></li>
7676 <li><a href="#struct">struct</a></li>
7777 <li><a href="#enum">enum</a></li>
78 <li><a href="#union">union</a></li>
7879 <li><a href="#switch">switch</a></li>
7980 <li><a href="#while">while</a></li>
8081 <li><a href="#for">for</a></li>
......@@ -209,6 +210,7 @@
209210 <li><a href="#undef-invalid-error-code">Invalid Error Code</a></li>
210211 <li><a href="#undef-invalid-enum-cast">Invalid Enum Cast</a></li>
211212 <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>
212214 </ul>
213215 </li>
214216 <li><a href="#memory">Memory</a></li>
......@@ -2189,6 +2191,8 @@ Test 4/4 enum builtins...OK</code></pre>
21892191 <li><a href="#builtin-enumTagName">@enumTagName</a></li>
21902192 <li><a href="#builtin-memberCount">@memberCount</a></li>
21912193 </ul>
2194 <h2 id="union">union</h2>
2195 <p>TODO union documentation</p>
21922196 <h2 id="switch">switch</h2>
21932197 <pre><code class="zig">const assert = @import("std").debug.assert;
21942198const builtin = @import("builtin");
......@@ -5117,6 +5121,9 @@ comptime {
51175121 <h3 id="undef-incorrect-pointer-alignment">Incorrect Pointer Alignment</h3>
51185122 <p>TODO</p>
51195123
5124 <h3 id="undef-bad-union-field">Wrong Union Field Access</h3>
5125 <p>TODO</p>
5126
51205127 <h2 id="memory">Memory</h2>
51215128 <p>TODO: explain no default allocator in zig</p>
51225129 <p>TODO: show how to use the allocator interface</p>
......@@ -5405,10 +5412,14 @@ const c = @cImport({
54055412export fn decode_base_64(dest_ptr: &amp;u8, dest_len: usize,
54065413 source_ptr: &amp;const u8, source_len: usize) -&gt; usize
54075414{
5408 const src = source_ptr[0...source_len];
5409 const dest = dest_ptr[0...dest_len];
5410 return base64.decode(dest, src).len;
5411}</code></pre>
5415 const src = source_ptr[0..source_len];
5416 const dest = dest_ptr[0..dest_len];
5417 const base64_decoder = base64.standard_decoder_unsafe;
5418 const decoded_size = base64_decoder.calcSize(src);
5419 base64_decoder.decode(dest[0..decoded_size], src);
5420 return decoded_size;
5421}
5422</code></pre>
54125423 <h4>test.c</h4>
54135424 <pre><code class="c">// This header is generated by zig from base64.zig
54145425#include "base64.h"
example/mix_o_files/base64.zig+4-1
......@@ -3,5 +3,8 @@ const base64 = @import("std").base64;
33export fn decode_base_64(dest_ptr: &u8, dest_len: usize, source_ptr: &const u8, source_len: usize) -> usize {
44 const src = source_ptr[0..source_len];
55 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;
710}
src-self-hosted/main.zig+1-1
......@@ -208,7 +208,7 @@ fn printUsage(outstream: &io.OutStream) -> %void {
208208 \\ build-exe [source] create executable from source or object files
209209 \\ build-lib [source] create library from source or object files
210210 \\ 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
212212 \\ targets list available compilation targets
213213 \\ test [source] create and run a test build
214214 \\ version print version number and exit
src/all_types.hpp+55-2
......@@ -36,6 +36,7 @@ struct IrInstructionCast;
3636struct IrBasicBlock;
3737struct ScopeDecls;
3838struct ZigWindowsSDK;
39struct Tld;
3940
4041struct IrGotoItem {
4142 AstNode *source_node;
......@@ -59,7 +60,9 @@ struct IrExecutable {
5960 Buf *c_import_buf;
6061 AstNode *source_node;
6162 IrExecutable *parent_exec;
63 IrExecutable *source_exec;
6264 Scope *begin_scope;
65 ZigList<Tld *> tld_list;
6366};
6467
6568enum OutType {
......@@ -73,6 +76,7 @@ enum ConstParentId {
7376 ConstParentIdNone,
7477 ConstParentIdStruct,
7578 ConstParentIdArray,
79 ConstParentIdUnion,
7680};
7781
7882struct ConstParent {
......@@ -87,6 +91,9 @@ struct ConstParent {
8791 ConstExprValue *struct_val;
8892 size_t field_index;
8993 } p_struct;
94 struct {
95 ConstExprValue *union_val;
96 } p_union;
9097 } data;
9198};
9299
......@@ -100,6 +107,12 @@ struct ConstStructValue {
100107 ConstParent parent;
101108};
102109
110struct ConstUnionValue {
111 uint64_t tag;
112 ConstExprValue *payload;
113 ConstParent parent;
114};
115
103116enum ConstArraySpecial {
104117 ConstArraySpecialNone,
105118 ConstArraySpecialUndef,
......@@ -238,6 +251,7 @@ struct ConstExprValue {
238251 ErrorTableEntry *x_pure_err;
239252 ConstEnumValue x_enum;
240253 ConstStructValue x_struct;
254 ConstUnionValue x_union;
241255 ConstArrayValue x_array;
242256 ConstPtrValue x_ptr;
243257 ImportTableEntry *x_import;
......@@ -336,6 +350,13 @@ struct TypeEnumField {
336350 uint32_t gen_index;
337351};
338352
353struct TypeUnionField {
354 Buf *name;
355 TypeTableEntry *type_entry;
356 uint32_t value;
357 uint32_t gen_index;
358};
359
339360enum NodeType {
340361 NodeTypeRoot,
341362 NodeTypeFnProto,
......@@ -1021,14 +1042,19 @@ struct TypeTableEntryEnumTag {
10211042 LLVMValueRef name_table;
10221043};
10231044
1045uint32_t type_ptr_hash(const TypeTableEntry *ptr);
1046bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b);
1047
10241048struct TypeTableEntryUnion {
10251049 AstNode *decl_node;
10261050 ContainerLayout layout;
10271051 uint32_t src_field_count;
10281052 uint32_t gen_field_count;
1029 TypeStructField *fields;
1030 uint64_t size_bytes;
1053 TypeUnionField *fields;
10311054 bool is_invalid; // true if any fields are invalid
1055 TypeTableEntry *tag_type;
1056 LLVMTypeRef union_type_ref;
1057
10321058 ScopeDecls *decls_scope;
10331059
10341060 // set this flag temporarily to detect infinite loops
......@@ -1039,6 +1065,13 @@ struct TypeTableEntryUnion {
10391065
10401066 bool zero_bits_loop_flag;
10411067 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;
10421075};
10431076
10441077struct FnGenParamInfo {
......@@ -1287,6 +1320,7 @@ enum PanicMsgId {
12871320 PanicMsgIdUnwrapMaybeFail,
12881321 PanicMsgIdInvalidErrorCode,
12891322 PanicMsgIdIncorrectAlignment,
1323 PanicMsgIdBadUnionField,
12901324
12911325 PanicMsgIdCount,
12921326};
......@@ -1796,6 +1830,7 @@ enum IrInstructionId {
17961830 IrInstructionIdFieldPtr,
17971831 IrInstructionIdStructFieldPtr,
17981832 IrInstructionIdEnumFieldPtr,
1833 IrInstructionIdUnionFieldPtr,
17991834 IrInstructionIdElemPtr,
18001835 IrInstructionIdVarPtr,
18011836 IrInstructionIdCall,
......@@ -1805,6 +1840,7 @@ enum IrInstructionId {
18051840 IrInstructionIdContainerInitList,
18061841 IrInstructionIdContainerInitFields,
18071842 IrInstructionIdStructInit,
1843 IrInstructionIdUnionInit,
18081844 IrInstructionIdUnreachable,
18091845 IrInstructionIdTypeOf,
18101846 IrInstructionIdToPtrType,
......@@ -2060,6 +2096,14 @@ struct IrInstructionEnumFieldPtr {
20602096 bool is_const;
20612097};
20622098
2099struct IrInstructionUnionFieldPtr {
2100 IrInstruction base;
2101
2102 IrInstruction *union_ptr;
2103 TypeUnionField *field;
2104 bool is_const;
2105};
2106
20632107struct IrInstructionElemPtr {
20642108 IrInstruction base;
20652109
......@@ -2150,6 +2194,15 @@ struct IrInstructionStructInit {
21502194 LLVMValueRef tmp_ptr;
21512195};
21522196
2197struct IrInstructionUnionInit {
2198 IrInstruction base;
2199
2200 TypeTableEntry *union_type;
2201 TypeUnionField *field;
2202 IrInstruction *init_value;
2203 LLVMValueRef tmp_ptr;
2204};
2205
21532206struct IrInstructionUnreachable {
21542207 IrInstruction base;
21552208};
src/analyze.cpp+334-9
......@@ -28,7 +28,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type);
2828
2929ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
3030 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
3232 // failed semantic analysis, which isn't supposed to happen
3333 ErrorMsg *err = add_node_error(g, node->owner->c_import_node,
3434 buf_sprintf("compiler bug: @cImport generated invalid zig code"));
......@@ -48,7 +48,7 @@ ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
4848
4949ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) {
5050 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
5252 // failed semantic analysis, which isn't supposed to happen
5353
5454 Buf *note_path = buf_create_from_str("?.c");
......@@ -338,7 +338,7 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
338338TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,
339339 bool is_volatile, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count)
340340{
341 assert(child_type->id != TypeTableEntryIdInvalid);
341 assert(!type_is_invalid(child_type));
342342
343343 TypeId type_id = {};
344344 TypeTableEntry **parent_pointer = nullptr;
......@@ -1008,11 +1008,12 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi
10081008 }
10091009
10101010 size_t line = decl_node ? decl_node->line : 0;
1011 unsigned dwarf_kind = ZigLLVMTag_DW_structure_type();
10111012
10121013 ImportTableEntry *import = get_scope_import(scope);
10131014 entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name);
10141015 entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
1015 ZigLLVMTag_DW_structure_type(), name,
1016 dwarf_kind, name,
10161017 ZigLLVMFileToScope(import->di_file), import->di_file, (unsigned)(line + 1));
10171018
10181019 buf_init_from_str(&entry->name, name);
......@@ -1285,7 +1286,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
12851286 return;
12861287
12871288 resolve_enum_zero_bits(g, enum_type);
1288 if (enum_type->data.enumeration.is_invalid)
1289 if (type_is_invalid(enum_type))
12891290 return;
12901291
12911292 AstNode *decl_node = enum_type->data.enumeration.decl_node;
......@@ -1834,7 +1835,246 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
18341835}
18351836
18361837static 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;
18382078}
18392079
18402080static 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) {
18732113 type_enum_field->value = i;
18742114
18752115 type_ensure_zero_bits_known(g, field_type);
1876 if (field_type->id == TypeTableEntryIdInvalid) {
2116 if (type_is_invalid(field_type)) {
18772117 enum_type->data.enumeration.is_invalid = true;
18782118 continue;
18792119 }
......@@ -1980,7 +2220,69 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
19802220}
19812221
19822222static 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 }
19842286}
19852287
19862288static 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) {
28513153 return nullptr;
28523154}
28533155
3156TypeUnionField *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
28543168static bool is_container(TypeTableEntry *type_entry) {
28553169 switch (type_entry->id) {
28563170 case TypeTableEntryIdInvalid:
......@@ -4703,6 +5017,8 @@ ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) {
47035017 return &value->data.x_array.s_none.parent;
47045018 } else if (type_entry->id == TypeTableEntryIdStruct) {
47055019 return &value->data.x_struct.parent;
5020 } else if (type_entry->id == TypeTableEntryIdUnion) {
5021 return &value->data.x_union.parent;
47065022 }
47075023 return nullptr;
47085024}
......@@ -4914,7 +5230,8 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) {
49145230 assert(type_entry->data.enumeration.abi_alignment != 0);
49155231 return type_entry->data.enumeration.abi_alignment;
49165232 } 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;
49185235 } else if (type_entry->id == TypeTableEntryIdOpaque) {
49195236 return 1;
49205237 } else {
......@@ -4929,3 +5246,11 @@ TypeTableEntry *get_align_amt_type(CodeGen *g) {
49295246 }
49305247 return g->align_amt_type;
49315248}
5249
5250uint32_t type_ptr_hash(const TypeTableEntry *ptr) {
5251 return hash_ptr((void*)ptr);
5252}
5253
5254bool 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);
6363TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name);
6464ScopeDecls *get_container_scope(TypeTableEntry *type_entry);
6565TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name);
66TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name);
6667bool is_container_ref(TypeTableEntry *type_entry);
6768void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
6869void scan_import(CodeGen *g, ImportTableEntry *import);
src/c_tokenizer.cpp+5-3
......@@ -120,6 +120,7 @@ static void begin_token(CTokenize *ctok, CTokId id) {
120120 case CTokIdLParen:
121121 case CTokIdRParen:
122122 case CTokIdEOF:
123 case CTokIdDot:
123124 break;
124125 }
125126}
......@@ -216,9 +217,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) {
216217 buf_append_char(&ctok->buf, '0');
217218 break;
218219 case '.':
219 begin_token(ctok, CTokIdNumLitFloat);
220 ctok->state = CTokStateFloat;
221 buf_init_from_str(&ctok->buf, "0.");
220 begin_token(ctok, CTokIdDot);
221 end_token(ctok);
222222 break;
223223 case '(':
224224 begin_token(ctok, CTokIdLParen);
......@@ -238,6 +238,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) {
238238 break;
239239 case CTokStateFloat:
240240 switch (*c) {
241 case '.':
242 break;
241243 case 'e':
242244 case 'E':
243245 buf_append_char(&ctok->buf, 'e');
src/c_tokenizer.hpp+1
......@@ -21,6 +21,7 @@ enum CTokId {
2121 CTokIdLParen,
2222 CTokIdRParen,
2323 CTokIdEOF,
24 CTokIdDot,
2425};
2526
2627enum CNumLitSuffix {
src/codegen.cpp+155-6
......@@ -15,7 +15,7 @@
1515#include "ir.hpp"
1616#include "link.hpp"
1717#include "os.hpp"
18#include "parsec.hpp"
18#include "translate_c.hpp"
1919#include "target.hpp"
2020#include "zig_llvm.hpp"
2121
......@@ -810,6 +810,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
810810 return buf_create_from_str("invalid error code");
811811 case PanicMsgIdIncorrectAlignment:
812812 return buf_create_from_str("incorrect alignment");
813 case PanicMsgIdBadUnionField:
814 return buf_create_from_str("access of inactive union field");
813815 }
814816 zig_unreachable();
815817}
......@@ -2393,6 +2395,50 @@ static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executabl
23932395 return bitcasted_union_field_ptr;
23942396}
23952397
2398static 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
23962442static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) {
23972443 const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2;
23982444 size_t len = tok->end - tok->start - 2;
......@@ -3365,6 +3411,42 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,
33653411 return instruction->tmp_ptr;
33663412}
33673413
3414static 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
33683450static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable,
33693451 IrInstructionContainerInitList *instruction)
33703452{
......@@ -3486,6 +3568,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
34863568 return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);
34873569 case IrInstructionIdEnumFieldPtr:
34883570 return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction);
3571 case IrInstructionIdUnionFieldPtr:
3572 return ir_render_union_field_ptr(g, executable, (IrInstructionUnionFieldPtr *)instruction);
34893573 case IrInstructionIdAsm:
34903574 return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
34913575 case IrInstructionIdTestNonNull:
......@@ -3544,6 +3628,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
35443628 return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction);
35453629 case IrInstructionIdStructInit:
35463630 return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);
3631 case IrInstructionIdUnionInit:
3632 return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction);
35473633 case IrInstructionIdPtrCast:
35483634 return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction);
35493635 case IrInstructionIdBitCast:
......@@ -3595,6 +3681,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {
35953681
35963682static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index);
35973683static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index);
3684static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *array_const_val);
35983685
35993686static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) {
36003687 switch (parent->id) {
......@@ -3608,6 +3695,8 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent
36083695 case ConstParentIdArray:
36093696 return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val,
36103697 parent->data.p_array.elem_index);
3698 case ConstParentIdUnion:
3699 return gen_const_ptr_union_recursive(g, parent->data.p_union.union_val);
36113700 }
36123701 zig_unreachable();
36133702}
......@@ -3637,6 +3726,18 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s
36373726 return LLVMConstInBoundsGEP(base_ptr, indices, 2);
36383727}
36393728
3729static 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
36403741static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) {
36413742 switch (const_val->special) {
36423743 case ConstValSpecialRuntime:
......@@ -3872,10 +3973,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
38723973 return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count);
38733974 }
38743975 }
3875 case TypeTableEntryIdUnion:
3876 {
3877 zig_panic("TODO");
3878 }
38793976 case TypeTableEntryIdArray:
38803977 {
38813978 uint64_t len = type_entry->data.array.len;
......@@ -3898,6 +3995,55 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
38983995 return LLVMConstArray(element_type_ref, values, (unsigned)len);
38993996 }
39003997 }
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 }
39014047 case TypeTableEntryIdEnum:
39024048 {
39034049 LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
......@@ -4376,6 +4522,9 @@ static void do_code_gen(CodeGen *g) {
43764522 } else if (instruction->id == IrInstructionIdStructInit) {
43774523 IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction;
43784524 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;
43794528 } else if (instruction->id == IrInstructionIdCall) {
43804529 IrInstructionCall *call_instruction = (IrInstructionCall *)instruction;
43814530 slot = &call_instruction->tmp_ptr;
......@@ -5204,7 +5353,7 @@ static void init(CodeGen *g) {
52045353 define_builtin_compile_vars(g);
52055354}
52065355
5207void codegen_parsec(CodeGen *g, Buf *full_path) {
5356void codegen_translate_c(CodeGen *g, Buf *full_path) {
52085357 find_libc_include_path(g);
52095358
52105359 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,
5656void codegen_add_assembly(CodeGen *g, Buf *path);
5757void codegen_add_object(CodeGen *g, Buf *object_path);
5858
59void codegen_parsec(CodeGen *g, Buf *path);
59void codegen_translate_c(CodeGen *g, Buf *path);
6060
6161
6262#endif
src/ir.cpp+221-38
......@@ -11,7 +11,7 @@
1111#include "ir.hpp"
1212#include "ir_print.hpp"
1313#include "os.hpp"
14#include "parsec.hpp"
14#include "translate_c.hpp"
1515#include "range_set.hpp"
1616#include "softfloat.hpp"
1717
......@@ -227,6 +227,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumFieldPtr *)
227227 return IrInstructionIdEnumFieldPtr;
228228}
229229
230static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionFieldPtr *) {
231 return IrInstructionIdUnionFieldPtr;
232}
233
230234static constexpr IrInstructionId ir_instruction_id(IrInstructionElemPtr *) {
231235 return IrInstructionIdElemPtr;
232236}
......@@ -351,6 +355,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) {
351355 return IrInstructionIdStructInit;
352356}
353357
358static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit *) {
359 return IrInstructionIdUnionInit;
360}
361
354362static constexpr IrInstructionId ir_instruction_id(IrInstructionMinValue *) {
355363 return IrInstructionIdMinValue;
356364}
......@@ -922,6 +930,27 @@ static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction
922930 return new_instruction;
923931}
924932
933static 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
945static 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
925954static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
926955 FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
927956 bool is_comptime, bool is_inline)
......@@ -1112,6 +1141,28 @@ static IrInstruction *ir_build_struct_init_from(IrBuilder *irb, IrInstruction *o
11121141 return new_instruction;
11131142}
11141143
1144static 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
1157static 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
11151166static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) {
11161167 IrInstructionUnreachable *unreachable_instruction =
11171168 ir_build_instruction<IrInstructionUnreachable>(irb, scope, source_node);
......@@ -2422,6 +2473,13 @@ static IrInstruction *ir_instruction_enumfieldptr_get_dep(IrInstructionEnumField
24222473 }
24232474}
24242475
2476static 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
24252483static IrInstruction *ir_instruction_elemptr_get_dep(IrInstructionElemPtr *instruction, size_t index) {
24262484 switch (index) {
24272485 case 0: return instruction->array_ptr;
......@@ -2485,6 +2543,13 @@ static IrInstruction *ir_instruction_structinit_get_dep(IrInstructionStructInit
24852543 return nullptr;
24862544}
24872545
2546static 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
24882553static IrInstruction *ir_instruction_unreachable_get_dep(IrInstructionUnreachable *instruction, size_t index) {
24892554 return nullptr;
24902555}
......@@ -3099,6 +3164,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
30993164 return ir_instruction_structfieldptr_get_dep((IrInstructionStructFieldPtr *) instruction, index);
31003165 case IrInstructionIdEnumFieldPtr:
31013166 return ir_instruction_enumfieldptr_get_dep((IrInstructionEnumFieldPtr *) instruction, index);
3167 case IrInstructionIdUnionFieldPtr:
3168 return ir_instruction_unionfieldptr_get_dep((IrInstructionUnionFieldPtr *) instruction, index);
31023169 case IrInstructionIdElemPtr:
31033170 return ir_instruction_elemptr_get_dep((IrInstructionElemPtr *) instruction, index);
31043171 case IrInstructionIdVarPtr:
......@@ -3117,6 +3184,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
31173184 return ir_instruction_containerinitfields_get_dep((IrInstructionContainerInitFields *) instruction, index);
31183185 case IrInstructionIdStructInit:
31193186 return ir_instruction_structinit_get_dep((IrInstructionStructInit *) instruction, index);
3187 case IrInstructionIdUnionInit:
3188 return ir_instruction_unioninit_get_dep((IrInstructionUnionInit *) instruction, index);
31203189 case IrInstructionIdUnreachable:
31213190 return ir_instruction_unreachable_get_dep((IrInstructionUnreachable *) instruction, index);
31223191 case IrInstructionIdTypeOf:
......@@ -6233,8 +6302,9 @@ static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char
62336302 buf_appendf(name, ")");
62346303 return name;
62356304 } else {
6305 //Note: C-imports do not have valid location information
62366306 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);
62386308 }
62396309 }
62406310}
......@@ -6263,6 +6333,9 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope,
62636333 }
62646334 irb->codegen->resolve_queue.append(&tld_container->base);
62656335
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
62666339 return ir_build_const_type(irb, parent_scope, node, container_type);
62676340}
62686341
......@@ -6485,6 +6558,20 @@ static bool ir_goto_pass2(IrBuilder *irb) {
64856558 return true;
64866559}
64876560
6561static 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
64886575bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_executable) {
64896576 assert(node->owner);
64906577
......@@ -6508,7 +6595,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
65086595 }
65096596
65106597 if (!ir_goto_pass2(irb)) {
6511 irb->exec->invalid = true;
6598 invalidate_exec(ir_executable);
65126599 return false;
65136600 }
65146601
......@@ -6534,7 +6621,7 @@ static void add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, ErrorMsg
65346621}
65356622
65366623static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) {
6537 exec->invalid = true;
6624 invalidate_exec(exec);
65386625 ErrorMsg *err_msg = add_node_error(codegen, source_node, msg);
65396626 if (exec->parent_exec) {
65406627 add_call_stack_errors(codegen, exec, err_msg, 10);
......@@ -7897,6 +7984,9 @@ static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instructio
78977984 ConstExprValue *const_val = &const_instr->value;
78987985 const_val->type = pointee_type;
78997986 type_ensure_zero_bits_known(ira->codegen, type_entry);
7987 if (type_is_invalid(type_entry)) {
7988 return ira->codegen->invalid_instruction;
7989 }
79007990 const_val->data.x_type = get_pointer_to_type_extra(ira->codegen, type_entry,
79017991 ptr_is_const, ptr_is_volatile, get_abi_alignment(ira->codegen, type_entry), 0, 0);
79027992 return const_instr;
......@@ -7984,6 +8074,7 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node
79848074 IrExecutable analyzed_executable = {0};
79858075 analyzed_executable.source_node = source_node;
79868076 analyzed_executable.parent_exec = parent_exec;
8077 analyzed_executable.source_exec = &ir_executable;
79878078 analyzed_executable.name = exec_name;
79888079 analyzed_executable.is_inline = true;
79898080 analyzed_executable.fn_entry = fn_entry;
......@@ -10279,30 +10370,40 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
1027910370
1028010371 bool is_const = (var->value->type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const;
1028110372 bool is_volatile = (var->value->type->id == TypeTableEntryIdMetaType) ? is_volatile_ptr : false;
10282 if (mem_slot && mem_slot->special != ConstValSpecialRuntime) {
10283 ConstPtrMut ptr_mut;
10284 if (comptime_var_mem) {
10285 ptr_mut = ConstPtrMutComptimeVar;
10286 } else if (var->gen_is_const) {
10287 ptr_mut = ConstPtrMutComptimeConst;
10288 } else {
10289 assert(!comptime_var_mem);
10290 ptr_mut = ConstPtrMutRuntimeVar;
10373 if (mem_slot != nullptr) {
10374 switch (mem_slot->special) {
10375 case ConstValSpecialRuntime:
10376 goto no_mem_slot;
10377 case ConstValSpecialStatic: // fallthrough
10378 case ConstValSpecialUndef: {
10379 ConstPtrMut ptr_mut;
10380 if (comptime_var_mem) {
10381 ptr_mut = ConstPtrMutComptimeVar;
10382 } else if (var->gen_is_const) {
10383 ptr_mut = ConstPtrMutComptimeConst;
10384 } else {
10385 assert(!comptime_var_mem);
10386 ptr_mut = ConstPtrMutRuntimeVar;
10387 }
10388 return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type,
10389 ptr_mut, is_const, is_volatile, var->align_bytes);
10390 }
1029110391 }
10292 return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type,
10293 ptr_mut, is_const, is_volatile, var->align_bytes);
10294 } else {
10295 IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb,
10296 instruction->scope, instruction->source_node, var, is_const, is_volatile);
10297 var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type,
10298 var->src_is_const, is_volatile, var->align_bytes, 0, 0);
10299 type_ensure_zero_bits_known(ira->codegen, var->value->type);
10392 zig_unreachable();
10393 }
1030010394
10301 bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr);
10302 var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack;
10395no_mem_slot:
1030310396
10304 return var_ptr_instruction;
10305 }
10397 IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb,
10398 instruction->scope, instruction->source_node, var, is_const, is_volatile);
10399 var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type,
10400 var->src_is_const, is_volatile, var->align_bytes, 0, 0);
10401 type_ensure_zero_bits_known(ira->codegen, var->value->type);
10402
10403 bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr);
10404 var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack;
10405
10406 return var_ptr_instruction;
1030610407}
1030710408
1030810409static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
......@@ -10408,10 +10509,11 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1040810509 result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type,
1040910510 ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry,
1041010511 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;
1041310512
1041410513 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;
1041510517 }
1041610518
1041710519 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,
1141711519 return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value, true, false);
1141811520 }
1141911521 }
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 }
1142011534 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)));
1142211536 return ira->codegen->builtin_types.entry_invalid;
1142311537}
1142411538
......@@ -11428,14 +11542,13 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
1142811542{
1142911543 TypeTableEntry *bare_type = container_ref_type(container_type);
1143011544 ensure_complete_type(ira->codegen, bare_type);
11545 if (type_is_invalid(bare_type))
11546 return ira->codegen->builtin_types.entry_invalid;
1143111547
1143211548 assert(container_ptr->value.type->id == TypeTableEntryIdPointer);
1143311549 bool is_const = container_ptr->value.type->data.pointer.is_const;
1143411550 bool is_volatile = container_ptr->value.type->data.pointer.is_volatile;
1143511551 if (bare_type->id == TypeTableEntryIdStruct) {
11436 if (bare_type->data.structure.is_invalid)
11437 return ira->codegen->builtin_types.entry_invalid;
11438
1143911552 TypeStructField *field = find_struct_type_field(bare_type, field_name);
1144011553 if (field) {
1144111554 bool is_packed = (bare_type->data.structure.layout == ContainerLayoutPacked);
......@@ -11476,9 +11589,6 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
1147611589 field_ptr_instruction, container_ptr, container_type);
1147711590 }
1147811591 } else if (bare_type->id == TypeTableEntryIdEnum) {
11479 if (bare_type->data.enumeration.is_invalid)
11480 return ira->codegen->builtin_types.entry_invalid;
11481
1148211592 TypeEnumField *field = find_enum_type_field(bare_type, field_name);
1148311593 if (field) {
1148411594 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
1148911599 field_ptr_instruction, container_ptr, container_type);
1149011600 }
1149111601 } 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 }
1149311611 } else {
1149411612 zig_unreachable();
1149511613 }
......@@ -13033,9 +13151,71 @@ static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionR
1303313151 return ir_analyze_ref(ira, &ref_instruction->base, value, ref_instruction->is_const, ref_instruction->is_volatile);
1303413152}
1303513153
13154static 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
1303613213static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction,
1303713214 TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields)
1303813215{
13216 if (container_type->id == TypeTableEntryIdUnion) {
13217 return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count, fields);
13218 }
1303913219 if (container_type->id != TypeTableEntryIdStruct || is_slice(container_type)) {
1304013220 ir_add_error(ira, instruction,
1304113221 buf_sprintf("type '%s' does not support struct initialization syntax",
......@@ -13043,8 +13223,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
1304313223 return ira->codegen->builtin_types.entry_invalid;
1304413224 }
1304513225
13046 if (!type_is_complete(container_type))
13047 resolve_container_type(ira->codegen, container_type);
13226 ensure_complete_type(ira->codegen, container_type);
1304813227
1304913228 size_t actual_field_count = container_type->data.structure.src_field_count;
1305013229
......@@ -13070,7 +13249,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
1307013249 TypeStructField *type_field = find_struct_type_field(container_type, field->name);
1307113250 if (!type_field) {
1307213251 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'",
1307413253 buf_ptr(field->name), buf_ptr(&container_type->name)));
1307513254 return ira->codegen->builtin_types.entry_invalid;
1307613255 }
......@@ -15657,8 +15836,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1565715836 case IrInstructionIdIntToErr:
1565815837 case IrInstructionIdErrToInt:
1565915838 case IrInstructionIdStructInit:
15839 case IrInstructionIdUnionInit:
1566015840 case IrInstructionIdStructFieldPtr:
1566115841 case IrInstructionIdEnumFieldPtr:
15842 case IrInstructionIdUnionFieldPtr:
1566215843 case IrInstructionIdInitEnum:
1566315844 case IrInstructionIdMaybeWrap:
1566415845 case IrInstructionIdErrWrapCode:
......@@ -15968,6 +16149,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1596816149 case IrInstructionIdContainerInitList:
1596916150 case IrInstructionIdContainerInitFields:
1597016151 case IrInstructionIdStructInit:
16152 case IrInstructionIdUnionInit:
1597116153 case IrInstructionIdFieldPtr:
1597216154 case IrInstructionIdElemPtr:
1597316155 case IrInstructionIdVarPtr:
......@@ -15977,6 +16159,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1597716159 case IrInstructionIdArrayLen:
1597816160 case IrInstructionIdStructFieldPtr:
1597916161 case IrInstructionIdEnumFieldPtr:
16162 case IrInstructionIdUnionFieldPtr:
1598016163 case IrInstructionIdArrayType:
1598116164 case IrInstructionIdSliceType:
1598216165 case IrInstructionIdSizeOf:
src/ir_print.cpp+22
......@@ -290,6 +290,15 @@ static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruct
290290 fprintf(irp->f, "} // struct init");
291291}
292292
293static 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
293302static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) {
294303 fprintf(irp->f, "unreachable");
295304}
......@@ -359,6 +368,13 @@ static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *ins
359368 fprintf(irp->f, ")");
360369}
361370
371static 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
362378static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety *instruction) {
363379 fprintf(irp->f, "@setDebugSafety(");
364380 ir_print_other_instruction(irp, instruction->scope_value);
......@@ -1023,6 +1039,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
10231039 case IrInstructionIdStructInit:
10241040 ir_print_struct_init(irp, (IrInstructionStructInit *)instruction);
10251041 break;
1042 case IrInstructionIdUnionInit:
1043 ir_print_union_init(irp, (IrInstructionUnionInit *)instruction);
1044 break;
10261045 case IrInstructionIdUnreachable:
10271046 ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction);
10281047 break;
......@@ -1056,6 +1075,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
10561075 case IrInstructionIdEnumFieldPtr:
10571076 ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction);
10581077 break;
1078 case IrInstructionIdUnionFieldPtr:
1079 ir_print_union_field_ptr(irp, (IrInstructionUnionFieldPtr *)instruction);
1080 break;
10591081 case IrInstructionIdSetDebugSafety:
10601082 ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction);
10611083 break;
src/main.cpp+11-11
......@@ -23,7 +23,7 @@ static int usage(const char *arg0) {
2323 " build-exe [source] create executable from source or object files\n"
2424 " build-lib [source] create library from source or object files\n"
2525 " 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"
2727 " targets list available compilation targets\n"
2828 " test [source] create and run a test build\n"
2929 " version print version number and exit\n"
......@@ -229,7 +229,7 @@ enum Cmd {
229229 CmdTest,
230230 CmdVersion,
231231 CmdZen,
232 CmdParseC,
232 CmdTranslateC,
233233 CmdTargets,
234234};
235235
......@@ -632,8 +632,8 @@ int main(int argc, char **argv) {
632632 cmd = CmdVersion;
633633 } else if (strcmp(arg, "zen") == 0) {
634634 cmd = CmdZen;
635 } else if (strcmp(arg, "parsec") == 0) {
636 cmd = CmdParseC;
635 } else if (strcmp(arg, "translate-c") == 0) {
636 cmd = CmdTranslateC;
637637 } else if (strcmp(arg, "test") == 0) {
638638 cmd = CmdTest;
639639 out_type = OutTypeExe;
......@@ -646,7 +646,7 @@ int main(int argc, char **argv) {
646646 } else {
647647 switch (cmd) {
648648 case CmdBuild:
649 case CmdParseC:
649 case CmdTranslateC:
650650 case CmdTest:
651651 if (!in_file) {
652652 in_file = arg;
......@@ -703,13 +703,13 @@ int main(int argc, char **argv) {
703703
704704 switch (cmd) {
705705 case CmdBuild:
706 case CmdParseC:
706 case CmdTranslateC:
707707 case CmdTest:
708708 {
709709 if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {
710710 fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n");
711711 return usage(arg0);
712 } else if ((cmd == CmdParseC || cmd == CmdTest) && !in_file) {
712 } else if ((cmd == CmdTranslateC || cmd == CmdTest) && !in_file) {
713713 fprintf(stderr, "Expected source file argument.\n");
714714 return usage(arg0);
715715 } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {
......@@ -719,7 +719,7 @@ int main(int argc, char **argv) {
719719
720720 assert(cmd != CmdBuild || out_type != OutTypeUnknown);
721721
722 bool need_name = (cmd == CmdBuild || cmd == CmdParseC);
722 bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC);
723723
724724 Buf *in_file_buf = nullptr;
725725
......@@ -742,7 +742,7 @@ int main(int argc, char **argv) {
742742 return usage(arg0);
743743 }
744744
745 Buf *zig_root_source_file = (cmd == CmdParseC) ? nullptr : in_file_buf;
745 Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf;
746746
747747 Buf *full_cache_dir = buf_alloc();
748748 os_path_resolve(buf_create_from_str("."),
......@@ -841,8 +841,8 @@ int main(int argc, char **argv) {
841841 if (timing_info)
842842 codegen_print_timing_report(g, stdout);
843843 return EXIT_SUCCESS;
844 } else if (cmd == CmdParseC) {
845 codegen_parsec(g, in_file_buf);
844 } else if (cmd == CmdTranslateC) {
845 codegen_translate_c(g, in_file_buf);
846846 ast_render(g, stdout, g->root_import->root, 4);
847847 if (timing_info)
848848 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
24using namespace clang;
25
26struct MacroSymbol {
27 Buf *name;
28 Buf *value;
29};
30
31struct Alias {
32 Buf *new_name;
33 Buf *canon_name;
34};
35
36struct 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
57static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl);
58static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl);
59static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl);
60
61
62ATTRIBUTE_PRINTF(3, 4)
63static 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
86static 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
92static 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
100static 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
107static 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
113static 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
117static 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
124static 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
128static AstNode *trans_create_node_opaque(Context *c) {
129 return trans_create_node_builtin_fn_call_str(c, "OpaqueType");
130}
131
132static 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
139static 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
149static 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
153static 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
160static 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
168static 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
176static 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
184static 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
191static 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
198static 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
205static AstNode *trans_create_node_unsigned(Context *c, uint64_t x) {
206 return trans_create_node_unsigned_negative(c, x, false);
207}
208
209static 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
217static 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
224static 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
231static 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
243static 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
249static 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
256static 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
295static AstNode *trans_create_node_unwrap_null(Context *c, AstNode *child) {
296 return trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, child);
297}
298
299static 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
314static 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
319static 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
327static 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
332static 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
340static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc);
341
342static bool is_c_void_type(AstNode *node) {
343 return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void"));
344}
345
346static 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
353static 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
368static 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
412static 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
445static 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
458static 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
467static 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
486static 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
507static 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
524static 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
534enum TransLRValue {
535 TransLValue,
536 TransRValue,
537};
538
539static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrval);
540static AstNode *const skip_add_to_block_node = (AstNode *) 0x2;
541
542static 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
546static 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
883static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc) {
884 return trans_type(c, qt.getTypePtr(), source_loc);
885}
886
887static 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
899static 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
913static 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
922static 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
944static 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
959static 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
1008static 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
1023static 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
1130static 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
1200static 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
1256static 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
1317static 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
1511static 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
1520static 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
1574static 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
1657static 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
1906static 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
1920static 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
1944static 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
1973static 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
1988static 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
2004static 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
2014static 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
2024static 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
2077static 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
2650static 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
2745static 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
2751static 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
2802struct 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
2817static 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
2929static 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
2944static 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
3028static 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
3106static 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
3132static bool name_exists(Context *c, Buf *name) {
3133 return get_global(c, name) != nullptr;
3134}
3135
3136static 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
3146static 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
3162static 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
3189static 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
3230static 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
3263static 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
3293static 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
3329int 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
3345int 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
14int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const char *target_file,
15 CodeGen *codegen, AstNode *source_node);
16
17int 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
24using namespace clang;
25
26struct Alias {
27 Buf *new_name;
28 Buf *canon_name;
29};
30
31enum TransScopeId {
32 TransScopeIdSwitch,
33 TransScopeIdVar,
34 TransScopeIdBlock,
35 TransScopeIdRoot,
36 TransScopeIdWhile,
37};
38
39struct TransScope {
40 TransScopeId id;
41 TransScope *parent;
42};
43
44struct TransScopeSwitch {
45 TransScope base;
46 AstNode *switch_node;
47 uint32_t case_index;
48 bool found_default;
49 Buf *end_label_name;
50};
51
52struct TransScopeVar {
53 TransScope base;
54 Buf *c_name;
55 Buf *zig_name;
56};
57
58struct TransScopeBlock {
59 TransScope base;
60 AstNode *node;
61};
62
63struct TransScopeRoot {
64 TransScope base;
65};
66
67struct TransScopeWhile {
68 TransScope base;
69 AstNode *node;
70};
71
72struct 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
93enum ResultUsed {
94 ResultUsedNo,
95 ResultUsedYes,
96};
97
98enum TransLRValue {
99 TransLValue,
100 TransRValue,
101};
102
103static TransScopeRoot *trans_scope_root_create(Context *c);
104static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope);
105static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope);
106static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name);
107static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope);
108
109static TransScopeBlock *trans_scope_block_find(TransScope *scope);
110static TransScopeSwitch *trans_scope_switch_find(TransScope *scope);
111
112static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl);
113static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl);
114static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl);
115
116static 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);
120static TransScope *trans_stmt(Context *c, TransScope *scope, const Stmt *stmt, AstNode **out_node);
121static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, TransLRValue lrval);
122static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc);
123
124
125ATTRIBUTE_PRINTF(3, 4)
126static 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
149static 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
155static 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
168static 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
176static 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
183static 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
189static 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
193static 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
200static 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
204static AstNode *trans_create_node_opaque(Context *c) {
205 return trans_create_node_builtin_fn_call_str(c, "OpaqueType");
206}
207
208static 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
215static 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
225static 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
229static 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
236static 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
244static 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
252static 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
260static 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
266static 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
272static 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
278static 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
285static 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
292static 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
299static AstNode *trans_create_node_unsigned(Context *c, uint64_t x) {
300 return trans_create_node_unsigned_negative(c, x, false);
301}
302
303static 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
311static 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
318static 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
325static 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
337static 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
343static 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
349static 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
388static AstNode *trans_create_node_unwrap_null(Context *c, AstNode *child) {
389 return trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, child);
390}
391
392static 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
410static 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
415static 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
423static 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
427static 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
432static 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
440static const Type *qual_type_canon(QualType qt) {
441 return qt.getCanonicalType().getTypePtr();
442}
443
444static 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
462static 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
466static 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
479static bool is_c_void_type(AstNode *node) {
480 return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void"));
481}
482
483static 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
490static bool qual_type_is_ptr(QualType qt) {
491 const Type *ty = qual_type_canon(qt);
492 return ty->getTypeClass() == Type::Pointer;
493}
494
495static 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
506static 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
550static 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
583static 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
596static 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
614static 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
633static 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
654static 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
671static 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
681static 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
1022static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc) {
1023 return trans_type(c, qt.getTypePtr(), source_loc);
1024}
1025
1026static 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
1044static 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
1053static 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
1066static 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
1075static 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
1099static 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
1114static 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
1163static 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
1180static 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
1291static 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
1372static 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
1430static 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
1493static 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
1692static 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
1702static 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
1757static 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
1806static 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
1904static 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
2165static 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
2180static 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
2204static 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
2247static 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
2262static 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
2278static 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
2288static 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
2300static 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
2357static 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
2418static 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
2461static 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
2496static 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
2549static 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
2567static 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
2581static AstNode *trans_continue_stmt(Context *c, TransScope *scope, const ContinueStmt *stmt) {
2582 return trans_create_node(c, NodeTypeContinue);
2583}
2584
2585static 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
2594static 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
3189static 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
3202static 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
3210static 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
3313static 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
3319static 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
3370struct 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
3385static 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
3497static 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
3512static 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
3606static 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
3693static 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
3753static 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
3779static bool name_exists_global(Context *c, Buf *name) {
3780 return get_global(c, name) != nullptr;
3781}
3782
3783static 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
3796static 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
3810static TransScopeRoot *trans_scope_root_create(Context *c) {
3811 TransScopeRoot *result = allocate<TransScopeRoot>(1);
3812 result->base.id = TransScopeIdRoot;
3813 return result;
3814}
3815
3816static 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
3824static 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
3832static 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
3841static 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
3849static 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
3859static 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
3869static 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
3879static AstNode *trans_lookup_ast_container_typeof(Context *c, AstNode *ref_node);
3880
3881static 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
3914static 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
3940static 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
3956static 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
3979static 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
4006static 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
4072static 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
4103static 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
4139int 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
4155int 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
14int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const char *target_file,
15 CodeGen *codegen, AstNode *source_node);
16
17int 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) {
403403 return dwarf::DW_TAG_structure_type;
404404}
405405
406unsigned ZigLLVMTag_DW_union_type(void) {
407 return dwarf::DW_TAG_union_type;
408}
409
406410ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) {
407411 DIBuilder *di_builder = new DIBuilder(*unwrap(module), allow_unresolved);
408412 return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder);
src/zig_llvm.hpp+1
......@@ -117,6 +117,7 @@ unsigned ZigLLVMEncoding_DW_ATE_signed_char(void);
117117unsigned ZigLLVMLang_DW_LANG_C99(void);
118118unsigned ZigLLVMTag_DW_variable(void);
119119unsigned ZigLLVMTag_DW_structure_type(void);
120unsigned ZigLLVMTag_DW_union_type(void);
120121
121122ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved);
122123void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);
std/base64.zig+432-133
......@@ -1,186 +1,485 @@
11const assert = @import("debug.zig").assert;
22const mem = @import("mem.zig");
33
4pub const standard_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
5
6pub fn encode(dest: []u8, source: []const u8) -> []u8 {
7 return encodeWithAlphabet(dest, source, standard_alphabet);
8}
9
10/// invalid characters in source are allowed, but they cause the value of dest to be undefined.
11pub fn decode(dest: []u8, source: []const u8) -> []u8 {
12 return decodeWithAlphabet(dest, source, standard_alphabet);
13}
14
15pub fn encodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8) -> []u8 {
16 assert(alphabet.len == 65);
17 assert(dest.len >= calcEncodedSize(source.len));
18
19 var i: usize = 0;
20 var out_index: usize = 0;
21 while (i + 2 < source.len) : (i += 3) {
22 dest[out_index] = alphabet[(source[i] >> 2) & 0x3f];
23 out_index += 1;
24
25 dest[out_index] = alphabet[((source[i] & 0x3) << 4) |
26 ((source[i + 1] & 0xf0) >> 4)];
27 out_index += 1;
4pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5pub const standard_pad_char = '=';
6pub const standard_encoder = Base64Encoder.init(standard_alphabet_chars, standard_pad_char);
7
8pub const Base64Encoder = struct {
9 alphabet_chars: []const u8,
10 pad_char: u8,
11
12 /// a bunch of assertions, then simply pass the data right through.
13 pub fn init(alphabet_chars: []const u8, pad_char: u8) -> Base64Encoder {
14 assert(alphabet_chars.len == 64);
15 var char_in_alphabet = []bool{false} ** 256;
16 for (alphabet_chars) |c| {
17 assert(!char_in_alphabet[c]);
18 assert(c != pad_char);
19 char_in_alphabet[c] = true;
20 }
2821
29 dest[out_index] = alphabet[((source[i + 1] & 0xf) << 2) |
30 ((source[i + 2] & 0xc0) >> 6)];
31 out_index += 1;
22 return Base64Encoder{
23 .alphabet_chars = alphabet_chars,
24 .pad_char = pad_char,
25 };
26 }
3227
33 dest[out_index] = alphabet[source[i + 2] & 0x3f];
34 out_index += 1;
28 /// ceil(source_len * 4/3)
29 pub fn calcSize(source_len: usize) -> usize {
30 return @divTrunc(source_len + 2, 3) * 4;
3531 }
3632
37 if (i < source.len) {
38 dest[out_index] = alphabet[(source[i] >> 2) & 0x3f];
39 out_index += 1;
33 /// dest.len must be what you get from ::calcSize.
34 pub fn encode(encoder: &const Base64Encoder, dest: []u8, source: []const u8) {
35 assert(dest.len == Base64Encoder.calcSize(source.len));
4036
41 if (i + 1 == source.len) {
42 dest[out_index] = alphabet[(source[i] & 0x3) << 4];
37 var i: usize = 0;
38 var out_index: usize = 0;
39 while (i + 2 < source.len) : (i += 3) {
40 dest[out_index] = encoder.alphabet_chars[(source[i] >> 2) & 0x3f];
4341 out_index += 1;
4442
45 dest[out_index] = alphabet[64];
46 out_index += 1;
47 } else {
48 dest[out_index] = alphabet[((source[i] & 0x3) << 4) |
43 dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) |
4944 ((source[i + 1] & 0xf0) >> 4)];
5045 out_index += 1;
5146
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];
5352 out_index += 1;
5453 }
5554
56 dest[out_index] = alphabet[64];
57 out_index += 1;
58 }
55 if (i < source.len) {
56 dest[out_index] = encoder.alphabet_chars[(source[i] >> 2) & 0x3f];
57 out_index += 1;
5958
60 return dest[0..out_index];
61}
59 if (i + 1 == source.len) {
60 dest[out_index] = encoder.alphabet_chars[(source[i] & 0x3) << 4];
61 out_index += 1;
62
63 dest[out_index] = encoder.pad_char;
64 out_index += 1;
65 } else {
66 dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) |
67 ((source[i + 1] & 0xf0) >> 4)];
68 out_index += 1;
6269
63/// invalid characters in source are allowed, but they cause the value of dest to be undefined.
64pub fn decodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8) -> []u8 {
65 assert(alphabet.len == 65);
70 dest[out_index] = encoder.alphabet_chars[(source[i + 1] & 0xf) << 2];
71 out_index += 1;
72 }
6673
67 var ascii6 = []u8{64} ** 256;
68 for (alphabet) |c, i| {
69 ascii6[c] = u8(i);
74 dest[out_index] = encoder.pad_char;
75 out_index += 1;
76 }
7077 }
78};
79
80pub const standard_decoder = Base64Decoder.init(standard_alphabet_chars, standard_pad_char);
81error InvalidPadding;
82error InvalidCharacter;
83
84pub 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 }
71108
72 return decodeWithAscii6BitMap(dest, source, ascii6[0..], alphabet[64]);
73}
109 return result;
110 }
74111
75pub fn decodeWithAscii6BitMap(dest: []u8, source: []const u8, ascii6: []const u8, pad_char: u8) -> []u8 {
76 assert(ascii6.len == 256);
77 assert(dest.len >= calcExactDecodedSizeWithPadChar(source, pad_char));
112 /// If the encoded buffer is detected to be invalid, returns error.InvalidPadding.
113 pub fn calcSize(decoder: &const Base64Decoder, source: []const u8) -> %usize {
114 if (source.len % 4 != 0) return error.InvalidPadding;
115 return calcDecodedSizeExactUnsafe(source, decoder.pad_char);
116 }
78117
79 var src_index: usize = 0;
80 var dest_index: usize = 0;
81 var in_buf_len: usize = source.len;
118 /// dest.len must be what you get from ::calcSize.
119 /// invalid characters result in error.InvalidCharacter.
120 /// invalid padding results in error.InvalidPadding.
121 pub fn decode(decoder: &const Base64Decoder, dest: []u8, source: []const u8) -> %void {
122 assert(dest.len == %%decoder.calcSize(source));
123 assert(source.len % 4 == 0);
124
125 var src_cursor: usize = 0;
126 var dest_cursor: usize = 0;
127
128 while (src_cursor < source.len) : (src_cursor += 4) {
129 if (!decoder.char_in_alphabet[source[src_cursor + 0]]) return error.InvalidCharacter;
130 if (!decoder.char_in_alphabet[source[src_cursor + 1]]) return error.InvalidCharacter;
131 if (src_cursor < source.len - 4 or source[src_cursor + 3] != decoder.pad_char) {
132 // common case
133 if (!decoder.char_in_alphabet[source[src_cursor + 2]]) return error.InvalidCharacter;
134 if (!decoder.char_in_alphabet[source[src_cursor + 3]]) return error.InvalidCharacter;
135 dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 |
136 decoder.char_to_index[source[src_cursor + 1]] >> 4;
137 dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 |
138 decoder.char_to_index[source[src_cursor + 2]] >> 2;
139 dest[dest_cursor + 2] = decoder.char_to_index[source[src_cursor + 2]] << 6 |
140 decoder.char_to_index[source[src_cursor + 3]];
141 dest_cursor += 3;
142 } else if (source[src_cursor + 2] != decoder.pad_char) {
143 // one pad char
144 if (!decoder.char_in_alphabet[source[src_cursor + 2]]) return error.InvalidCharacter;
145 dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 |
146 decoder.char_to_index[source[src_cursor + 1]] >> 4;
147 dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 |
148 decoder.char_to_index[source[src_cursor + 2]] >> 2;
149 if (decoder.char_to_index[source[src_cursor + 2]] << 6 != 0) return error.InvalidPadding;
150 dest_cursor += 2;
151 } else {
152 // two pad chars
153 dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 |
154 decoder.char_to_index[source[src_cursor + 1]] >> 4;
155 if (decoder.char_to_index[source[src_cursor + 1]] << 4 != 0) return error.InvalidPadding;
156 dest_cursor += 1;
157 }
158 }
82159
83 while (in_buf_len > 0 and source[in_buf_len - 1] == pad_char) {
84 in_buf_len -= 1;
160 assert(src_cursor == source.len);
161 assert(dest_cursor == dest.len);
85162 }
163};
164
165error OutputTooSmall;
166
167pub 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 }
86182
87 while (in_buf_len > 4) {
88 dest[dest_index] = ascii6[source[src_index + 0]] << 2 |
89 ascii6[source[src_index + 1]] >> 4;
90 dest_index += 1;
183 return result;
184 }
91185
92 dest[dest_index] = ascii6[source[src_index + 1]] << 4 |
93 ascii6[source[src_index + 2]] >> 2;
94 dest_index += 1;
186 /// If no characters end up being ignored or padding, this will be the exact decoded size.
187 pub fn calcSizeUpperBound(encoded_len: usize) -> %usize {
188 return @divTrunc(encoded_len, 4) * 3;
189 }
95190
96 dest[dest_index] = ascii6[source[src_index + 2]] << 6 |
97 ascii6[source[src_index + 3]];
98 dest_index += 1;
191 /// Invalid characters that are not ignored result in error.InvalidCharacter.
192 /// Invalid padding results in error.InvalidPadding.
193 /// Decoding more data than can fit in dest results in error.OutputTooSmall. See also ::calcSizeUpperBound.
194 /// Returns the number of bytes writen to dest.
195 pub fn decode(decoder_with_ignore: &const Base64DecoderWithIgnore, dest: []u8, source: []const u8) -> %usize {
196 const decoder = &const decoder_with_ignore.decoder;
197
198 var src_cursor: usize = 0;
199 var dest_cursor: usize = 0;
200
201 while (true) {
202 // get the next 4 chars, if available
203 var next_4_chars: [4]u8 = undefined;
204 var available_chars: usize = 0;
205 var pad_char_count: usize = 0;
206 while (available_chars < 4 and src_cursor < source.len) {
207 var c = source[src_cursor];
208 src_cursor += 1;
209
210 if (decoder.char_in_alphabet[c]) {
211 // normal char
212 next_4_chars[available_chars] = c;
213 available_chars += 1;
214 } else if (decoder_with_ignore.char_is_ignored[c]) {
215 // we're told to skip this one
216 continue;
217 } else if (c == decoder.pad_char) {
218 // the padding has begun. count the pad chars.
219 pad_char_count += 1;
220 while (src_cursor < source.len) {
221 c = source[src_cursor];
222 src_cursor += 1;
223 if (c == decoder.pad_char) {
224 pad_char_count += 1;
225 if (pad_char_count > 2) return error.InvalidCharacter;
226 } else if (decoder_with_ignore.char_is_ignored[c]) {
227 // we can even ignore chars during the padding
228 continue;
229 } else return error.InvalidCharacter;
230 }
231 break;
232 } else return error.InvalidCharacter;
233 }
234
235 switch (available_chars) {
236 4 => {
237 // common case
238 if (dest_cursor + 3 > dest.len) return error.OutputTooSmall;
239 assert(pad_char_count == 0);
240 dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 |
241 decoder.char_to_index[next_4_chars[1]] >> 4;
242 dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 |
243 decoder.char_to_index[next_4_chars[2]] >> 2;
244 dest[dest_cursor + 2] = decoder.char_to_index[next_4_chars[2]] << 6 |
245 decoder.char_to_index[next_4_chars[3]];
246 dest_cursor += 3;
247 continue;
248 },
249 3 => {
250 if (dest_cursor + 2 > dest.len) return error.OutputTooSmall;
251 if (pad_char_count != 1) return error.InvalidPadding;
252 dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 |
253 decoder.char_to_index[next_4_chars[1]] >> 4;
254 dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 |
255 decoder.char_to_index[next_4_chars[2]] >> 2;
256 if (decoder.char_to_index[next_4_chars[2]] << 6 != 0) return error.InvalidPadding;
257 dest_cursor += 2;
258 break;
259 },
260 2 => {
261 if (dest_cursor + 1 > dest.len) return error.OutputTooSmall;
262 if (pad_char_count != 2) return error.InvalidPadding;
263 dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 |
264 decoder.char_to_index[next_4_chars[1]] >> 4;
265 if (decoder.char_to_index[next_4_chars[1]] << 4 != 0) return error.InvalidPadding;
266 dest_cursor += 1;
267 break;
268 },
269 1 => {
270 return error.InvalidPadding;
271 },
272 0 => {
273 if (pad_char_count != 0) return error.InvalidPadding;
274 break;
275 },
276 else => unreachable,
277 }
278 }
99279
100 src_index += 4;
101 in_buf_len -= 4;
102 }
280 assert(src_cursor == source.len);
103281
104 if (in_buf_len > 1) {
105 dest[dest_index] = ascii6[source[src_index + 0]] << 2 |
106 ascii6[source[src_index + 1]] >> 4;
107 dest_index += 1;
282 return dest_cursor;
108283 }
109 if (in_buf_len > 2) {
110 dest[dest_index] = ascii6[source[src_index + 1]] << 4 |
111 ascii6[source[src_index + 2]] >> 2;
112 dest_index += 1;
284};
285
286
287pub const standard_decoder_unsafe = Base64DecoderUnsafe.init(standard_alphabet_chars, standard_pad_char);
288
289pub 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;
113306 }
114 if (in_buf_len > 3) {
115 dest[dest_index] = ascii6[source[src_index + 2]] << 6 |
116 ascii6[source[src_index + 3]];
117 dest_index += 1;
307
308 /// The source buffer must be valid.
309 pub fn calcSize(decoder: &const Base64DecoderUnsafe, source: []const u8) -> usize {
310 return calcDecodedSizeExactUnsafe(source, decoder.pad_char);
118311 }
119312
120 return dest[0..dest_index];
121}
313 /// dest.len must be what you get from ::calcDecodedSizeExactUnsafe.
314 /// invalid characters or padding will result in undefined values.
315 pub fn decode(decoder: &const Base64DecoderUnsafe, dest: []u8, source: []const u8) {
316 assert(dest.len == decoder.calcSize(source));
122317
123pub fn calcEncodedSize(source_len: usize) -> usize {
124 return (((source_len * 4) / 3 + 3) / 4) * 4;
125}
318 var src_index: usize = 0;
319 var dest_index: usize = 0;
320 var in_buf_len: usize = source.len;
126321
127/// Computes the upper bound of the decoded size based only on the encoded length.
128/// To compute the exact decoded size, see ::calcExactDecodedSize
129pub fn calcMaxDecodedSize(encoded_len: usize) -> usize {
130 return @divExact(encoded_len * 3, 4);
131}
322 while (in_buf_len > 0 and source[in_buf_len - 1] == decoder.pad_char) {
323 in_buf_len -= 1;
324 }
132325
133/// Computes the number of decoded bytes there will be. This function must
134/// be given the encoded buffer because there might be padding
135/// bytes at the end ('=' in the standard alphabet)
136pub fn calcExactDecodedSize(encoded: []const u8) -> usize {
137 return calcExactDecodedSizeWithAlphabet(encoded, standard_alphabet);
138}
326 while (in_buf_len > 4) {
327 dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 |
328 decoder.char_to_index[source[src_index + 1]] >> 4;
329 dest_index += 1;
139330
140pub fn calcExactDecodedSizeWithAlphabet(encoded: []const u8, alphabet: []const u8) -> usize {
141 assert(alphabet.len == 65);
142 return calcExactDecodedSizeWithPadChar(encoded, alphabet[64]);
143}
331 dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 |
332 decoder.char_to_index[source[src_index + 2]] >> 2;
333 dest_index += 1;
144334
145pub fn calcExactDecodedSizeWithPadChar(encoded: []const u8, pad_char: u8) -> usize {
146 var buf_len = encoded.len;
335 dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 |
336 decoder.char_to_index[source[src_index + 3]];
337 dest_index += 1;
147338
148 while (buf_len > 0 and encoded[buf_len - 1] == pad_char) {
149 buf_len -= 1;
150 }
339 src_index += 4;
340 in_buf_len -= 4;
341 }
151342
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
361fn 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;
153371}
154372
373
155374test "base64" {
156 testBase64();
157 comptime testBase64();
375 @setEvalBranchQuota(5000);
376 %%testBase64();
377 comptime %%testBase64();
158378}
159379
160fn testBase64() {
161 testBase64Case("", "");
162 testBase64Case("f", "Zg==");
163 testBase64Case("fo", "Zm8=");
164 testBase64Case("foo", "Zm9v");
165 testBase64Case("foob", "Zm9vYg==");
166 testBase64Case("fooba", "Zm9vYmE=");
167 testBase64Case("foobar", "Zm9vYmFy");
380fn testBase64() -> %void {
381 %return testAllApis("", "");
382 %return testAllApis("f", "Zg==");
383 %return testAllApis("fo", "Zm8=");
384 %return testAllApis("foo", "Zm9v");
385 %return testAllApis("foob", "Zm9vYg==");
386 %return testAllApis("fooba", "Zm9vYmE=");
387 %return testAllApis("foobar", "Zm9vYmFy");
388
389 %return testDecodeIgnoreSpace("", " ");
390 %return testDecodeIgnoreSpace("f", "Z g= =");
391 %return testDecodeIgnoreSpace("fo", " Zm8=");
392 %return testDecodeIgnoreSpace("foo", "Zm9v ");
393 %return testDecodeIgnoreSpace("foob", "Zm9vYg = = ");
394 %return testDecodeIgnoreSpace("fooba", "Zm9v YmE=");
395 %return testDecodeIgnoreSpace("foobar", " Z m 9 v Y m F y ");
396
397 // test getting some api errors
398 %return testError("A", error.InvalidPadding);
399 %return testError("AA", error.InvalidPadding);
400 %return testError("AAA", error.InvalidPadding);
401 %return testError("A..A", error.InvalidCharacter);
402 %return testError("AA=A", error.InvalidCharacter);
403 %return testError("AA/=", error.InvalidPadding);
404 %return testError("A/==", error.InvalidPadding);
405 %return testError("A===", error.InvalidCharacter);
406 %return testError("====", error.InvalidCharacter);
407
408 %return testOutputTooSmallError("AA==");
409 %return testOutputTooSmallError("AAA=");
410 %return testOutputTooSmallError("AAAA");
411 %return testOutputTooSmallError("AAAAAA==");
168412}
169413
170fn testBase64Case(expected_decoded: []const u8, expected_encoded: []const u8) {
171 const calculated_decoded_len = calcExactDecodedSize(expected_encoded);
172 assert(calculated_decoded_len == expected_decoded.len);
414fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) -> %void {
415 // Base64Encoder
416 {
417 var buffer: [0x100]u8 = undefined;
418 var encoded = buffer[0..Base64Encoder.calcSize(expected_decoded.len)];
419 standard_encoder.encode(encoded, expected_decoded);
420 assert(mem.eql(u8, encoded, expected_encoded));
421 }
173422
174 const calculated_encoded_len = calcEncodedSize(expected_decoded.len);
175 assert(calculated_encoded_len == expected_encoded.len);
423 // Base64Decoder
424 {
425 var buffer: [0x100]u8 = undefined;
426 var decoded = buffer[0..%return standard_decoder.calcSize(expected_encoded)];
427 %return standard_decoder.decode(decoded, expected_encoded);
428 assert(mem.eql(u8, decoded, expected_decoded));
429 }
176430
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 }
178441
179 const actual_decoded = decode(buf[0..], expected_encoded);
180 assert(actual_decoded.len == expected_decoded.len);
181 assert(mem.eql(u8, expected_decoded, actual_decoded));
442 // Base64DecoderUnsafe
443 {
444 var buffer: [0x100]u8 = undefined;
445 var decoded = buffer[0..standard_decoder_unsafe.calcSize(expected_encoded)];
446 standard_decoder_unsafe.decode(decoded, expected_encoded);
447 assert(mem.eql(u8, decoded, expected_decoded));
448 }
449}
450
451fn 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
460error ExpectedError;
461fn 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}
182476
183 const actual_encoded = encode(buf[0..], expected_decoded);
184 assert(actual_encoded.len == expected_encoded.len);
185 assert(mem.eql(u8, expected_encoded, actual_encoded));
477fn testOutputTooSmallError(encoded: []const u8) -> %void {
478 const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
479 standard_alphabet_chars, standard_pad_char, " ");
480 var buffer: [0x100]u8 = undefined;
481 var decoded = buffer[0..calcDecodedSizeExactUnsafe(encoded, standard_pad_char) - 1];
482 if (standard_decoder_ignore_space.decode(decoded, encoded)) |_| {
483 return error.ExpectedError;
484 } else |err| if (err != error.OutputTooSmall) return err;
186485}
std/os/index.zig+9-5
......@@ -31,6 +31,8 @@ pub const windowsWaitSingle = windows_util.windowsWaitSingle;
3131pub const windowsWrite = windows_util.windowsWrite;
3232pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
3333pub const windowsOpen = windows_util.windowsOpen;
34pub const windowsLoadDll = windows_util.windowsLoadDll;
35pub const windowsUnloadDll = windows_util.windowsUnloadDll;
3436pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
3537
3638pub const FileHandle = if (is_windows) windows.HANDLE else i32;
......@@ -620,7 +622,9 @@ pub fn symLinkPosix(allocator: &Allocator, existing_path: []const u8, new_path:
620622}
621623
622624// here we replace the standard +/ with -_ so that it can be used in a file name
623const b64_fs_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=";
625const b64_fs_encoder = base64.Base64Encoder.init(
626 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
627 base64.standard_pad_char);
624628
625629pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) -> %void {
626630 if (symLink(allocator, existing_path, new_path)) {
......@@ -632,12 +636,12 @@ pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path:
632636 }
633637
634638 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));
636640 defer allocator.free(tmp_path);
637641 mem.copy(u8, tmp_path[0..], new_path);
638642 while (true) {
639643 %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);
641645 if (symLink(allocator, existing_path, tmp_path)) {
642646 return rename(allocator, tmp_path, new_path);
643647 } else |err| {
......@@ -715,11 +719,11 @@ pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []con
715719/// Guaranteed to be atomic.
716720pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: []const u8, mode: usize) -> %void {
717721 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));
719723 defer allocator.free(tmp_path);
720724 mem.copy(u8, tmp_path[0..], dest_path);
721725 %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);
723727
724728 var out_file = %return io.File.openWriteMode(tmp_path, mode, allocator);
725729 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
8484 in_nNumberOfBytesToWrite: DWORD, out_lpNumberOfBytesWritten: ?&DWORD,
8585 in_out_lpOverlapped: ?&OVERLAPPED) -> BOOL;
8686
87//TODO: call unicode versions instead of relying on ANSI code page
88pub extern "kernel32" stdcallcc fn LoadLibraryA(lpLibFileName: LPCSTR) -> ?HMODULE;
89
90pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) -> BOOL;
91
8792pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) -> c_int;
8893
8994pub const PROV_RSA_FULL = 1;
......@@ -97,6 +102,7 @@ pub const FLOAT = f32;
97102pub const HANDLE = &c_void;
98103pub const HCRYPTPROV = ULONG_PTR;
99104pub const HINSTANCE = &@OpaqueType();
105pub const HMODULE = &@OpaqueType();
100106pub const INT = c_int;
101107pub const LPBYTE = &BYTE;
102108pub const LPCH = &CHAR;
std/os/windows/util.zig+23
......@@ -4,6 +4,7 @@ const windows = std.os.windows;
44const assert = std.debug.assert;
55const mem = std.mem;
66const BufMap = std.BufMap;
7const cstr = std.cstr;
78
89error WaitAbandoned;
910error WaitTimeOut;
......@@ -149,3 +150,25 @@ pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap)
149150 result[i] = 0;
150151 return result;
151152}
153
154error DllNotFound;
155pub 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
161pub fn windowsUnloadDll(hModule: windows.HMODULE) {
162 assert(windows.FreeLibrary(hModule)!= 0);
163}
164
165
166test "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" {
3131 else => unreachable,
3232 }
3333}
34
35
36const Foo = union {
37 float: f64,
38 int: i32,
39};
40
41test "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
48test "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
58fn setFloat(foo: &Foo, x: f64) {
59 *foo = Foo { .float = x };
60}
61
62fn setInt(foo: &Foo, x: i32) {
63 *foo = Foo { .int = x };
64}
65
66const FooExtern = extern union {
67 float: f64,
68 int: i32,
69};
70
71test "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) {
389389 \\ const y = a.bar;
390390 \\}
391391 ,
392 ".tmp_source.zig:4:6: error: no member named 'foo' in 'A'",
393 ".tmp_source.zig:5:16: error: no member named 'bar' in 'A'");
392 ".tmp_source.zig:4:6: error: no member named 'foo' in struct 'A'",
393 ".tmp_source.zig:5:16: error: no member named 'bar' in struct 'A'");
394394
395395 cases.add("redefinition of struct",
396396 \\const A = struct { x : i32, };
......@@ -454,7 +454,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
454454 \\ .foo = 42,
455455 \\ };
456456 \\}
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'");
458458
459459 cases.add("invalid break expression",
460460 \\export fn f() {
......@@ -2343,4 +2343,23 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
23432343 \\pub extern fn foo(format: &const u8, ...);
23442344 ,
23452345 ".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");
23462365}
test/debug_safety.zig+20
......@@ -260,4 +260,24 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
260260 \\ return int_slice[0];
261261 \\}
262262 );
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 );
263283}
test/parsec.zig deleted-871
......@@ -1,871 +0,0 @@
1const tests = @import("tests.zig");
2
3pub 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");
1818const compile_errors = @import("compile_errors.zig");
1919const assemble_and_link = @import("assemble_and_link.zig");
2020const debug_safety = @import("debug_safety.zig");
21const parsec = @import("parsec.zig");
21const translate_c = @import("translate_c.zig");
2222
2323const TestTarget = struct {
2424 os: builtin.Os,
......@@ -123,16 +123,16 @@ pub fn addAssembleAndLinkTests(b: &build.Builder, test_filter: ?[]const u8) -> &
123123 return cases.step;
124124}
125125
126pub fn addParseCTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {
127 const cases = %%b.allocator.create(ParseCContext);
128 *cases = ParseCContext {
126pub fn addTranslateCTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {
127 const cases = %%b.allocator.create(TranslateCContext);
128 *cases = TranslateCContext {
129129 .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"),
131131 .test_index = 0,
132132 .test_filter = test_filter,
133133 };
134134
135 parsec.addCases(cases);
135 translate_c.addCases(cases);
136136
137137 return cases.step;
138138}
......@@ -770,7 +770,7 @@ pub const BuildExamplesContext = struct {
770770 }
771771};
772772
773pub const ParseCContext = struct {
773pub const TranslateCContext = struct {
774774 b: &build.Builder,
775775 step: &build.Step,
776776 test_index: usize,
......@@ -799,17 +799,17 @@ pub const ParseCContext = struct {
799799 }
800800 };
801801
802 const ParseCCmpOutputStep = struct {
802 const TranslateCCmpOutputStep = struct {
803803 step: build.Step,
804 context: &ParseCContext,
804 context: &TranslateCContext,
805805 name: []const u8,
806806 test_index: usize,
807807 case: &const TestCase,
808808
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 {
810810 const allocator = context.b.allocator;
811 const ptr = %%allocator.create(ParseCCmpOutputStep);
812 *ptr = ParseCCmpOutputStep {
811 const ptr = %%allocator.create(TranslateCCmpOutputStep);
812 *ptr = TranslateCCmpOutputStep {
813813 .step = build.Step.init("ParseCCmpOutput", allocator, make),
814814 .context = context,
815815 .name = name,
......@@ -821,7 +821,7 @@ pub const ParseCContext = struct {
821821 }
822822
823823 fn make(step: &build.Step) -> %void {
824 const self = @fieldParentPtr(ParseCCmpOutputStep, "step", step);
824 const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step);
825825 const b = self.context.b;
826826
827827 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 {
829829 var zig_args = ArrayList([]const u8).init(b.allocator);
830830 %%zig_args.append(b.zig_exe);
831831
832 %%zig_args.append("parsec");
832 %%zig_args.append("translate-c");
833833 %%zig_args.append(b.pathFromRoot(root_src));
834834
835835 warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
......@@ -882,7 +882,7 @@ pub const ParseCContext = struct {
882882
883883 if (stderr.len != 0 and !self.case.allow_warnings) {
884884 warn(
885 \\====== parsec emitted warnings: ============
885 \\====== translate-c emitted warnings: =======
886886 \\{}
887887 \\============================================
888888 \\
......@@ -914,7 +914,7 @@ pub const ParseCContext = struct {
914914 warn("\n");
915915 }
916916
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,
918918 source: []const u8, expected_lines: ...) -> &TestCase
919919 {
920920 const tc = %%self.b.allocator.create(TestCase);
......@@ -932,37 +932,37 @@ pub const ParseCContext = struct {
932932 return tc;
933933 }
934934
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: ...) {
936936 const tc = self.create(false, "source.h", name, source, expected_lines);
937937 self.addCase(tc);
938938 }
939939
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: ...) {
941941 const tc = self.create(false, "source.c", name, source, expected_lines);
942942 self.addCase(tc);
943943 }
944944
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: ...) {
946946 const tc = self.create(true, "source.h", name, source, expected_lines);
947947 self.addCase(tc);
948948 }
949949
950 pub fn addCase(self: &ParseCContext, case: &const TestCase) {
950 pub fn addCase(self: &TranslateCContext, case: &const TestCase) {
951951 const b = self.b;
952952
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);
954954 if (self.test_filter) |filter| {
955955 if (mem.indexOf(u8, annotated_case_name, filter) == null)
956956 return;
957957 }
958958
959 const parsec_and_cmp = ParseCCmpOutputStep.create(self, annotated_case_name, case);
960 self.step.dependOn(&parsec_and_cmp.step);
959 const translate_c_and_cmp = TranslateCCmpOutputStep.create(self, annotated_case_name, case);
960 self.step.dependOn(&translate_c_and_cmp.step);
961961
962962 for (case.sources.toSliceConst()) |src_file| {
963963 const expanded_src_path = %%os.path.join(b.allocator, b.cache_root, src_file.filename);
964964 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);
966966 }
967967 }
968968};
test/translate_c.zig created+1181
......@@ -0,0 +1,1181 @@
1const tests = @import("tests.zig");
2
3pub 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}