diff --git a/CMakeLists.txt b/CMakeLists.txt index 8906798c69..72c480cd40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -339,7 +339,7 @@ set(ZIG_SOURCES "${CMAKE_SOURCE_DIR}/src/target.cpp" "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" "${CMAKE_SOURCE_DIR}/src/util.cpp" - "${CMAKE_SOURCE_DIR}/src/parsec.cpp" + "${CMAKE_SOURCE_DIR}/src/translate_c.cpp" "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" ) diff --git a/build.zig b/build.zig index 79fefd5c7a..1c1d4f832e 100644 --- a/build.zig +++ b/build.zig @@ -58,5 +58,5 @@ pub fn build(b: &Builder) { test_step.dependOn(tests.addCompileErrorTests(b, test_filter)); test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter)); test_step.dependOn(tests.addDebugSafetyTests(b, test_filter)); - test_step.dependOn(tests.addParseCTests(b, test_filter)); + test_step.dependOn(tests.addTranslateCTests(b, test_filter)); } diff --git a/ci/travis_osx_script b/ci/travis_osx_script index 1f345c9c50..a55132395b 100755 --- a/ci/travis_osx_script +++ b/ci/travis_osx_script @@ -22,4 +22,4 @@ make install ./zig build --build-file ../build.zig test-compile-errors --verbose ./zig build --build-file ../build.zig test-asm-link --verbose ./zig build --build-file ../build.zig test-debug-safety --verbose -./zig build --build-file ../build.zig test-parsec --verbose +./zig build --build-file ../build.zig test-translate-c --verbose diff --git a/doc/home.html.in b/doc/home.html.in index 002ac0b70a..3b2ef3407b 100644 --- a/doc/home.html.in +++ b/doc/home.html.in @@ -70,10 +70,14 @@
const io = @import("std").io;
+ const std = @import("std");
pub fn main() -> %void {
- %return io.stdout.printf("Hello, world!\n");
+ // If this program is run without stdout attached, exit with an error.
+ var stdout_file = %return std.io.getStdOut();
+ // If this program encounters pipe failure when printing to stdout, exit
+ // with an error.
+ %return stdout_file.write("Hello, world!\n");
}
Build this with:
zig build-exe hello.zig
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 9aa142fc46..e8f76e230b 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -75,6 +75,7 @@
Slices
struct
enum
+ union
switch
while
for
@@ -209,6 +210,7 @@
Invalid Error Code
Invalid Enum Cast
Incorrect Pointer Alignment
+ Wrong Union Field Access
Memory
@@ -2189,6 +2191,8 @@ Test 4/4 enum builtins...OK
TODO union documentation
const assert = @import("std").debug.assert;
const builtin = @import("builtin");
@@ -5117,6 +5121,9 @@ comptime {
Incorrect Pointer Alignment
TODO
+ Wrong Union Field Access
+ TODO
+
Memory
TODO: explain no default allocator in zig
TODO: show how to use the allocator interface
@@ -5405,10 +5412,14 @@ const c = @cImport({
export fn decode_base_64(dest_ptr: &u8, dest_len: usize,
source_ptr: &const u8, source_len: usize) -> usize
{
- const src = source_ptr[0...source_len];
- const dest = dest_ptr[0...dest_len];
- return base64.decode(dest, src).len;
-}
+ const src = source_ptr[0..source_len];
+ const dest = dest_ptr[0..dest_len];
+ const base64_decoder = base64.standard_decoder_unsafe;
+ const decoded_size = base64_decoder.calcSize(src);
+ base64_decoder.decode(dest[0..decoded_size], src);
+ return decoded_size;
+}
+
// This header is generated by zig from base64.zig
#include "base64.h"
diff --git a/example/mix_o_files/base64.zig b/example/mix_o_files/base64.zig
index 10438ad077..49c9bc6012 100644
--- a/example/mix_o_files/base64.zig
+++ b/example/mix_o_files/base64.zig
@@ -3,5 +3,8 @@ const base64 = @import("std").base64;
export fn decode_base_64(dest_ptr: &u8, dest_len: usize, source_ptr: &const u8, source_len: usize) -> usize {
const src = source_ptr[0..source_len];
const dest = dest_ptr[0..dest_len];
- return base64.decode(dest, src).len;
+ const base64_decoder = base64.standard_decoder_unsafe;
+ const decoded_size = base64_decoder.calcSize(src);
+ base64_decoder.decode(dest[0..decoded_size], src);
+ return decoded_size;
}
diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig
index 0716ad433b..71180b2001 100644
--- a/src-self-hosted/main.zig
+++ b/src-self-hosted/main.zig
@@ -208,7 +208,7 @@ fn printUsage(outstream: &io.OutStream) -> %void {
\\ build-exe [source] create executable from source or object files
\\ build-lib [source] create library from source or object files
\\ build-obj [source] create object from source or assembly
- \\ parsec [source] convert c code to zig code
+ \\ translate-c [source] convert c code to zig code
\\ targets list available compilation targets
\\ test [source] create and run a test build
\\ version print version number and exit
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 0b4efd8415..2fccf08e88 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -36,6 +36,7 @@ struct IrInstructionCast;
struct IrBasicBlock;
struct ScopeDecls;
struct ZigWindowsSDK;
+struct Tld;
struct IrGotoItem {
AstNode *source_node;
@@ -59,7 +60,9 @@ struct IrExecutable {
Buf *c_import_buf;
AstNode *source_node;
IrExecutable *parent_exec;
+ IrExecutable *source_exec;
Scope *begin_scope;
+ ZigList tld_list;
};
enum OutType {
@@ -73,6 +76,7 @@ enum ConstParentId {
ConstParentIdNone,
ConstParentIdStruct,
ConstParentIdArray,
+ ConstParentIdUnion,
};
struct ConstParent {
@@ -87,6 +91,9 @@ struct ConstParent {
ConstExprValue *struct_val;
size_t field_index;
} p_struct;
+ struct {
+ ConstExprValue *union_val;
+ } p_union;
} data;
};
@@ -100,6 +107,12 @@ struct ConstStructValue {
ConstParent parent;
};
+struct ConstUnionValue {
+ uint64_t tag;
+ ConstExprValue *payload;
+ ConstParent parent;
+};
+
enum ConstArraySpecial {
ConstArraySpecialNone,
ConstArraySpecialUndef,
@@ -238,6 +251,7 @@ struct ConstExprValue {
ErrorTableEntry *x_pure_err;
ConstEnumValue x_enum;
ConstStructValue x_struct;
+ ConstUnionValue x_union;
ConstArrayValue x_array;
ConstPtrValue x_ptr;
ImportTableEntry *x_import;
@@ -336,6 +350,13 @@ struct TypeEnumField {
uint32_t gen_index;
};
+struct TypeUnionField {
+ Buf *name;
+ TypeTableEntry *type_entry;
+ uint32_t value;
+ uint32_t gen_index;
+};
+
enum NodeType {
NodeTypeRoot,
NodeTypeFnProto,
@@ -1021,14 +1042,19 @@ struct TypeTableEntryEnumTag {
LLVMValueRef name_table;
};
+uint32_t type_ptr_hash(const TypeTableEntry *ptr);
+bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b);
+
struct TypeTableEntryUnion {
AstNode *decl_node;
ContainerLayout layout;
uint32_t src_field_count;
uint32_t gen_field_count;
- TypeStructField *fields;
- uint64_t size_bytes;
+ TypeUnionField *fields;
bool is_invalid; // true if any fields are invalid
+ TypeTableEntry *tag_type;
+ LLVMTypeRef union_type_ref;
+
ScopeDecls *decls_scope;
// set this flag temporarily to detect infinite loops
@@ -1039,6 +1065,13 @@ struct TypeTableEntryUnion {
bool zero_bits_loop_flag;
bool zero_bits_known;
+ uint32_t abi_alignment; // also figured out with zero_bits pass
+
+ size_t gen_union_index;
+ size_t gen_tag_index;
+
+ uint32_t union_size_bytes;
+ TypeTableEntry *most_aligned_union_member;
};
struct FnGenParamInfo {
@@ -1287,6 +1320,7 @@ enum PanicMsgId {
PanicMsgIdUnwrapMaybeFail,
PanicMsgIdInvalidErrorCode,
PanicMsgIdIncorrectAlignment,
+ PanicMsgIdBadUnionField,
PanicMsgIdCount,
};
@@ -1796,6 +1830,7 @@ enum IrInstructionId {
IrInstructionIdFieldPtr,
IrInstructionIdStructFieldPtr,
IrInstructionIdEnumFieldPtr,
+ IrInstructionIdUnionFieldPtr,
IrInstructionIdElemPtr,
IrInstructionIdVarPtr,
IrInstructionIdCall,
@@ -1805,6 +1840,7 @@ enum IrInstructionId {
IrInstructionIdContainerInitList,
IrInstructionIdContainerInitFields,
IrInstructionIdStructInit,
+ IrInstructionIdUnionInit,
IrInstructionIdUnreachable,
IrInstructionIdTypeOf,
IrInstructionIdToPtrType,
@@ -2060,6 +2096,14 @@ struct IrInstructionEnumFieldPtr {
bool is_const;
};
+struct IrInstructionUnionFieldPtr {
+ IrInstruction base;
+
+ IrInstruction *union_ptr;
+ TypeUnionField *field;
+ bool is_const;
+};
+
struct IrInstructionElemPtr {
IrInstruction base;
@@ -2150,6 +2194,15 @@ struct IrInstructionStructInit {
LLVMValueRef tmp_ptr;
};
+struct IrInstructionUnionInit {
+ IrInstruction base;
+
+ TypeTableEntry *union_type;
+ TypeUnionField *field;
+ IrInstruction *init_value;
+ LLVMValueRef tmp_ptr;
+};
+
struct IrInstructionUnreachable {
IrInstruction base;
};
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 343b1ecdb0..1c223c63f7 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -28,7 +28,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type);
ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
if (node->owner->c_import_node != nullptr) {
- // if this happens, then parsec generated code that
+ // if this happens, then translate_c generated code that
// failed semantic analysis, which isn't supposed to happen
ErrorMsg *err = add_node_error(g, node->owner->c_import_node,
buf_sprintf("compiler bug: @cImport generated invalid zig code"));
@@ -48,7 +48,7 @@ ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) {
if (node->owner->c_import_node != nullptr) {
- // if this happens, then parsec generated code that
+ // if this happens, then translate_c generated code that
// failed semantic analysis, which isn't supposed to happen
Buf *note_path = buf_create_from_str("?.c");
@@ -338,7 +338,7 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,
bool is_volatile, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count)
{
- assert(child_type->id != TypeTableEntryIdInvalid);
+ assert(!type_is_invalid(child_type));
TypeId type_id = {};
TypeTableEntry **parent_pointer = nullptr;
@@ -1008,11 +1008,12 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi
}
size_t line = decl_node ? decl_node->line : 0;
+ unsigned dwarf_kind = ZigLLVMTag_DW_structure_type();
ImportTableEntry *import = get_scope_import(scope);
entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name);
entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
- ZigLLVMTag_DW_structure_type(), name,
+ dwarf_kind, name,
ZigLLVMFileToScope(import->di_file), import->di_file, (unsigned)(line + 1));
buf_init_from_str(&entry->name, name);
@@ -1285,7 +1286,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
return;
resolve_enum_zero_bits(g, enum_type);
- if (enum_type->data.enumeration.is_invalid)
+ if (type_is_invalid(enum_type))
return;
AstNode *decl_node = enum_type->data.enumeration.decl_node;
@@ -1834,7 +1835,246 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
}
static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
- zig_panic("TODO");
+ assert(union_type->id == TypeTableEntryIdUnion);
+
+ if (union_type->data.unionation.complete)
+ return;
+
+ resolve_union_zero_bits(g, union_type);
+ if (type_is_invalid(union_type))
+ return;
+
+ AstNode *decl_node = union_type->data.unionation.decl_node;
+
+ if (union_type->data.unionation.embedded_in_current) {
+ if (!union_type->data.unionation.reported_infinite_err) {
+ union_type->data.unionation.reported_infinite_err = true;
+ add_node_error(g, decl_node, buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name)));
+ }
+ return;
+ }
+
+ assert(!union_type->data.unionation.zero_bits_loop_flag);
+ assert(decl_node->type == NodeTypeContainerDecl);
+ assert(union_type->di_type);
+
+ uint32_t field_count = union_type->data.unionation.src_field_count;
+
+ assert(union_type->data.unionation.fields);
+
+ uint32_t gen_field_count = union_type->data.unionation.gen_field_count;
+ ZigLLVMDIType **union_inner_di_types = allocate(gen_field_count);
+
+ TypeTableEntry *most_aligned_union_member = nullptr;
+ uint64_t size_of_most_aligned_member_in_bits = 0;
+ uint64_t biggest_align_in_bits = 0;
+ uint64_t biggest_size_in_bits = 0;
+
+ bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
+ ZigLLVMDIEnumerator **di_enumerators = allocate(field_count);
+
+ Scope *scope = &union_type->data.unionation.decls_scope->base;
+ ImportTableEntry *import = get_scope_import(scope);
+
+ // set temporary flag
+ union_type->data.unionation.embedded_in_current = true;
+
+ for (uint32_t i = 0; i < field_count; i += 1) {
+ AstNode *field_node = decl_node->data.container_decl.fields.at(i);
+ TypeUnionField *type_union_field = &union_type->data.unionation.fields[i];
+ TypeTableEntry *field_type = type_union_field->type_entry;
+
+ ensure_complete_type(g, field_type);
+ if (type_is_invalid(field_type)) {
+ union_type->data.unionation.is_invalid = true;
+ continue;
+ }
+
+ if (!type_has_bits(field_type))
+ continue;
+
+ di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(type_union_field->name), i);
+
+ uint64_t store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
+ uint64_t abi_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref);
+
+ assert(store_size_in_bits > 0);
+ assert(abi_align_in_bits > 0);
+
+ union_inner_di_types[type_union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
+ ZigLLVMTypeToScope(union_type->di_type), buf_ptr(type_union_field->name),
+ import->di_file, (unsigned)(field_node->line + 1),
+ store_size_in_bits,
+ abi_align_in_bits,
+ 0,
+ 0, field_type->di_type);
+
+ biggest_size_in_bits = max(biggest_size_in_bits, store_size_in_bits);
+
+ if (!most_aligned_union_member || abi_align_in_bits > biggest_align_in_bits) {
+ most_aligned_union_member = field_type;
+ biggest_align_in_bits = abi_align_in_bits;
+ size_of_most_aligned_member_in_bits = store_size_in_bits;
+ }
+ }
+
+ // unset temporary flag
+ union_type->data.unionation.embedded_in_current = false;
+ union_type->data.unionation.complete = true;
+ union_type->data.unionation.union_size_bytes = biggest_size_in_bits / 8;
+ union_type->data.unionation.most_aligned_union_member = most_aligned_union_member;
+
+ if (union_type->data.unionation.is_invalid)
+ return;
+
+ if (union_type->zero_bits) {
+ union_type->type_ref = LLVMVoidType();
+
+ uint64_t debug_size_in_bits = 0;
+ uint64_t debug_align_in_bits = 0;
+ ZigLLVMDIType **di_root_members = nullptr;
+ size_t debug_member_count = 0;
+ ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
+ ZigLLVMFileToScope(import->di_file),
+ buf_ptr(&union_type->name),
+ import->di_file, (unsigned)(decl_node->line + 1),
+ debug_size_in_bits,
+ debug_align_in_bits,
+ 0, di_root_members, (int)debug_member_count, 0, "");
+
+ ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type);
+ union_type->di_type = replacement_di_type;
+ return;
+ }
+
+ assert(most_aligned_union_member != nullptr);
+
+ bool want_safety = auto_layout && (field_count >= 2);
+ uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
+
+
+ if (!want_safety) {
+ if (padding_in_bits > 0) {
+ TypeTableEntry *u8_type = get_int_type(g, false, 8);
+ TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
+ LLVMTypeRef union_element_types[] = {
+ most_aligned_union_member->type_ref,
+ padding_array->type_ref,
+ };
+ LLVMStructSetBody(union_type->type_ref, union_element_types, 2, false);
+ } else {
+ LLVMStructSetBody(union_type->type_ref, &most_aligned_union_member->type_ref, 1, false);
+ }
+ union_type->data.unionation.union_type_ref = union_type->type_ref;
+ union_type->data.unionation.gen_tag_index = SIZE_MAX;
+ union_type->data.unionation.gen_union_index = SIZE_MAX;
+
+ assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type->type_ref) >= biggest_align_in_bits);
+ assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref) >= biggest_size_in_bits);
+
+ // create debug type for union
+ ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
+ ZigLLVMFileToScope(import->di_file), buf_ptr(&union_type->name),
+ import->di_file, (unsigned)(decl_node->line + 1),
+ biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
+ gen_field_count, 0, "");
+
+ ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type);
+ union_type->di_type = replacement_di_type;
+ return;
+ }
+
+ LLVMTypeRef union_type_ref;
+ if (padding_in_bits > 0) {
+ TypeTableEntry *u8_type = get_int_type(g, false, 8);
+ TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
+ LLVMTypeRef union_element_types[] = {
+ most_aligned_union_member->type_ref,
+ padding_array->type_ref,
+ };
+ union_type_ref = LLVMStructType(union_element_types, 2, false);
+ } else {
+ union_type_ref = most_aligned_union_member->type_ref;
+ }
+ union_type->data.unionation.union_type_ref = union_type_ref;
+
+ assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);
+ assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);
+
+ // create llvm type for root struct
+ TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
+ TypeTableEntry *tag_type_entry = tag_int_type;
+ union_type->data.unionation.tag_type = tag_type_entry;
+ uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
+
+ if (align_of_tag_in_bits >= biggest_align_in_bits) {
+ union_type->data.unionation.gen_tag_index = 0;
+ union_type->data.unionation.gen_union_index = 1;
+ } else {
+ union_type->data.unionation.gen_union_index = 0;
+ union_type->data.unionation.gen_tag_index = 1;
+ }
+
+ LLVMTypeRef root_struct_element_types[2];
+ root_struct_element_types[union_type->data.unionation.gen_tag_index] = tag_type_entry->type_ref;
+ root_struct_element_types[union_type->data.unionation.gen_union_index] = union_type_ref;
+ LLVMStructSetBody(union_type->type_ref, root_struct_element_types, 2, false);
+
+
+ // create debug type for root struct
+
+ // create debug type for tag
+ uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
+ uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
+ ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
+ ZigLLVMTypeToScope(union_type->di_type), "AnonEnum",
+ import->di_file, (unsigned)(decl_node->line + 1),
+ tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
+ tag_type_entry->di_type, "");
+
+ // create debug type for union
+ ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
+ ZigLLVMTypeToScope(union_type->di_type), "AnonUnion",
+ import->di_file, (unsigned)(decl_node->line + 1),
+ biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
+ gen_field_count, 0, "");
+
+ uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->type_ref,
+ union_type->data.unionation.gen_union_index);
+ uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->type_ref,
+ union_type->data.unionation.gen_tag_index);
+
+ ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
+ ZigLLVMTypeToScope(union_type->di_type), "union_field",
+ import->di_file, (unsigned)(decl_node->line + 1),
+ biggest_size_in_bits,
+ biggest_align_in_bits,
+ union_offset_in_bits,
+ 0, union_di_type);
+ ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
+ ZigLLVMTypeToScope(union_type->di_type), "tag_field",
+ import->di_file, (unsigned)(decl_node->line + 1),
+ tag_debug_size_in_bits,
+ tag_debug_align_in_bits,
+ tag_offset_in_bits,
+ 0, tag_di_type);
+
+ ZigLLVMDIType *di_root_members[2];
+ di_root_members[union_type->data.unionation.gen_tag_index] = tag_member_di_type;
+ di_root_members[union_type->data.unionation.gen_union_index] = union_member_di_type;
+
+ uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref);
+ uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, union_type->type_ref);
+ ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
+ ZigLLVMFileToScope(import->di_file),
+ buf_ptr(&union_type->name),
+ import->di_file, (unsigned)(decl_node->line + 1),
+ debug_size_in_bits,
+ debug_align_in_bits,
+ 0, nullptr, di_root_members, 2, 0, nullptr, "");
+
+ ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type);
+ union_type->di_type = replacement_di_type;
}
static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
@@ -1873,7 +2113,7 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
type_enum_field->value = i;
type_ensure_zero_bits_known(g, field_type);
- if (field_type->id == TypeTableEntryIdInvalid) {
+ if (type_is_invalid(field_type)) {
enum_type->data.enumeration.is_invalid = true;
continue;
}
@@ -1980,7 +2220,69 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
}
static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
- zig_panic("TODO resolve_union_zero_bits");
+ assert(union_type->id == TypeTableEntryIdUnion);
+
+ if (union_type->data.unionation.zero_bits_known)
+ return;
+
+ if (union_type->data.unionation.zero_bits_loop_flag) {
+ union_type->data.unionation.zero_bits_known = true;
+ return;
+ }
+
+ union_type->data.unionation.zero_bits_loop_flag = true;
+
+ AstNode *decl_node = union_type->data.unionation.decl_node;
+ assert(decl_node->type == NodeTypeContainerDecl);
+ assert(union_type->di_type);
+
+ assert(!union_type->data.unionation.fields);
+ uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length;
+ union_type->data.unionation.src_field_count = field_count;
+ union_type->data.unionation.fields = allocate(field_count);
+
+ uint32_t biggest_align_bytes = 0;
+
+ Scope *scope = &union_type->data.unionation.decls_scope->base;
+
+ uint32_t gen_field_index = 0;
+ for (uint32_t i = 0; i < field_count; i += 1) {
+ AstNode *field_node = decl_node->data.container_decl.fields.at(i);
+ TypeUnionField *type_union_field = &union_type->data.unionation.fields[i];
+ type_union_field->name = field_node->data.struct_field.name;
+ TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
+ type_union_field->type_entry = field_type;
+ type_union_field->value = i;
+
+ type_ensure_zero_bits_known(g, field_type);
+ if (type_is_invalid(field_type)) {
+ union_type->data.unionation.is_invalid = true;
+ continue;
+ }
+
+ if (!type_has_bits(field_type))
+ continue;
+
+ type_union_field->gen_index = gen_field_index;
+ gen_field_index += 1;
+
+ uint32_t field_align_bytes = get_abi_alignment(g, field_type);
+ if (field_align_bytes > biggest_align_bytes) {
+ biggest_align_bytes = field_align_bytes;
+ }
+ }
+
+ bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
+
+ union_type->data.unionation.zero_bits_loop_flag = false;
+ union_type->data.unionation.gen_field_count = gen_field_index;
+ union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !auto_layout));
+ union_type->data.unionation.zero_bits_known = true;
+
+ // also compute abi_alignment
+ if (!union_type->zero_bits) {
+ union_type->data.unionation.abi_alignment = biggest_align_bytes;
+ }
}
static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) {
@@ -2851,6 +3153,18 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) {
return nullptr;
}
+TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {
+ assert(type_entry->id == TypeTableEntryIdUnion);
+ assert(type_entry->data.unionation.complete);
+ for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {
+ TypeUnionField *field = &type_entry->data.unionation.fields[i];
+ if (buf_eql_buf(field->name, name)) {
+ return field;
+ }
+ }
+ return nullptr;
+}
+
static bool is_container(TypeTableEntry *type_entry) {
switch (type_entry->id) {
case TypeTableEntryIdInvalid:
@@ -4703,6 +5017,8 @@ ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) {
return &value->data.x_array.s_none.parent;
} else if (type_entry->id == TypeTableEntryIdStruct) {
return &value->data.x_struct.parent;
+ } else if (type_entry->id == TypeTableEntryIdUnion) {
+ return &value->data.x_union.parent;
}
return nullptr;
}
@@ -4914,7 +5230,8 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) {
assert(type_entry->data.enumeration.abi_alignment != 0);
return type_entry->data.enumeration.abi_alignment;
} else if (type_entry->id == TypeTableEntryIdUnion) {
- zig_panic("TODO");
+ assert(type_entry->data.unionation.abi_alignment != 0);
+ return type_entry->data.unionation.abi_alignment;
} else if (type_entry->id == TypeTableEntryIdOpaque) {
return 1;
} else {
@@ -4929,3 +5246,11 @@ TypeTableEntry *get_align_amt_type(CodeGen *g) {
}
return g->align_amt_type;
}
+
+uint32_t type_ptr_hash(const TypeTableEntry *ptr) {
+ return hash_ptr((void*)ptr);
+}
+
+bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) {
+ return a == b;
+}
diff --git a/src/analyze.hpp b/src/analyze.hpp
index 4f56640592..b2464af9a0 100644
--- a/src/analyze.hpp
+++ b/src/analyze.hpp
@@ -63,6 +63,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry);
TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name);
ScopeDecls *get_container_scope(TypeTableEntry *type_entry);
TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name);
+TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name);
bool is_container_ref(TypeTableEntry *type_entry);
void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
void scan_import(CodeGen *g, ImportTableEntry *import);
diff --git a/src/c_tokenizer.cpp b/src/c_tokenizer.cpp
index 044831f72e..6be2cf991e 100644
--- a/src/c_tokenizer.cpp
+++ b/src/c_tokenizer.cpp
@@ -120,6 +120,7 @@ static void begin_token(CTokenize *ctok, CTokId id) {
case CTokIdLParen:
case CTokIdRParen:
case CTokIdEOF:
+ case CTokIdDot:
break;
}
}
@@ -216,9 +217,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) {
buf_append_char(&ctok->buf, '0');
break;
case '.':
- begin_token(ctok, CTokIdNumLitFloat);
- ctok->state = CTokStateFloat;
- buf_init_from_str(&ctok->buf, "0.");
+ begin_token(ctok, CTokIdDot);
+ end_token(ctok);
break;
case '(':
begin_token(ctok, CTokIdLParen);
@@ -238,6 +238,8 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) {
break;
case CTokStateFloat:
switch (*c) {
+ case '.':
+ break;
case 'e':
case 'E':
buf_append_char(&ctok->buf, 'e');
diff --git a/src/c_tokenizer.hpp b/src/c_tokenizer.hpp
index 8eea6c56c7..a3df2b94af 100644
--- a/src/c_tokenizer.hpp
+++ b/src/c_tokenizer.hpp
@@ -21,6 +21,7 @@ enum CTokId {
CTokIdLParen,
CTokIdRParen,
CTokIdEOF,
+ CTokIdDot,
};
enum CNumLitSuffix {
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 17c0ffc653..24d24a91e5 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -15,7 +15,7 @@
#include "ir.hpp"
#include "link.hpp"
#include "os.hpp"
-#include "parsec.hpp"
+#include "translate_c.hpp"
#include "target.hpp"
#include "zig_llvm.hpp"
@@ -810,6 +810,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
return buf_create_from_str("invalid error code");
case PanicMsgIdIncorrectAlignment:
return buf_create_from_str("incorrect alignment");
+ case PanicMsgIdBadUnionField:
+ return buf_create_from_str("access of inactive union field");
}
zig_unreachable();
}
@@ -2393,6 +2395,50 @@ static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executabl
return bitcasted_union_field_ptr;
}
+static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executable,
+ IrInstructionUnionFieldPtr *instruction)
+{
+ TypeTableEntry *union_ptr_type = instruction->union_ptr->value.type;
+ assert(union_ptr_type->id == TypeTableEntryIdPointer);
+ TypeTableEntry *union_type = union_ptr_type->data.pointer.child_type;
+ assert(union_type->id == TypeTableEntryIdUnion);
+
+ TypeUnionField *field = instruction->field;
+
+ if (!type_has_bits(field->type_entry))
+ return nullptr;
+
+ LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr);
+ LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0);
+
+ if (union_type->data.unionation.gen_tag_index == SIZE_MAX) {
+ LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, 0, "");
+ LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
+ return bitcasted_union_field_ptr;
+ }
+
+ if (ir_want_debug_safety(g, &instruction->base)) {
+ LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_tag_index, "");
+ LLVMValueRef tag_value = gen_load_untyped(g, tag_field_ptr, 0, false, "");
+ LLVMValueRef expected_tag_value = LLVMConstInt(union_type->data.unionation.tag_type->type_ref,
+ field->value, false);
+
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckOk");
+ LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckFail");
+ LLVMValueRef ok_val = LLVMBuildICmp(g->builder, LLVMIntEQ, tag_value, expected_tag_value, "");
+ LLVMBuildCondBr(g->builder, ok_val, ok_block, bad_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, bad_block);
+ gen_debug_safety_crash(g, PanicMsgIdBadUnionField);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ }
+
+ LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_union_index, "");
+ LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
+ return bitcasted_union_field_ptr;
+}
+
static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) {
const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2;
size_t len = tok->end - tok->start - 2;
@@ -3365,6 +3411,42 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,
return instruction->tmp_ptr;
}
+static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, IrInstructionUnionInit *instruction) {
+ TypeUnionField *type_union_field = instruction->field;
+
+ if (!type_has_bits(type_union_field->type_entry))
+ return nullptr;
+
+ uint32_t field_align_bytes = get_abi_alignment(g, type_union_field->type_entry);
+ TypeTableEntry *ptr_type = get_pointer_to_type_extra(g, type_union_field->type_entry,
+ false, false, field_align_bytes,
+ 0, 0);
+
+ LLVMValueRef uncasted_union_ptr;
+ // Even if safety is off in this block, if the union type has the safety field, we have to populate it
+ // correctly. Otherwise safety code somewhere other than here could fail.
+ TypeTableEntry *union_type = instruction->union_type;
+ if (union_type->data.unionation.gen_tag_index != SIZE_MAX) {
+ LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
+ union_type->data.unionation.gen_tag_index, "");
+ LLVMValueRef tag_value = LLVMConstInt(union_type->data.unionation.tag_type->type_ref,
+ type_union_field->value, false);
+ gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
+
+ uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
+ (unsigned)union_type->data.unionation.gen_union_index, "");
+ } else {
+ uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, (unsigned)0, "");
+ }
+
+ LLVMValueRef field_ptr = LLVMBuildBitCast(g->builder, uncasted_union_ptr, ptr_type->type_ref, "");
+ LLVMValueRef value = ir_llvm_value(g, instruction->init_value);
+
+ gen_assign_raw(g, field_ptr, ptr_type, value);
+
+ return instruction->tmp_ptr;
+}
+
static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable,
IrInstructionContainerInitList *instruction)
{
@@ -3486,6 +3568,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);
case IrInstructionIdEnumFieldPtr:
return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction);
+ case IrInstructionIdUnionFieldPtr:
+ return ir_render_union_field_ptr(g, executable, (IrInstructionUnionFieldPtr *)instruction);
case IrInstructionIdAsm:
return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
case IrInstructionIdTestNonNull:
@@ -3544,6 +3628,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction);
case IrInstructionIdStructInit:
return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);
+ case IrInstructionIdUnionInit:
+ return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction);
case IrInstructionIdPtrCast:
return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction);
case IrInstructionIdBitCast:
@@ -3595,6 +3681,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {
static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index);
static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index);
+static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *array_const_val);
static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) {
switch (parent->id) {
@@ -3608,6 +3695,8 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent
case ConstParentIdArray:
return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val,
parent->data.p_array.elem_index);
+ case ConstParentIdUnion:
+ return gen_const_ptr_union_recursive(g, parent->data.p_union.union_val);
}
zig_unreachable();
}
@@ -3637,6 +3726,18 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s
return LLVMConstInBoundsGEP(base_ptr, indices, 2);
}
+static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val) {
+ ConstParent *parent = &union_const_val->data.x_union.parent;
+ LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent);
+
+ TypeTableEntry *u32 = g->builtin_types.entry_u32;
+ LLVMValueRef indices[] = {
+ LLVMConstNull(u32->type_ref),
+ LLVMConstInt(u32->type_ref, 0, false),
+ };
+ return LLVMConstInBoundsGEP(base_ptr, indices, 2);
+}
+
static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) {
switch (const_val->special) {
case ConstValSpecialRuntime:
@@ -3872,10 +3973,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count);
}
}
- case TypeTableEntryIdUnion:
- {
- zig_panic("TODO");
- }
case TypeTableEntryIdArray:
{
uint64_t len = type_entry->data.array.len;
@@ -3898,6 +3995,55 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
return LLVMConstArray(element_type_ref, values, (unsigned)len);
}
}
+ case TypeTableEntryIdUnion:
+ {
+ LLVMTypeRef union_type_ref = type_entry->data.unionation.union_type_ref;
+ ConstExprValue *payload_value = const_val->data.x_union.payload;
+ assert(payload_value != nullptr);
+
+ if (!type_has_bits(payload_value->type)) {
+ return LLVMGetUndef(union_type_ref);
+ }
+
+ uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref);
+ uint64_t pad_bytes = type_entry->data.unionation.union_size_bytes - field_type_bytes;
+ LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value);
+ bool make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) ||
+ payload_value->type != type_entry->data.unionation.most_aligned_union_member;
+
+ LLVMValueRef union_value_ref;
+ {
+ if (pad_bytes == 0) {
+ union_value_ref = correctly_typed_value;
+ } else {
+ LLVMValueRef fields[2];
+ fields[0] = correctly_typed_value;
+ fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes));
+ if (make_unnamed_struct || type_entry->data.unionation.gen_tag_index != SIZE_MAX) {
+ union_value_ref = LLVMConstStruct(fields, 2, false);
+ } else {
+ union_value_ref = LLVMConstNamedStruct(union_type_ref, fields, 2);
+ }
+ }
+ }
+
+ if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) {
+ return union_value_ref;
+ }
+
+ LLVMValueRef tag_value = LLVMConstInt(type_entry->data.unionation.tag_type->type_ref, const_val->data.x_union.tag, false);
+
+ LLVMValueRef fields[2];
+ fields[type_entry->data.unionation.gen_union_index] = union_value_ref;
+ fields[type_entry->data.unionation.gen_tag_index] = tag_value;
+
+ if (make_unnamed_struct) {
+ return LLVMConstStruct(fields, 2, false);
+ } else {
+ return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
+ }
+
+ }
case TypeTableEntryIdEnum:
{
LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
@@ -4376,6 +4522,9 @@ static void do_code_gen(CodeGen *g) {
} else if (instruction->id == IrInstructionIdStructInit) {
IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction;
slot = &struct_init_instruction->tmp_ptr;
+ } else if (instruction->id == IrInstructionIdUnionInit) {
+ IrInstructionUnionInit *union_init_instruction = (IrInstructionUnionInit *)instruction;
+ slot = &union_init_instruction->tmp_ptr;
} else if (instruction->id == IrInstructionIdCall) {
IrInstructionCall *call_instruction = (IrInstructionCall *)instruction;
slot = &call_instruction->tmp_ptr;
@@ -5204,7 +5353,7 @@ static void init(CodeGen *g) {
define_builtin_compile_vars(g);
}
-void codegen_parsec(CodeGen *g, Buf *full_path) {
+void codegen_translate_c(CodeGen *g, Buf *full_path) {
find_libc_include_path(g);
Buf *src_basename = buf_alloc();
diff --git a/src/codegen.hpp b/src/codegen.hpp
index b71a7fa651..b29cadee55 100644
--- a/src/codegen.hpp
+++ b/src/codegen.hpp
@@ -56,7 +56,7 @@ PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir,
void codegen_add_assembly(CodeGen *g, Buf *path);
void codegen_add_object(CodeGen *g, Buf *object_path);
-void codegen_parsec(CodeGen *g, Buf *path);
+void codegen_translate_c(CodeGen *g, Buf *path);
#endif
diff --git a/src/ir.cpp b/src/ir.cpp
index fdaced6806..7c15b48bee 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -11,7 +11,7 @@
#include "ir.hpp"
#include "ir_print.hpp"
#include "os.hpp"
-#include "parsec.hpp"
+#include "translate_c.hpp"
#include "range_set.hpp"
#include "softfloat.hpp"
@@ -227,6 +227,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumFieldPtr *)
return IrInstructionIdEnumFieldPtr;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionFieldPtr *) {
+ return IrInstructionIdUnionFieldPtr;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionElemPtr *) {
return IrInstructionIdElemPtr;
}
@@ -351,6 +355,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) {
return IrInstructionIdStructInit;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit *) {
+ return IrInstructionIdUnionInit;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionMinValue *) {
return IrInstructionIdMinValue;
}
@@ -922,6 +930,27 @@ static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction
return new_instruction;
}
+static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *union_ptr, TypeUnionField *field)
+{
+ IrInstructionUnionFieldPtr *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->union_ptr = union_ptr;
+ instruction->field = field;
+
+ ir_ref_instruction(union_ptr, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstruction *old_instruction,
+ IrInstruction *union_ptr, TypeUnionField *type_union_field)
+{
+ IrInstruction *new_instruction = ir_build_union_field_ptr(irb, old_instruction->scope,
+ old_instruction->source_node, union_ptr, type_union_field);
+ ir_link_new_instruction(new_instruction, old_instruction);
+ return new_instruction;
+}
+
static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
bool is_comptime, bool is_inline)
@@ -1112,6 +1141,28 @@ static IrInstruction *ir_build_struct_init_from(IrBuilder *irb, IrInstruction *o
return new_instruction;
}
+static IrInstruction *ir_build_union_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ TypeTableEntry *union_type, TypeUnionField *field, IrInstruction *init_value)
+{
+ IrInstructionUnionInit *union_init_instruction = ir_build_instruction(irb, scope, source_node);
+ union_init_instruction->union_type = union_type;
+ union_init_instruction->field = field;
+ union_init_instruction->init_value = init_value;
+
+ ir_ref_instruction(init_value, irb->current_basic_block);
+
+ return &union_init_instruction->base;
+}
+
+static IrInstruction *ir_build_union_init_from(IrBuilder *irb, IrInstruction *old_instruction,
+ TypeTableEntry *union_type, TypeUnionField *field, IrInstruction *init_value)
+{
+ IrInstruction *new_instruction = ir_build_union_init(irb, old_instruction->scope,
+ old_instruction->source_node, union_type, field, init_value);
+ ir_link_new_instruction(new_instruction, old_instruction);
+ return new_instruction;
+}
+
static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) {
IrInstructionUnreachable *unreachable_instruction =
ir_build_instruction(irb, scope, source_node);
@@ -2422,6 +2473,13 @@ static IrInstruction *ir_instruction_enumfieldptr_get_dep(IrInstructionEnumField
}
}
+static IrInstruction *ir_instruction_unionfieldptr_get_dep(IrInstructionUnionFieldPtr *instruction, size_t index) {
+ switch (index) {
+ case 0: return instruction->union_ptr;
+ default: return nullptr;
+ }
+}
+
static IrInstruction *ir_instruction_elemptr_get_dep(IrInstructionElemPtr *instruction, size_t index) {
switch (index) {
case 0: return instruction->array_ptr;
@@ -2485,6 +2543,13 @@ static IrInstruction *ir_instruction_structinit_get_dep(IrInstructionStructInit
return nullptr;
}
+static IrInstruction *ir_instruction_unioninit_get_dep(IrInstructionUnionInit *instruction, size_t index) {
+ switch (index) {
+ case 0: return instruction->init_value;
+ default: return nullptr;
+ }
+}
+
static IrInstruction *ir_instruction_unreachable_get_dep(IrInstructionUnreachable *instruction, size_t index) {
return nullptr;
}
@@ -3099,6 +3164,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_structfieldptr_get_dep((IrInstructionStructFieldPtr *) instruction, index);
case IrInstructionIdEnumFieldPtr:
return ir_instruction_enumfieldptr_get_dep((IrInstructionEnumFieldPtr *) instruction, index);
+ case IrInstructionIdUnionFieldPtr:
+ return ir_instruction_unionfieldptr_get_dep((IrInstructionUnionFieldPtr *) instruction, index);
case IrInstructionIdElemPtr:
return ir_instruction_elemptr_get_dep((IrInstructionElemPtr *) instruction, index);
case IrInstructionIdVarPtr:
@@ -3117,6 +3184,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_containerinitfields_get_dep((IrInstructionContainerInitFields *) instruction, index);
case IrInstructionIdStructInit:
return ir_instruction_structinit_get_dep((IrInstructionStructInit *) instruction, index);
+ case IrInstructionIdUnionInit:
+ return ir_instruction_unioninit_get_dep((IrInstructionUnionInit *) instruction, index);
case IrInstructionIdUnreachable:
return ir_instruction_unreachable_get_dep((IrInstructionUnreachable *) instruction, index);
case IrInstructionIdTypeOf:
@@ -6233,8 +6302,9 @@ static Buf *get_anon_type_name(CodeGen *codegen, IrExecutable *exec, const char
buf_appendf(name, ")");
return name;
} else {
+ //Note: C-imports do not have valid location information
return buf_sprintf("(anonymous %s at %s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ")", kind_name,
- buf_ptr(source_node->owner->path), source_node->line + 1, source_node->column + 1);
+ (source_node->owner->path != nullptr) ? buf_ptr(source_node->owner->path) : "(null)", source_node->line + 1, source_node->column + 1);
}
}
}
@@ -6263,6 +6333,9 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope,
}
irb->codegen->resolve_queue.append(&tld_container->base);
+ // Add this to the list to mark as invalid if analyzing this exec fails.
+ irb->exec->tld_list.append(&tld_container->base);
+
return ir_build_const_type(irb, parent_scope, node, container_type);
}
@@ -6485,6 +6558,20 @@ static bool ir_goto_pass2(IrBuilder *irb) {
return true;
}
+static void invalidate_exec(IrExecutable *exec) {
+ if (exec->invalid)
+ return;
+
+ exec->invalid = true;
+
+ for (size_t i = 0; i < exec->tld_list.length; i += 1) {
+ exec->tld_list.items[i]->resolution = TldResolutionInvalid;
+ }
+
+ if (exec->source_exec != nullptr)
+ invalidate_exec(exec->source_exec);
+}
+
bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_executable) {
assert(node->owner);
@@ -6508,7 +6595,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
}
if (!ir_goto_pass2(irb)) {
- irb->exec->invalid = true;
+ invalidate_exec(ir_executable);
return false;
}
@@ -6534,7 +6621,7 @@ static void add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, ErrorMsg
}
static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) {
- exec->invalid = true;
+ invalidate_exec(exec);
ErrorMsg *err_msg = add_node_error(codegen, source_node, msg);
if (exec->parent_exec) {
add_call_stack_errors(codegen, exec, err_msg, 10);
@@ -7897,6 +7984,9 @@ static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instructio
ConstExprValue *const_val = &const_instr->value;
const_val->type = pointee_type;
type_ensure_zero_bits_known(ira->codegen, type_entry);
+ if (type_is_invalid(type_entry)) {
+ return ira->codegen->invalid_instruction;
+ }
const_val->data.x_type = get_pointer_to_type_extra(ira->codegen, type_entry,
ptr_is_const, ptr_is_volatile, get_abi_alignment(ira->codegen, type_entry), 0, 0);
return const_instr;
@@ -7984,6 +8074,7 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node
IrExecutable analyzed_executable = {0};
analyzed_executable.source_node = source_node;
analyzed_executable.parent_exec = parent_exec;
+ analyzed_executable.source_exec = &ir_executable;
analyzed_executable.name = exec_name;
analyzed_executable.is_inline = true;
analyzed_executable.fn_entry = fn_entry;
@@ -10279,30 +10370,40 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
bool is_const = (var->value->type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const;
bool is_volatile = (var->value->type->id == TypeTableEntryIdMetaType) ? is_volatile_ptr : false;
- if (mem_slot && mem_slot->special != ConstValSpecialRuntime) {
- ConstPtrMut ptr_mut;
- if (comptime_var_mem) {
- ptr_mut = ConstPtrMutComptimeVar;
- } else if (var->gen_is_const) {
- ptr_mut = ConstPtrMutComptimeConst;
- } else {
- assert(!comptime_var_mem);
- ptr_mut = ConstPtrMutRuntimeVar;
+ if (mem_slot != nullptr) {
+ switch (mem_slot->special) {
+ case ConstValSpecialRuntime:
+ goto no_mem_slot;
+ case ConstValSpecialStatic: // fallthrough
+ case ConstValSpecialUndef: {
+ ConstPtrMut ptr_mut;
+ if (comptime_var_mem) {
+ ptr_mut = ConstPtrMutComptimeVar;
+ } else if (var->gen_is_const) {
+ ptr_mut = ConstPtrMutComptimeConst;
+ } else {
+ assert(!comptime_var_mem);
+ ptr_mut = ConstPtrMutRuntimeVar;
+ }
+ return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type,
+ ptr_mut, is_const, is_volatile, var->align_bytes);
+ }
}
- return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type,
- ptr_mut, is_const, is_volatile, var->align_bytes);
- } else {
- IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb,
- instruction->scope, instruction->source_node, var, is_const, is_volatile);
- var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type,
- var->src_is_const, is_volatile, var->align_bytes, 0, 0);
- type_ensure_zero_bits_known(ira->codegen, var->value->type);
-
- bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr);
- var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack;
-
- return var_ptr_instruction;
+ zig_unreachable();
}
+
+no_mem_slot:
+
+ IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb,
+ instruction->scope, instruction->source_node, var, is_const, is_volatile);
+ var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type,
+ var->src_is_const, is_volatile, var->align_bytes, 0, 0);
+ type_ensure_zero_bits_known(ira->codegen, var->value->type);
+
+ bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr);
+ var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack;
+
+ return var_ptr_instruction;
}
static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
@@ -10408,10 +10509,11 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type,
ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry,
nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec);
- if (type_is_invalid(result->value.type))
- return ira->codegen->builtin_types.entry_invalid;
ira->codegen->memoized_fn_eval_table.put(exec_scope, result);
+
+ if (type_is_invalid(result->value.type))
+ return ira->codegen->builtin_types.entry_invalid;
}
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,
return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value, true, false);
}
}
+ const char *prefix_name;
+ if (is_slice(bare_struct_type)) {
+ prefix_name = "";
+ } else if (bare_struct_type->id == TypeTableEntryIdStruct) {
+ prefix_name = "struct ";
+ } else if (bare_struct_type->id == TypeTableEntryIdEnum) {
+ prefix_name = "enum ";
+ } else if (bare_struct_type->id == TypeTableEntryIdUnion) {
+ prefix_name = "union ";
+ } else {
+ prefix_name = "";
+ }
ir_add_error_node(ira, field_ptr_instruction->base.source_node,
- buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&bare_struct_type->name)));
+ buf_sprintf("no member named '%s' in %s'%s'", buf_ptr(field_name), prefix_name, buf_ptr(&bare_struct_type->name)));
return ira->codegen->builtin_types.entry_invalid;
}
@@ -11428,14 +11542,13 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
{
TypeTableEntry *bare_type = container_ref_type(container_type);
ensure_complete_type(ira->codegen, bare_type);
+ if (type_is_invalid(bare_type))
+ return ira->codegen->builtin_types.entry_invalid;
assert(container_ptr->value.type->id == TypeTableEntryIdPointer);
bool is_const = container_ptr->value.type->data.pointer.is_const;
bool is_volatile = container_ptr->value.type->data.pointer.is_volatile;
if (bare_type->id == TypeTableEntryIdStruct) {
- if (bare_type->data.structure.is_invalid)
- return ira->codegen->builtin_types.entry_invalid;
-
TypeStructField *field = find_struct_type_field(bare_type, field_name);
if (field) {
bool is_packed = (bare_type->data.structure.layout == ContainerLayoutPacked);
@@ -11476,9 +11589,6 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
field_ptr_instruction, container_ptr, container_type);
}
} else if (bare_type->id == TypeTableEntryIdEnum) {
- if (bare_type->data.enumeration.is_invalid)
- return ira->codegen->builtin_types.entry_invalid;
-
TypeEnumField *field = find_enum_type_field(bare_type, field_name);
if (field) {
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
field_ptr_instruction, container_ptr, container_type);
}
} else if (bare_type->id == TypeTableEntryIdUnion) {
- zig_panic("TODO");
+ TypeUnionField *field = find_union_type_field(bare_type, field_name);
+ if (field) {
+ ir_build_union_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
+ return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
+ get_abi_alignment(ira->codegen, field->type_entry), 0, 0);
+ } else {
+ return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
+ field_ptr_instruction, container_ptr, container_type);
+ }
} else {
zig_unreachable();
}
@@ -13033,9 +13151,71 @@ static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionR
return ir_analyze_ref(ira, &ref_instruction->base, value, ref_instruction->is_const, ref_instruction->is_volatile);
}
+static TypeTableEntry *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruction *instruction,
+ TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields)
+{
+ assert(container_type->id == TypeTableEntryIdUnion);
+
+ ensure_complete_type(ira->codegen, container_type);
+
+ if (instr_field_count != 1) {
+ ir_add_error(ira, instruction,
+ buf_sprintf("union initialization expects exactly one field"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ IrInstructionContainerInitFieldsField *field = &fields[0];
+ IrInstruction *field_value = field->value->other;
+ if (type_is_invalid(field_value->value.type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ TypeUnionField *type_field = find_union_type_field(container_type, field->name);
+ if (!type_field) {
+ ir_add_error_node(ira, field->source_node,
+ buf_sprintf("no member named '%s' in union '%s'",
+ buf_ptr(field->name), buf_ptr(&container_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ if (type_is_invalid(type_field->type_entry))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ IrInstruction *casted_field_value = ir_implicit_cast(ira, field_value, type_field->type_entry);
+ if (casted_field_value == ira->codegen->invalid_instruction)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope);
+ if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime) {
+ ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk);
+ if (!field_val)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ ConstExprValue *out_val = ir_build_const_from(ira, instruction);
+ out_val->data.x_union.payload = field_val;
+ out_val->data.x_union.tag = type_field->value;
+
+ ConstParent *parent = get_const_val_parent(ira->codegen, field_val);
+ if (parent != nullptr) {
+ parent->id = ConstParentIdUnion;
+ parent->data.p_union.union_val = out_val;
+ }
+
+ return container_type;
+ }
+
+ IrInstruction *new_instruction = ir_build_union_init_from(&ira->new_irb, instruction,
+ container_type, type_field, casted_field_value);
+
+ ir_add_alloca(ira, new_instruction, container_type);
+ return container_type;
+}
+
static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction,
TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields)
{
+ if (container_type->id == TypeTableEntryIdUnion) {
+ return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count, fields);
+ }
if (container_type->id != TypeTableEntryIdStruct || is_slice(container_type)) {
ir_add_error(ira, instruction,
buf_sprintf("type '%s' does not support struct initialization syntax",
@@ -13043,8 +13223,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
return ira->codegen->builtin_types.entry_invalid;
}
- if (!type_is_complete(container_type))
- resolve_container_type(ira->codegen, container_type);
+ ensure_complete_type(ira->codegen, container_type);
size_t actual_field_count = container_type->data.structure.src_field_count;
@@ -13070,7 +13249,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru
TypeStructField *type_field = find_struct_type_field(container_type, field->name);
if (!type_field) {
ir_add_error_node(ira, field->source_node,
- buf_sprintf("no member named '%s' in '%s'",
+ buf_sprintf("no member named '%s' in struct '%s'",
buf_ptr(field->name), buf_ptr(&container_type->name)));
return ira->codegen->builtin_types.entry_invalid;
}
@@ -15657,8 +15836,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
case IrInstructionIdIntToErr:
case IrInstructionIdErrToInt:
case IrInstructionIdStructInit:
+ case IrInstructionIdUnionInit:
case IrInstructionIdStructFieldPtr:
case IrInstructionIdEnumFieldPtr:
+ case IrInstructionIdUnionFieldPtr:
case IrInstructionIdInitEnum:
case IrInstructionIdMaybeWrap:
case IrInstructionIdErrWrapCode:
@@ -15968,6 +16149,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdContainerInitList:
case IrInstructionIdContainerInitFields:
case IrInstructionIdStructInit:
+ case IrInstructionIdUnionInit:
case IrInstructionIdFieldPtr:
case IrInstructionIdElemPtr:
case IrInstructionIdVarPtr:
@@ -15977,6 +16159,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdArrayLen:
case IrInstructionIdStructFieldPtr:
case IrInstructionIdEnumFieldPtr:
+ case IrInstructionIdUnionFieldPtr:
case IrInstructionIdArrayType:
case IrInstructionIdSliceType:
case IrInstructionIdSizeOf:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 1c60d68628..55ad3ceb6c 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -290,6 +290,15 @@ static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruct
fprintf(irp->f, "} // struct init");
}
+static void ir_print_union_init(IrPrint *irp, IrInstructionUnionInit *instruction) {
+ Buf *field_name = instruction->field->name;
+
+ fprintf(irp->f, "%s {", buf_ptr(&instruction->union_type->name));
+ fprintf(irp->f, ".%s = ", buf_ptr(field_name));
+ ir_print_other_instruction(irp, instruction->init_value);
+ fprintf(irp->f, "} // union init");
+}
+
static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) {
fprintf(irp->f, "unreachable");
}
@@ -359,6 +368,13 @@ static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *ins
fprintf(irp->f, ")");
}
+static void ir_print_union_field_ptr(IrPrint *irp, IrInstructionUnionFieldPtr *instruction) {
+ fprintf(irp->f, "@UnionFieldPtr(&");
+ ir_print_other_instruction(irp, instruction->union_ptr);
+ fprintf(irp->f, ".%s", buf_ptr(instruction->field->name));
+ fprintf(irp->f, ")");
+}
+
static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety *instruction) {
fprintf(irp->f, "@setDebugSafety(");
ir_print_other_instruction(irp, instruction->scope_value);
@@ -1023,6 +1039,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdStructInit:
ir_print_struct_init(irp, (IrInstructionStructInit *)instruction);
break;
+ case IrInstructionIdUnionInit:
+ ir_print_union_init(irp, (IrInstructionUnionInit *)instruction);
+ break;
case IrInstructionIdUnreachable:
ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction);
break;
@@ -1056,6 +1075,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdEnumFieldPtr:
ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction);
break;
+ case IrInstructionIdUnionFieldPtr:
+ ir_print_union_field_ptr(irp, (IrInstructionUnionFieldPtr *)instruction);
+ break;
case IrInstructionIdSetDebugSafety:
ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction);
break;
diff --git a/src/main.cpp b/src/main.cpp
index 13da71f9e8..60d2750bde 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -23,7 +23,7 @@ static int usage(const char *arg0) {
" build-exe [source] create executable from source or object files\n"
" build-lib [source] create library from source or object files\n"
" build-obj [source] create object from source or assembly\n"
- " parsec [source] convert c code to zig code\n"
+ " translate-c [source] convert c code to zig code\n"
" targets list available compilation targets\n"
" test [source] create and run a test build\n"
" version print version number and exit\n"
@@ -229,7 +229,7 @@ enum Cmd {
CmdTest,
CmdVersion,
CmdZen,
- CmdParseC,
+ CmdTranslateC,
CmdTargets,
};
@@ -632,8 +632,8 @@ int main(int argc, char **argv) {
cmd = CmdVersion;
} else if (strcmp(arg, "zen") == 0) {
cmd = CmdZen;
- } else if (strcmp(arg, "parsec") == 0) {
- cmd = CmdParseC;
+ } else if (strcmp(arg, "translate-c") == 0) {
+ cmd = CmdTranslateC;
} else if (strcmp(arg, "test") == 0) {
cmd = CmdTest;
out_type = OutTypeExe;
@@ -646,7 +646,7 @@ int main(int argc, char **argv) {
} else {
switch (cmd) {
case CmdBuild:
- case CmdParseC:
+ case CmdTranslateC:
case CmdTest:
if (!in_file) {
in_file = arg;
@@ -703,13 +703,13 @@ int main(int argc, char **argv) {
switch (cmd) {
case CmdBuild:
- case CmdParseC:
+ case CmdTranslateC:
case CmdTest:
{
if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {
fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n");
return usage(arg0);
- } else if ((cmd == CmdParseC || cmd == CmdTest) && !in_file) {
+ } else if ((cmd == CmdTranslateC || cmd == CmdTest) && !in_file) {
fprintf(stderr, "Expected source file argument.\n");
return usage(arg0);
} else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {
@@ -719,7 +719,7 @@ int main(int argc, char **argv) {
assert(cmd != CmdBuild || out_type != OutTypeUnknown);
- bool need_name = (cmd == CmdBuild || cmd == CmdParseC);
+ bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC);
Buf *in_file_buf = nullptr;
@@ -742,7 +742,7 @@ int main(int argc, char **argv) {
return usage(arg0);
}
- Buf *zig_root_source_file = (cmd == CmdParseC) ? nullptr : in_file_buf;
+ Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf;
Buf *full_cache_dir = buf_alloc();
os_path_resolve(buf_create_from_str("."),
@@ -841,8 +841,8 @@ int main(int argc, char **argv) {
if (timing_info)
codegen_print_timing_report(g, stdout);
return EXIT_SUCCESS;
- } else if (cmd == CmdParseC) {
- codegen_parsec(g, in_file_buf);
+ } else if (cmd == CmdTranslateC) {
+ codegen_translate_c(g, in_file_buf);
ast_render(g, stdout, g->root_import->root, 4);
if (timing_info)
codegen_print_timing_report(g, stdout);
diff --git a/src/parsec.cpp b/src/translate_c.cpp
similarity index 67%
rename from src/parsec.cpp
rename to src/translate_c.cpp
index 8053527eb7..dbf9613308 100644
--- a/src/parsec.cpp
+++ b/src/translate_c.cpp
@@ -11,7 +11,7 @@
#include "error.hpp"
#include "ir.hpp"
#include "os.hpp"
-#include "parsec.hpp"
+#include "translate_c.hpp"
#include "parser.hpp"
@@ -23,16 +23,52 @@
using namespace clang;
-struct MacroSymbol {
- Buf *name;
- Buf *value;
-};
-
struct Alias {
Buf *new_name;
Buf *canon_name;
};
+enum TransScopeId {
+ TransScopeIdSwitch,
+ TransScopeIdVar,
+ TransScopeIdBlock,
+ TransScopeIdRoot,
+ TransScopeIdWhile,
+};
+
+struct TransScope {
+ TransScopeId id;
+ TransScope *parent;
+};
+
+struct TransScopeSwitch {
+ TransScope base;
+ AstNode *switch_node;
+ uint32_t case_index;
+ bool found_default;
+ Buf *end_label_name;
+};
+
+struct TransScopeVar {
+ TransScope base;
+ Buf *c_name;
+ Buf *zig_name;
+};
+
+struct TransScopeBlock {
+ TransScope base;
+ AstNode *node;
+};
+
+struct TransScopeRoot {
+ TransScope base;
+};
+
+struct TransScopeWhile {
+ TransScope base;
+ AstNode *node;
+};
+
struct Context {
ImportTableEntry *import;
ZigList *errors;
@@ -44,20 +80,47 @@ struct Context {
HashMap global_table;
SourceManager *source_manager;
ZigList aliases;
- ZigList macro_symbols;
AstNode *source_node;
bool warnings_on;
CodeGen *codegen;
ASTContext *ctx;
+ TransScopeRoot *global_scope;
HashMap ptr_params;
};
+enum ResultUsed {
+ ResultUsedNo,
+ ResultUsedYes,
+};
+
+enum TransLRValue {
+ TransLValue,
+ TransRValue,
+};
+
+static TransScopeRoot *trans_scope_root_create(Context *c);
+static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope);
+static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope);
+static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name);
+static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope);
+
+static TransScopeBlock *trans_scope_block_find(TransScope *scope);
+static TransScopeSwitch *trans_scope_switch_find(TransScope *scope);
+
static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl);
static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl);
static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl);
+static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,
+ ResultUsed result_used, TransLRValue lrval,
+ AstNode **out_node, TransScope **out_child_scope,
+ TransScope **out_node_scope);
+static TransScope *trans_stmt(Context *c, TransScope *scope, const Stmt *stmt, AstNode **out_node);
+static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, TransLRValue lrval);
+static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc);
+
ATTRIBUTE_PRINTF(3, 4)
static void emit_warning(Context *c, const SourceLocation &sl, const char *format, ...) {
@@ -70,7 +133,7 @@ static void emit_warning(Context *c, const SourceLocation &sl, const char *forma
Buf *msg = buf_vprintf(format, ap);
va_end(ap);
- StringRef filename = c->source_manager->getFilename(sl);
+ StringRef filename = c->source_manager->getFilename(c->source_manager->getSpellingLoc(sl));
const char *filename_bytes = (const char *)filename.bytes_begin();
Buf *path;
if (filename_bytes) {
@@ -89,6 +152,19 @@ static void add_global_weak_alias(Context *c, Buf *new_name, Buf *canon_name) {
alias->canon_name = canon_name;
}
+static Buf *trans_lookup_zig_symbol(Context *c, TransScope *scope, Buf *c_symbol_name) {
+ while (scope != nullptr) {
+ if (scope->id == TransScopeIdVar) {
+ TransScopeVar *var_scope = (TransScopeVar *)scope;
+ if (buf_eql_buf(var_scope->c_name, c_symbol_name)) {
+ return var_scope->zig_name;
+ }
+ }
+ scope = scope->parent;
+ }
+ return c_symbol_name;
+}
+
static AstNode * trans_create_node(Context *c, NodeType id) {
AstNode *node = allocate(1);
node->type = id;
@@ -165,8 +241,8 @@ static AstNode *trans_create_node_bin_op(Context *c, AstNode *lhs_node, BinOpTyp
return node;
}
-static AstNode *maybe_suppress_result(Context *c, bool result_used, AstNode *node) {
- if (result_used) return node;
+static AstNode *maybe_suppress_result(Context *c, ResultUsed result_used, AstNode *node) {
+ if (result_used == ResultUsedYes) return node;
return trans_create_node_bin_op(c,
trans_create_node_symbol_str(c, "_"),
BinOpTypeAssign,
@@ -181,6 +257,24 @@ static AstNode *trans_create_node_addr_of(Context *c, bool is_const, bool is_vol
return node;
}
+static AstNode *trans_create_node_goto(Context *c, Buf *label_name) {
+ AstNode *goto_node = trans_create_node(c, NodeTypeGoto);
+ goto_node->data.goto_expr.name = label_name;
+ return goto_node;
+}
+
+static AstNode *trans_create_node_label(Context *c, Buf *label_name) {
+ AstNode *label_node = trans_create_node(c, NodeTypeLabel);
+ label_node->data.label.name = label_name;
+ return label_node;
+}
+
+static AstNode *trans_create_node_bool(Context *c, bool value) {
+ AstNode *bool_node = trans_create_node(c, NodeTypeBoolLiteral);
+ bool_node->data.bool_literal.value = value;
+ return bool_node;
+}
+
static AstNode *trans_create_node_str_lit_c(Context *c, Buf *buf) {
AstNode *node = trans_create_node(c, NodeTypeStringLiteral);
node->data.string_literal.buf = buf;
@@ -252,8 +346,7 @@ static AstNode *trans_create_node_var_decl_local(Context *c, bool is_const, Buf
return trans_create_node_var_decl(c, VisibModPrivate, is_const, var_name, type_node, init_node);
}
-
-static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_name, AstNode *src_proto_node) {
+static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *ref_node, AstNode *src_proto_node) {
AstNode *fn_def = trans_create_node(c, NodeTypeFnDef);
AstNode *fn_proto = trans_create_node(c, NodeTypeFnProto);
fn_proto->data.fn_proto.visib_mod = c->visib_mod;
@@ -264,7 +357,7 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_n
fn_def->data.fn_def.fn_proto = fn_proto;
fn_proto->data.fn_proto.fn_def_node = fn_def;
- AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, trans_create_node_symbol(c, var_name));
+ AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, ref_node);
AstNode *fn_call_node = trans_create_node(c, NodeTypeFnCallExpr);
fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node;
@@ -308,6 +401,9 @@ static AstNode *get_global(Context *c, Buf *name) {
if (entry)
return entry->value;
}
+ if (c->codegen->primitive_type_table.maybe_get(name) != nullptr) {
+ return trans_create_node_symbol(c, name);
+ }
return nullptr;
}
@@ -324,6 +420,10 @@ static AstNode *add_global_var(Context *c, Buf *var_name, AstNode *value_node) {
return node;
}
+static Buf *string_ref_to_buf(StringRef string_ref) {
+ return buf_create_from_mem((const char *)string_ref.bytes_begin(), string_ref.size());
+}
+
static const char *decl_name(const Decl *decl) {
const NamedDecl *named_decl = static_cast(decl);
return (const char *)named_decl->getName().bytes_begin();
@@ -337,32 +437,70 @@ static AstNode *trans_create_node_apint(Context *c, const llvm::APSInt &aps_int)
}
-static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc);
+static const Type *qual_type_canon(QualType qt) {
+ return qt.getCanonicalType().getTypePtr();
+}
+
+static QualType get_expr_qual_type(Context *c, const Expr *expr) {
+ // String literals in C are `char *` but they should really be `const char *`.
+ if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) {
+ const ImplicitCastExpr *cast_expr = static_cast(expr);
+ if (cast_expr->getCastKind() == CK_ArrayToPointerDecay) {
+ const Expr *sub_expr = cast_expr->getSubExpr();
+ if (sub_expr->getStmtClass() == Stmt::StringLiteralClass) {
+ QualType array_qt = sub_expr->getType();
+ const ArrayType *array_type = static_cast(array_qt.getTypePtr());
+ QualType pointee_qt = array_type->getElementType();
+ pointee_qt.addConst();
+ return c->ctx->getPointerType(pointee_qt);
+ }
+ }
+ }
+ return expr->getType();
+}
+
+static AstNode *get_expr_type(Context *c, const Expr *expr) {
+ return trans_qual_type(c, get_expr_qual_type(c, expr), expr->getLocStart());
+}
+
+static bool qual_types_equal(QualType t1, QualType t2) {
+ if (t1.isConstQualified() != t2.isConstQualified()) {
+ return false;
+ }
+ if (t1.isVolatileQualified() != t2.isVolatileQualified()) {
+ return false;
+ }
+ if (t1.isRestrictQualified() != t2.isRestrictQualified()) {
+ return false;
+ }
+ return t1.getTypePtr() == t2.getTypePtr();
+}
static bool is_c_void_type(AstNode *node) {
return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void"));
}
-static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location, const QualType &qt, AstNode *expr) {
- // TODO: maybe widen to increase size
- // TODO: maybe bitcast to change sign
- // TODO: maybe truncate to reduce size
- return trans_create_node_fn_call_1(c, trans_qual_type(c, qt, source_location), expr);
+static bool expr_types_equal(Context *c, const Expr *expr1, const Expr *expr2) {
+ QualType t1 = get_expr_qual_type(c, expr1);
+ QualType t2 = get_expr_qual_type(c, expr2);
+
+ return qual_types_equal(t1, t2);
}
-static bool qual_type_is_fn_ptr(Context *c, const QualType &qt) {
- const Type *ty = qt.getTypePtr();
+static bool qual_type_is_ptr(QualType qt) {
+ const Type *ty = qual_type_canon(qt);
+ return ty->getTypeClass() == Type::Pointer;
+}
+
+static bool qual_type_is_fn_ptr(Context *c, QualType qt) {
+ const Type *ty = qual_type_canon(qt);
if (ty->getTypeClass() != Type::Pointer) {
return false;
}
const PointerType *pointer_ty = static_cast(ty);
QualType child_qt = pointer_ty->getPointeeType();
const Type *child_ty = child_qt.getTypePtr();
- if (child_ty->getTypeClass() != Type::Paren) {
- return false;
- }
- const ParenType *paren_ty = static_cast(child_ty);
- return paren_ty->getInnerType().getTypePtr()->getTypeClass() == Type::FunctionProto;
+ return child_ty->getTypeClass() == Type::FunctionProto;
}
static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const SourceLocation &source_loc) {
@@ -455,17 +593,26 @@ static bool qual_type_child_is_fn_proto(const QualType &qt) {
return false;
}
-static QualType resolve_any_typedef(Context *c, QualType qt) {
- const Type * ty = qt.getTypePtr();
- if (ty->getTypeClass() != Type::Typedef)
- return qt;
- const TypedefType *typedef_ty = static_cast(ty);
- const TypedefNameDecl *typedef_decl = typedef_ty->getDecl();
- return typedef_decl->getUnderlyingType();
+static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location, QualType dest_type,
+ QualType src_type, AstNode *expr)
+{
+ if (qual_types_equal(dest_type, src_type)) {
+ return expr;
+ }
+ if (qual_type_is_ptr(dest_type) && qual_type_is_ptr(src_type)) {
+ AstNode *ptr_cast_node = trans_create_node_builtin_fn_call_str(c, "ptrCast");
+ ptr_cast_node->data.fn_call_expr.params.append(trans_qual_type(c, dest_type, source_location));
+ ptr_cast_node->data.fn_call_expr.params.append(expr);
+ return ptr_cast_node;
+ }
+ // TODO: maybe widen to increase size
+ // TODO: maybe bitcast to change sign
+ // TODO: maybe truncate to reduce size
+ return trans_create_node_fn_call_1(c, trans_qual_type(c, dest_type, source_location), expr);
}
static bool c_is_signed_integer(Context *c, QualType qt) {
- const Type *c_type = resolve_any_typedef(c, qt).getTypePtr();
+ const Type *c_type = qual_type_canon(qt);
if (c_type->getTypeClass() != Type::Builtin)
return false;
const BuiltinType *builtin_ty = static_cast(c_type);
@@ -484,7 +631,7 @@ static bool c_is_signed_integer(Context *c, QualType qt) {
}
static bool c_is_unsigned_integer(Context *c, QualType qt) {
- const Type *c_type = resolve_any_typedef(c, qt).getTypePtr();
+ const Type *c_type = qual_type_canon(qt);
if (c_type->getTypeClass() != Type::Builtin)
return false;
const BuiltinType *builtin_ty = static_cast(c_type);
@@ -531,18 +678,6 @@ static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) {
}
}
-enum TransLRValue {
- TransLValue,
- TransRValue,
-};
-
-static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrval);
-static AstNode *const skip_add_to_block_node = (AstNode *) 0x2;
-
-static AstNode *trans_expr(Context *c, bool result_used, AstNode *block, Expr *expr, TransLRValue lrval) {
- return trans_stmt(c, result_used, block, expr, lrval);
-}
-
static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) {
switch (ty->getTypeClass()) {
case Type::Builtin:
@@ -682,11 +817,10 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
const ElaboratedType *elaborated_ty = static_cast(ty);
switch (elaborated_ty->getKeyword()) {
case ETK_Struct:
- return trans_qual_type(c, elaborated_ty->getNamedType(), source_loc);
case ETK_Enum:
+ case ETK_Union:
return trans_qual_type(c, elaborated_ty->getNamedType(), source_loc);
case ETK_Interface:
- case ETK_Union:
case ETK_Class:
case ETK_Typename:
case ETK_None:
@@ -767,6 +901,11 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
return nullptr;
}
// convert c_void to actual void (only for return type)
+ // we do want to look at the AstNode instead of QualType, because
+ // if they do something like:
+ // typedef Foo void;
+ // void foo(void) -> Foo;
+ // we want to keep the return type AST node.
if (is_c_void_type(proto_node->data.fn_proto.return_type)) {
proto_node->data.fn_proto.return_type = nullptr;
}
@@ -884,33 +1023,47 @@ static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &s
return trans_type(c, qt.getTypePtr(), source_loc);
}
-static AstNode *trans_compound_stmt(Context *c, AstNode *parent, CompoundStmt *stmt) {
- AstNode *child_block = trans_create_node(c, NodeTypeBlock);
- for (CompoundStmt::body_iterator it = stmt->body_begin(), end_it = stmt->body_end(); it != end_it; ++it) {
- AstNode *child_node = trans_stmt(c, false, child_block, *it, TransRValue);
- if (child_node == nullptr)
- return nullptr;
- if (child_node != skip_add_to_block_node)
- child_block->data.block.statements.append(child_node);
+static int trans_compound_stmt_inline(Context *c, TransScope *scope, const CompoundStmt *stmt,
+ AstNode *block_node, TransScope **out_node_scope)
+{
+ assert(block_node->type == NodeTypeBlock);
+ for (CompoundStmt::const_body_iterator it = stmt->body_begin(), end_it = stmt->body_end(); it != end_it; ++it) {
+ AstNode *child_node;
+ scope = trans_stmt(c, scope, *it, &child_node);
+ if (scope == nullptr)
+ return ErrorUnexpected;
+ if (child_node != nullptr)
+ block_node->data.block.statements.append(child_node);
}
- return child_block;
+ if (out_node_scope != nullptr) {
+ *out_node_scope = scope;
+ }
+ return ErrorNone;
}
-static AstNode *trans_return_stmt(Context *c, AstNode *block, ReturnStmt *stmt) {
- Expr *value_expr = stmt->getRetValue();
- if (value_expr == nullptr) {
- emit_warning(c, stmt->getLocStart(), "TODO handle C return void");
+static AstNode *trans_compound_stmt(Context *c, TransScope *scope, const CompoundStmt *stmt,
+ TransScope **out_node_scope)
+{
+ TransScopeBlock *child_scope_block = trans_scope_block_create(c, scope);
+ if (trans_compound_stmt_inline(c, &child_scope_block->base, stmt, child_scope_block->node, out_node_scope))
return nullptr;
+ return child_scope_block->node;
+}
+
+static AstNode *trans_return_stmt(Context *c, TransScope *scope, const ReturnStmt *stmt) {
+ const Expr *value_expr = stmt->getRetValue();
+ if (value_expr == nullptr) {
+ return trans_create_node(c, NodeTypeReturnExpr);
} else {
AstNode *return_node = trans_create_node(c, NodeTypeReturnExpr);
- return_node->data.return_expr.expr = trans_expr(c, true, block, value_expr, TransRValue);
+ return_node->data.return_expr.expr = trans_expr(c, ResultUsedYes, scope, value_expr, TransRValue);
if (return_node->data.return_expr.expr == nullptr)
return nullptr;
return return_node;
}
}
-static AstNode *trans_integer_literal(Context *c, IntegerLiteral *stmt) {
+static AstNode *trans_integer_literal(Context *c, const IntegerLiteral *stmt) {
llvm::APSInt result;
if (!stmt->EvaluateAsInt(result, *c->ctx)) {
emit_warning(c, stmt->getLocStart(), "invalid integer literal");
@@ -919,54 +1072,56 @@ static AstNode *trans_integer_literal(Context *c, IntegerLiteral *stmt) {
return trans_create_node_apint(c, result);
}
-static AstNode *trans_conditional_operator(Context *c, bool result_used, AstNode *block, ConditionalOperator *stmt) {
+static AstNode *trans_conditional_operator(Context *c, ResultUsed result_used, TransScope *scope,
+ const ConditionalOperator *stmt)
+{
AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr);
Expr *cond_expr = stmt->getCond();
Expr *true_expr = stmt->getTrueExpr();
Expr *false_expr = stmt->getFalseExpr();
- node->data.if_bool_expr.condition = trans_expr(c, true, block, cond_expr, TransRValue);
+ node->data.if_bool_expr.condition = trans_expr(c, ResultUsedYes, scope, cond_expr, TransRValue);
if (node->data.if_bool_expr.condition == nullptr)
return nullptr;
- node->data.if_bool_expr.then_block = trans_expr(c, result_used, block, true_expr, TransRValue);
+ node->data.if_bool_expr.then_block = trans_expr(c, result_used, scope, true_expr, TransRValue);
if (node->data.if_bool_expr.then_block == nullptr)
return nullptr;
- node->data.if_bool_expr.else_node = trans_expr(c, result_used, block, false_expr, TransRValue);
+ node->data.if_bool_expr.else_node = trans_expr(c, result_used, scope, false_expr, TransRValue);
if (node->data.if_bool_expr.else_node == nullptr)
return nullptr;
return maybe_suppress_result(c, result_used, node);
}
-static AstNode *trans_create_bin_op(Context *c, AstNode *block, Expr *lhs, BinOpType bin_op, Expr *rhs) {
+static AstNode *trans_create_bin_op(Context *c, TransScope *scope, Expr *lhs, BinOpType bin_op, Expr *rhs) {
AstNode *node = trans_create_node(c, NodeTypeBinOpExpr);
node->data.bin_op_expr.bin_op = bin_op;
- node->data.bin_op_expr.op1 = trans_expr(c, true, block, lhs, TransRValue);
+ node->data.bin_op_expr.op1 = trans_expr(c, ResultUsedYes, scope, lhs, TransRValue);
if (node->data.bin_op_expr.op1 == nullptr)
return nullptr;
- node->data.bin_op_expr.op2 = trans_expr(c, true, block, rhs, TransRValue);
+ node->data.bin_op_expr.op2 = trans_expr(c, ResultUsedYes, scope, rhs, TransRValue);
if (node->data.bin_op_expr.op2 == nullptr)
return nullptr;
return node;
}
-static AstNode *trans_create_assign(Context *c, bool result_used, AstNode *block, Expr *lhs, Expr *rhs) {
- if (!result_used) {
+static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransScope *scope, Expr *lhs, Expr *rhs) {
+ if (result_used == ResultUsedNo) {
// common case
AstNode *node = trans_create_node(c, NodeTypeBinOpExpr);
node->data.bin_op_expr.bin_op = BinOpTypeAssign;
- node->data.bin_op_expr.op1 = trans_expr(c, true, block, lhs, TransLValue);
+ node->data.bin_op_expr.op1 = trans_expr(c, ResultUsedYes, scope, lhs, TransLValue);
if (node->data.bin_op_expr.op1 == nullptr)
return nullptr;
- node->data.bin_op_expr.op2 = trans_expr(c, true, block, rhs, TransRValue);
+ node->data.bin_op_expr.op2 = trans_expr(c, ResultUsedYes, scope, rhs, TransRValue);
if (node->data.bin_op_expr.op2 == nullptr)
return nullptr;
@@ -980,47 +1135,49 @@ static AstNode *trans_create_assign(Context *c, bool result_used, AstNode *block
// zig: _tmp
// zig: }
- AstNode *child_block = trans_create_node(c, NodeTypeBlock);
+ TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
// const _tmp = rhs;
- AstNode *rhs_node = trans_expr(c, true, child_block, rhs, TransRValue);
+ AstNode *rhs_node = trans_expr(c, ResultUsedYes, &child_scope->base, rhs, TransRValue);
if (rhs_node == nullptr) return nullptr;
// TODO: avoid name collisions with generated variable names
Buf* tmp_var_name = buf_create_from_str("_tmp");
AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, rhs_node);
- child_block->data.block.statements.append(tmp_var_decl);
+ child_scope->node->data.block.statements.append(tmp_var_decl);
// lhs = _tmp;
- AstNode *lhs_node = trans_expr(c, true, child_block, lhs, TransLValue);
+ AstNode *lhs_node = trans_expr(c, ResultUsedYes, &child_scope->base, lhs, TransLValue);
if (lhs_node == nullptr) return nullptr;
- child_block->data.block.statements.append(
+ child_scope->node->data.block.statements.append(
trans_create_node_bin_op(c, lhs_node, BinOpTypeAssign,
trans_create_node_symbol(c, tmp_var_name)));
// _tmp
- child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
- child_block->data.block.last_statement_is_result_expression = true;
+ child_scope->node->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
+ child_scope->node->data.block.last_statement_is_result_expression = true;
- return child_block;
+ return child_scope->node;
}
}
-static AstNode *trans_create_shift_op(Context *c, AstNode *block, QualType result_type, Expr *lhs_expr, BinOpType bin_op, Expr *rhs_expr) {
+static AstNode *trans_create_shift_op(Context *c, TransScope *scope, QualType result_type,
+ Expr *lhs_expr, BinOpType bin_op, Expr *rhs_expr)
+{
const SourceLocation &rhs_location = rhs_expr->getLocStart();
AstNode *rhs_type = qual_type_to_log2_int_ref(c, result_type, rhs_location);
// lhs >> u5(rh)
- AstNode *lhs = trans_expr(c, true, block, lhs_expr, TransLValue);
+ AstNode *lhs = trans_expr(c, ResultUsedYes, scope, lhs_expr, TransLValue);
if (lhs == nullptr) return nullptr;
- AstNode *rhs = trans_expr(c, true, block, rhs_expr, TransRValue);
+ AstNode *rhs = trans_expr(c, ResultUsedYes, scope, rhs_expr, TransRValue);
if (rhs == nullptr) return nullptr;
AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
return trans_create_node_bin_op(c, lhs, bin_op, coerced_rhs);
}
-static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *block, BinaryOperator *stmt) {
+static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransScope *scope, const BinaryOperator *stmt) {
switch (stmt->getOpcode()) {
case BO_PtrMemD:
emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_PtrMemD");
@@ -1029,20 +1186,20 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_PtrMemI");
return nullptr;
case BO_Mul:
- return trans_create_bin_op(c, block, stmt->getLHS(),
+ return trans_create_bin_op(c, scope, stmt->getLHS(),
qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeMultWrap : BinOpTypeMult,
stmt->getRHS());
case BO_Div:
if (qual_type_has_wrapping_overflow(c, stmt->getType())) {
// unsigned/float division uses the operator
- return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeDiv, stmt->getRHS());
+ return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeDiv, stmt->getRHS());
} else {
// signed integer division uses @divTrunc
AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "divTrunc");
- AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
+ AstNode *lhs = trans_expr(c, ResultUsedYes, scope, stmt->getLHS(), TransLValue);
if (lhs == nullptr) return nullptr;
fn_call->data.fn_call_expr.params.append(lhs);
- AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransLValue);
+ AstNode *rhs = trans_expr(c, ResultUsedYes, scope, stmt->getRHS(), TransLValue);
if (rhs == nullptr) return nullptr;
fn_call->data.fn_call_expr.params.append(rhs);
return fn_call;
@@ -1050,66 +1207,70 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
case BO_Rem:
if (qual_type_has_wrapping_overflow(c, stmt->getType())) {
// unsigned/float division uses the operator
- return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeMod, stmt->getRHS());
+ return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeMod, stmt->getRHS());
} else {
// signed integer division uses @rem
AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "rem");
- AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
+ AstNode *lhs = trans_expr(c, ResultUsedYes, scope, stmt->getLHS(), TransLValue);
if (lhs == nullptr) return nullptr;
fn_call->data.fn_call_expr.params.append(lhs);
- AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransLValue);
+ AstNode *rhs = trans_expr(c, ResultUsedYes, scope, stmt->getRHS(), TransLValue);
if (rhs == nullptr) return nullptr;
fn_call->data.fn_call_expr.params.append(rhs);
return fn_call;
}
case BO_Add:
- return trans_create_bin_op(c, block, stmt->getLHS(),
+ return trans_create_bin_op(c, scope, stmt->getLHS(),
qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeAddWrap : BinOpTypeAdd,
stmt->getRHS());
case BO_Sub:
- return trans_create_bin_op(c, block, stmt->getLHS(),
+ return trans_create_bin_op(c, scope, stmt->getLHS(),
qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeSubWrap : BinOpTypeSub,
stmt->getRHS());
case BO_Shl:
- return trans_create_shift_op(c, block, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftLeft, stmt->getRHS());
+ return trans_create_shift_op(c, scope, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftLeft, stmt->getRHS());
case BO_Shr:
- return trans_create_shift_op(c, block, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftRight, stmt->getRHS());
+ return trans_create_shift_op(c, scope, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftRight, stmt->getRHS());
case BO_LT:
- return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpLessThan, stmt->getRHS());
+ return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpLessThan, stmt->getRHS());
case BO_GT:
- return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpGreaterThan, stmt->getRHS());
+ return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpGreaterThan, stmt->getRHS());
case BO_LE:
- return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpLessOrEq, stmt->getRHS());
+ return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpLessOrEq, stmt->getRHS());
case BO_GE:
- return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpGreaterOrEq, stmt->getRHS());
+ return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpGreaterOrEq, stmt->getRHS());
case BO_EQ:
- return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpEq, stmt->getRHS());
+ return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpEq, stmt->getRHS());
case BO_NE:
- return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpNotEq, stmt->getRHS());
+ return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeCmpNotEq, stmt->getRHS());
case BO_And:
- return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBinAnd, stmt->getRHS());
+ return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinAnd, stmt->getRHS());
case BO_Xor:
- return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBinXor, stmt->getRHS());
+ return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinXor, stmt->getRHS());
case BO_Or:
- return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBinOr, stmt->getRHS());
+ return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinOr, stmt->getRHS());
case BO_LAnd:
- return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS());
+ return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS());
case BO_LOr:
// TODO: int vs bool
- return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS());
+ return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS());
case BO_Assign:
- return trans_create_assign(c, result_used, block, stmt->getLHS(), stmt->getRHS());
+ return trans_create_assign(c, result_used, scope, stmt->getLHS(), stmt->getRHS());
case BO_Comma:
{
- block = trans_create_node(c, NodeTypeBlock);
- AstNode *lhs = trans_expr(c, false, block, stmt->getLHS(), TransRValue);
- if (lhs == nullptr) return nullptr;
- block->data.block.statements.append(maybe_suppress_result(c, false, lhs));
- AstNode *rhs = trans_expr(c, result_used, block, stmt->getRHS(), TransRValue);
- if (rhs == nullptr) return nullptr;
- block->data.block.statements.append(maybe_suppress_result(c, result_used, rhs));
- block->data.block.last_statement_is_result_expression = true;
- return block;
+ TransScopeBlock *scope_block = trans_scope_block_create(c, scope);
+ AstNode *lhs = trans_expr(c, ResultUsedNo, &scope_block->base, stmt->getLHS(), TransRValue);
+ if (lhs == nullptr)
+ return nullptr;
+ scope_block->node->data.block.statements.append(maybe_suppress_result(c, ResultUsedNo, lhs));
+
+ AstNode *rhs = trans_expr(c, result_used, &scope_block->base, stmt->getRHS(), TransRValue);
+ if (rhs == nullptr)
+ return nullptr;
+ scope_block->node->data.block.statements.append(maybe_suppress_result(c, result_used, rhs));
+
+ scope_block->node->data.block.last_statement_is_result_expression = true;
+ return scope_block->node;
}
case BO_MulAssign:
case BO_DivAssign:
@@ -1127,18 +1288,20 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
zig_unreachable();
}
-static AstNode *trans_create_compound_assign_shift(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) {
+static AstNode *trans_create_compound_assign_shift(Context *c, ResultUsed result_used, TransScope *scope,
+ const CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op)
+{
const SourceLocation &rhs_location = stmt->getRHS()->getLocStart();
AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location);
bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr();
- if (!use_intermediate_casts && !result_used) {
+ if (!use_intermediate_casts && result_used == ResultUsedNo) {
// simple common case, where the C and Zig are identical:
// lhs >>= rhs
- AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
+ AstNode *lhs = trans_expr(c, ResultUsedYes, scope, stmt->getLHS(), TransLValue);
if (lhs == nullptr) return nullptr;
- AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue);
+ AstNode *rhs = trans_expr(c, ResultUsedYes, scope, stmt->getRHS(), TransRValue);
if (rhs == nullptr) return nullptr;
AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
@@ -1153,57 +1316,68 @@ static AstNode *trans_create_compound_assign_shift(Context *c, bool result_used,
// zig: }
// where u5 is the appropriate type
- AstNode *child_block = trans_create_node(c, NodeTypeBlock);
+ TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
// const _ref = &lhs;
- AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue);
+ AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue);
if (lhs == nullptr) return nullptr;
AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs);
// TODO: avoid name collisions with generated variable names
Buf* tmp_var_name = buf_create_from_str("_ref");
AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs);
- child_block->data.block.statements.append(tmp_var_decl);
+ child_scope->node->data.block.statements.append(tmp_var_decl);
// *_ref = result_type(operation_type(*_ref) >> u5(rhs));
- AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue);
+ AstNode *rhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getRHS(), TransRValue);
if (rhs == nullptr) return nullptr;
AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
+ // operation_type(*_ref)
+ AstNode *operation_type_cast = trans_c_cast(c, rhs_location,
+ stmt->getComputationLHSType(),
+ stmt->getLHS()->getType(),
+ trans_create_node_prefix_op(c, PrefixOpDereference,
+ trans_create_node_symbol(c, tmp_var_name)));
+
+ // result_type(... >> u5(rhs))
+ AstNode *result_type_cast = trans_c_cast(c, rhs_location,
+ stmt->getComputationResultType(),
+ stmt->getComputationLHSType(),
+ trans_create_node_bin_op(c,
+ operation_type_cast,
+ bin_op,
+ coerced_rhs));
+
+ // *_ref = ...
AstNode *assign_statement = trans_create_node_bin_op(c,
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, tmp_var_name)),
- BinOpTypeAssign,
- trans_c_cast(c, rhs_location,
- stmt->getComputationResultType(),
- trans_create_node_bin_op(c,
- trans_c_cast(c, rhs_location,
- stmt->getComputationLHSType(),
- trans_create_node_prefix_op(c, PrefixOpDereference,
- trans_create_node_symbol(c, tmp_var_name))),
- bin_op,
- coerced_rhs)));
- child_block->data.block.statements.append(assign_statement);
+ BinOpTypeAssign, result_type_cast);
- if (result_used) {
+ child_scope->node->data.block.statements.append(assign_statement);
+
+ if (result_used == ResultUsedYes) {
// *_ref
- child_block->data.block.statements.append(
+ child_scope->node->data.block.statements.append(
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, tmp_var_name)));
- child_block->data.block.last_statement_is_result_expression = true;
+ child_scope->node->data.block.last_statement_is_result_expression = true;
}
- return child_block;
+ return child_scope->node;
}
}
-static AstNode *trans_create_compound_assign(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) {
- if (!result_used) {
+static AstNode *trans_create_compound_assign(Context *c, ResultUsed result_used, TransScope *scope,
+ const CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op)
+{
+ if (result_used == ResultUsedNo) {
// simple common case, where the C and Zig are identical:
// lhs += rhs
- AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
+ AstNode *lhs = trans_expr(c, ResultUsedYes, scope, stmt->getLHS(), TransLValue);
if (lhs == nullptr) return nullptr;
- AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue);
+ AstNode *rhs = trans_expr(c, ResultUsedYes, scope, stmt->getRHS(), TransRValue);
if (rhs == nullptr) return nullptr;
return trans_create_node_bin_op(c, lhs, assign_op, rhs);
} else {
@@ -1215,20 +1389,20 @@ static AstNode *trans_create_compound_assign(Context *c, bool result_used, AstNo
// zig: *_ref
// zig: }
- AstNode *child_block = trans_create_node(c, NodeTypeBlock);
+ TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
// const _ref = &lhs;
- AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue);
+ AstNode *lhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getLHS(), TransLValue);
if (lhs == nullptr) return nullptr;
AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs);
// TODO: avoid name collisions with generated variable names
Buf* tmp_var_name = buf_create_from_str("_ref");
AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs);
- child_block->data.block.statements.append(tmp_var_decl);
+ child_scope->node->data.block.statements.append(tmp_var_decl);
// *_ref = *_ref + rhs;
- AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue);
+ AstNode *rhs = trans_expr(c, ResultUsedYes, &child_scope->base, stmt->getRHS(), TransRValue);
if (rhs == nullptr) return nullptr;
AstNode *assign_statement = trans_create_node_bin_op(c,
@@ -1240,26 +1414,28 @@ static AstNode *trans_create_compound_assign(Context *c, bool result_used, AstNo
trans_create_node_symbol(c, tmp_var_name)),
bin_op,
rhs));
- child_block->data.block.statements.append(assign_statement);
+ child_scope->node->data.block.statements.append(assign_statement);
// *_ref
- child_block->data.block.statements.append(
+ child_scope->node->data.block.statements.append(
trans_create_node_prefix_op(c, PrefixOpDereference,
trans_create_node_symbol(c, tmp_var_name)));
- child_block->data.block.last_statement_is_result_expression = true;
+ child_scope->node->data.block.last_statement_is_result_expression = true;
- return child_block;
+ return child_scope->node;
}
}
-static AstNode *trans_compound_assign_operator(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt) {
+static AstNode *trans_compound_assign_operator(Context *c, ResultUsed result_used, TransScope *scope,
+ const CompoundAssignOperator *stmt)
+{
switch (stmt->getOpcode()) {
case BO_MulAssign:
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
- return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignTimesWrap, BinOpTypeMultWrap);
+ return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignTimesWrap, BinOpTypeMultWrap);
else
- return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignTimes, BinOpTypeMult);
+ return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignTimes, BinOpTypeMult);
case BO_DivAssign:
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_DivAssign");
return nullptr;
@@ -1268,24 +1444,24 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast
return nullptr;
case BO_AddAssign:
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
- return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignPlusWrap, BinOpTypeAddWrap);
+ return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap, BinOpTypeAddWrap);
else
- return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignPlus, BinOpTypeAdd);
+ return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignPlus, BinOpTypeAdd);
case BO_SubAssign:
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
- return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignMinusWrap, BinOpTypeSubWrap);
+ return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap, BinOpTypeSubWrap);
else
- return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignMinus, BinOpTypeSub);
+ return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignMinus, BinOpTypeSub);
case BO_ShlAssign:
- return trans_create_compound_assign_shift(c, result_used, block, stmt, BinOpTypeAssignBitShiftLeft, BinOpTypeBitShiftLeft);
+ return trans_create_compound_assign_shift(c, result_used, scope, stmt, BinOpTypeAssignBitShiftLeft, BinOpTypeBitShiftLeft);
case BO_ShrAssign:
- return trans_create_compound_assign_shift(c, result_used, block, stmt, BinOpTypeAssignBitShiftRight, BinOpTypeBitShiftRight);
+ return trans_create_compound_assign_shift(c, result_used, scope, stmt, BinOpTypeAssignBitShiftRight, BinOpTypeBitShiftRight);
case BO_AndAssign:
- return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitAnd, BinOpTypeBinAnd);
+ return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignBitAnd, BinOpTypeBinAnd);
case BO_XorAssign:
- return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitXor, BinOpTypeBinXor);
+ return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignBitXor, BinOpTypeBinXor);
case BO_OrAssign:
- return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitOr, BinOpTypeBinOr);
+ return trans_create_compound_assign(c, result_used, scope, stmt, BinOpTypeAssignBitOr, BinOpTypeBinOr);
case BO_PtrMemD:
case BO_PtrMemI:
case BO_Assign:
@@ -1314,32 +1490,37 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast
zig_unreachable();
}
-static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCastExpr *stmt) {
+static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const ImplicitCastExpr *stmt) {
switch (stmt->getCastKind()) {
case CK_LValueToRValue:
- return trans_expr(c, true, block, stmt->getSubExpr(), TransRValue);
+ return trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue);
case CK_IntegralCast:
{
- AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue);
+ AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue);
if (target_node == nullptr)
return nullptr;
- return trans_c_cast(c, stmt->getExprLoc(), stmt->getType(), target_node);
+ return trans_c_cast(c, stmt->getExprLoc(), stmt->getType(),
+ stmt->getSubExpr()->getType(), target_node);
}
case CK_FunctionToPointerDecay:
case CK_ArrayToPointerDecay:
{
- AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue);
+ AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue);
if (target_node == nullptr)
return nullptr;
return target_node;
}
case CK_BitCast:
{
- AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue);
+ AstNode *target_node = trans_expr(c, ResultUsedYes, scope, stmt->getSubExpr(), TransRValue);
if (target_node == nullptr)
return nullptr;
- AstNode *dest_type_node = trans_qual_type(c, stmt->getType(), stmt->getLocStart());
+ if (expr_types_equal(c, stmt, stmt->getSubExpr())) {
+ return target_node;
+ }
+
+ AstNode *dest_type_node = get_expr_type(c, stmt);
AstNode *node = trans_create_node_builtin_fn_call_str(c, "ptrCast");
node->data.fn_call_expr.params.append(dest_type_node);
@@ -1508,94 +1689,155 @@ static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCas
zig_unreachable();
}
-static AstNode *trans_decl_ref_expr(Context *c, DeclRefExpr *stmt, TransLRValue lrval) {
- ValueDecl *value_decl = stmt->getDecl();
- Buf *symbol_name = buf_create_from_str(decl_name(value_decl));
+static AstNode *trans_decl_ref_expr(Context *c, TransScope *scope, const DeclRefExpr *stmt, TransLRValue lrval) {
+ const ValueDecl *value_decl = stmt->getDecl();
+ Buf *c_symbol_name = buf_create_from_str(decl_name(value_decl));
+ Buf *zig_symbol_name = trans_lookup_zig_symbol(c, scope, c_symbol_name);
if (lrval == TransLValue) {
- c->ptr_params.put(symbol_name, true);
+ c->ptr_params.put(zig_symbol_name, true);
}
- return trans_create_node_symbol(c, symbol_name);
+ return trans_create_node_symbol(c, zig_symbol_name);
}
-static AstNode *trans_create_post_crement(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt, BinOpType assign_op) {
+static AstNode *trans_create_post_crement(Context *c, ResultUsed result_used, TransScope *scope,
+ const UnaryOperator *stmt, BinOpType assign_op)
+{
Expr *op_expr = stmt->getSubExpr();
- if (!result_used) {
+ if (result_used == ResultUsedNo) {
// common case
// c: expr++
// zig: expr += 1
return trans_create_node_bin_op(c,
- trans_expr(c, true, block, op_expr, TransLValue),
+ trans_expr(c, ResultUsedYes, scope, op_expr, TransLValue),
assign_op,
trans_create_node_unsigned(c, 1));
- } else {
- // worst case
- // c: expr++
- // zig: {
- // zig: const _ref = &expr;
- // zig: const _tmp = *_ref;
- // zig: *_ref += 1;
- // zig: _tmp
- // zig: }
- AstNode *child_block = trans_create_node(c, NodeTypeBlock);
-
- // const _ref = &expr;
- AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue);
- if (expr == nullptr) return nullptr;
- AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr);
- // TODO: avoid name collisions with generated variable names
- Buf* ref_var_name = buf_create_from_str("_ref");
- AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr);
- child_block->data.block.statements.append(ref_var_decl);
-
- // const _tmp = *_ref;
- Buf* tmp_var_name = buf_create_from_str("_tmp");
- AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,
- trans_create_node_prefix_op(c, PrefixOpDereference,
- trans_create_node_symbol(c, ref_var_name)));
- child_block->data.block.statements.append(tmp_var_decl);
-
- // *_ref += 1;
- AstNode *assign_statement = trans_create_node_bin_op(c,
- trans_create_node_prefix_op(c, PrefixOpDereference,
- trans_create_node_symbol(c, ref_var_name)),
- assign_op,
- trans_create_node_unsigned(c, 1));
- child_block->data.block.statements.append(assign_statement);
-
- // _tmp
- child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
- child_block->data.block.last_statement_is_result_expression = true;
-
- return child_block;
}
+ // worst case
+ // c: expr++
+ // zig: {
+ // zig: const _ref = &expr;
+ // zig: const _tmp = *_ref;
+ // zig: *_ref += 1;
+ // zig: _tmp
+ // zig: }
+ TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
+
+ // const _ref = &expr;
+ AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue);
+ if (expr == nullptr) return nullptr;
+ AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr);
+ // TODO: avoid name collisions with generated variable names
+ Buf* ref_var_name = buf_create_from_str("_ref");
+ AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr);
+ child_scope->node->data.block.statements.append(ref_var_decl);
+
+ // const _tmp = *_ref;
+ Buf* tmp_var_name = buf_create_from_str("_tmp");
+ AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,
+ trans_create_node_prefix_op(c, PrefixOpDereference,
+ trans_create_node_symbol(c, ref_var_name)));
+ child_scope->node->data.block.statements.append(tmp_var_decl);
+
+ // *_ref += 1;
+ AstNode *assign_statement = trans_create_node_bin_op(c,
+ trans_create_node_prefix_op(c, PrefixOpDereference,
+ trans_create_node_symbol(c, ref_var_name)),
+ assign_op,
+ trans_create_node_unsigned(c, 1));
+ child_scope->node->data.block.statements.append(assign_statement);
+
+ // _tmp
+ child_scope->node->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
+ child_scope->node->data.block.last_statement_is_result_expression = true;
+
+ return child_scope->node;
}
-static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) {
+static AstNode *trans_create_pre_crement(Context *c, ResultUsed result_used, TransScope *scope,
+ const UnaryOperator *stmt, BinOpType assign_op)
+{
+ Expr *op_expr = stmt->getSubExpr();
+
+ if (result_used == ResultUsedNo) {
+ // common case
+ // c: ++expr
+ // zig: expr += 1
+ return trans_create_node_bin_op(c,
+ trans_expr(c, ResultUsedYes, scope, op_expr, TransLValue),
+ assign_op,
+ trans_create_node_unsigned(c, 1));
+ }
+ // worst case
+ // c: ++expr
+ // zig: {
+ // zig: const _ref = &expr;
+ // zig: *_ref += 1;
+ // zig: *_ref
+ // zig: }
+ TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
+
+ // const _ref = &expr;
+ AstNode *expr = trans_expr(c, ResultUsedYes, &child_scope->base, op_expr, TransLValue);
+ if (expr == nullptr) return nullptr;
+ AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr);
+ // TODO: avoid name collisions with generated variable names
+ Buf* ref_var_name = buf_create_from_str("_ref");
+ AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr);
+ child_scope->node->data.block.statements.append(ref_var_decl);
+
+ // *_ref += 1;
+ AstNode *assign_statement = trans_create_node_bin_op(c,
+ trans_create_node_prefix_op(c, PrefixOpDereference,
+ trans_create_node_symbol(c, ref_var_name)),
+ assign_op,
+ trans_create_node_unsigned(c, 1));
+ child_scope->node->data.block.statements.append(assign_statement);
+
+ // *_ref
+ AstNode *deref_expr = trans_create_node_prefix_op(c, PrefixOpDereference,
+ trans_create_node_symbol(c, ref_var_name));
+ child_scope->node->data.block.statements.append(deref_expr);
+ child_scope->node->data.block.last_statement_is_result_expression = true;
+
+ return child_scope->node;
+}
+
+static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransScope *scope, const UnaryOperator *stmt) {
switch (stmt->getOpcode()) {
case UO_PostInc:
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
- return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlusWrap);
+ return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap);
else
- return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlus);
+ return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignPlus);
case UO_PostDec:
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
- return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinusWrap);
+ return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap);
else
- return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinus);
+ return trans_create_post_crement(c, result_used, scope, stmt, BinOpTypeAssignMinus);
case UO_PreInc:
- emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreInc");
- return nullptr;
+ if (qual_type_has_wrapping_overflow(c, stmt->getType()))
+ return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignPlusWrap);
+ else
+ return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignPlus);
case UO_PreDec:
- emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreDec");
- return nullptr;
+ if (qual_type_has_wrapping_overflow(c, stmt->getType()))
+ return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignMinusWrap);
+ else
+ return trans_create_pre_crement(c, result_used, scope, stmt, BinOpTypeAssignMinus);
case UO_AddrOf:
- emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_AddrOf");
- return nullptr;
+ {
+ AstNode *value_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), TransLValue);
+ if (value_node == nullptr)
+ return value_node;
+ return trans_create_node_addr_of(c, false, false, value_node);
+ }
case UO_Deref:
{
+ AstNode *value_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), TransRValue);
+ if (value_node == nullptr)
+ return nullptr;
bool is_fn_ptr = qual_type_is_fn_ptr(c, stmt->getSubExpr()->getType());
- AstNode *value_node = trans_expr(c, result_used, block, stmt->getSubExpr(), TransRValue);
if (is_fn_ptr)
return value_node;
AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node);
@@ -1611,7 +1853,7 @@ static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *bloc
AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr);
node->data.prefix_op_expr.prefix_op = PrefixOpNegation;
- node->data.prefix_op_expr.primary_expr = trans_expr(c, true, block, op_expr, TransRValue);
+ node->data.prefix_op_expr.primary_expr = trans_expr(c, ResultUsedYes, scope, op_expr, TransRValue);
if (node->data.prefix_op_expr.primary_expr == nullptr)
return nullptr;
@@ -1621,7 +1863,7 @@ static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *bloc
AstNode *node = trans_create_node(c, NodeTypeBinOpExpr);
node->data.bin_op_expr.op1 = trans_create_node_unsigned(c, 0);
- node->data.bin_op_expr.op2 = trans_expr(c, true, block, op_expr, TransRValue);
+ node->data.bin_op_expr.op2 = trans_expr(c, ResultUsedYes, scope, op_expr, TransRValue);
if (node->data.bin_op_expr.op2 == nullptr)
return nullptr;
@@ -1633,8 +1875,13 @@ static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *bloc
}
}
case UO_Not:
- emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Not");
- return nullptr;
+ {
+ Expr *op_expr = stmt->getSubExpr();
+ AstNode *sub_node = trans_expr(c, ResultUsedYes, scope, op_expr, TransRValue);
+ if (sub_node == nullptr)
+ return nullptr;
+ return trans_create_node_prefix_op(c, PrefixOpBinNot, sub_node);
+ }
case UO_LNot:
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_LNot");
return nullptr;
@@ -1654,7 +1901,15 @@ static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *bloc
zig_unreachable();
}
-static AstNode *trans_local_declaration(Context *c, AstNode *block, DeclStmt *stmt) {
+static int trans_local_declaration(Context *c, TransScope *scope, const DeclStmt *stmt,
+ AstNode **out_node, TransScope **out_scope)
+{
+ // declarations are added via the scope
+ *out_node = nullptr;
+
+ TransScopeBlock *scope_block = trans_scope_block_find(scope);
+ assert(scope_block != nullptr);
+
for (auto iter = stmt->decl_begin(); iter != stmt->decl_end(); iter++) {
Decl *decl = *iter;
switch (decl->getKind()) {
@@ -1663,294 +1918,313 @@ static AstNode *trans_local_declaration(Context *c, AstNode *block, DeclStmt *st
QualType qual_type = var_decl->getTypeSourceInfo()->getType();
AstNode *init_node = nullptr;
if (var_decl->hasInit()) {
- init_node = trans_expr(c, true, block, var_decl->getInit(), TransRValue);
+ init_node = trans_expr(c, ResultUsedYes, scope, var_decl->getInit(), TransRValue);
if (init_node == nullptr)
- return nullptr;
+ return ErrorUnexpected;
}
AstNode *type_node = trans_qual_type(c, qual_type, stmt->getLocStart());
if (type_node == nullptr)
- return nullptr;
+ return ErrorUnexpected;
- Buf *symbol_name = buf_create_from_str(decl_name(var_decl));
+ Buf *c_symbol_name = buf_create_from_str(decl_name(var_decl));
+
+ TransScopeVar *var_scope = trans_scope_var_create(c, scope, c_symbol_name);
+ scope = &var_scope->base;
AstNode *node = trans_create_node_var_decl_local(c, qual_type.isConstQualified(),
- symbol_name, type_node, init_node);
- block->data.block.statements.append(node);
+ var_scope->zig_name, type_node, init_node);
+
+ scope_block->node->data.block.statements.append(node);
continue;
}
case Decl::AccessSpec:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind AccessSpec");
- return nullptr;
+ return ErrorUnexpected;
case Decl::Block:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Block");
- return nullptr;
+ return ErrorUnexpected;
case Decl::Captured:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Captured");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ClassScopeFunctionSpecialization:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassScopeFunctionSpecialization");
- return nullptr;
+ return ErrorUnexpected;
case Decl::Empty:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Empty");
- return nullptr;
+ return ErrorUnexpected;
case Decl::Export:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Export");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ExternCContext:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ExternCContext");
- return nullptr;
+ return ErrorUnexpected;
case Decl::FileScopeAsm:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FileScopeAsm");
- return nullptr;
+ return ErrorUnexpected;
case Decl::Friend:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Friend");
- return nullptr;
+ return ErrorUnexpected;
case Decl::FriendTemplate:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FriendTemplate");
- return nullptr;
+ return ErrorUnexpected;
case Decl::Import:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Import");
- return nullptr;
+ return ErrorUnexpected;
case Decl::LinkageSpec:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind LinkageSpec");
- return nullptr;
+ return ErrorUnexpected;
case Decl::Label:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Label");
- return nullptr;
+ return ErrorUnexpected;
case Decl::Namespace:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Namespace");
- return nullptr;
+ return ErrorUnexpected;
case Decl::NamespaceAlias:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind NamespaceAlias");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ObjCCompatibleAlias:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCompatibleAlias");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ObjCCategory:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCategory");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ObjCCategoryImpl:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCategoryImpl");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ObjCImplementation:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCImplementation");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ObjCInterface:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCInterface");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ObjCProtocol:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCProtocol");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ObjCMethod:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCMethod");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ObjCProperty:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCProperty");
- return nullptr;
+ return ErrorUnexpected;
case Decl::BuiltinTemplate:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind BuiltinTemplate");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ClassTemplate:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplate");
- return nullptr;
+ return ErrorUnexpected;
case Decl::FunctionTemplate:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FunctionTemplate");
- return nullptr;
+ return ErrorUnexpected;
case Decl::TypeAliasTemplate:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TypeAliasTemplate");
- return nullptr;
+ return ErrorUnexpected;
case Decl::VarTemplate:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplate");
- return nullptr;
+ return ErrorUnexpected;
case Decl::TemplateTemplateParm:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TemplateTemplateParm");
- return nullptr;
+ return ErrorUnexpected;
case Decl::Enum:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Enum");
- return nullptr;
+ return ErrorUnexpected;
case Decl::Record:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Record");
- return nullptr;
+ return ErrorUnexpected;
case Decl::CXXRecord:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXRecord");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ClassTemplateSpecialization:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplateSpecialization");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ClassTemplatePartialSpecialization:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplatePartialSpecialization");
- return nullptr;
+ return ErrorUnexpected;
case Decl::TemplateTypeParm:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TemplateTypeParm");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ObjCTypeParam:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCTypeParam");
- return nullptr;
+ return ErrorUnexpected;
case Decl::TypeAlias:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TypeAlias");
- return nullptr;
+ return ErrorUnexpected;
case Decl::Typedef:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Typedef");
- return nullptr;
+ return ErrorUnexpected;
case Decl::UnresolvedUsingTypename:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UnresolvedUsingTypename");
- return nullptr;
+ return ErrorUnexpected;
case Decl::Using:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Using");
- return nullptr;
+ return ErrorUnexpected;
case Decl::UsingDirective:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingDirective");
- return nullptr;
+ return ErrorUnexpected;
case Decl::UsingPack:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingPack");
- return nullptr;
+ return ErrorUnexpected;
case Decl::UsingShadow:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingShadow");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ConstructorUsingShadow:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ConstructorUsingShadow");
- return nullptr;
+ return ErrorUnexpected;
case Decl::Binding:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Binding");
- return nullptr;
+ return ErrorUnexpected;
case Decl::Field:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Field");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ObjCAtDefsField:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCAtDefsField");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ObjCIvar:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCIvar");
- return nullptr;
+ return ErrorUnexpected;
case Decl::Function:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Function");
- return nullptr;
+ return ErrorUnexpected;
case Decl::CXXDeductionGuide:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXDeductionGuide");
- return nullptr;
+ return ErrorUnexpected;
case Decl::CXXMethod:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXMethod");
- return nullptr;
+ return ErrorUnexpected;
case Decl::CXXConstructor:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXConstructor");
- return nullptr;
+ return ErrorUnexpected;
case Decl::CXXConversion:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXConversion");
- return nullptr;
+ return ErrorUnexpected;
case Decl::CXXDestructor:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXDestructor");
- return nullptr;
+ return ErrorUnexpected;
case Decl::MSProperty:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind MSProperty");
- return nullptr;
+ return ErrorUnexpected;
case Decl::NonTypeTemplateParm:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind NonTypeTemplateParm");
- return nullptr;
+ return ErrorUnexpected;
case Decl::Decomposition:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Decomposition");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ImplicitParam:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ImplicitParam");
- return nullptr;
+ return ErrorUnexpected;
case Decl::OMPCapturedExpr:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPCapturedExpr");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ParmVar:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ParmVar");
- return nullptr;
+ return ErrorUnexpected;
case Decl::VarTemplateSpecialization:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplateSpecialization");
- return nullptr;
+ return ErrorUnexpected;
case Decl::VarTemplatePartialSpecialization:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplatePartialSpecialization");
- return nullptr;
+ return ErrorUnexpected;
case Decl::EnumConstant:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind EnumConstant");
- return nullptr;
+ return ErrorUnexpected;
case Decl::IndirectField:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind IndirectField");
- return nullptr;
+ return ErrorUnexpected;
case Decl::OMPDeclareReduction:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPDeclareReduction");
- return nullptr;
+ return ErrorUnexpected;
case Decl::UnresolvedUsingValue:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UnresolvedUsingValue");
- return nullptr;
+ return ErrorUnexpected;
case Decl::OMPThreadPrivate:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPThreadPrivate");
- return nullptr;
+ return ErrorUnexpected;
case Decl::ObjCPropertyImpl:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCPropertyImpl");
- return nullptr;
+ return ErrorUnexpected;
case Decl::PragmaComment:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind PragmaComment");
- return nullptr;
+ return ErrorUnexpected;
case Decl::PragmaDetectMismatch:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind PragmaDetectMismatch");
- return nullptr;
+ return ErrorUnexpected;
case Decl::StaticAssert:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind StaticAssert");
- return nullptr;
+ return ErrorUnexpected;
case Decl::TranslationUnit:
emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TranslationUnit");
- return nullptr;
+ return ErrorUnexpected;
}
zig_unreachable();
}
- // declarations were already added
- return skip_add_to_block_node;
+ *out_scope = scope;
+ return ErrorNone;
}
-static AstNode *trans_while_loop(Context *c, AstNode *block, WhileStmt *stmt) {
- AstNode *while_node = trans_create_node(c, NodeTypeWhileExpr);
+static AstNode *trans_while_loop(Context *c, TransScope *scope, const WhileStmt *stmt) {
+ TransScopeWhile *while_scope = trans_scope_while_create(c, scope);
- while_node->data.while_expr.condition = trans_expr(c, true, block, stmt->getCond(), TransRValue);
- if (while_node->data.while_expr.condition == nullptr)
+ while_scope->node->data.while_expr.condition = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
+ if (while_scope->node->data.while_expr.condition == nullptr)
return nullptr;
- while_node->data.while_expr.body = trans_stmt(c, false, block, stmt->getBody(), TransRValue);
- if (while_node->data.while_expr.body == nullptr)
+ TransScope *body_scope = trans_stmt(c, &while_scope->base, stmt->getBody(),
+ &while_scope->node->data.while_expr.body);
+ if (body_scope == nullptr)
return nullptr;
- return while_node;
+ return while_scope->node;
}
-static AstNode *trans_if_statement(Context *c, AstNode *block, IfStmt *stmt) {
+static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *stmt) {
// if (c) t
// if (c) t else e
AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr);
// TODO: condition != 0
- AstNode *condition_node = trans_expr(c, true, block, stmt->getCond(), TransRValue);
+ AstNode *condition_node = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
if (condition_node == nullptr)
return nullptr;
if_node->data.if_bool_expr.condition = condition_node;
- if_node->data.if_bool_expr.then_block = trans_stmt(c, false, block, stmt->getThen(), TransRValue);
- if (if_node->data.if_bool_expr.then_block == nullptr)
+ TransScope *then_scope = trans_stmt(c, scope, stmt->getThen(), &if_node->data.if_bool_expr.then_block);
+ if (then_scope == nullptr)
return nullptr;
if (stmt->getElse() != nullptr) {
- if_node->data.if_bool_expr.else_node = trans_stmt(c, false, block, stmt->getElse(), TransRValue);
- if (if_node->data.if_bool_expr.else_node == nullptr)
+ TransScope *else_scope = trans_stmt(c, scope, stmt->getElse(), &if_node->data.if_bool_expr.else_node);
+ if (else_scope == nullptr)
return nullptr;
}
return if_node;
}
-static AstNode *trans_call_expr(Context *c, bool result_used, AstNode *block, CallExpr *stmt) {
+static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *scope, const CallExpr *stmt) {
AstNode *node = trans_create_node(c, NodeTypeFnCallExpr);
- AstNode *callee_raw_node = trans_expr(c, true, block, stmt->getCallee(), TransRValue);
+ AstNode *callee_raw_node = trans_expr(c, ResultUsedYes, scope, stmt->getCallee(), TransRValue);
if (callee_raw_node == nullptr)
return nullptr;
- AstNode *callee_node;
+ AstNode *callee_node = nullptr;
if (qual_type_is_fn_ptr(c, stmt->getCallee()->getType())) {
- callee_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, callee_raw_node);
+ if (stmt->getCallee()->getStmtClass() == Stmt::ImplicitCastExprClass) {
+ const ImplicitCastExpr *implicit_cast = static_cast(stmt->getCallee());
+ if (implicit_cast->getCastKind() == CK_FunctionToPointerDecay) {
+ if (implicit_cast->getSubExpr()->getStmtClass() == Stmt::DeclRefExprClass) {
+ const DeclRefExpr *decl_ref = static_cast(implicit_cast->getSubExpr());
+ const Decl *decl = decl_ref->getFoundDecl();
+ if (decl->getKind() == Decl::Function) {
+ callee_node = callee_raw_node;
+ }
+ }
+ }
+ }
+ if (callee_node == nullptr) {
+ callee_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, callee_raw_node);
+ }
} else {
callee_node = callee_raw_node;
}
@@ -1958,9 +2232,9 @@ static AstNode *trans_call_expr(Context *c, bool result_used, AstNode *block, Ca
node->data.fn_call_expr.fn_ref_expr = callee_node;
unsigned num_args = stmt->getNumArgs();
- Expr **args = stmt->getArgs();
+ const Expr * const* args = stmt->getArgs();
for (unsigned i = 0; i < num_args; i += 1) {
- AstNode *arg_node = trans_expr(c, true, block, args[i], TransRValue);
+ AstNode *arg_node = trans_expr(c, ResultUsedYes, scope, args[i], TransRValue);
if (arg_node == nullptr)
return nullptr;
@@ -1970,8 +2244,8 @@ static AstNode *trans_call_expr(Context *c, bool result_used, AstNode *block, Ca
return node;
}
-static AstNode *trans_member_expr(Context *c, AstNode *block, MemberExpr *stmt) {
- AstNode *container_node = trans_expr(c, true, block, stmt->getBase(), TransRValue);
+static AstNode *trans_member_expr(Context *c, TransScope *scope, const MemberExpr *stmt) {
+ AstNode *container_node = trans_expr(c, ResultUsedYes, scope, stmt->getBase(), TransRValue);
if (container_node == nullptr)
return nullptr;
@@ -1985,12 +2259,12 @@ static AstNode *trans_member_expr(Context *c, AstNode *block, MemberExpr *stmt)
return node;
}
-static AstNode *trans_array_subscript_expr(Context *c, AstNode *block, ArraySubscriptExpr *stmt) {
- AstNode *container_node = trans_expr(c, true, block, stmt->getBase(), TransRValue);
+static AstNode *trans_array_subscript_expr(Context *c, TransScope *scope, const ArraySubscriptExpr *stmt) {
+ AstNode *container_node = trans_expr(c, ResultUsedYes, scope, stmt->getBase(), TransRValue);
if (container_node == nullptr)
return nullptr;
- AstNode *idx_node = trans_expr(c, true, block, stmt->getIdx(), TransRValue);
+ AstNode *idx_node = trans_expr(c, ResultUsedYes, scope, stmt->getIdx(), TransRValue);
if (idx_node == nullptr)
return nullptr;
@@ -2001,17 +2275,19 @@ static AstNode *trans_array_subscript_expr(Context *c, AstNode *block, ArraySubs
return node;
}
-static AstNode *trans_c_style_cast_expr(Context *c, bool result_used, AstNode *block,
- CStyleCastExpr *stmt, TransLRValue lrvalue)
+static AstNode *trans_c_style_cast_expr(Context *c, ResultUsed result_used, TransScope *scope,
+ const CStyleCastExpr *stmt, TransLRValue lrvalue)
{
- AstNode *sub_expr_node = trans_expr(c, result_used, block, stmt->getSubExpr(), lrvalue);
+ AstNode *sub_expr_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), lrvalue);
if (sub_expr_node == nullptr)
return nullptr;
- return trans_c_cast(c, stmt->getLocStart(), stmt->getType(), sub_expr_node);
+ return trans_c_cast(c, stmt->getLocStart(), stmt->getType(), stmt->getSubExpr()->getType(), sub_expr_node);
}
-static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, AstNode *block, UnaryExprOrTypeTraitExpr *stmt) {
+static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, TransScope *scope,
+ const UnaryExprOrTypeTraitExpr *stmt)
+{
AstNode *type_node = trans_qual_type(c, stmt->getTypeOfArgument(), stmt->getLocStart());
if (type_node == nullptr)
return nullptr;
@@ -2021,17 +2297,13 @@ static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, AstNode *block,
return node;
}
-static AstNode *trans_do_loop(Context *c, AstNode *block, DoStmt *stmt) {
- stmt->getBody();
- stmt->getCond();
+static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const DoStmt *stmt) {
+ TransScopeWhile *while_scope = trans_scope_while_create(c, parent_scope);
- AstNode *while_node = trans_create_node(c, NodeTypeWhileExpr);
-
- AstNode *true_node = trans_create_node(c, NodeTypeBoolLiteral);
- true_node->data.bool_literal.value = true;
- while_node->data.while_expr.condition = true_node;
+ while_scope->node->data.while_expr.condition = trans_create_node_bool(c, true);
AstNode *body_node;
+ TransScope *child_scope;
if (stmt->getBody()->getStmtClass() == Stmt::CompoundStmtClass) {
// there's already a block in C, so we'll append our condition to it.
// c: do {
@@ -2043,8 +2315,13 @@ static AstNode *trans_do_loop(Context *c, AstNode *block, DoStmt *stmt) {
// zig: b;
// zig: if (!cond) break;
// zig: }
- body_node = trans_stmt(c, false, block, stmt->getBody(), TransRValue);
- if (body_node == nullptr) return nullptr;
+
+ // We call the low level function so that we can set child_scope to the scope of the generated block.
+ if (trans_stmt_extra(c, &while_scope->base, stmt->getBody(), ResultUsedNo, TransRValue, &body_node,
+ nullptr, &child_scope))
+ {
+ return nullptr;
+ }
assert(body_node->type == NodeTypeBlock);
} else {
// the C statement is without a block, so we need to create a block to contain it.
@@ -2055,598 +2332,881 @@ static AstNode *trans_do_loop(Context *c, AstNode *block, DoStmt *stmt) {
// zig: a;
// zig: if (!cond) break;
// zig: }
- body_node = trans_create_node(c, NodeTypeBlock);
- AstNode *child_statement = trans_stmt(c, false, body_node, stmt->getBody(), TransRValue);
- if (child_statement == nullptr) return nullptr;
+ TransScopeBlock *child_block_scope = trans_scope_block_create(c, &while_scope->base);
+ body_node = child_block_scope->node;
+ AstNode *child_statement;
+ child_scope = trans_stmt(c, &child_block_scope->base, stmt->getBody(), &child_statement);
+ if (child_scope == nullptr) return nullptr;
body_node->data.block.statements.append(child_statement);
}
// if (!cond) break;
- AstNode *condition_node = trans_expr(c, true, body_node, stmt->getCond(), TransRValue);
+ AstNode *condition_node = trans_expr(c, ResultUsedYes, child_scope, stmt->getCond(), TransRValue);
if (condition_node == nullptr) return nullptr;
AstNode *terminator_node = trans_create_node(c, NodeTypeIfBoolExpr);
terminator_node->data.if_bool_expr.condition = trans_create_node_prefix_op(c, PrefixOpBoolNot, condition_node);
terminator_node->data.if_bool_expr.then_block = trans_create_node(c, NodeTypeBreak);
+
body_node->data.block.statements.append(terminator_node);
- while_node->data.while_expr.body = body_node;
+ while_scope->node->data.while_expr.body = body_node;
- return while_node;
+ return while_scope->node;
}
-static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrvalue) {
- Stmt::StmtClass sc = stmt->getStmtClass();
- switch (sc) {
- case Stmt::ReturnStmtClass:
- return trans_return_stmt(c, block, (ReturnStmt *)stmt);
- case Stmt::CompoundStmtClass:
- return trans_compound_stmt(c, block, (CompoundStmt *)stmt);
- case Stmt::IntegerLiteralClass:
- return trans_integer_literal(c, (IntegerLiteral *)stmt);
- case Stmt::ConditionalOperatorClass:
- return trans_conditional_operator(c, result_used, block, (ConditionalOperator *)stmt);
- case Stmt::BinaryOperatorClass:
- return trans_binary_operator(c, result_used, block, (BinaryOperator *)stmt);
- case Stmt::CompoundAssignOperatorClass:
- return trans_compound_assign_operator(c, result_used, block, (CompoundAssignOperator *)stmt);
- case Stmt::ImplicitCastExprClass:
- return trans_implicit_cast_expr(c, block, (ImplicitCastExpr *)stmt);
- case Stmt::DeclRefExprClass:
- return trans_decl_ref_expr(c, (DeclRefExpr *)stmt, lrvalue);
- case Stmt::UnaryOperatorClass:
- return trans_unary_operator(c, result_used, block, (UnaryOperator *)stmt);
- case Stmt::DeclStmtClass:
- return trans_local_declaration(c, block, (DeclStmt *)stmt);
- case Stmt::WhileStmtClass:
- return trans_while_loop(c, block, (WhileStmt *)stmt);
- case Stmt::IfStmtClass:
- return trans_if_statement(c, block, (IfStmt *)stmt);
- case Stmt::CallExprClass:
- return trans_call_expr(c, result_used, block, (CallExpr *)stmt);
- case Stmt::NullStmtClass:
- return skip_add_to_block_node;
- case Stmt::MemberExprClass:
- return trans_member_expr(c, block, (MemberExpr *)stmt);
- case Stmt::ArraySubscriptExprClass:
- return trans_array_subscript_expr(c, block, (ArraySubscriptExpr *)stmt);
- case Stmt::CStyleCastExprClass:
- return trans_c_style_cast_expr(c, result_used, block, (CStyleCastExpr *)stmt, lrvalue);
- case Stmt::UnaryExprOrTypeTraitExprClass:
- return trans_unary_expr_or_type_trait_expr(c, block, (UnaryExprOrTypeTraitExpr *)stmt);
- case Stmt::DoStmtClass:
- return trans_do_loop(c, block, (DoStmt *)stmt);
- case Stmt::CaseStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass");
- return nullptr;
- case Stmt::DefaultStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C DefaultStmtClass");
- return nullptr;
- case Stmt::SwitchStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C SwitchStmtClass");
- return nullptr;
- case Stmt::NoStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C NoStmtClass");
- return nullptr;
- case Stmt::GCCAsmStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C GCCAsmStmtClass");
- return nullptr;
- case Stmt::MSAsmStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C MSAsmStmtClass");
- return nullptr;
- case Stmt::AttributedStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C AttributedStmtClass");
- return nullptr;
- case Stmt::BreakStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C BreakStmtClass");
- return nullptr;
- case Stmt::CXXCatchStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXCatchStmtClass");
- return nullptr;
- case Stmt::CXXForRangeStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXForRangeStmtClass");
- return nullptr;
- case Stmt::CXXTryStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTryStmtClass");
- return nullptr;
- case Stmt::CapturedStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CapturedStmtClass");
- return nullptr;
- case Stmt::ContinueStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ContinueStmtClass");
- return nullptr;
- case Stmt::CoreturnStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CoreturnStmtClass");
- return nullptr;
- case Stmt::CoroutineBodyStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CoroutineBodyStmtClass");
- return nullptr;
- case Stmt::BinaryConditionalOperatorClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C BinaryConditionalOperatorClass");
- return nullptr;
- case Stmt::AddrLabelExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C AddrLabelExprClass");
- return nullptr;
- case Stmt::ArrayInitIndexExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayInitIndexExprClass");
- return nullptr;
- case Stmt::ArrayInitLoopExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayInitLoopExprClass");
- return nullptr;
- case Stmt::ArrayTypeTraitExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayTypeTraitExprClass");
- return nullptr;
- case Stmt::AsTypeExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C AsTypeExprClass");
- return nullptr;
- case Stmt::AtomicExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C AtomicExprClass");
- return nullptr;
- case Stmt::BlockExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C BlockExprClass");
- return nullptr;
- case Stmt::CXXBindTemporaryExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXBindTemporaryExprClass");
- return nullptr;
- case Stmt::CXXBoolLiteralExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXBoolLiteralExprClass");
- return nullptr;
- case Stmt::CXXConstructExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXConstructExprClass");
- return nullptr;
- case Stmt::CXXTemporaryObjectExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTemporaryObjectExprClass");
- return nullptr;
- case Stmt::CXXDefaultArgExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDefaultArgExprClass");
- return nullptr;
- case Stmt::CXXDefaultInitExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDefaultInitExprClass");
- return nullptr;
- case Stmt::CXXDeleteExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDeleteExprClass");
- return nullptr;
- case Stmt::CXXDependentScopeMemberExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDependentScopeMemberExprClass");
- return nullptr;
- case Stmt::CXXFoldExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXFoldExprClass");
- return nullptr;
- case Stmt::CXXInheritedCtorInitExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXInheritedCtorInitExprClass");
- return nullptr;
- case Stmt::CXXNewExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNewExprClass");
- return nullptr;
- case Stmt::CXXNoexceptExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNoexceptExprClass");
- return nullptr;
- case Stmt::CXXNullPtrLiteralExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNullPtrLiteralExprClass");
- return nullptr;
- case Stmt::CXXPseudoDestructorExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXPseudoDestructorExprClass");
- return nullptr;
- case Stmt::CXXScalarValueInitExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXScalarValueInitExprClass");
- return nullptr;
- case Stmt::CXXStdInitializerListExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXStdInitializerListExprClass");
- return nullptr;
- case Stmt::CXXThisExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXThisExprClass");
- return nullptr;
- case Stmt::CXXThrowExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXThrowExprClass");
- return nullptr;
- case Stmt::CXXTypeidExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTypeidExprClass");
- return nullptr;
- case Stmt::CXXUnresolvedConstructExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUnresolvedConstructExprClass");
- return nullptr;
- case Stmt::CXXUuidofExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUuidofExprClass");
- return nullptr;
- case Stmt::CUDAKernelCallExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CUDAKernelCallExprClass");
- return nullptr;
- case Stmt::CXXMemberCallExprClass:
- (void)result_used;
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXMemberCallExprClass");
- return nullptr;
- case Stmt::CXXOperatorCallExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXOperatorCallExprClass");
- return nullptr;
- case Stmt::UserDefinedLiteralClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C UserDefinedLiteralClass");
- return nullptr;
- case Stmt::CXXFunctionalCastExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXFunctionalCastExprClass");
- return nullptr;
- case Stmt::CXXConstCastExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXConstCastExprClass");
- return nullptr;
- case Stmt::CXXDynamicCastExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDynamicCastExprClass");
- return nullptr;
- case Stmt::CXXReinterpretCastExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXReinterpretCastExprClass");
- return nullptr;
- case Stmt::CXXStaticCastExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CXXStaticCastExprClass");
- return nullptr;
- case Stmt::ObjCBridgedCastExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBridgedCastExprClass");
- return nullptr;
- case Stmt::CharacterLiteralClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CharacterLiteralClass");
- return nullptr;
- case Stmt::ChooseExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ChooseExprClass");
- return nullptr;
- case Stmt::CompoundLiteralExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CompoundLiteralExprClass");
- return nullptr;
- case Stmt::ConvertVectorExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ConvertVectorExprClass");
- return nullptr;
- case Stmt::CoawaitExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CoawaitExprClass");
- return nullptr;
- case Stmt::CoyieldExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C CoyieldExprClass");
- return nullptr;
- case Stmt::DependentCoawaitExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C DependentCoawaitExprClass");
- return nullptr;
- case Stmt::DependentScopeDeclRefExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C DependentScopeDeclRefExprClass");
- return nullptr;
- case Stmt::DesignatedInitExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C DesignatedInitExprClass");
- return nullptr;
- case Stmt::DesignatedInitUpdateExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C DesignatedInitUpdateExprClass");
- return nullptr;
- case Stmt::ExprWithCleanupsClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ExprWithCleanupsClass");
- return nullptr;
- case Stmt::ExpressionTraitExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ExpressionTraitExprClass");
- return nullptr;
- case Stmt::ExtVectorElementExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ExtVectorElementExprClass");
- return nullptr;
- case Stmt::FloatingLiteralClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C FloatingLiteralClass");
- return nullptr;
- case Stmt::FunctionParmPackExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C FunctionParmPackExprClass");
- return nullptr;
- case Stmt::GNUNullExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C GNUNullExprClass");
- return nullptr;
- case Stmt::GenericSelectionExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C GenericSelectionExprClass");
- return nullptr;
- case Stmt::ImaginaryLiteralClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ImaginaryLiteralClass");
- return nullptr;
- case Stmt::ImplicitValueInitExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ImplicitValueInitExprClass");
- return nullptr;
- case Stmt::InitListExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C InitListExprClass");
- return nullptr;
- case Stmt::LambdaExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C LambdaExprClass");
- return nullptr;
- case Stmt::MSPropertyRefExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C MSPropertyRefExprClass");
- return nullptr;
- case Stmt::MSPropertySubscriptExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C MSPropertySubscriptExprClass");
- return nullptr;
- case Stmt::MaterializeTemporaryExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C MaterializeTemporaryExprClass");
- return nullptr;
- case Stmt::NoInitExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C NoInitExprClass");
- return nullptr;
- case Stmt::OMPArraySectionExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPArraySectionExprClass");
- return nullptr;
- case Stmt::ObjCArrayLiteralClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCArrayLiteralClass");
- return nullptr;
- case Stmt::ObjCAvailabilityCheckExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAvailabilityCheckExprClass");
- return nullptr;
- case Stmt::ObjCBoolLiteralExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBoolLiteralExprClass");
- return nullptr;
- case Stmt::ObjCBoxedExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBoxedExprClass");
- return nullptr;
- case Stmt::ObjCDictionaryLiteralClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCDictionaryLiteralClass");
- return nullptr;
- case Stmt::ObjCEncodeExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCEncodeExprClass");
- return nullptr;
- case Stmt::ObjCIndirectCopyRestoreExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIndirectCopyRestoreExprClass");
- return nullptr;
- case Stmt::ObjCIsaExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIsaExprClass");
- return nullptr;
- case Stmt::ObjCIvarRefExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIvarRefExprClass");
- return nullptr;
- case Stmt::ObjCMessageExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCMessageExprClass");
- return nullptr;
- case Stmt::ObjCPropertyRefExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCPropertyRefExprClass");
- return nullptr;
- case Stmt::ObjCProtocolExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCProtocolExprClass");
- return nullptr;
- case Stmt::ObjCSelectorExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCSelectorExprClass");
- return nullptr;
- case Stmt::ObjCStringLiteralClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCStringLiteralClass");
- return nullptr;
- case Stmt::ObjCSubscriptRefExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCSubscriptRefExprClass");
- return nullptr;
- case Stmt::OffsetOfExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OffsetOfExprClass");
- return nullptr;
- case Stmt::OpaqueValueExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OpaqueValueExprClass");
- return nullptr;
- case Stmt::UnresolvedLookupExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C UnresolvedLookupExprClass");
- return nullptr;
- case Stmt::UnresolvedMemberExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C UnresolvedMemberExprClass");
- return nullptr;
- case Stmt::PackExpansionExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C PackExpansionExprClass");
- return nullptr;
- case Stmt::ParenExprClass:
- return trans_expr(c, result_used, block, ((ParenExpr*)stmt)->getSubExpr(), lrvalue);
- case Stmt::ParenListExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ParenListExprClass");
- return nullptr;
- case Stmt::PredefinedExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C PredefinedExprClass");
- return nullptr;
- case Stmt::PseudoObjectExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C PseudoObjectExprClass");
- return nullptr;
- case Stmt::ShuffleVectorExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ShuffleVectorExprClass");
- return nullptr;
- case Stmt::SizeOfPackExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C SizeOfPackExprClass");
- return nullptr;
- case Stmt::StmtExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C StmtExprClass");
- return nullptr;
- case Stmt::StringLiteralClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C StringLiteralClass");
- return nullptr;
- case Stmt::SubstNonTypeTemplateParmExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C SubstNonTypeTemplateParmExprClass");
- return nullptr;
- case Stmt::SubstNonTypeTemplateParmPackExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C SubstNonTypeTemplateParmPackExprClass");
- return nullptr;
- case Stmt::TypeTraitExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C TypeTraitExprClass");
- return nullptr;
- case Stmt::TypoExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C TypoExprClass");
- return nullptr;
- case Stmt::VAArgExprClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C VAArgExprClass");
- return nullptr;
- case Stmt::ForStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ForStmtClass");
- return nullptr;
- case Stmt::GotoStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C GotoStmtClass");
- return nullptr;
- case Stmt::IndirectGotoStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C IndirectGotoStmtClass");
- return nullptr;
- case Stmt::LabelStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C LabelStmtClass");
- return nullptr;
- case Stmt::MSDependentExistsStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C MSDependentExistsStmtClass");
- return nullptr;
- case Stmt::OMPAtomicDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPAtomicDirectiveClass");
- return nullptr;
- case Stmt::OMPBarrierDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPBarrierDirectiveClass");
- return nullptr;
- case Stmt::OMPCancelDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCancelDirectiveClass");
- return nullptr;
- case Stmt::OMPCancellationPointDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCancellationPointDirectiveClass");
- return nullptr;
- case Stmt::OMPCriticalDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCriticalDirectiveClass");
- return nullptr;
- case Stmt::OMPFlushDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPFlushDirectiveClass");
- return nullptr;
- case Stmt::OMPDistributeDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeDirectiveClass");
- return nullptr;
- case Stmt::OMPDistributeParallelForDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeParallelForDirectiveClass");
- return nullptr;
- case Stmt::OMPDistributeParallelForSimdDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeParallelForSimdDirectiveClass");
- return nullptr;
- case Stmt::OMPDistributeSimdDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeSimdDirectiveClass");
- return nullptr;
- case Stmt::OMPForDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPForDirectiveClass");
- return nullptr;
- case Stmt::OMPForSimdDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPForSimdDirectiveClass");
- return nullptr;
- case Stmt::OMPParallelForDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelForDirectiveClass");
- return nullptr;
- case Stmt::OMPParallelForSimdDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelForSimdDirectiveClass");
- return nullptr;
- case Stmt::OMPSimdDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSimdDirectiveClass");
- return nullptr;
- case Stmt::OMPTargetParallelForSimdDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelForSimdDirectiveClass");
- return nullptr;
- case Stmt::OMPTargetSimdDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetSimdDirectiveClass");
- return nullptr;
- case Stmt::OMPTargetTeamsDistributeDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeDirectiveClass");
- return nullptr;
- case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeParallelForDirectiveClass");
- return nullptr;
- case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeParallelForSimdDirectiveClass");
- return nullptr;
- case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeSimdDirectiveClass");
- return nullptr;
- case Stmt::OMPTaskLoopDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskLoopDirectiveClass");
- return nullptr;
- case Stmt::OMPTaskLoopSimdDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskLoopSimdDirectiveClass");
- return nullptr;
- case Stmt::OMPTeamsDistributeDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeDirectiveClass");
- return nullptr;
- case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeParallelForDirectiveClass");
- return nullptr;
- case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeParallelForSimdDirectiveClass");
- return nullptr;
- case Stmt::OMPTeamsDistributeSimdDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeSimdDirectiveClass");
- return nullptr;
- case Stmt::OMPMasterDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPMasterDirectiveClass");
- return nullptr;
- case Stmt::OMPOrderedDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPOrderedDirectiveClass");
- return nullptr;
- case Stmt::OMPParallelDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelDirectiveClass");
- return nullptr;
- case Stmt::OMPParallelSectionsDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelSectionsDirectiveClass");
- return nullptr;
- case Stmt::OMPSectionDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSectionDirectiveClass");
- return nullptr;
- case Stmt::OMPSectionsDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSectionsDirectiveClass");
- return nullptr;
- case Stmt::OMPSingleDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSingleDirectiveClass");
- return nullptr;
- case Stmt::OMPTargetDataDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetDataDirectiveClass");
- return nullptr;
- case Stmt::OMPTargetDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetDirectiveClass");
- return nullptr;
- case Stmt::OMPTargetEnterDataDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetEnterDataDirectiveClass");
- return nullptr;
- case Stmt::OMPTargetExitDataDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetExitDataDirectiveClass");
- return nullptr;
- case Stmt::OMPTargetParallelDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelDirectiveClass");
- return nullptr;
- case Stmt::OMPTargetParallelForDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelForDirectiveClass");
- return nullptr;
- case Stmt::OMPTargetTeamsDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDirectiveClass");
- return nullptr;
- case Stmt::OMPTargetUpdateDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetUpdateDirectiveClass");
- return nullptr;
- case Stmt::OMPTaskDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskDirectiveClass");
- return nullptr;
- case Stmt::OMPTaskgroupDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskgroupDirectiveClass");
- return nullptr;
- case Stmt::OMPTaskwaitDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskwaitDirectiveClass");
- return nullptr;
- case Stmt::OMPTaskyieldDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskyieldDirectiveClass");
- return nullptr;
- case Stmt::OMPTeamsDirectiveClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDirectiveClass");
- return nullptr;
- case Stmt::ObjCAtCatchStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtCatchStmtClass");
- return nullptr;
- case Stmt::ObjCAtFinallyStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtFinallyStmtClass");
- return nullptr;
- case Stmt::ObjCAtSynchronizedStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtSynchronizedStmtClass");
- return nullptr;
- case Stmt::ObjCAtThrowStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtThrowStmtClass");
- return nullptr;
- case Stmt::ObjCAtTryStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtTryStmtClass");
- return nullptr;
- case Stmt::ObjCAutoreleasePoolStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAutoreleasePoolStmtClass");
- return nullptr;
- case Stmt::ObjCForCollectionStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCForCollectionStmtClass");
- return nullptr;
- case Stmt::SEHExceptStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C SEHExceptStmtClass");
- return nullptr;
- case Stmt::SEHFinallyStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C SEHFinallyStmtClass");
- return nullptr;
- case Stmt::SEHLeaveStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C SEHLeaveStmtClass");
- return nullptr;
- case Stmt::SEHTryStmtClass:
- emit_warning(c, stmt->getLocStart(), "TODO handle C SEHTryStmtClass");
+static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const SwitchStmt *stmt) {
+ TransScopeBlock *block_scope = trans_scope_block_create(c, parent_scope);
+
+ TransScopeSwitch *switch_scope;
+
+ const DeclStmt *var_decl_stmt = stmt->getConditionVariableDeclStmt();
+ if (var_decl_stmt == nullptr) {
+ switch_scope = trans_scope_switch_create(c, &block_scope->base);
+ } else {
+ AstNode *vars_node;
+ TransScope *var_scope = trans_stmt(c, &block_scope->base, var_decl_stmt, &vars_node);
+ if (var_scope == nullptr)
+ return nullptr;
+ if (vars_node != nullptr)
+ block_scope->node->data.block.statements.append(vars_node);
+ switch_scope = trans_scope_switch_create(c, var_scope);
+ }
+ block_scope->node->data.block.statements.append(switch_scope->switch_node);
+
+ // TODO avoid name collisions
+ Buf *end_label_name = buf_create_from_str("end");
+ switch_scope->end_label_name = end_label_name;
+
+ const Expr *cond_expr = stmt->getCond();
+ assert(cond_expr != nullptr);
+
+ AstNode *expr_node = trans_expr(c, ResultUsedYes, &block_scope->base, cond_expr, TransRValue);
+ if (expr_node == nullptr)
+ return nullptr;
+ switch_scope->switch_node->data.switch_expr.expr = expr_node;
+
+ AstNode *body_node;
+ const Stmt *body_stmt = stmt->getBody();
+ if (body_stmt->getStmtClass() == Stmt::CompoundStmtClass) {
+ if (trans_compound_stmt_inline(c, &switch_scope->base, (const CompoundStmt *)body_stmt,
+ block_scope->node, nullptr))
+ {
+ return nullptr;
+ }
+ } else {
+ TransScope *body_scope = trans_stmt(c, &switch_scope->base, body_stmt, &body_node);
+ if (body_scope == nullptr)
+ return nullptr;
+ if (body_node != nullptr)
+ block_scope->node->data.block.statements.append(body_node);
+ }
+
+ if (!switch_scope->found_default && !stmt->isAllEnumCasesCovered()) {
+ AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng);
+ prong_node->data.switch_prong.expr = trans_create_node_goto(c, end_label_name);
+ switch_scope->switch_node->data.switch_expr.prongs.append(prong_node);
+ }
+
+ // This is necessary if the last switch case "falls through" the end of the switch block
+ block_scope->node->data.block.statements.append(trans_create_node_goto(c, end_label_name));
+
+ block_scope->node->data.block.statements.append(trans_create_node_label(c, end_label_name));
+
+ return block_scope->node;
+}
+
+static int trans_switch_case(Context *c, TransScope *parent_scope, const CaseStmt *stmt, AstNode **out_node,
+ TransScope **out_scope)
+{
+ *out_node = nullptr;
+
+ if (stmt->getRHS() != nullptr) {
+ emit_warning(c, stmt->getLocStart(), "TODO support GNU switch case a ... b extension");
+ return ErrorUnexpected;
+ }
+
+ TransScopeSwitch *switch_scope = trans_scope_switch_find(parent_scope);
+ assert(switch_scope != nullptr);
+
+ Buf *label_name = buf_sprintf("case_%" PRIu32, switch_scope->case_index);
+ switch_scope->case_index += 1;
+
+ {
+ // Add the prong
+ AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng);
+ AstNode *item_node = trans_expr(c, ResultUsedYes, &switch_scope->base, stmt->getLHS(), TransRValue);
+ if (item_node == nullptr)
+ return ErrorUnexpected;
+ prong_node->data.switch_prong.items.append(item_node);
+
+ prong_node->data.switch_prong.expr = trans_create_node_goto(c, label_name);
+
+ switch_scope->switch_node->data.switch_expr.prongs.append(prong_node);
+ }
+
+ TransScopeBlock *scope_block = trans_scope_block_find(parent_scope);
+ scope_block->node->data.block.statements.append(trans_create_node_label(c, label_name));
+
+ AstNode *sub_stmt_node;
+ TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node);
+ if (new_scope == nullptr)
+ return ErrorUnexpected;
+ if (sub_stmt_node != nullptr)
+ scope_block->node->data.block.statements.append(sub_stmt_node);
+
+ *out_scope = new_scope;
+ return ErrorNone;
+}
+
+static int trans_switch_default(Context *c, TransScope *parent_scope, const DefaultStmt *stmt, AstNode **out_node,
+ TransScope **out_scope)
+{
+ *out_node = nullptr;
+
+ TransScopeSwitch *switch_scope = trans_scope_switch_find(parent_scope);
+ assert(switch_scope != nullptr);
+
+ Buf *label_name = buf_sprintf("default");
+
+ {
+ // Add the prong
+ AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng);
+
+ prong_node->data.switch_prong.expr = trans_create_node_goto(c, label_name);
+
+ switch_scope->switch_node->data.switch_expr.prongs.append(prong_node);
+ switch_scope->found_default = true;
+ }
+
+ TransScopeBlock *scope_block = trans_scope_block_find(parent_scope);
+ scope_block->node->data.block.statements.append(trans_create_node_label(c, label_name));
+
+
+ AstNode *sub_stmt_node;
+ TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node);
+ if (new_scope == nullptr)
+ return ErrorUnexpected;
+ if (sub_stmt_node != nullptr)
+ scope_block->node->data.block.statements.append(sub_stmt_node);
+
+ *out_scope = new_scope;
+ return ErrorNone;
+}
+
+static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForStmt *stmt) {
+ AstNode *loop_block_node;
+ TransScopeWhile *while_scope;
+ TransScope *cond_scope;
+ const Stmt *init_stmt = stmt->getInit();
+ if (init_stmt == nullptr) {
+ while_scope = trans_scope_while_create(c, parent_scope);
+ loop_block_node = while_scope->node;
+ cond_scope = parent_scope;
+ } else {
+ TransScopeBlock *child_scope = trans_scope_block_create(c, parent_scope);
+ loop_block_node = child_scope->node;
+
+ AstNode *vars_node;
+ cond_scope = trans_stmt(c, &child_scope->base, init_stmt, &vars_node);
+ if (cond_scope == nullptr)
+ return nullptr;
+ if (vars_node != nullptr)
+ child_scope->node->data.block.statements.append(vars_node);
+
+ while_scope = trans_scope_while_create(c, cond_scope);
+
+ child_scope->node->data.block.statements.append(while_scope->node);
+ }
+
+ const Stmt *cond_stmt = stmt->getCond();
+ if (cond_stmt == nullptr) {
+ while_scope->node->data.while_expr.condition = trans_create_node_bool(c, true);
+ } else {
+ TransScope *end_cond_scope = trans_stmt(c, cond_scope, cond_stmt,
+ &while_scope->node->data.while_expr.condition);
+ if (end_cond_scope == nullptr)
+ return nullptr;
+ }
+
+ const Stmt *inc_stmt = stmt->getInc();
+ if (inc_stmt != nullptr) {
+ AstNode *inc_node;
+ TransScope *inc_scope = trans_stmt(c, cond_scope, inc_stmt, &inc_node);
+ if (inc_scope == nullptr)
+ return nullptr;
+ while_scope->node->data.while_expr.continue_expr = inc_node;
+ }
+
+ AstNode *body_statement;
+ TransScope *body_scope = trans_stmt(c, &while_scope->base, stmt->getBody(), &body_statement);
+ if (body_scope == nullptr)
+ return nullptr;
+ while_scope->node->data.while_expr.body = body_statement;
+
+ return loop_block_node;
+}
+
+static AstNode *trans_string_literal(Context *c, TransScope *scope, const StringLiteral *stmt) {
+ switch (stmt->getKind()) {
+ case StringLiteral::Ascii:
+ case StringLiteral::UTF8:
+ return trans_create_node_str_lit_c(c, string_ref_to_buf(stmt->getString()));
+ case StringLiteral::UTF16:
+ emit_warning(c, stmt->getLocStart(), "TODO support UTF16 string literals");
+ return nullptr;
+ case StringLiteral::UTF32:
+ emit_warning(c, stmt->getLocStart(), "TODO support UTF32 string literals");
+ return nullptr;
+ case StringLiteral::Wide:
+ emit_warning(c, stmt->getLocStart(), "TODO support wide string literals");
return nullptr;
}
zig_unreachable();
}
+static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt *stmt) {
+ TransScope *cur_scope = scope;
+ while (cur_scope != nullptr) {
+ if (cur_scope->id == TransScopeIdWhile) {
+ return trans_create_node(c, NodeTypeBreak);
+ } else if (cur_scope->id == TransScopeIdSwitch) {
+ TransScopeSwitch *switch_scope = (TransScopeSwitch *)cur_scope;
+ return trans_create_node_goto(c, switch_scope->end_label_name);
+ }
+ cur_scope = cur_scope->parent;
+ }
+ zig_unreachable();
+}
+
+static AstNode *trans_continue_stmt(Context *c, TransScope *scope, const ContinueStmt *stmt) {
+ return trans_create_node(c, NodeTypeContinue);
+}
+
+static int wrap_stmt(AstNode **out_node, TransScope **out_scope, TransScope *in_scope, AstNode *result_node) {
+ if (result_node == nullptr)
+ return ErrorUnexpected;
+ *out_node = result_node;
+ if (out_scope != nullptr)
+ *out_scope = in_scope;
+ return ErrorNone;
+}
+
+static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,
+ ResultUsed result_used, TransLRValue lrvalue,
+ AstNode **out_node, TransScope **out_child_scope,
+ TransScope **out_node_scope)
+{
+ Stmt::StmtClass sc = stmt->getStmtClass();
+ switch (sc) {
+ case Stmt::ReturnStmtClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_return_stmt(c, scope, (const ReturnStmt *)stmt));
+ case Stmt::CompoundStmtClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_compound_stmt(c, scope, (const CompoundStmt *)stmt, out_node_scope));
+ case Stmt::IntegerLiteralClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_integer_literal(c, (const IntegerLiteral *)stmt));
+ case Stmt::ConditionalOperatorClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_conditional_operator(c, result_used, scope, (const ConditionalOperator *)stmt));
+ case Stmt::BinaryOperatorClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_binary_operator(c, result_used, scope, (const BinaryOperator *)stmt));
+ case Stmt::CompoundAssignOperatorClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_compound_assign_operator(c, result_used, scope, (const CompoundAssignOperator *)stmt));
+ case Stmt::ImplicitCastExprClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_implicit_cast_expr(c, scope, (const ImplicitCastExpr *)stmt));
+ case Stmt::DeclRefExprClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_decl_ref_expr(c, scope, (const DeclRefExpr *)stmt, lrvalue));
+ case Stmt::UnaryOperatorClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_unary_operator(c, result_used, scope, (const UnaryOperator *)stmt));
+ case Stmt::DeclStmtClass:
+ return trans_local_declaration(c, scope, (const DeclStmt *)stmt, out_node, out_child_scope);
+ case Stmt::WhileStmtClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_while_loop(c, scope, (const WhileStmt *)stmt));
+ case Stmt::IfStmtClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_if_statement(c, scope, (const IfStmt *)stmt));
+ case Stmt::CallExprClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_call_expr(c, result_used, scope, (const CallExpr *)stmt));
+ case Stmt::NullStmtClass:
+ *out_node = nullptr;
+ *out_child_scope = scope;
+ return ErrorNone;
+ case Stmt::MemberExprClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_member_expr(c, scope, (const MemberExpr *)stmt));
+ case Stmt::ArraySubscriptExprClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_array_subscript_expr(c, scope, (const ArraySubscriptExpr *)stmt));
+ case Stmt::CStyleCastExprClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_c_style_cast_expr(c, result_used, scope, (const CStyleCastExpr *)stmt, lrvalue));
+ case Stmt::UnaryExprOrTypeTraitExprClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_unary_expr_or_type_trait_expr(c, scope, (const UnaryExprOrTypeTraitExpr *)stmt));
+ case Stmt::DoStmtClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_do_loop(c, scope, (const DoStmt *)stmt));
+ case Stmt::ForStmtClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_for_loop(c, scope, (const ForStmt *)stmt));
+ case Stmt::StringLiteralClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_string_literal(c, scope, (const StringLiteral *)stmt));
+ case Stmt::BreakStmtClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_break_stmt(c, scope, (const BreakStmt *)stmt));
+ case Stmt::ContinueStmtClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_continue_stmt(c, scope, (const ContinueStmt *)stmt));
+ case Stmt::ParenExprClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_expr(c, result_used, scope, ((const ParenExpr*)stmt)->getSubExpr(), lrvalue));
+ case Stmt::SwitchStmtClass:
+ return wrap_stmt(out_node, out_child_scope, scope,
+ trans_switch_stmt(c, scope, (const SwitchStmt *)stmt));
+ case Stmt::CaseStmtClass:
+ return trans_switch_case(c, scope, (const CaseStmt *)stmt, out_node, out_child_scope);
+ case Stmt::DefaultStmtClass:
+ return trans_switch_default(c, scope, (const DefaultStmt *)stmt, out_node, out_child_scope);
+ case Stmt::NoStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C NoStmtClass");
+ return ErrorUnexpected;
+ case Stmt::GCCAsmStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C GCCAsmStmtClass");
+ return ErrorUnexpected;
+ case Stmt::MSAsmStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C MSAsmStmtClass");
+ return ErrorUnexpected;
+ case Stmt::AttributedStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C AttributedStmtClass");
+ return ErrorUnexpected;
+ case Stmt::CXXCatchStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXCatchStmtClass");
+ return ErrorUnexpected;
+ case Stmt::CXXForRangeStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXForRangeStmtClass");
+ return ErrorUnexpected;
+ case Stmt::CXXTryStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTryStmtClass");
+ return ErrorUnexpected;
+ case Stmt::CapturedStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CapturedStmtClass");
+ return ErrorUnexpected;
+ case Stmt::CoreturnStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CoreturnStmtClass");
+ return ErrorUnexpected;
+ case Stmt::CoroutineBodyStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CoroutineBodyStmtClass");
+ return ErrorUnexpected;
+ case Stmt::BinaryConditionalOperatorClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C BinaryConditionalOperatorClass");
+ return ErrorUnexpected;
+ case Stmt::AddrLabelExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C AddrLabelExprClass");
+ return ErrorUnexpected;
+ case Stmt::ArrayInitIndexExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayInitIndexExprClass");
+ return ErrorUnexpected;
+ case Stmt::ArrayInitLoopExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayInitLoopExprClass");
+ return ErrorUnexpected;
+ case Stmt::ArrayTypeTraitExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayTypeTraitExprClass");
+ return ErrorUnexpected;
+ case Stmt::AsTypeExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C AsTypeExprClass");
+ return ErrorUnexpected;
+ case Stmt::AtomicExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C AtomicExprClass");
+ return ErrorUnexpected;
+ case Stmt::BlockExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C BlockExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXBindTemporaryExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXBindTemporaryExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXBoolLiteralExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXBoolLiteralExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXConstructExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXConstructExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXTemporaryObjectExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTemporaryObjectExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXDefaultArgExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDefaultArgExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXDefaultInitExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDefaultInitExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXDeleteExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDeleteExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXDependentScopeMemberExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDependentScopeMemberExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXFoldExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXFoldExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXInheritedCtorInitExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXInheritedCtorInitExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXNewExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNewExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXNoexceptExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNoexceptExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXNullPtrLiteralExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNullPtrLiteralExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXPseudoDestructorExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXPseudoDestructorExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXScalarValueInitExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXScalarValueInitExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXStdInitializerListExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXStdInitializerListExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXThisExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXThisExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXThrowExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXThrowExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXTypeidExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTypeidExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXUnresolvedConstructExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUnresolvedConstructExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXUuidofExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUuidofExprClass");
+ return ErrorUnexpected;
+ case Stmt::CUDAKernelCallExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CUDAKernelCallExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXMemberCallExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXMemberCallExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXOperatorCallExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXOperatorCallExprClass");
+ return ErrorUnexpected;
+ case Stmt::UserDefinedLiteralClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C UserDefinedLiteralClass");
+ return ErrorUnexpected;
+ case Stmt::CXXFunctionalCastExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXFunctionalCastExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXConstCastExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXConstCastExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXDynamicCastExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDynamicCastExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXReinterpretCastExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXReinterpretCastExprClass");
+ return ErrorUnexpected;
+ case Stmt::CXXStaticCastExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CXXStaticCastExprClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCBridgedCastExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBridgedCastExprClass");
+ return ErrorUnexpected;
+ case Stmt::CharacterLiteralClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CharacterLiteralClass");
+ return ErrorUnexpected;
+ case Stmt::ChooseExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ChooseExprClass");
+ return ErrorUnexpected;
+ case Stmt::CompoundLiteralExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CompoundLiteralExprClass");
+ return ErrorUnexpected;
+ case Stmt::ConvertVectorExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ConvertVectorExprClass");
+ return ErrorUnexpected;
+ case Stmt::CoawaitExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CoawaitExprClass");
+ return ErrorUnexpected;
+ case Stmt::CoyieldExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C CoyieldExprClass");
+ return ErrorUnexpected;
+ case Stmt::DependentCoawaitExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C DependentCoawaitExprClass");
+ return ErrorUnexpected;
+ case Stmt::DependentScopeDeclRefExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C DependentScopeDeclRefExprClass");
+ return ErrorUnexpected;
+ case Stmt::DesignatedInitExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C DesignatedInitExprClass");
+ return ErrorUnexpected;
+ case Stmt::DesignatedInitUpdateExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C DesignatedInitUpdateExprClass");
+ return ErrorUnexpected;
+ case Stmt::ExprWithCleanupsClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ExprWithCleanupsClass");
+ return ErrorUnexpected;
+ case Stmt::ExpressionTraitExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ExpressionTraitExprClass");
+ return ErrorUnexpected;
+ case Stmt::ExtVectorElementExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ExtVectorElementExprClass");
+ return ErrorUnexpected;
+ case Stmt::FloatingLiteralClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C FloatingLiteralClass");
+ return ErrorUnexpected;
+ case Stmt::FunctionParmPackExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C FunctionParmPackExprClass");
+ return ErrorUnexpected;
+ case Stmt::GNUNullExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C GNUNullExprClass");
+ return ErrorUnexpected;
+ case Stmt::GenericSelectionExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C GenericSelectionExprClass");
+ return ErrorUnexpected;
+ case Stmt::ImaginaryLiteralClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ImaginaryLiteralClass");
+ return ErrorUnexpected;
+ case Stmt::ImplicitValueInitExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ImplicitValueInitExprClass");
+ return ErrorUnexpected;
+ case Stmt::InitListExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C InitListExprClass");
+ return ErrorUnexpected;
+ case Stmt::LambdaExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C LambdaExprClass");
+ return ErrorUnexpected;
+ case Stmt::MSPropertyRefExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C MSPropertyRefExprClass");
+ return ErrorUnexpected;
+ case Stmt::MSPropertySubscriptExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C MSPropertySubscriptExprClass");
+ return ErrorUnexpected;
+ case Stmt::MaterializeTemporaryExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C MaterializeTemporaryExprClass");
+ return ErrorUnexpected;
+ case Stmt::NoInitExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C NoInitExprClass");
+ return ErrorUnexpected;
+ case Stmt::OMPArraySectionExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPArraySectionExprClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCArrayLiteralClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCArrayLiteralClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCAvailabilityCheckExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAvailabilityCheckExprClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCBoolLiteralExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBoolLiteralExprClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCBoxedExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBoxedExprClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCDictionaryLiteralClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCDictionaryLiteralClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCEncodeExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCEncodeExprClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCIndirectCopyRestoreExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIndirectCopyRestoreExprClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCIsaExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIsaExprClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCIvarRefExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIvarRefExprClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCMessageExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCMessageExprClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCPropertyRefExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCPropertyRefExprClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCProtocolExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCProtocolExprClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCSelectorExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCSelectorExprClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCStringLiteralClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCStringLiteralClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCSubscriptRefExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCSubscriptRefExprClass");
+ return ErrorUnexpected;
+ case Stmt::OffsetOfExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OffsetOfExprClass");
+ return ErrorUnexpected;
+ case Stmt::OpaqueValueExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OpaqueValueExprClass");
+ return ErrorUnexpected;
+ case Stmt::UnresolvedLookupExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C UnresolvedLookupExprClass");
+ return ErrorUnexpected;
+ case Stmt::UnresolvedMemberExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C UnresolvedMemberExprClass");
+ return ErrorUnexpected;
+ case Stmt::PackExpansionExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C PackExpansionExprClass");
+ return ErrorUnexpected;
+ case Stmt::ParenListExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ParenListExprClass");
+ return ErrorUnexpected;
+ case Stmt::PredefinedExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C PredefinedExprClass");
+ return ErrorUnexpected;
+ case Stmt::PseudoObjectExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C PseudoObjectExprClass");
+ return ErrorUnexpected;
+ case Stmt::ShuffleVectorExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ShuffleVectorExprClass");
+ return ErrorUnexpected;
+ case Stmt::SizeOfPackExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C SizeOfPackExprClass");
+ return ErrorUnexpected;
+ case Stmt::StmtExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C StmtExprClass");
+ return ErrorUnexpected;
+ case Stmt::SubstNonTypeTemplateParmExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C SubstNonTypeTemplateParmExprClass");
+ return ErrorUnexpected;
+ case Stmt::SubstNonTypeTemplateParmPackExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C SubstNonTypeTemplateParmPackExprClass");
+ return ErrorUnexpected;
+ case Stmt::TypeTraitExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C TypeTraitExprClass");
+ return ErrorUnexpected;
+ case Stmt::TypoExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C TypoExprClass");
+ return ErrorUnexpected;
+ case Stmt::VAArgExprClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C VAArgExprClass");
+ return ErrorUnexpected;
+ case Stmt::GotoStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C GotoStmtClass");
+ return ErrorUnexpected;
+ case Stmt::IndirectGotoStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C IndirectGotoStmtClass");
+ return ErrorUnexpected;
+ case Stmt::LabelStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C LabelStmtClass");
+ return ErrorUnexpected;
+ case Stmt::MSDependentExistsStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C MSDependentExistsStmtClass");
+ return ErrorUnexpected;
+ case Stmt::OMPAtomicDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPAtomicDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPBarrierDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPBarrierDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPCancelDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCancelDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPCancellationPointDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCancellationPointDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPCriticalDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCriticalDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPFlushDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPFlushDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPDistributeDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPDistributeParallelForDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeParallelForDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPDistributeParallelForSimdDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeParallelForSimdDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPDistributeSimdDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeSimdDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPForDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPForDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPForSimdDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPForSimdDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPParallelForDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelForDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPParallelForSimdDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelForSimdDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPSimdDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSimdDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTargetParallelForSimdDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelForSimdDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTargetSimdDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetSimdDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTargetTeamsDistributeDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeParallelForDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeParallelForSimdDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeSimdDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTaskLoopDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskLoopDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTaskLoopSimdDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskLoopSimdDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTeamsDistributeDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeParallelForDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeParallelForSimdDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTeamsDistributeSimdDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeSimdDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPMasterDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPMasterDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPOrderedDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPOrderedDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPParallelDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPParallelSectionsDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelSectionsDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPSectionDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSectionDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPSectionsDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSectionsDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPSingleDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSingleDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTargetDataDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetDataDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTargetDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTargetEnterDataDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetEnterDataDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTargetExitDataDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetExitDataDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTargetParallelDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTargetParallelForDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelForDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTargetTeamsDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTargetUpdateDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetUpdateDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTaskDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTaskgroupDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskgroupDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTaskwaitDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskwaitDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTaskyieldDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskyieldDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::OMPTeamsDirectiveClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDirectiveClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCAtCatchStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtCatchStmtClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCAtFinallyStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtFinallyStmtClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCAtSynchronizedStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtSynchronizedStmtClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCAtThrowStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtThrowStmtClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCAtTryStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtTryStmtClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCAutoreleasePoolStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAutoreleasePoolStmtClass");
+ return ErrorUnexpected;
+ case Stmt::ObjCForCollectionStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCForCollectionStmtClass");
+ return ErrorUnexpected;
+ case Stmt::SEHExceptStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C SEHExceptStmtClass");
+ return ErrorUnexpected;
+ case Stmt::SEHFinallyStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C SEHFinallyStmtClass");
+ return ErrorUnexpected;
+ case Stmt::SEHLeaveStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C SEHLeaveStmtClass");
+ return ErrorUnexpected;
+ case Stmt::SEHTryStmtClass:
+ emit_warning(c, stmt->getLocStart(), "TODO handle C SEHTryStmtClass");
+ return ErrorUnexpected;
+ }
+ zig_unreachable();
+}
+
+// Returns null if there was an error
+static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr,
+ TransLRValue lrval)
+{
+ AstNode *result_node;
+ TransScope *result_scope;
+ if (trans_stmt_extra(c, scope, expr, result_used, lrval, &result_node, &result_scope, nullptr)) {
+ return nullptr;
+ }
+ return result_node;
+}
+
+// Statements have no result and no concept of L or R value.
+// Returns child scope, or null if there was an error
+static TransScope *trans_stmt(Context *c, TransScope *scope, const Stmt *stmt, AstNode **out_node) {
+ TransScope *child_scope;
+ if (trans_stmt_extra(c, scope, stmt, ResultUsedNo, TransRValue, out_node, &child_scope, nullptr)) {
+ return nullptr;
+ }
+ return child_scope;
+}
+
static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
Buf *fn_name = buf_create_from_str(decl_name(fn_decl));
@@ -2677,10 +3237,13 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
return;
}
+ TransScope *scope = &c->global_scope->base;
+
for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) {
AstNode *param_node = proto_node->data.fn_proto.params.at(i);
const ParmVarDecl *param = fn_decl->getParamDecl(i);
const char *name = decl_name(param);
+
Buf *proto_param_name;
if (strlen(name) != 0) {
proto_param_name = buf_create_from_str(name);
@@ -2690,7 +3253,11 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
proto_param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i);
}
}
- param_node->data.param_decl.name = proto_param_name;
+
+ TransScopeVar *scope_var = trans_scope_var_create(c, scope, proto_param_name);
+ scope = &scope_var->base;
+
+ param_node->data.param_decl.name = scope_var->zig_name;
}
if (!fn_decl->hasBody()) {
@@ -2702,16 +3269,17 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
// actual function definition with body
c->ptr_params.clear();
Stmt *body = fn_decl->getBody();
- AstNode *actual_body_node = trans_stmt(c, false, nullptr, body, TransRValue);
- assert(actual_body_node != skip_add_to_block_node);
- if (actual_body_node == nullptr) {
+ AstNode *actual_body_node;
+ TransScope *result_scope = trans_stmt(c, scope, body, &actual_body_node);
+ if (result_scope == nullptr) {
emit_warning(c, fn_decl->getLocation(), "unable to translate function");
return;
}
+ assert(actual_body_node != nullptr);
+ assert(actual_body_node->type == NodeTypeBlock);
// it worked
- assert(actual_body_node->type == NodeTypeBlock);
AstNode *body_node_with_param_inits = trans_create_node(c, NodeTypeBlock);
for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) {
@@ -2948,16 +3516,24 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) {
}
const char *raw_name = decl_name(record_decl);
-
- if (!record_decl->isStruct()) {
- emit_warning(c, record_decl->getLocation(), "skipping record %s, not a struct", raw_name);
+ const char *container_kind_name;
+ ContainerKind container_kind;
+ if (record_decl->isUnion()) {
+ container_kind_name = "union";
+ container_kind = ContainerKindUnion;
+ } else if (record_decl->isStruct()) {
+ container_kind_name = "struct";
+ container_kind = ContainerKindStruct;
+ } else {
+ emit_warning(c, record_decl->getLocation(), "skipping record %s, not a struct or union", raw_name);
c->decl_table.put(record_decl->getCanonicalDecl(), nullptr);
return nullptr;
}
bool is_anonymous = record_decl->isAnonymousStructOrUnion() || raw_name[0] == 0;
Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name);
- Buf *full_type_name = (bare_name == nullptr) ? nullptr : buf_sprintf("struct_%s", buf_ptr(bare_name));
+ Buf *full_type_name = (bare_name == nullptr) ?
+ nullptr : buf_sprintf("%s_%s", container_kind_name, buf_ptr(bare_name));
RecordDecl *record_def = record_decl->getDefinition();
if (record_def == nullptr) {
@@ -2973,14 +3549,15 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) {
const FieldDecl *field_decl = *it;
if (field_decl->isBitField()) {
- emit_warning(c, field_decl->getLocation(), "struct %s demoted to opaque type - has bitfield",
+ emit_warning(c, field_decl->getLocation(), "%s %s demoted to opaque type - has bitfield",
+ container_kind_name,
is_anonymous ? "(anon)" : buf_ptr(bare_name));
return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name);
}
}
AstNode *struct_node = trans_create_node(c, NodeTypeContainerDecl);
- struct_node->data.container_decl.kind = ContainerKindStruct;
+ struct_node->data.container_decl.kind = container_kind;
struct_node->data.container_decl.layout = ContainerLayoutExtern;
// TODO handle attribute packed
@@ -3007,7 +3584,8 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) {
if (field_node->data.struct_field.type == nullptr) {
emit_warning(c, field_decl->getLocation(),
- "struct %s demoted to opaque type - unresolved type",
+ "%s %s demoted to opaque type - unresolved type",
+ container_kind_name,
is_anonymous ? "(anon)" : buf_ptr(bare_name));
return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name);
@@ -3025,6 +3603,93 @@ static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) {
}
}
+static AstNode *trans_ap_value(Context *c, APValue *ap_value, QualType qt, const SourceLocation &source_loc) {
+ switch (ap_value->getKind()) {
+ case APValue::Int:
+ return trans_create_node_apint(c, ap_value->getInt());
+ case APValue::Uninitialized:
+ return trans_create_node(c, NodeTypeUndefinedLiteral);
+ case APValue::Array: {
+ emit_warning(c, source_loc, "TODO add a test case for this code");
+
+ unsigned init_count = ap_value->getArrayInitializedElts();
+ unsigned all_count = ap_value->getArraySize();
+ unsigned leftover_count = all_count - init_count;
+ AstNode *init_node = trans_create_node(c, NodeTypeContainerInitExpr);
+ AstNode *arr_type_node = trans_qual_type(c, qt, source_loc);
+ init_node->data.container_init_expr.type = arr_type_node;
+ init_node->data.container_init_expr.kind = ContainerInitKindArray;
+
+ QualType child_qt = qt.getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();
+
+ for (size_t i = 0; i < init_count; i += 1) {
+ APValue &elem_ap_val = ap_value->getArrayInitializedElt(i);
+ AstNode *elem_node = trans_ap_value(c, &elem_ap_val, child_qt, source_loc);
+ if (elem_node == nullptr)
+ return nullptr;
+ init_node->data.container_init_expr.entries.append(elem_node);
+ }
+ if (leftover_count == 0) {
+ return init_node;
+ }
+
+ APValue &filler_ap_val = ap_value->getArrayFiller();
+ AstNode *filler_node = trans_ap_value(c, &filler_ap_val, child_qt, source_loc);
+ if (filler_node == nullptr)
+ return nullptr;
+
+ AstNode *filler_arr_1 = trans_create_node(c, NodeTypeContainerInitExpr);
+ init_node->data.container_init_expr.type = arr_type_node;
+ init_node->data.container_init_expr.kind = ContainerInitKindArray;
+ init_node->data.container_init_expr.entries.append(filler_node);
+
+ AstNode *rhs_node;
+ if (leftover_count == 1) {
+ rhs_node = filler_arr_1;
+ } else {
+ AstNode *amt_node = trans_create_node_unsigned(c, leftover_count);
+ rhs_node = trans_create_node_bin_op(c, filler_arr_1, BinOpTypeArrayMult, amt_node);
+ }
+
+ return trans_create_node_bin_op(c, init_node, BinOpTypeArrayCat, rhs_node);
+ }
+ case APValue::LValue: {
+ const APValue::LValueBase lval_base = ap_value->getLValueBase();
+ if (const Expr *expr = lval_base.dyn_cast()) {
+ return trans_expr(c, ResultUsedYes, &c->global_scope->base, expr, TransRValue);
+ }
+ //const ValueDecl *value_decl = lval_base.get();
+ emit_warning(c, source_loc, "TODO handle initializer LValue ValueDecl");
+ return nullptr;
+ }
+ case APValue::Float:
+ emit_warning(c, source_loc, "unsupported initializer value kind: Float");
+ return nullptr;
+ case APValue::ComplexInt:
+ emit_warning(c, source_loc, "unsupported initializer value kind: ComplexInt");
+ return nullptr;
+ case APValue::ComplexFloat:
+ emit_warning(c, source_loc, "unsupported initializer value kind: ComplexFloat");
+ return nullptr;
+ case APValue::Vector:
+ emit_warning(c, source_loc, "unsupported initializer value kind: Vector");
+ return nullptr;
+ case APValue::Struct:
+ emit_warning(c, source_loc, "unsupported initializer value kind: Struct");
+ return nullptr;
+ case APValue::Union:
+ emit_warning(c, source_loc, "unsupported initializer value kind: Union");
+ return nullptr;
+ case APValue::MemberPointer:
+ emit_warning(c, source_loc, "unsupported initializer value kind: MemberPointer");
+ return nullptr;
+ case APValue::AddrLabelDiff:
+ emit_warning(c, source_loc, "unsupported initializer value kind: AddrLabelDiff");
+ return nullptr;
+ }
+ zig_unreachable();
+}
+
static void visit_var_decl(Context *c, const VarDecl *var_decl) {
Buf *name = buf_create_from_str(decl_name(var_decl));
@@ -3061,27 +3726,9 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) {
"ignoring variable '%s' - unable to evaluate initializer", buf_ptr(name));
return;
}
- switch (ap_value->getKind()) {
- case APValue::Int:
- init_node = trans_create_node_apint(c, ap_value->getInt());
- break;
- case APValue::Uninitialized:
- init_node = trans_create_node(c, NodeTypeUndefinedLiteral);
- break;
- case APValue::Float:
- case APValue::ComplexInt:
- case APValue::ComplexFloat:
- case APValue::LValue:
- case APValue::Vector:
- case APValue::Array:
- case APValue::Struct:
- case APValue::Union:
- case APValue::MemberPointer:
- case APValue::AddrLabelDiff:
- emit_warning(c, var_decl->getLocation(),
- "ignoring variable '%s' - unrecognized initializer value kind", buf_ptr(name));
- return;
- }
+ init_node = trans_ap_value(c, ap_value, qt, var_decl->getLocation());
+ if (init_node == nullptr)
+ return;
} else {
init_node = trans_create_node(c, NodeTypeUndefinedLiteral);
}
@@ -3129,20 +3776,183 @@ static bool decl_visitor(void *context, const Decl *decl) {
return true;
}
-static bool name_exists(Context *c, Buf *name) {
+static bool name_exists_global(Context *c, Buf *name) {
return get_global(c, name) != nullptr;
}
+static bool name_exists_scope(Context *c, Buf *name, TransScope *scope) {
+ while (scope != nullptr) {
+ if (scope->id == TransScopeIdVar) {
+ TransScopeVar *var_scope = (TransScopeVar *)scope;
+ if (buf_eql_buf(name, var_scope->zig_name)) {
+ return true;
+ }
+ }
+ scope = scope->parent;
+ }
+ return name_exists_global(c, name);
+}
+
+static Buf *get_unique_name(Context *c, Buf *name, TransScope *scope) {
+ Buf *proposed_name = name;
+ int count = 0;
+ while (name_exists_scope(c, proposed_name, scope)) {
+ if (proposed_name == name) {
+ proposed_name = buf_alloc();
+ }
+ buf_resize(proposed_name, 0);
+ buf_appendf(proposed_name, "%s_%d", buf_ptr(name), count);
+ count += 1;
+ }
+ return proposed_name;
+}
+
+static TransScopeRoot *trans_scope_root_create(Context *c) {
+ TransScopeRoot *result = allocate(1);
+ result->base.id = TransScopeIdRoot;
+ return result;
+}
+
+static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope) {
+ TransScopeWhile *result = allocate(1);
+ result->base.id = TransScopeIdWhile;
+ result->base.parent = parent_scope;
+ result->node = trans_create_node(c, NodeTypeWhileExpr);
+ return result;
+}
+
+static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope) {
+ TransScopeBlock *result = allocate(1);
+ result->base.id = TransScopeIdBlock;
+ result->base.parent = parent_scope;
+ result->node = trans_create_node(c, NodeTypeBlock);
+ return result;
+}
+
+static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name) {
+ TransScopeVar *result = allocate(1);
+ result->base.id = TransScopeIdVar;
+ result->base.parent = parent_scope;
+ result->c_name = wanted_name;
+ result->zig_name = get_unique_name(c, wanted_name, parent_scope);
+ return result;
+}
+
+static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope) {
+ TransScopeSwitch *result = allocate(1);
+ result->base.id = TransScopeIdSwitch;
+ result->base.parent = parent_scope;
+ result->switch_node = trans_create_node(c, NodeTypeSwitchExpr);
+ return result;
+}
+
+static TransScopeBlock *trans_scope_block_find(TransScope *scope) {
+ while (scope != nullptr) {
+ if (scope->id == TransScopeIdBlock) {
+ return (TransScopeBlock *)scope;
+ }
+ scope = scope->parent;
+ }
+ return nullptr;
+}
+
+static TransScopeSwitch *trans_scope_switch_find(TransScope *scope) {
+ while (scope != nullptr) {
+ if (scope->id == TransScopeIdSwitch) {
+ return (TransScopeSwitch *)scope;
+ }
+ scope = scope->parent;
+ }
+ return nullptr;
+}
+
static void render_aliases(Context *c) {
for (size_t i = 0; i < c->aliases.length; i += 1) {
Alias *alias = &c->aliases.at(i);
- if (name_exists(c, alias->new_name))
+ if (name_exists_global(c, alias->new_name))
continue;
add_global_var(c, alias->new_name, trans_create_node_symbol(c, alias->canon_name));
}
}
+static AstNode *trans_lookup_ast_container_typeof(Context *c, AstNode *ref_node);
+
+static AstNode *trans_lookup_ast_container(Context *c, AstNode *type_node) {
+ if (type_node == nullptr) {
+ return nullptr;
+ } else if (type_node->type == NodeTypeContainerDecl) {
+ return type_node;
+ } else if (type_node->type == NodeTypePrefixOpExpr) {
+ return type_node;
+ } else if (type_node->type == NodeTypeSymbol) {
+ AstNode *existing_node = get_global(c, type_node->data.symbol_expr.symbol);
+ if (existing_node == nullptr)
+ return nullptr;
+ if (existing_node->type != NodeTypeVariableDeclaration)
+ return nullptr;
+ return trans_lookup_ast_container(c, existing_node->data.variable_declaration.expr);
+ } else if (type_node->type == NodeTypeFieldAccessExpr) {
+ AstNode *container_node = trans_lookup_ast_container_typeof(c, type_node->data.field_access_expr.struct_expr);
+ if (container_node == nullptr)
+ return nullptr;
+ if (container_node->type != NodeTypeContainerDecl)
+ return container_node;
+
+ for (size_t i = 0; i < container_node->data.container_decl.fields.length; i += 1) {
+ AstNode *field_node = container_node->data.container_decl.fields.items[i];
+ if (buf_eql_buf(field_node->data.struct_field.name, type_node->data.field_access_expr.field_name)) {
+ return trans_lookup_ast_container(c, field_node->data.struct_field.type);
+ }
+ }
+ return nullptr;
+ } else {
+ return nullptr;
+ }
+}
+
+static AstNode *trans_lookup_ast_container_typeof(Context *c, AstNode *ref_node) {
+ if (ref_node->type == NodeTypeSymbol) {
+ AstNode *existing_node = get_global(c, ref_node->data.symbol_expr.symbol);
+ if (existing_node == nullptr)
+ return nullptr;
+ if (existing_node->type != NodeTypeVariableDeclaration)
+ return nullptr;
+ return trans_lookup_ast_container(c, existing_node->data.variable_declaration.type);
+ } else if (ref_node->type == NodeTypeFieldAccessExpr) {
+ AstNode *container_node = trans_lookup_ast_container_typeof(c, ref_node->data.field_access_expr.struct_expr);
+ if (container_node == nullptr)
+ return nullptr;
+ if (container_node->type != NodeTypeContainerDecl)
+ return container_node;
+ for (size_t i = 0; i < container_node->data.container_decl.fields.length; i += 1) {
+ AstNode *field_node = container_node->data.container_decl.fields.items[i];
+ if (buf_eql_buf(field_node->data.struct_field.name, ref_node->data.field_access_expr.field_name)) {
+ return trans_lookup_ast_container(c, field_node->data.struct_field.type);
+ }
+ }
+ return nullptr;
+ } else {
+ return nullptr;
+ }
+}
+
+static AstNode *trans_lookup_ast_maybe_fn(Context *c, AstNode *ref_node) {
+ AstNode *prefix_node = trans_lookup_ast_container_typeof(c, ref_node);
+ if (prefix_node == nullptr)
+ return nullptr;
+ if (prefix_node->type != NodeTypePrefixOpExpr)
+ return nullptr;
+ if (prefix_node->data.prefix_op_expr.prefix_op != PrefixOpMaybe)
+ return nullptr;
+
+ AstNode *fn_proto_node = prefix_node->data.prefix_op_expr.primary_expr;
+ if (fn_proto_node->type != NodeTypeFnProto)
+ return nullptr;
+
+ return fn_proto_node;
+}
+
static void render_macros(Context *c) {
auto it = c->macro_table.entry_iterator();
for (;;) {
@@ -3150,9 +3960,16 @@ static void render_macros(Context *c) {
if (!entry)
break;
+ AstNode *proto_node;
AstNode *value_node = entry->value;
if (value_node->type == NodeTypeFnDef) {
add_top_level_decl(c, value_node->data.fn_def.fn_proto->data.fn_proto.name, value_node);
+ } else if ((proto_node = trans_lookup_ast_maybe_fn(c, value_node))) {
+ // If a macro aliases a global variable which is a function pointer, we conclude that
+ // the macro is intended to represent a function that assumes the function pointer
+ // variable is non-null and calls it.
+ AstNode *inline_fn_node = trans_create_node_inline_fn(c, entry->key, value_node, proto_node);
+ add_top_level_decl(c, entry->key, inline_fn_node);
} else {
add_global_var(c, entry->key, value_node);
}
@@ -3203,9 +4020,33 @@ static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) {
return parse_ctok_num_lit(c, ctok, tok_i, false);
case CTokIdSymbol:
{
- *tok_i += 1;
+ bool need_symbol = false;
+ CTokId curr_id = CTokIdSymbol;
Buf *symbol_name = buf_create_from_buf(&tok->data.symbol);
- return trans_create_node_symbol(c, symbol_name);
+ AstNode *curr_node = trans_create_node_symbol(c, symbol_name);
+ AstNode *parent_node = curr_node;
+ do {
+ *tok_i += 1;
+ CTok* curr_tok = &ctok->tokens.at(*tok_i);
+ if (need_symbol) {
+ if (curr_tok->id == CTokIdSymbol) {
+ symbol_name = buf_create_from_buf(&curr_tok->data.symbol);
+ curr_node = trans_create_node_field_access(c, parent_node, buf_create_from_buf(symbol_name));
+ parent_node = curr_node;
+ need_symbol = false;
+ } else {
+ return nullptr;
+ }
+ } else {
+ if (curr_tok->id == CTokIdDot) {
+ need_symbol = true;
+ continue;
+ } else {
+ break;
+ }
+ }
+ } while (curr_id != CTokIdEOF);
+ return curr_node;
}
case CTokIdLParen:
{
@@ -3219,6 +4060,7 @@ static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) {
*tok_i += 1;
return inner_node;
}
+ case CTokIdDot:
case CTokIdEOF:
case CTokIdRParen:
// not able to make sense of this
@@ -3254,40 +4096,8 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch
if (buf_eql_buf(name, symbol_name)) {
return;
}
- c->macro_symbols.append({name, symbol_name});
- } else {
- c->macro_table.put(name, result_node);
- }
-}
-
-static void process_symbol_macros(Context *c) {
- for (size_t i = 0; i < c->macro_symbols.length; i += 1) {
- MacroSymbol ms = c->macro_symbols.at(i);
-
- // Check if this macro aliases another top level declaration
- AstNode *existing_node = get_global(c, ms.value);
- if (!existing_node || name_exists(c, ms.name))
- continue;
-
- // If a macro aliases a global variable which is a function pointer, we conclude that
- // the macro is intended to represent a function that assumes the function pointer
- // variable is non-null and calls it.
- if (existing_node->type == NodeTypeVariableDeclaration) {
- AstNode *var_type = existing_node->data.variable_declaration.type;
- if (var_type != nullptr && var_type->type == NodeTypePrefixOpExpr &&
- var_type->data.prefix_op_expr.prefix_op == PrefixOpMaybe)
- {
- AstNode *fn_proto_node = var_type->data.prefix_op_expr.primary_expr;
- if (fn_proto_node->type == NodeTypeFnProto) {
- AstNode *inline_fn_node = trans_create_node_inline_fn(c, ms.name, ms.value, fn_proto_node);
- c->macro_table.put(ms.name, inline_fn_node);
- continue;
- }
- }
- }
-
- add_global_var(c, ms.name, trans_create_node_symbol(c, ms.value));
}
+ c->macro_table.put(name, result_node);
}
static void process_preprocessor_entities(Context *c, ASTUnit &unit) {
@@ -3315,7 +4125,7 @@ static void process_preprocessor_entities(Context *c, ASTUnit &unit) {
continue;
}
Buf *name = buf_create_from_str(raw_name);
- if (name_exists(c, name)) {
+ if (name_exists_global(c, name)) {
continue;
}
@@ -3363,6 +4173,7 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch
c->ptr_params.init(8);
c->codegen = codegen;
c->source_node = source_node;
+ c->global_scope = trans_scope_root_create(c);
ZigList clang_argv = {0};
@@ -3467,7 +4278,7 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch
break;
}
StringRef msg_str_ref = it->getMessage();
- Buf *msg = buf_create_from_str((const char *)msg_str_ref.bytes_begin());
+ Buf *msg = string_ref_to_buf(msg_str_ref);
FullSourceLoc fsl = it->getLocation();
if (fsl.hasManager()) {
FileID file_id = fsl.getFileID();
@@ -3480,7 +4291,7 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch
if (filename.empty()) {
path = buf_alloc();
} else {
- path = buf_create_from_mem((const char *)filename.bytes_begin(), filename.size());
+ path = string_ref_to_buf(filename);
}
ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg);
@@ -3504,7 +4315,6 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch
process_preprocessor_entities(c, *ast_unit);
- process_symbol_macros(c);
render_macros(c);
render_aliases(c);
diff --git a/src/parsec.hpp b/src/translate_c.hpp
similarity index 100%
rename from src/parsec.hpp
rename to src/translate_c.hpp
diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp
index 46ac45caff..a74a683358 100644
--- a/src/zig_llvm.cpp
+++ b/src/zig_llvm.cpp
@@ -403,6 +403,10 @@ unsigned ZigLLVMTag_DW_structure_type(void) {
return dwarf::DW_TAG_structure_type;
}
+unsigned ZigLLVMTag_DW_union_type(void) {
+ return dwarf::DW_TAG_union_type;
+}
+
ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) {
DIBuilder *di_builder = new DIBuilder(*unwrap(module), allow_unresolved);
return reinterpret_cast(di_builder);
diff --git a/src/zig_llvm.hpp b/src/zig_llvm.hpp
index c7bb211960..2f742566f4 100644
--- a/src/zig_llvm.hpp
+++ b/src/zig_llvm.hpp
@@ -117,6 +117,7 @@ unsigned ZigLLVMEncoding_DW_ATE_signed_char(void);
unsigned ZigLLVMLang_DW_LANG_C99(void);
unsigned ZigLLVMTag_DW_variable(void);
unsigned ZigLLVMTag_DW_structure_type(void);
+unsigned ZigLLVMTag_DW_union_type(void);
ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved);
void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);
diff --git a/std/base64.zig b/std/base64.zig
index 5a57e7777f..25e438c4fb 100644
--- a/std/base64.zig
+++ b/std/base64.zig
@@ -1,186 +1,485 @@
const assert = @import("debug.zig").assert;
const mem = @import("mem.zig");
-pub const standard_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+pub const standard_pad_char = '=';
+pub const standard_encoder = Base64Encoder.init(standard_alphabet_chars, standard_pad_char);
-pub fn encode(dest: []u8, source: []const u8) -> []u8 {
- return encodeWithAlphabet(dest, source, standard_alphabet);
-}
+pub const Base64Encoder = struct {
+ alphabet_chars: []const u8,
+ pad_char: u8,
-/// invalid characters in source are allowed, but they cause the value of dest to be undefined.
-pub fn decode(dest: []u8, source: []const u8) -> []u8 {
- return decodeWithAlphabet(dest, source, standard_alphabet);
-}
+ /// a bunch of assertions, then simply pass the data right through.
+ pub fn init(alphabet_chars: []const u8, pad_char: u8) -> Base64Encoder {
+ assert(alphabet_chars.len == 64);
+ var char_in_alphabet = []bool{false} ** 256;
+ for (alphabet_chars) |c| {
+ assert(!char_in_alphabet[c]);
+ assert(c != pad_char);
+ char_in_alphabet[c] = true;
+ }
-pub fn encodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8) -> []u8 {
- assert(alphabet.len == 65);
- assert(dest.len >= calcEncodedSize(source.len));
-
- var i: usize = 0;
- var out_index: usize = 0;
- while (i + 2 < source.len) : (i += 3) {
- dest[out_index] = alphabet[(source[i] >> 2) & 0x3f];
- out_index += 1;
-
- dest[out_index] = alphabet[((source[i] & 0x3) << 4) |
- ((source[i + 1] & 0xf0) >> 4)];
- out_index += 1;
-
- dest[out_index] = alphabet[((source[i + 1] & 0xf) << 2) |
- ((source[i + 2] & 0xc0) >> 6)];
- out_index += 1;
-
- dest[out_index] = alphabet[source[i + 2] & 0x3f];
- out_index += 1;
+ return Base64Encoder{
+ .alphabet_chars = alphabet_chars,
+ .pad_char = pad_char,
+ };
}
- if (i < source.len) {
- dest[out_index] = alphabet[(source[i] >> 2) & 0x3f];
- out_index += 1;
+ /// ceil(source_len * 4/3)
+ pub fn calcSize(source_len: usize) -> usize {
+ return @divTrunc(source_len + 2, 3) * 4;
+ }
- if (i + 1 == source.len) {
- dest[out_index] = alphabet[(source[i] & 0x3) << 4];
+ /// dest.len must be what you get from ::calcSize.
+ pub fn encode(encoder: &const Base64Encoder, dest: []u8, source: []const u8) {
+ assert(dest.len == Base64Encoder.calcSize(source.len));
+
+ var i: usize = 0;
+ var out_index: usize = 0;
+ while (i + 2 < source.len) : (i += 3) {
+ dest[out_index] = encoder.alphabet_chars[(source[i] >> 2) & 0x3f];
out_index += 1;
- dest[out_index] = alphabet[64];
- out_index += 1;
- } else {
- dest[out_index] = alphabet[((source[i] & 0x3) << 4) |
+ dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) |
((source[i + 1] & 0xf0) >> 4)];
out_index += 1;
- dest[out_index] = alphabet[(source[i + 1] & 0xf) << 2];
+ dest[out_index] = encoder.alphabet_chars[((source[i + 1] & 0xf) << 2) |
+ ((source[i + 2] & 0xc0) >> 6)];
+ out_index += 1;
+
+ dest[out_index] = encoder.alphabet_chars[source[i + 2] & 0x3f];
out_index += 1;
}
- dest[out_index] = alphabet[64];
- out_index += 1;
+ if (i < source.len) {
+ dest[out_index] = encoder.alphabet_chars[(source[i] >> 2) & 0x3f];
+ out_index += 1;
+
+ if (i + 1 == source.len) {
+ dest[out_index] = encoder.alphabet_chars[(source[i] & 0x3) << 4];
+ out_index += 1;
+
+ dest[out_index] = encoder.pad_char;
+ out_index += 1;
+ } else {
+ dest[out_index] = encoder.alphabet_chars[((source[i] & 0x3) << 4) |
+ ((source[i + 1] & 0xf0) >> 4)];
+ out_index += 1;
+
+ dest[out_index] = encoder.alphabet_chars[(source[i + 1] & 0xf) << 2];
+ out_index += 1;
+ }
+
+ dest[out_index] = encoder.pad_char;
+ out_index += 1;
+ }
+ }
+};
+
+pub const standard_decoder = Base64Decoder.init(standard_alphabet_chars, standard_pad_char);
+error InvalidPadding;
+error InvalidCharacter;
+
+pub const Base64Decoder = struct {
+ /// e.g. 'A' => 0.
+ /// undefined for any value not in the 64 alphabet chars.
+ char_to_index: [256]u8,
+ /// true only for the 64 chars in the alphabet, not the pad char.
+ char_in_alphabet: [256]bool,
+ pad_char: u8,
+
+ pub fn init(alphabet_chars: []const u8, pad_char: u8) -> Base64Decoder {
+ assert(alphabet_chars.len == 64);
+
+ var result = Base64Decoder{
+ .char_to_index = undefined,
+ .char_in_alphabet = []bool{false} ** 256,
+ .pad_char = pad_char,
+ };
+
+ for (alphabet_chars) |c, i| {
+ assert(!result.char_in_alphabet[c]);
+ assert(c != pad_char);
+
+ result.char_to_index[c] = u8(i);
+ result.char_in_alphabet[c] = true;
+ }
+
+ return result;
}
- return dest[0..out_index];
-}
-
-/// invalid characters in source are allowed, but they cause the value of dest to be undefined.
-pub fn decodeWithAlphabet(dest: []u8, source: []const u8, alphabet: []const u8) -> []u8 {
- assert(alphabet.len == 65);
-
- var ascii6 = []u8{64} ** 256;
- for (alphabet) |c, i| {
- ascii6[c] = u8(i);
+ /// If the encoded buffer is detected to be invalid, returns error.InvalidPadding.
+ pub fn calcSize(decoder: &const Base64Decoder, source: []const u8) -> %usize {
+ if (source.len % 4 != 0) return error.InvalidPadding;
+ return calcDecodedSizeExactUnsafe(source, decoder.pad_char);
}
- return decodeWithAscii6BitMap(dest, source, ascii6[0..], alphabet[64]);
-}
+ /// dest.len must be what you get from ::calcSize.
+ /// invalid characters result in error.InvalidCharacter.
+ /// invalid padding results in error.InvalidPadding.
+ pub fn decode(decoder: &const Base64Decoder, dest: []u8, source: []const u8) -> %void {
+ assert(dest.len == %%decoder.calcSize(source));
+ assert(source.len % 4 == 0);
-pub fn decodeWithAscii6BitMap(dest: []u8, source: []const u8, ascii6: []const u8, pad_char: u8) -> []u8 {
- assert(ascii6.len == 256);
- assert(dest.len >= calcExactDecodedSizeWithPadChar(source, pad_char));
+ var src_cursor: usize = 0;
+ var dest_cursor: usize = 0;
- var src_index: usize = 0;
- var dest_index: usize = 0;
- var in_buf_len: usize = source.len;
+ while (src_cursor < source.len) : (src_cursor += 4) {
+ if (!decoder.char_in_alphabet[source[src_cursor + 0]]) return error.InvalidCharacter;
+ if (!decoder.char_in_alphabet[source[src_cursor + 1]]) return error.InvalidCharacter;
+ if (src_cursor < source.len - 4 or source[src_cursor + 3] != decoder.pad_char) {
+ // common case
+ if (!decoder.char_in_alphabet[source[src_cursor + 2]]) return error.InvalidCharacter;
+ if (!decoder.char_in_alphabet[source[src_cursor + 3]]) return error.InvalidCharacter;
+ dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 |
+ decoder.char_to_index[source[src_cursor + 1]] >> 4;
+ dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 |
+ decoder.char_to_index[source[src_cursor + 2]] >> 2;
+ dest[dest_cursor + 2] = decoder.char_to_index[source[src_cursor + 2]] << 6 |
+ decoder.char_to_index[source[src_cursor + 3]];
+ dest_cursor += 3;
+ } else if (source[src_cursor + 2] != decoder.pad_char) {
+ // one pad char
+ if (!decoder.char_in_alphabet[source[src_cursor + 2]]) return error.InvalidCharacter;
+ dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 |
+ decoder.char_to_index[source[src_cursor + 1]] >> 4;
+ dest[dest_cursor + 1] = decoder.char_to_index[source[src_cursor + 1]] << 4 |
+ decoder.char_to_index[source[src_cursor + 2]] >> 2;
+ if (decoder.char_to_index[source[src_cursor + 2]] << 6 != 0) return error.InvalidPadding;
+ dest_cursor += 2;
+ } else {
+ // two pad chars
+ dest[dest_cursor + 0] = decoder.char_to_index[source[src_cursor + 0]] << 2 |
+ decoder.char_to_index[source[src_cursor + 1]] >> 4;
+ if (decoder.char_to_index[source[src_cursor + 1]] << 4 != 0) return error.InvalidPadding;
+ dest_cursor += 1;
+ }
+ }
- while (in_buf_len > 0 and source[in_buf_len - 1] == pad_char) {
- in_buf_len -= 1;
+ assert(src_cursor == source.len);
+ assert(dest_cursor == dest.len);
+ }
+};
+
+error OutputTooSmall;
+
+pub const Base64DecoderWithIgnore = struct {
+ decoder: Base64Decoder,
+ char_is_ignored: [256]bool,
+ pub fn init(alphabet_chars: []const u8, pad_char: u8, ignore_chars: []const u8) -> Base64DecoderWithIgnore {
+ var result = Base64DecoderWithIgnore {
+ .decoder = Base64Decoder.init(alphabet_chars, pad_char),
+ .char_is_ignored = []bool{false} ** 256,
+ };
+
+ for (ignore_chars) |c| {
+ assert(!result.decoder.char_in_alphabet[c]);
+ assert(!result.char_is_ignored[c]);
+ assert(result.decoder.pad_char != c);
+ result.char_is_ignored[c] = true;
+ }
+
+ return result;
}
- while (in_buf_len > 4) {
- dest[dest_index] = ascii6[source[src_index + 0]] << 2 |
- ascii6[source[src_index + 1]] >> 4;
- dest_index += 1;
-
- dest[dest_index] = ascii6[source[src_index + 1]] << 4 |
- ascii6[source[src_index + 2]] >> 2;
- dest_index += 1;
-
- dest[dest_index] = ascii6[source[src_index + 2]] << 6 |
- ascii6[source[src_index + 3]];
- dest_index += 1;
-
- src_index += 4;
- in_buf_len -= 4;
+ /// If no characters end up being ignored or padding, this will be the exact decoded size.
+ pub fn calcSizeUpperBound(encoded_len: usize) -> %usize {
+ return @divTrunc(encoded_len, 4) * 3;
}
- if (in_buf_len > 1) {
- dest[dest_index] = ascii6[source[src_index + 0]] << 2 |
- ascii6[source[src_index + 1]] >> 4;
- dest_index += 1;
+ /// Invalid characters that are not ignored result in error.InvalidCharacter.
+ /// Invalid padding results in error.InvalidPadding.
+ /// Decoding more data than can fit in dest results in error.OutputTooSmall. See also ::calcSizeUpperBound.
+ /// Returns the number of bytes writen to dest.
+ pub fn decode(decoder_with_ignore: &const Base64DecoderWithIgnore, dest: []u8, source: []const u8) -> %usize {
+ const decoder = &const decoder_with_ignore.decoder;
+
+ var src_cursor: usize = 0;
+ var dest_cursor: usize = 0;
+
+ while (true) {
+ // get the next 4 chars, if available
+ var next_4_chars: [4]u8 = undefined;
+ var available_chars: usize = 0;
+ var pad_char_count: usize = 0;
+ while (available_chars < 4 and src_cursor < source.len) {
+ var c = source[src_cursor];
+ src_cursor += 1;
+
+ if (decoder.char_in_alphabet[c]) {
+ // normal char
+ next_4_chars[available_chars] = c;
+ available_chars += 1;
+ } else if (decoder_with_ignore.char_is_ignored[c]) {
+ // we're told to skip this one
+ continue;
+ } else if (c == decoder.pad_char) {
+ // the padding has begun. count the pad chars.
+ pad_char_count += 1;
+ while (src_cursor < source.len) {
+ c = source[src_cursor];
+ src_cursor += 1;
+ if (c == decoder.pad_char) {
+ pad_char_count += 1;
+ if (pad_char_count > 2) return error.InvalidCharacter;
+ } else if (decoder_with_ignore.char_is_ignored[c]) {
+ // we can even ignore chars during the padding
+ continue;
+ } else return error.InvalidCharacter;
+ }
+ break;
+ } else return error.InvalidCharacter;
+ }
+
+ switch (available_chars) {
+ 4 => {
+ // common case
+ if (dest_cursor + 3 > dest.len) return error.OutputTooSmall;
+ assert(pad_char_count == 0);
+ dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 |
+ decoder.char_to_index[next_4_chars[1]] >> 4;
+ dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 |
+ decoder.char_to_index[next_4_chars[2]] >> 2;
+ dest[dest_cursor + 2] = decoder.char_to_index[next_4_chars[2]] << 6 |
+ decoder.char_to_index[next_4_chars[3]];
+ dest_cursor += 3;
+ continue;
+ },
+ 3 => {
+ if (dest_cursor + 2 > dest.len) return error.OutputTooSmall;
+ if (pad_char_count != 1) return error.InvalidPadding;
+ dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 |
+ decoder.char_to_index[next_4_chars[1]] >> 4;
+ dest[dest_cursor + 1] = decoder.char_to_index[next_4_chars[1]] << 4 |
+ decoder.char_to_index[next_4_chars[2]] >> 2;
+ if (decoder.char_to_index[next_4_chars[2]] << 6 != 0) return error.InvalidPadding;
+ dest_cursor += 2;
+ break;
+ },
+ 2 => {
+ if (dest_cursor + 1 > dest.len) return error.OutputTooSmall;
+ if (pad_char_count != 2) return error.InvalidPadding;
+ dest[dest_cursor + 0] = decoder.char_to_index[next_4_chars[0]] << 2 |
+ decoder.char_to_index[next_4_chars[1]] >> 4;
+ if (decoder.char_to_index[next_4_chars[1]] << 4 != 0) return error.InvalidPadding;
+ dest_cursor += 1;
+ break;
+ },
+ 1 => {
+ return error.InvalidPadding;
+ },
+ 0 => {
+ if (pad_char_count != 0) return error.InvalidPadding;
+ break;
+ },
+ else => unreachable,
+ }
+ }
+
+ assert(src_cursor == source.len);
+
+ return dest_cursor;
}
- if (in_buf_len > 2) {
- dest[dest_index] = ascii6[source[src_index + 1]] << 4 |
- ascii6[source[src_index + 2]] >> 2;
- dest_index += 1;
- }
- if (in_buf_len > 3) {
- dest[dest_index] = ascii6[source[src_index + 2]] << 6 |
- ascii6[source[src_index + 3]];
- dest_index += 1;
+};
+
+
+pub const standard_decoder_unsafe = Base64DecoderUnsafe.init(standard_alphabet_chars, standard_pad_char);
+
+pub const Base64DecoderUnsafe = struct {
+ /// e.g. 'A' => 0.
+ /// undefined for any value not in the 64 alphabet chars.
+ char_to_index: [256]u8,
+ pad_char: u8,
+
+ pub fn init(alphabet_chars: []const u8, pad_char: u8) -> Base64DecoderUnsafe {
+ assert(alphabet_chars.len == 64);
+ var result = Base64DecoderUnsafe {
+ .char_to_index = undefined,
+ .pad_char = pad_char,
+ };
+ for (alphabet_chars) |c, i| {
+ assert(c != pad_char);
+ result.char_to_index[c] = u8(i);
+ }
+ return result;
}
- return dest[0..dest_index];
-}
-
-pub fn calcEncodedSize(source_len: usize) -> usize {
- return (((source_len * 4) / 3 + 3) / 4) * 4;
-}
-
-/// Computes the upper bound of the decoded size based only on the encoded length.
-/// To compute the exact decoded size, see ::calcExactDecodedSize
-pub fn calcMaxDecodedSize(encoded_len: usize) -> usize {
- return @divExact(encoded_len * 3, 4);
-}
-
-/// Computes the number of decoded bytes there will be. This function must
-/// be given the encoded buffer because there might be padding
-/// bytes at the end ('=' in the standard alphabet)
-pub fn calcExactDecodedSize(encoded: []const u8) -> usize {
- return calcExactDecodedSizeWithAlphabet(encoded, standard_alphabet);
-}
-
-pub fn calcExactDecodedSizeWithAlphabet(encoded: []const u8, alphabet: []const u8) -> usize {
- assert(alphabet.len == 65);
- return calcExactDecodedSizeWithPadChar(encoded, alphabet[64]);
-}
-
-pub fn calcExactDecodedSizeWithPadChar(encoded: []const u8, pad_char: u8) -> usize {
- var buf_len = encoded.len;
-
- while (buf_len > 0 and encoded[buf_len - 1] == pad_char) {
- buf_len -= 1;
+ /// The source buffer must be valid.
+ pub fn calcSize(decoder: &const Base64DecoderUnsafe, source: []const u8) -> usize {
+ return calcDecodedSizeExactUnsafe(source, decoder.pad_char);
}
- return (buf_len * 3) / 4;
+ /// dest.len must be what you get from ::calcDecodedSizeExactUnsafe.
+ /// invalid characters or padding will result in undefined values.
+ pub fn decode(decoder: &const Base64DecoderUnsafe, dest: []u8, source: []const u8) {
+ assert(dest.len == decoder.calcSize(source));
+
+ var src_index: usize = 0;
+ var dest_index: usize = 0;
+ var in_buf_len: usize = source.len;
+
+ while (in_buf_len > 0 and source[in_buf_len - 1] == decoder.pad_char) {
+ in_buf_len -= 1;
+ }
+
+ while (in_buf_len > 4) {
+ dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 |
+ decoder.char_to_index[source[src_index + 1]] >> 4;
+ dest_index += 1;
+
+ dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 |
+ decoder.char_to_index[source[src_index + 2]] >> 2;
+ dest_index += 1;
+
+ dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 |
+ decoder.char_to_index[source[src_index + 3]];
+ dest_index += 1;
+
+ src_index += 4;
+ in_buf_len -= 4;
+ }
+
+ if (in_buf_len > 1) {
+ dest[dest_index] = decoder.char_to_index[source[src_index + 0]] << 2 |
+ decoder.char_to_index[source[src_index + 1]] >> 4;
+ dest_index += 1;
+ }
+ if (in_buf_len > 2) {
+ dest[dest_index] = decoder.char_to_index[source[src_index + 1]] << 4 |
+ decoder.char_to_index[source[src_index + 2]] >> 2;
+ dest_index += 1;
+ }
+ if (in_buf_len > 3) {
+ dest[dest_index] = decoder.char_to_index[source[src_index + 2]] << 6 |
+ decoder.char_to_index[source[src_index + 3]];
+ dest_index += 1;
+ }
+ }
+};
+
+fn calcDecodedSizeExactUnsafe(source: []const u8, pad_char: u8) -> usize {
+ if (source.len == 0) return 0;
+ var result = @divExact(source.len, 4) * 3;
+ if (source[source.len - 1] == pad_char) {
+ result -= 1;
+ if (source[source.len - 2] == pad_char) {
+ result -= 1;
+ }
+ }
+ return result;
}
+
test "base64" {
- testBase64();
- comptime testBase64();
+ @setEvalBranchQuota(5000);
+ %%testBase64();
+ comptime %%testBase64();
}
-fn testBase64() {
- testBase64Case("", "");
- testBase64Case("f", "Zg==");
- testBase64Case("fo", "Zm8=");
- testBase64Case("foo", "Zm9v");
- testBase64Case("foob", "Zm9vYg==");
- testBase64Case("fooba", "Zm9vYmE=");
- testBase64Case("foobar", "Zm9vYmFy");
+fn testBase64() -> %void {
+ %return testAllApis("", "");
+ %return testAllApis("f", "Zg==");
+ %return testAllApis("fo", "Zm8=");
+ %return testAllApis("foo", "Zm9v");
+ %return testAllApis("foob", "Zm9vYg==");
+ %return testAllApis("fooba", "Zm9vYmE=");
+ %return testAllApis("foobar", "Zm9vYmFy");
+
+ %return testDecodeIgnoreSpace("", " ");
+ %return testDecodeIgnoreSpace("f", "Z g= =");
+ %return testDecodeIgnoreSpace("fo", " Zm8=");
+ %return testDecodeIgnoreSpace("foo", "Zm9v ");
+ %return testDecodeIgnoreSpace("foob", "Zm9vYg = = ");
+ %return testDecodeIgnoreSpace("fooba", "Zm9v YmE=");
+ %return testDecodeIgnoreSpace("foobar", " Z m 9 v Y m F y ");
+
+ // test getting some api errors
+ %return testError("A", error.InvalidPadding);
+ %return testError("AA", error.InvalidPadding);
+ %return testError("AAA", error.InvalidPadding);
+ %return testError("A..A", error.InvalidCharacter);
+ %return testError("AA=A", error.InvalidCharacter);
+ %return testError("AA/=", error.InvalidPadding);
+ %return testError("A/==", error.InvalidPadding);
+ %return testError("A===", error.InvalidCharacter);
+ %return testError("====", error.InvalidCharacter);
+
+ %return testOutputTooSmallError("AA==");
+ %return testOutputTooSmallError("AAA=");
+ %return testOutputTooSmallError("AAAA");
+ %return testOutputTooSmallError("AAAAAA==");
}
-fn testBase64Case(expected_decoded: []const u8, expected_encoded: []const u8) {
- const calculated_decoded_len = calcExactDecodedSize(expected_encoded);
- assert(calculated_decoded_len == expected_decoded.len);
+fn testAllApis(expected_decoded: []const u8, expected_encoded: []const u8) -> %void {
+ // Base64Encoder
+ {
+ var buffer: [0x100]u8 = undefined;
+ var encoded = buffer[0..Base64Encoder.calcSize(expected_decoded.len)];
+ standard_encoder.encode(encoded, expected_decoded);
+ assert(mem.eql(u8, encoded, expected_encoded));
+ }
- const calculated_encoded_len = calcEncodedSize(expected_decoded.len);
- assert(calculated_encoded_len == expected_encoded.len);
+ // Base64Decoder
+ {
+ var buffer: [0x100]u8 = undefined;
+ var decoded = buffer[0..%return standard_decoder.calcSize(expected_encoded)];
+ %return standard_decoder.decode(decoded, expected_encoded);
+ assert(mem.eql(u8, decoded, expected_decoded));
+ }
- var buf: [100]u8 = undefined;
+ // Base64DecoderWithIgnore
+ {
+ const standard_decoder_ignore_nothing = Base64DecoderWithIgnore.init(
+ standard_alphabet_chars, standard_pad_char, "");
+ var buffer: [0x100]u8 = undefined;
+ var decoded = buffer[0..%return Base64DecoderWithIgnore.calcSizeUpperBound(expected_encoded.len)];
+ var written = %return standard_decoder_ignore_nothing.decode(decoded, expected_encoded);
+ assert(written <= decoded.len);
+ assert(mem.eql(u8, decoded[0..written], expected_decoded));
+ }
- const actual_decoded = decode(buf[0..], expected_encoded);
- assert(actual_decoded.len == expected_decoded.len);
- assert(mem.eql(u8, expected_decoded, actual_decoded));
-
- const actual_encoded = encode(buf[0..], expected_decoded);
- assert(actual_encoded.len == expected_encoded.len);
- assert(mem.eql(u8, expected_encoded, actual_encoded));
+ // Base64DecoderUnsafe
+ {
+ var buffer: [0x100]u8 = undefined;
+ var decoded = buffer[0..standard_decoder_unsafe.calcSize(expected_encoded)];
+ standard_decoder_unsafe.decode(decoded, expected_encoded);
+ assert(mem.eql(u8, decoded, expected_decoded));
+ }
+}
+
+fn testDecodeIgnoreSpace(expected_decoded: []const u8, encoded: []const u8) -> %void {
+ const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
+ standard_alphabet_chars, standard_pad_char, " ");
+ var buffer: [0x100]u8 = undefined;
+ var decoded = buffer[0..%return Base64DecoderWithIgnore.calcSizeUpperBound(encoded.len)];
+ var written = %return standard_decoder_ignore_space.decode(decoded, encoded);
+ assert(mem.eql(u8, decoded[0..written], expected_decoded));
+}
+
+error ExpectedError;
+fn testError(encoded: []const u8, expected_err: error) -> %void {
+ const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
+ standard_alphabet_chars, standard_pad_char, " ");
+ var buffer: [0x100]u8 = undefined;
+ if (standard_decoder.calcSize(encoded)) |decoded_size| {
+ var decoded = buffer[0..decoded_size];
+ if (standard_decoder.decode(decoded, encoded)) |_| {
+ return error.ExpectedError;
+ } else |err| if (err != expected_err) return err;
+ } else |err| if (err != expected_err) return err;
+
+ if (standard_decoder_ignore_space.decode(buffer[0..], encoded)) |_| {
+ return error.ExpectedError;
+ } else |err| if (err != expected_err) return err;
+}
+
+fn testOutputTooSmallError(encoded: []const u8) -> %void {
+ const standard_decoder_ignore_space = Base64DecoderWithIgnore.init(
+ standard_alphabet_chars, standard_pad_char, " ");
+ var buffer: [0x100]u8 = undefined;
+ var decoded = buffer[0..calcDecodedSizeExactUnsafe(encoded, standard_pad_char) - 1];
+ if (standard_decoder_ignore_space.decode(decoded, encoded)) |_| {
+ return error.ExpectedError;
+ } else |err| if (err != error.OutputTooSmall) return err;
}
diff --git a/std/os/index.zig b/std/os/index.zig
index c3f33c4ccd..e6a5fc4d15 100644
--- a/std/os/index.zig
+++ b/std/os/index.zig
@@ -31,6 +31,8 @@ pub const windowsWaitSingle = windows_util.windowsWaitSingle;
pub const windowsWrite = windows_util.windowsWrite;
pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
pub const windowsOpen = windows_util.windowsOpen;
+pub const windowsLoadDll = windows_util.windowsLoadDll;
+pub const windowsUnloadDll = windows_util.windowsUnloadDll;
pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
pub const FileHandle = if (is_windows) windows.HANDLE else i32;
@@ -620,7 +622,9 @@ pub fn symLinkPosix(allocator: &Allocator, existing_path: []const u8, new_path:
}
// here we replace the standard +/ with -_ so that it can be used in a file name
-const b64_fs_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=";
+const b64_fs_encoder = base64.Base64Encoder.init(
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
+ base64.standard_pad_char);
pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) -> %void {
if (symLink(allocator, existing_path, new_path)) {
@@ -632,12 +636,12 @@ pub fn atomicSymLink(allocator: &Allocator, existing_path: []const u8, new_path:
}
var rand_buf: [12]u8 = undefined;
- const tmp_path = %return allocator.alloc(u8, new_path.len + base64.calcEncodedSize(rand_buf.len));
+ const tmp_path = %return allocator.alloc(u8, new_path.len + base64.Base64Encoder.calcSize(rand_buf.len));
defer allocator.free(tmp_path);
mem.copy(u8, tmp_path[0..], new_path);
while (true) {
%return getRandomBytes(rand_buf[0..]);
- _ = base64.encodeWithAlphabet(tmp_path[new_path.len..], rand_buf, b64_fs_alphabet);
+ b64_fs_encoder.encode(tmp_path[new_path.len..], rand_buf);
if (symLink(allocator, existing_path, tmp_path)) {
return rename(allocator, tmp_path, new_path);
} else |err| {
@@ -715,11 +719,11 @@ pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []con
/// Guaranteed to be atomic.
pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: []const u8, mode: usize) -> %void {
var rand_buf: [12]u8 = undefined;
- const tmp_path = %return allocator.alloc(u8, dest_path.len + base64.calcEncodedSize(rand_buf.len));
+ const tmp_path = %return allocator.alloc(u8, dest_path.len + base64.Base64Encoder.calcSize(rand_buf.len));
defer allocator.free(tmp_path);
mem.copy(u8, tmp_path[0..], dest_path);
%return getRandomBytes(rand_buf[0..]);
- _ = base64.encodeWithAlphabet(tmp_path[dest_path.len..], rand_buf, b64_fs_alphabet);
+ b64_fs_encoder.encode(tmp_path[dest_path.len..], rand_buf);
var out_file = %return io.File.openWriteMode(tmp_path, mode, allocator);
defer out_file.close();
diff --git a/std/os/windows/index.zig b/std/os/windows/index.zig
index 913cc79801..0ce3794cdc 100644
--- a/std/os/windows/index.zig
+++ b/std/os/windows/index.zig
@@ -84,6 +84,11 @@ pub extern "kernel32" stdcallcc fn WriteFile(in_hFile: HANDLE, in_lpBuffer: &con
in_nNumberOfBytesToWrite: DWORD, out_lpNumberOfBytesWritten: ?&DWORD,
in_out_lpOverlapped: ?&OVERLAPPED) -> BOOL;
+//TODO: call unicode versions instead of relying on ANSI code page
+pub extern "kernel32" stdcallcc fn LoadLibraryA(lpLibFileName: LPCSTR) -> ?HMODULE;
+
+pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) -> BOOL;
+
pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) -> c_int;
pub const PROV_RSA_FULL = 1;
@@ -97,6 +102,7 @@ pub const FLOAT = f32;
pub const HANDLE = &c_void;
pub const HCRYPTPROV = ULONG_PTR;
pub const HINSTANCE = &@OpaqueType();
+pub const HMODULE = &@OpaqueType();
pub const INT = c_int;
pub const LPBYTE = &BYTE;
pub const LPCH = &CHAR;
diff --git a/std/os/windows/util.zig b/std/os/windows/util.zig
index de2babe8d7..b3fc095d43 100644
--- a/std/os/windows/util.zig
+++ b/std/os/windows/util.zig
@@ -4,6 +4,7 @@ const windows = std.os.windows;
const assert = std.debug.assert;
const mem = std.mem;
const BufMap = std.BufMap;
+const cstr = std.cstr;
error WaitAbandoned;
error WaitTimeOut;
@@ -149,3 +150,25 @@ pub fn createWindowsEnvBlock(allocator: &mem.Allocator, env_map: &const BufMap)
result[i] = 0;
return result;
}
+
+error DllNotFound;
+pub fn windowsLoadDll(allocator: &mem.Allocator, dll_path: []const u8) -> %windows.HMODULE {
+ const padded_buff = %return cstr.addNullByte(allocator, dll_path);
+ defer allocator.free(padded_buff);
+ return windows.LoadLibraryA(padded_buff.ptr) ?? error.DllNotFound;
+}
+
+pub fn windowsUnloadDll(hModule: windows.HMODULE) {
+ assert(windows.FreeLibrary(hModule)!= 0);
+}
+
+
+test "InvalidDll" {
+ const DllName = "asdf.dll";
+ const allocator = std.debug.global_allocator;
+ const handle = os.windowsLoadDll(allocator, DllName) %% |err| {
+ assert(err == error.DllNotFound);
+ return;
+ };
+}
+
diff --git a/test/cases/union.zig b/test/cases/union.zig
index 4b8ccb7245..4044721582 100644
--- a/test/cases/union.zig
+++ b/test/cases/union.zig
@@ -31,3 +31,47 @@ test "unions embedded in aggregate types" {
else => unreachable,
}
}
+
+
+const Foo = union {
+ float: f64,
+ int: i32,
+};
+
+test "basic unions" {
+ var foo = Foo { .int = 1 };
+ assert(foo.int == 1);
+ foo = Foo {.float = 12.34};
+ assert(foo.float == 12.34);
+}
+
+test "init union with runtime value" {
+ var foo: Foo = undefined;
+
+ setFloat(&foo, 12.34);
+ assert(foo.float == 12.34);
+
+ setInt(&foo, 42);
+ assert(foo.int == 42);
+}
+
+fn setFloat(foo: &Foo, x: f64) {
+ *foo = Foo { .float = x };
+}
+
+fn setInt(foo: &Foo, x: i32) {
+ *foo = Foo { .int = x };
+}
+
+const FooExtern = extern union {
+ float: f64,
+ int: i32,
+};
+
+test "basic extern unions" {
+ var foo = FooExtern { .int = 1 };
+ assert(foo.int == 1);
+ foo.float = 12.34;
+ assert(foo.float == 12.34);
+}
+
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index fa90661158..3ef4a63e5f 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -389,8 +389,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\ const y = a.bar;
\\}
,
- ".tmp_source.zig:4:6: error: no member named 'foo' in 'A'",
- ".tmp_source.zig:5:16: error: no member named 'bar' in 'A'");
+ ".tmp_source.zig:4:6: error: no member named 'foo' in struct 'A'",
+ ".tmp_source.zig:5:16: error: no member named 'bar' in struct 'A'");
cases.add("redefinition of struct",
\\const A = struct { x : i32, };
@@ -454,7 +454,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\ .foo = 42,
\\ };
\\}
- , ".tmp_source.zig:10:9: error: no member named 'foo' in 'A'");
+ , ".tmp_source.zig:10:9: error: no member named 'foo' in struct 'A'");
cases.add("invalid break expression",
\\export fn f() {
@@ -2343,4 +2343,23 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\pub extern fn foo(format: &const u8, ...);
,
".tmp_source.zig:2:9: error: expected type '&const u8', found '[5]u8'");
+
+ cases.add("constant inside comptime function has compile error",
+ \\const ContextAllocator = MemoryPool(usize);
+ \\
+ \\pub fn MemoryPool(comptime T: type) -> type {
+ \\ const free_list_t = @compileError("aoeu");
+ \\
+ \\ struct {
+ \\ free_list: free_list_t,
+ \\ }
+ \\}
+ \\
+ \\export fn entry() {
+ \\ var allocator: ContextAllocator = undefined;
+ \\}
+ ,
+ ".tmp_source.zig:4:25: error: aoeu",
+ ".tmp_source.zig:1:36: note: called from here",
+ ".tmp_source.zig:12:20: note: referenced here");
}
diff --git a/test/debug_safety.zig b/test/debug_safety.zig
index 9e9ff98349..36f8d020c3 100644
--- a/test/debug_safety.zig
+++ b/test/debug_safety.zig
@@ -260,4 +260,24 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
\\ return int_slice[0];
\\}
);
+
+ cases.addDebugSafety("bad union field access",
+ \\pub fn panic(message: []const u8) -> noreturn {
+ \\ @import("std").os.exit(126);
+ \\}
+ \\
+ \\const Foo = union {
+ \\ float: f32,
+ \\ int: u32,
+ \\};
+ \\
+ \\pub fn main() -> %void {
+ \\ var f = Foo { .int = 42 };
+ \\ bar(&f);
+ \\}
+ \\
+ \\fn bar(f: &Foo) {
+ \\ f.float = 12.34;
+ \\}
+ );
}
diff --git a/test/tests.zig b/test/tests.zig
index 20b57c7573..73d9646552 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -18,7 +18,7 @@ const build_examples = @import("build_examples.zig");
const compile_errors = @import("compile_errors.zig");
const assemble_and_link = @import("assemble_and_link.zig");
const debug_safety = @import("debug_safety.zig");
-const parsec = @import("parsec.zig");
+const translate_c = @import("translate_c.zig");
const TestTarget = struct {
os: builtin.Os,
@@ -123,16 +123,16 @@ pub fn addAssembleAndLinkTests(b: &build.Builder, test_filter: ?[]const u8) -> &
return cases.step;
}
-pub fn addParseCTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {
- const cases = %%b.allocator.create(ParseCContext);
- *cases = ParseCContext {
+pub fn addTranslateCTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {
+ const cases = %%b.allocator.create(TranslateCContext);
+ *cases = TranslateCContext {
.b = b,
- .step = b.step("test-parsec", "Run the C header file parsing tests"),
+ .step = b.step("test-translate-c", "Run the C header file parsing tests"),
.test_index = 0,
.test_filter = test_filter,
};
- parsec.addCases(cases);
+ translate_c.addCases(cases);
return cases.step;
}
@@ -770,7 +770,7 @@ pub const BuildExamplesContext = struct {
}
};
-pub const ParseCContext = struct {
+pub const TranslateCContext = struct {
b: &build.Builder,
step: &build.Step,
test_index: usize,
@@ -799,17 +799,17 @@ pub const ParseCContext = struct {
}
};
- const ParseCCmpOutputStep = struct {
+ const TranslateCCmpOutputStep = struct {
step: build.Step,
- context: &ParseCContext,
+ context: &TranslateCContext,
name: []const u8,
test_index: usize,
case: &const TestCase,
- pub fn create(context: &ParseCContext, name: []const u8, case: &const TestCase) -> &ParseCCmpOutputStep {
+ pub fn create(context: &TranslateCContext, name: []const u8, case: &const TestCase) -> &TranslateCCmpOutputStep {
const allocator = context.b.allocator;
- const ptr = %%allocator.create(ParseCCmpOutputStep);
- *ptr = ParseCCmpOutputStep {
+ const ptr = %%allocator.create(TranslateCCmpOutputStep);
+ *ptr = TranslateCCmpOutputStep {
.step = build.Step.init("ParseCCmpOutput", allocator, make),
.context = context,
.name = name,
@@ -821,7 +821,7 @@ pub const ParseCContext = struct {
}
fn make(step: &build.Step) -> %void {
- const self = @fieldParentPtr(ParseCCmpOutputStep, "step", step);
+ const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step);
const b = self.context.b;
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 {
var zig_args = ArrayList([]const u8).init(b.allocator);
%%zig_args.append(b.zig_exe);
- %%zig_args.append("parsec");
+ %%zig_args.append("translate-c");
%%zig_args.append(b.pathFromRoot(root_src));
warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
@@ -882,7 +882,7 @@ pub const ParseCContext = struct {
if (stderr.len != 0 and !self.case.allow_warnings) {
warn(
- \\====== parsec emitted warnings: ============
+ \\====== translate-c emitted warnings: =======
\\{}
\\============================================
\\
@@ -914,7 +914,7 @@ pub const ParseCContext = struct {
warn("\n");
}
- pub fn create(self: &ParseCContext, allow_warnings: bool, filename: []const u8, name: []const u8,
+ pub fn create(self: &TranslateCContext, allow_warnings: bool, filename: []const u8, name: []const u8,
source: []const u8, expected_lines: ...) -> &TestCase
{
const tc = %%self.b.allocator.create(TestCase);
@@ -932,37 +932,37 @@ pub const ParseCContext = struct {
return tc;
}
- pub fn add(self: &ParseCContext, name: []const u8, source: []const u8, expected_lines: ...) {
+ pub fn add(self: &TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) {
const tc = self.create(false, "source.h", name, source, expected_lines);
self.addCase(tc);
}
- pub fn addC(self: &ParseCContext, name: []const u8, source: []const u8, expected_lines: ...) {
+ pub fn addC(self: &TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) {
const tc = self.create(false, "source.c", name, source, expected_lines);
self.addCase(tc);
}
- pub fn addAllowWarnings(self: &ParseCContext, name: []const u8, source: []const u8, expected_lines: ...) {
+ pub fn addAllowWarnings(self: &TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) {
const tc = self.create(true, "source.h", name, source, expected_lines);
self.addCase(tc);
}
- pub fn addCase(self: &ParseCContext, case: &const TestCase) {
+ pub fn addCase(self: &TranslateCContext, case: &const TestCase) {
const b = self.b;
- const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "parsec {}", case.name);
+ const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "translate-c {}", case.name);
if (self.test_filter) |filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null)
return;
}
- const parsec_and_cmp = ParseCCmpOutputStep.create(self, annotated_case_name, case);
- self.step.dependOn(&parsec_and_cmp.step);
+ const translate_c_and_cmp = TranslateCCmpOutputStep.create(self, annotated_case_name, case);
+ self.step.dependOn(&translate_c_and_cmp.step);
for (case.sources.toSliceConst()) |src_file| {
const expanded_src_path = %%os.path.join(b.allocator, b.cache_root, src_file.filename);
const write_src = b.addWriteFile(expanded_src_path, src_file.source);
- parsec_and_cmp.step.dependOn(&write_src.step);
+ translate_c_and_cmp.step.dependOn(&write_src.step);
}
}
};
diff --git a/test/parsec.zig b/test/translate_c.zig
similarity index 72%
rename from test/parsec.zig
rename to test/translate_c.zig
index f9e90cb705..90b99b5faf 100644
--- a/test/parsec.zig
+++ b/test/translate_c.zig
@@ -1,6 +1,6 @@
const tests = @import("tests.zig");
-pub fn addCases(cases: &tests.ParseCContext) {
+pub fn addCases(cases: &tests.TranslateCContext) {
cases.addAllowWarnings("simple data types",
\\#include
\\int foo(char a, unsigned char b, signed char c);
@@ -677,12 +677,12 @@ pub fn addCases(cases: &tests.ParseCContext) {
\\ };
\\ a >>= @import("std").math.Log2Int(c_int)({
\\ const _ref = &a;
- \\ (*_ref) = c_int(c_int(*_ref) >> @import("std").math.Log2Int(c_int)(1));
+ \\ (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_int)(1));
\\ *_ref
\\ });
\\ a <<= @import("std").math.Log2Int(c_int)({
\\ const _ref = &a;
- \\ (*_ref) = c_int(c_int(*_ref) << @import("std").math.Log2Int(c_int)(1));
+ \\ (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_int)(1));
\\ *_ref
\\ });
\\}
@@ -735,12 +735,12 @@ pub fn addCases(cases: &tests.ParseCContext) {
\\ };
\\ a >>= @import("std").math.Log2Int(c_uint)({
\\ const _ref = &a;
- \\ (*_ref) = c_uint(c_uint(*_ref) >> @import("std").math.Log2Int(c_uint)(1));
+ \\ (*_ref) = ((*_ref) >> @import("std").math.Log2Int(c_uint)(1));
\\ *_ref
\\ });
\\ a <<= @import("std").math.Log2Int(c_uint)({
\\ const _ref = &a;
- \\ (*_ref) = c_uint(c_uint(*_ref) << @import("std").math.Log2Int(c_uint)(1));
+ \\ (*_ref) = ((*_ref) << @import("std").math.Log2Int(c_uint)(1));
\\ *_ref
\\ });
\\}
@@ -805,6 +805,50 @@ pub fn addCases(cases: &tests.ParseCContext) {
\\}
);
+ cases.addC("pre increment/decrement",
+ \\void foo(void) {
+ \\ int i = 0;
+ \\ unsigned u = 0;
+ \\ ++i;
+ \\ --i;
+ \\ ++u;
+ \\ --u;
+ \\ i = ++i;
+ \\ i = --i;
+ \\ u = ++u;
+ \\ u = --u;
+ \\}
+ ,
+ \\export fn foo() {
+ \\ var i: c_int = 0;
+ \\ var u: c_uint = c_uint(0);
+ \\ i += 1;
+ \\ i -= 1;
+ \\ u +%= 1;
+ \\ u -%= 1;
+ \\ i = {
+ \\ const _ref = &i;
+ \\ (*_ref) += 1;
+ \\ *_ref
+ \\ };
+ \\ i = {
+ \\ const _ref = &i;
+ \\ (*_ref) -= 1;
+ \\ *_ref
+ \\ };
+ \\ u = {
+ \\ const _ref = &u;
+ \\ (*_ref) +%= 1;
+ \\ *_ref
+ \\ };
+ \\ u = {
+ \\ const _ref = &u;
+ \\ (*_ref) -%= 1;
+ \\ *_ref
+ \\ };
+ \\}
+ );
+
cases.addC("do loop",
\\void foo(void) {
\\ int a = 2;
@@ -834,17 +878,21 @@ pub fn addCases(cases: &tests.ParseCContext) {
cases.addC("deref function pointer",
\\void foo(void) {}
+ \\void baz(void) {}
\\void bar(void) {
\\ void(*f)(void) = foo;
\\ f();
\\ (*(f))();
+ \\ baz();
\\}
,
\\export fn foo() {}
+ \\export fn baz() {}
\\export fn bar() {
\\ var f: ?extern fn() = foo;
\\ (??f)();
\\ (??f)();
+ \\ baz();
\\}
);
@@ -857,15 +905,277 @@ pub fn addCases(cases: &tests.ParseCContext) {
\\ (*(??x)) = 1;
\\}
);
+
+ cases.add("simple union",
+ \\union Foo {
+ \\ int x;
+ \\ double y;
+ \\};
+ ,
+ \\pub const union_Foo = extern union {
+ \\ x: c_int,
+ \\ y: f64,
+ \\};
+ ,
+ \\pub const Foo = union_Foo;
+ );
+
+ cases.add("address of operator",
+ \\int foo(void) {
+ \\ int x = 1234;
+ \\ int *ptr = &x;
+ \\ return *ptr;
+ \\}
+ ,
+ \\pub fn foo() -> c_int {
+ \\ var x: c_int = 1234;
+ \\ var ptr: ?&c_int = &x;
+ \\ return *(??ptr);
+ \\}
+ );
+
+ cases.add("string literal",
+ \\const char *foo(void) {
+ \\ return "bar";
+ \\}
+ ,
+ \\pub fn foo() -> ?&const u8 {
+ \\ return c"bar";
+ \\}
+ );
+
+ cases.add("return void",
+ \\void foo(void) {
+ \\ return;
+ \\}
+ ,
+ \\pub fn foo() {
+ \\ return;
+ \\}
+ );
+
+ cases.add("for loop",
+ \\void foo(void) {
+ \\ for (int i = 0; i < 10; i += 1) { }
+ \\}
+ ,
+ \\pub fn foo() {
+ \\ {
+ \\ var i: c_int = 0;
+ \\ while (i < 10) : (i += 1) {};
+ \\ };
+ \\}
+ );
+
+ cases.add("empty for loop",
+ \\void foo(void) {
+ \\ for (;;) { }
+ \\}
+ ,
+ \\pub fn foo() {
+ \\ while (true) {};
+ \\}
+ );
+
+ cases.add("break statement",
+ \\void foo(void) {
+ \\ for (;;) {
+ \\ break;
+ \\ }
+ \\}
+ ,
+ \\pub fn foo() {
+ \\ while (true) {
+ \\ break;
+ \\ };
+ \\}
+ );
+
+ cases.add("continue statement",
+ \\void foo(void) {
+ \\ for (;;) {
+ \\ continue;
+ \\ }
+ \\}
+ ,
+ \\pub fn foo() {
+ \\ while (true) {
+ \\ continue;
+ \\ };
+ \\}
+ );
+
+ cases.add("switch statement",
+ \\int foo(int x) {
+ \\ switch (x) {
+ \\ case 1:
+ \\ x += 1;
+ \\ case 2:
+ \\ break;
+ \\ case 3:
+ \\ case 4:
+ \\ return x + 1;
+ \\ default:
+ \\ return 10;
+ \\ }
+ \\ return x + 13;
+ \\}
+ ,
+ \\fn foo(_arg_x: c_int) -> c_int {
+ \\ var x = _arg_x;
+ \\ {
+ \\ switch (x) {
+ \\ 1 => goto case_0,
+ \\ 2 => goto case_1,
+ \\ 3 => goto case_2,
+ \\ 4 => goto case_3,
+ \\ else => goto default,
+ \\ };
+ \\ case_0:
+ \\ x += 1;
+ \\ case_1:
+ \\ goto end;
+ \\ case_2:
+ \\ case_3:
+ \\ return x + 1;
+ \\ default:
+ \\ return 10;
+ \\ goto end;
+ \\ end:
+ \\ };
+ \\ return x + 13;
+ \\}
+ );
+
+ cases.add("macros with field targets",
+ \\typedef unsigned int GLbitfield;
+ \\typedef void (*PFNGLCLEARPROC) (GLbitfield mask);
+ \\typedef void(*OpenGLProc)(void);
+ \\union OpenGLProcs {
+ \\ OpenGLProc ptr[1];
+ \\ struct {
+ \\ PFNGLCLEARPROC Clear;
+ \\ } gl;
+ \\};
+ \\extern union OpenGLProcs glProcs;
+ \\#define glClearUnion glProcs.gl.Clear
+ \\#define glClearPFN PFNGLCLEARPROC
+ ,
+ \\pub const GLbitfield = c_uint;
+ ,
+ \\pub const PFNGLCLEARPROC = ?extern fn(GLbitfield);
+ ,
+ \\pub const OpenGLProc = ?extern fn();
+ ,
+ \\pub const union_OpenGLProcs = extern union {
+ \\ ptr: [1]OpenGLProc,
+ \\ gl: extern struct {
+ \\ Clear: PFNGLCLEARPROC,
+ \\ },
+ \\};
+ ,
+ \\pub extern var glProcs: union_OpenGLProcs;
+ ,
+ \\pub const glClearPFN = PFNGLCLEARPROC;
+ ,
+ \\pub inline fn glClearUnion(arg0: GLbitfield) {
+ \\ (??glProcs.gl.Clear)(arg0)
+ \\}
+ ,
+ \\pub const OpenGLProcs = union_OpenGLProcs;
+ );
+
+ cases.add("switch statement with no default",
+ \\int foo(int x) {
+ \\ switch (x) {
+ \\ case 1:
+ \\ x += 1;
+ \\ case 2:
+ \\ break;
+ \\ case 3:
+ \\ case 4:
+ \\ return x + 1;
+ \\ }
+ \\ return x + 13;
+ \\}
+ ,
+ \\fn foo(_arg_x: c_int) -> c_int {
+ \\ var x = _arg_x;
+ \\ {
+ \\ switch (x) {
+ \\ 1 => goto case_0,
+ \\ 2 => goto case_1,
+ \\ 3 => goto case_2,
+ \\ 4 => goto case_3,
+ \\ else => goto end,
+ \\ };
+ \\ case_0:
+ \\ x += 1;
+ \\ case_1:
+ \\ goto end;
+ \\ case_2:
+ \\ case_3:
+ \\ return x + 1;
+ \\ goto end;
+ \\ end:
+ \\ };
+ \\ return x + 13;
+ \\}
+ );
+
+ cases.add("variable name shadowing",
+ \\int foo(void) {
+ \\ int x = 1;
+ \\ {
+ \\ int x = 2;
+ \\ x += 1;
+ \\ }
+ \\ return x;
+ \\}
+ ,
+ \\pub fn foo() -> c_int {
+ \\ var x: c_int = 1;
+ \\ {
+ \\ var x_0: c_int = 2;
+ \\ x_0 += 1;
+ \\ };
+ \\ return x;
+ \\}
+ );
+
+ cases.add("pointer casting",
+ \\float *ptrcast(int *a) {
+ \\ return (float *)a;
+ \\}
+ ,
+ \\fn ptrcast(a: ?&c_int) -> ?&f32 {
+ \\ return @ptrCast(?&f32, a);
+ \\}
+ );
+
+ cases.add("bin not",
+ \\int foo(int x) {
+ \\ return ~x;
+ \\}
+ ,
+ \\pub fn foo(x: c_int) -> c_int {
+ \\ return ~x;
+ \\}
+ );
+
+ cases.add("primitive types included in defined symbols",
+ \\int foo(int u32) {
+ \\ return u32;
+ \\}
+ ,
+ \\pub fn foo(u32_0: c_int) -> c_int {
+ \\ return u32_0;
+ \\}
+ );
+
+ cases.add("const ptr initializer",
+ \\static const char *v0 = "0.0.0";
+ ,
+ \\pub var v0: ?&const u8 = c"0.0.0";
+ );
}
-
-
-
-// TODO
-//float *ptrcast(int *a) {
-// return (float *)a;
-//}
-// should translate to
-// fn ptrcast(a: ?&c_int) -> ?&f32 {
-// return @ptrCast(?&f32, a);
-// }