mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
Merge remote-tracking branch 'origin/master' into llvm6
This commit is contained in:
commit
3a600297ca
@ -3,24 +3,27 @@ const io = @import("std").io;
|
||||
const os = @import("std").os;
|
||||
const heap = @import("std").mem;
|
||||
|
||||
// TODO: OutSteam and InStream interface
|
||||
// TODO: move allocator to heap namespace
|
||||
// TODO: sync up CLI with c++ code
|
||||
// TODO: concurrency
|
||||
|
||||
error InvalidArgument;
|
||||
error MissingArg0;
|
||||
|
||||
var arg0: []u8 = undefined;
|
||||
|
||||
var stderr_file: io.File = undefined;
|
||||
const stderr = &stderr_file.out_stream;
|
||||
|
||||
pub fn main() -> %void {
|
||||
stderr_file = %return io.getStdErr();
|
||||
if (internal_main()) |_| {
|
||||
return;
|
||||
} else |err| {
|
||||
if (err == error.InvalidArgument) {
|
||||
io.stderr.printf("\n") %% return err;
|
||||
printUsage(&io.stderr) %% return err;
|
||||
stderr.print("\n") %% return err;
|
||||
printUsage(stderr) %% return err;
|
||||
} else {
|
||||
io.stderr.printf("{}\n", err) %% return err;
|
||||
stderr.print("{}\n", err) %% return err;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@ -266,7 +269,6 @@ fn printUsage(outstream: &io.OutStream) -> %void {
|
||||
\\ --test-cmd-bin appends test binary path to test cmd args
|
||||
\\
|
||||
);
|
||||
%return outstream.flush();
|
||||
}
|
||||
|
||||
const ZIG_ZEN =
|
||||
|
||||
@ -1211,6 +1211,8 @@ enum BuiltinFnId {
|
||||
BuiltinFnIdMaxValue,
|
||||
BuiltinFnIdMinValue,
|
||||
BuiltinFnIdMemberCount,
|
||||
BuiltinFnIdMemberType,
|
||||
BuiltinFnIdMemberName,
|
||||
BuiltinFnIdTypeof,
|
||||
BuiltinFnIdAddWithOverflow,
|
||||
BuiltinFnIdSubWithOverflow,
|
||||
@ -1261,6 +1263,7 @@ enum BuiltinFnId {
|
||||
BuiltinFnIdAlignCast,
|
||||
BuiltinFnIdOpaqueType,
|
||||
BuiltinFnIdSetAlignStack,
|
||||
BuiltinFnIdArgType,
|
||||
};
|
||||
|
||||
struct BuiltinFnEntry {
|
||||
@ -1366,6 +1369,12 @@ enum BuildMode {
|
||||
BuildModeSafeRelease,
|
||||
};
|
||||
|
||||
enum EmitFileType {
|
||||
EmitFileTypeBinary,
|
||||
EmitFileTypeAssembly,
|
||||
EmitFileTypeLLVMIr,
|
||||
};
|
||||
|
||||
struct LinkLib {
|
||||
Buf *name;
|
||||
Buf *path;
|
||||
@ -1449,6 +1458,7 @@ struct CodeGen {
|
||||
TypeTableEntry *entry_arg_tuple;
|
||||
} builtin_types;
|
||||
|
||||
EmitFileType emit_file_type;
|
||||
ZigTarget zig_target;
|
||||
LLVMTargetDataRef target_data_ref;
|
||||
unsigned pointer_size_bytes;
|
||||
@ -1837,6 +1847,8 @@ enum IrInstructionId {
|
||||
IrInstructionIdMemcpy,
|
||||
IrInstructionIdSlice,
|
||||
IrInstructionIdMemberCount,
|
||||
IrInstructionIdMemberType,
|
||||
IrInstructionIdMemberName,
|
||||
IrInstructionIdBreakpoint,
|
||||
IrInstructionIdReturnAddress,
|
||||
IrInstructionIdFrameAddress,
|
||||
@ -1875,6 +1887,7 @@ enum IrInstructionId {
|
||||
IrInstructionIdAlignCast,
|
||||
IrInstructionIdOpaqueType,
|
||||
IrInstructionIdSetAlignStack,
|
||||
IrInstructionIdArgType,
|
||||
};
|
||||
|
||||
struct IrInstruction {
|
||||
@ -2399,6 +2412,20 @@ struct IrInstructionMemberCount {
|
||||
IrInstruction *container;
|
||||
};
|
||||
|
||||
struct IrInstructionMemberType {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *container_type;
|
||||
IrInstruction *member_index;
|
||||
};
|
||||
|
||||
struct IrInstructionMemberName {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *container_type;
|
||||
IrInstruction *member_index;
|
||||
};
|
||||
|
||||
struct IrInstructionBreakpoint {
|
||||
IrInstruction base;
|
||||
};
|
||||
@ -2675,6 +2702,13 @@ struct IrInstructionSetAlignStack {
|
||||
IrInstruction *align_bytes;
|
||||
};
|
||||
|
||||
struct IrInstructionArgType {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *fn_type;
|
||||
IrInstruction *arg_index;
|
||||
};
|
||||
|
||||
static const size_t slice_ptr_index = 0;
|
||||
static const size_t slice_len_index = 1;
|
||||
|
||||
|
||||
247
src/analyze.cpp
247
src/analyze.cpp
@ -1366,119 +1366,140 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
enum_type->data.enumeration.union_size_bytes = biggest_size_in_bits / 8;
|
||||
enum_type->data.enumeration.most_aligned_union_member = most_aligned_union_member;
|
||||
|
||||
if (!enum_type->data.enumeration.is_invalid) {
|
||||
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
|
||||
TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
|
||||
enum_type->data.enumeration.tag_type = tag_type_entry;
|
||||
if (enum_type->data.enumeration.is_invalid)
|
||||
return;
|
||||
|
||||
uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
|
||||
if (enum_type->zero_bits) {
|
||||
enum_type->type_ref = LLVMVoidType();
|
||||
|
||||
if (most_aligned_union_member) {
|
||||
// create llvm type for union
|
||||
uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
|
||||
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;
|
||||
}
|
||||
enum_type->data.enumeration.union_type_ref = union_type_ref;
|
||||
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 = ZigLLVMCreateDebugStructType(g->dbuilder,
|
||||
ZigLLVMFileToScope(import->di_file),
|
||||
buf_ptr(&enum_type->name),
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
debug_size_in_bits,
|
||||
debug_align_in_bits,
|
||||
0, nullptr, di_root_members, (int)debug_member_count, 0, nullptr, "");
|
||||
|
||||
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);
|
||||
ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type);
|
||||
enum_type->di_type = replacement_di_type;
|
||||
return;
|
||||
}
|
||||
|
||||
if (align_of_tag_in_bits >= biggest_align_in_bits) {
|
||||
enum_type->data.enumeration.gen_tag_index = 0;
|
||||
enum_type->data.enumeration.gen_union_index = 1;
|
||||
} else {
|
||||
enum_type->data.enumeration.gen_union_index = 0;
|
||||
enum_type->data.enumeration.gen_tag_index = 1;
|
||||
}
|
||||
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
|
||||
TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
|
||||
enum_type->data.enumeration.tag_type = tag_type_entry;
|
||||
|
||||
// create llvm type for root struct
|
||||
LLVMTypeRef root_struct_element_types[2];
|
||||
root_struct_element_types[enum_type->data.enumeration.gen_tag_index] = tag_type_entry->type_ref;
|
||||
root_struct_element_types[enum_type->data.enumeration.gen_union_index] = union_type_ref;
|
||||
LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false);
|
||||
uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
|
||||
|
||||
// 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(enum_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(enum_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, "");
|
||||
|
||||
// create debug types for members of root struct
|
||||
uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
|
||||
enum_type->data.enumeration.gen_tag_index);
|
||||
ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(enum_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);
|
||||
|
||||
uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
|
||||
enum_type->data.enumeration.gen_union_index);
|
||||
ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(enum_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);
|
||||
|
||||
// create debug type for root struct
|
||||
ZigLLVMDIType *di_root_members[2];
|
||||
di_root_members[enum_type->data.enumeration.gen_tag_index] = tag_member_di_type;
|
||||
di_root_members[enum_type->data.enumeration.gen_union_index] = union_member_di_type;
|
||||
|
||||
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, enum_type->type_ref);
|
||||
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref);
|
||||
ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
|
||||
ZigLLVMFileToScope(import->di_file),
|
||||
buf_ptr(&enum_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, enum_type->di_type, replacement_di_type);
|
||||
enum_type->di_type = replacement_di_type;
|
||||
if (most_aligned_union_member) {
|
||||
// create llvm type for union
|
||||
uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
|
||||
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 {
|
||||
// create llvm type for root struct
|
||||
enum_type->type_ref = tag_type_entry->type_ref;
|
||||
|
||||
// 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,
|
||||
ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
|
||||
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, "");
|
||||
|
||||
ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type);
|
||||
enum_type->di_type = tag_di_type;
|
||||
union_type_ref = most_aligned_union_member->type_ref;
|
||||
}
|
||||
enum_type->data.enumeration.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);
|
||||
|
||||
if (align_of_tag_in_bits >= biggest_align_in_bits) {
|
||||
enum_type->data.enumeration.gen_tag_index = 0;
|
||||
enum_type->data.enumeration.gen_union_index = 1;
|
||||
} else {
|
||||
enum_type->data.enumeration.gen_union_index = 0;
|
||||
enum_type->data.enumeration.gen_tag_index = 1;
|
||||
}
|
||||
|
||||
// create llvm type for root struct
|
||||
LLVMTypeRef root_struct_element_types[2];
|
||||
root_struct_element_types[enum_type->data.enumeration.gen_tag_index] = tag_type_entry->type_ref;
|
||||
root_struct_element_types[enum_type->data.enumeration.gen_union_index] = union_type_ref;
|
||||
LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false);
|
||||
|
||||
// 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(enum_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(enum_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, "");
|
||||
|
||||
// create debug types for members of root struct
|
||||
uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
|
||||
enum_type->data.enumeration.gen_tag_index);
|
||||
ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(enum_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);
|
||||
|
||||
uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
|
||||
enum_type->data.enumeration.gen_union_index);
|
||||
ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(enum_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);
|
||||
|
||||
// create debug type for root struct
|
||||
ZigLLVMDIType *di_root_members[2];
|
||||
di_root_members[enum_type->data.enumeration.gen_tag_index] = tag_member_di_type;
|
||||
di_root_members[enum_type->data.enumeration.gen_union_index] = union_member_di_type;
|
||||
|
||||
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, enum_type->type_ref);
|
||||
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref);
|
||||
ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
|
||||
ZigLLVMFileToScope(import->di_file),
|
||||
buf_ptr(&enum_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, enum_type->di_type, replacement_di_type);
|
||||
enum_type->di_type = replacement_di_type;
|
||||
} else {
|
||||
// create llvm type for root struct
|
||||
enum_type->type_ref = tag_type_entry->type_ref;
|
||||
|
||||
// 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,
|
||||
ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
|
||||
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, "");
|
||||
|
||||
ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type);
|
||||
enum_type->di_type = tag_di_type;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1875,9 +1896,11 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
enum_type->data.enumeration.zero_bits_known = true;
|
||||
|
||||
// also compute abi_alignment
|
||||
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
|
||||
uint32_t align_of_tag_in_bytes = LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
|
||||
enum_type->data.enumeration.abi_alignment = max(align_of_tag_in_bytes, biggest_align_bytes);
|
||||
if (!enum_type->zero_bits) {
|
||||
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
|
||||
uint32_t align_of_tag_in_bytes = LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
|
||||
enum_type->data.enumeration.abi_alignment = max(align_of_tag_in_bytes, biggest_align_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
|
||||
@ -3440,8 +3463,14 @@ void find_libc_lib_path(CodeGen *g) {
|
||||
zig_panic("Unable to determine libc lib path.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!g->libc_static_lib_dir || buf_len(g->libc_static_lib_dir) == 0) {
|
||||
zig_panic("Unable to determine libc static lib path.");
|
||||
if ((g->zig_target.os == ZigLLVM_Win32) && (g->msvc_lib_dir != NULL)) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
zig_panic("Unable to determine libc static lib path.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -91,6 +91,9 @@
|
||||
IDENT_START: \
|
||||
case DIGIT
|
||||
|
||||
#define LINE_ENDING \
|
||||
'\r': \
|
||||
case '\n'
|
||||
|
||||
static void begin_token(CTokenize *ctok, CTokId id) {
|
||||
assert(ctok->cur_tok == nullptr);
|
||||
@ -191,7 +194,7 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) {
|
||||
case '\\':
|
||||
ctok->state = CTokStateBackslash;
|
||||
break;
|
||||
case '\n':
|
||||
case LINE_ENDING:
|
||||
goto found_end_of_macro;
|
||||
case IDENT_START:
|
||||
ctok->state = CTokStateIdentifier;
|
||||
|
||||
@ -189,6 +189,10 @@ void codegen_set_is_test(CodeGen *g, bool is_test_build) {
|
||||
g->is_test_build = is_test_build;
|
||||
}
|
||||
|
||||
void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type) {
|
||||
g->emit_file_type = emit_file_type;
|
||||
}
|
||||
|
||||
void codegen_set_is_static(CodeGen *g, bool is_static) {
|
||||
g->is_static = is_static;
|
||||
}
|
||||
@ -3380,6 +3384,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
case IrInstructionIdEmbedFile:
|
||||
case IrInstructionIdIntType:
|
||||
case IrInstructionIdMemberCount:
|
||||
case IrInstructionIdMemberType:
|
||||
case IrInstructionIdMemberName:
|
||||
case IrInstructionIdAlignOf:
|
||||
case IrInstructionIdFnProto:
|
||||
case IrInstructionIdTestComptime:
|
||||
@ -3397,6 +3403,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
case IrInstructionIdPtrTypeOf:
|
||||
case IrInstructionIdOpaqueType:
|
||||
case IrInstructionIdSetAlignStack:
|
||||
case IrInstructionIdArgType:
|
||||
zig_unreachable();
|
||||
case IrInstructionIdReturn:
|
||||
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
|
||||
@ -4493,24 +4500,70 @@ static void do_code_gen(CodeGen *g) {
|
||||
LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error);
|
||||
#endif
|
||||
|
||||
codegen_add_time_event(g, "LLVM Emit Object");
|
||||
codegen_add_time_event(g, "LLVM Emit Output");
|
||||
|
||||
char *err_msg = nullptr;
|
||||
Buf *o_basename = buf_create_from_buf(g->root_out_name);
|
||||
const char *o_ext = target_o_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, o_ext);
|
||||
|
||||
switch (g->emit_file_type) {
|
||||
case EmitFileTypeBinary:
|
||||
{
|
||||
const char *o_ext = target_o_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, o_ext);
|
||||
break;
|
||||
}
|
||||
case EmitFileTypeAssembly:
|
||||
{
|
||||
const char *asm_ext = target_asm_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, asm_ext);
|
||||
break;
|
||||
}
|
||||
case EmitFileTypeLLVMIr:
|
||||
{
|
||||
const char *llvm_ir_ext = target_llvm_ir_file_ext(&g->zig_target);
|
||||
buf_append_str(o_basename, llvm_ir_ext);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
Buf *output_path = buf_alloc();
|
||||
os_path_join(g->cache_dir, o_basename, output_path);
|
||||
ensure_cache_dir(g);
|
||||
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
|
||||
LLVMObjectFile, &err_msg, g->build_mode == BuildModeDebug))
|
||||
{
|
||||
zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg);
|
||||
|
||||
switch (g->emit_file_type) {
|
||||
case EmitFileTypeBinary:
|
||||
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
|
||||
ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug))
|
||||
{
|
||||
zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg);
|
||||
}
|
||||
validate_inline_fns(g);
|
||||
g->link_objects.append(output_path);
|
||||
break;
|
||||
|
||||
case EmitFileTypeAssembly:
|
||||
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
|
||||
ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug))
|
||||
{
|
||||
zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg);
|
||||
}
|
||||
validate_inline_fns(g);
|
||||
break;
|
||||
|
||||
case EmitFileTypeLLVMIr:
|
||||
if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path),
|
||||
ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug))
|
||||
{
|
||||
zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg);
|
||||
}
|
||||
validate_inline_fns(g);
|
||||
break;
|
||||
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
validate_inline_fns(g);
|
||||
|
||||
g->link_objects.append(output_path);
|
||||
}
|
||||
|
||||
static const uint8_t int_sizes_in_bits[] = {
|
||||
@ -4816,7 +4869,9 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn(g, BuiltinFnIdMaxValue, "maxValue", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdMinValue, "minValue", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdMemberCount, "memberCount", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf
|
||||
create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);
|
||||
create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);
|
||||
create_builtin_fn(g, BuiltinFnIdMulWithOverflow, "mulWithOverflow", 4);
|
||||
@ -4863,6 +4918,7 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0);
|
||||
create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2);
|
||||
}
|
||||
|
||||
static const char *bool_to_str(bool b) {
|
||||
|
||||
@ -23,6 +23,7 @@ void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len);
|
||||
void codegen_set_is_test(CodeGen *codegen, bool is_test);
|
||||
void codegen_set_each_lib_rpath(CodeGen *codegen, bool each_lib_rpath);
|
||||
|
||||
void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type);
|
||||
void codegen_set_is_static(CodeGen *codegen, bool is_static);
|
||||
void codegen_set_strip(CodeGen *codegen, bool strip);
|
||||
void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color);
|
||||
|
||||
303
src/ir.cpp
303
src/ir.cpp
@ -411,6 +411,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberCount *) {
|
||||
return IrInstructionIdMemberCount;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberType *) {
|
||||
return IrInstructionIdMemberType;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberName *) {
|
||||
return IrInstructionIdMemberName;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionBreakpoint *) {
|
||||
return IrInstructionIdBreakpoint;
|
||||
}
|
||||
@ -567,6 +575,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetAlignStack *)
|
||||
return IrInstructionIdSetAlignStack;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionArgType *) {
|
||||
return IrInstructionIdArgType;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
|
||||
T *special_instruction = allocate<T>(1);
|
||||
@ -1779,6 +1791,32 @@ static IrInstruction *ir_build_member_count(IrBuilder *irb, Scope *scope, AstNod
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_member_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *container_type, IrInstruction *member_index)
|
||||
{
|
||||
IrInstructionMemberType *instruction = ir_build_instruction<IrInstructionMemberType>(irb, scope, source_node);
|
||||
instruction->container_type = container_type;
|
||||
instruction->member_index = member_index;
|
||||
|
||||
ir_ref_instruction(container_type, irb->current_basic_block);
|
||||
ir_ref_instruction(member_index, irb->current_basic_block);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_member_name(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *container_type, IrInstruction *member_index)
|
||||
{
|
||||
IrInstructionMemberName *instruction = ir_build_instruction<IrInstructionMemberName>(irb, scope, source_node);
|
||||
instruction->container_type = container_type;
|
||||
instruction->member_index = member_index;
|
||||
|
||||
ir_ref_instruction(container_type, irb->current_basic_block);
|
||||
ir_ref_instruction(member_index, irb->current_basic_block);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_breakpoint(IrBuilder *irb, Scope *scope, AstNode *source_node) {
|
||||
IrInstructionBreakpoint *instruction = ir_build_instruction<IrInstructionBreakpoint>(irb, scope, source_node);
|
||||
return &instruction->base;
|
||||
@ -2263,6 +2301,19 @@ static IrInstruction *ir_build_set_align_stack(IrBuilder *irb, Scope *scope, Ast
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *fn_type, IrInstruction *arg_index)
|
||||
{
|
||||
IrInstructionArgType *instruction = ir_build_instruction<IrInstructionArgType>(irb, scope, source_node);
|
||||
instruction->fn_type = fn_type;
|
||||
instruction->arg_index = arg_index;
|
||||
|
||||
ir_ref_instruction(fn_type, irb->current_basic_block);
|
||||
ir_ref_instruction(arg_index, irb->current_basic_block);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -2710,6 +2761,22 @@ static IrInstruction *ir_instruction_membercount_get_dep(IrInstructionMemberCoun
|
||||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_instruction_membertype_get_dep(IrInstructionMemberType *instruction, size_t index) {
|
||||
switch (index) {
|
||||
case 0: return instruction->container_type;
|
||||
case 1: return instruction->member_index;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_instruction_membername_get_dep(IrInstructionMemberName *instruction, size_t index) {
|
||||
switch (index) {
|
||||
case 0: return instruction->container_type;
|
||||
case 1: return instruction->member_index;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_instruction_breakpoint_get_dep(IrInstructionBreakpoint *instruction, size_t index) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -2992,6 +3059,14 @@ static IrInstruction *ir_instruction_setalignstack_get_dep(IrInstructionSetAlign
|
||||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_instruction_argtype_get_dep(IrInstructionArgType *instruction, size_t index) {
|
||||
switch (index) {
|
||||
case 0: return instruction->fn_type;
|
||||
case 1: return instruction->arg_index;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
|
||||
switch (instruction->id) {
|
||||
case IrInstructionIdInvalid:
|
||||
@ -3118,6 +3193,10 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
|
||||
return ir_instruction_slice_get_dep((IrInstructionSlice *) instruction, index);
|
||||
case IrInstructionIdMemberCount:
|
||||
return ir_instruction_membercount_get_dep((IrInstructionMemberCount *) instruction, index);
|
||||
case IrInstructionIdMemberType:
|
||||
return ir_instruction_membertype_get_dep((IrInstructionMemberType *) instruction, index);
|
||||
case IrInstructionIdMemberName:
|
||||
return ir_instruction_membername_get_dep((IrInstructionMemberName *) instruction, index);
|
||||
case IrInstructionIdBreakpoint:
|
||||
return ir_instruction_breakpoint_get_dep((IrInstructionBreakpoint *) instruction, index);
|
||||
case IrInstructionIdReturnAddress:
|
||||
@ -3194,6 +3273,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
|
||||
return ir_instruction_opaquetype_get_dep((IrInstructionOpaqueType *) instruction, index);
|
||||
case IrInstructionIdSetAlignStack:
|
||||
return ir_instruction_setalignstack_get_dep((IrInstructionSetAlignStack *) instruction, index);
|
||||
case IrInstructionIdArgType:
|
||||
return ir_instruction_argtype_get_dep((IrInstructionArgType *) instruction, index);
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -4352,6 +4433,36 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
||||
|
||||
return ir_build_member_count(irb, scope, node, arg0_value);
|
||||
}
|
||||
case BuiltinFnIdMemberType:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
|
||||
if (arg0_value == irb->codegen->invalid_instruction)
|
||||
return arg0_value;
|
||||
|
||||
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
|
||||
IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
|
||||
if (arg1_value == irb->codegen->invalid_instruction)
|
||||
return arg1_value;
|
||||
|
||||
|
||||
return ir_build_member_type(irb, scope, node, arg0_value, arg1_value);
|
||||
}
|
||||
case BuiltinFnIdMemberName:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
|
||||
if (arg0_value == irb->codegen->invalid_instruction)
|
||||
return arg0_value;
|
||||
|
||||
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
|
||||
IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
|
||||
if (arg1_value == irb->codegen->invalid_instruction)
|
||||
return arg1_value;
|
||||
|
||||
|
||||
return ir_build_member_name(irb, scope, node, arg0_value, arg1_value);
|
||||
}
|
||||
case BuiltinFnIdBreakpoint:
|
||||
return ir_build_breakpoint(irb, scope, node);
|
||||
case BuiltinFnIdReturnAddress:
|
||||
@ -4629,6 +4740,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
||||
|
||||
return ir_build_set_align_stack(irb, scope, node, arg0_value);
|
||||
}
|
||||
case BuiltinFnIdArgType:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
|
||||
if (arg0_value == irb->codegen->invalid_instruction)
|
||||
return arg0_value;
|
||||
|
||||
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
|
||||
IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
|
||||
if (arg1_value == irb->codegen->invalid_instruction)
|
||||
return arg1_value;
|
||||
|
||||
return ir_build_arg_type(irb, scope, node, arg0_value, arg1_value);
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -11643,6 +11768,62 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
|
||||
buf_ptr(&child_type->name), buf_ptr(field_name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
} else if (child_type->id == TypeTableEntryIdErrorUnion) {
|
||||
if (buf_eql_str(field_name, "Child")) {
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
|
||||
create_const_type(ira->codegen, child_type->data.error.child_type),
|
||||
ira->codegen->builtin_types.entry_type,
|
||||
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
} else {
|
||||
ir_add_error(ira, &field_ptr_instruction->base,
|
||||
buf_sprintf("type '%s' has no member called '%s'",
|
||||
buf_ptr(&child_type->name), buf_ptr(field_name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
} else if (child_type->id == TypeTableEntryIdMaybe) {
|
||||
if (buf_eql_str(field_name, "Child")) {
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
|
||||
create_const_type(ira->codegen, child_type->data.maybe.child_type),
|
||||
ira->codegen->builtin_types.entry_type,
|
||||
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
} else {
|
||||
ir_add_error(ira, &field_ptr_instruction->base,
|
||||
buf_sprintf("type '%s' has no member called '%s'",
|
||||
buf_ptr(&child_type->name), buf_ptr(field_name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
} else if (child_type->id == TypeTableEntryIdFn) {
|
||||
if (buf_eql_str(field_name, "ReturnType")) {
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
|
||||
create_const_type(ira->codegen, child_type->data.fn.fn_type_id.return_type),
|
||||
ira->codegen->builtin_types.entry_type,
|
||||
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
} else if (buf_eql_str(field_name, "is_var_args")) {
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
|
||||
create_const_bool(ira->codegen, child_type->data.fn.fn_type_id.is_var_args),
|
||||
ira->codegen->builtin_types.entry_bool,
|
||||
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
} else if (buf_eql_str(field_name, "arg_count")) {
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
|
||||
create_const_usize(ira->codegen, child_type->data.fn.fn_type_id.param_count),
|
||||
ira->codegen->builtin_types.entry_usize,
|
||||
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
} else {
|
||||
ir_add_error(ira, &field_ptr_instruction->base,
|
||||
buf_sprintf("type '%s' has no member called '%s'",
|
||||
buf_ptr(&child_type->name), buf_ptr(field_name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
} else {
|
||||
ir_add_error(ira, &field_ptr_instruction->base,
|
||||
buf_sprintf("type '%s' does not support field access", buf_ptr(&child_type->name)));
|
||||
@ -14240,6 +14421,90 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns
|
||||
return ira->codegen->builtin_types.entry_num_lit_int;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstructionMemberType *instruction) {
|
||||
IrInstruction *container_type_value = instruction->container_type->other;
|
||||
TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
|
||||
if (type_is_invalid(container_type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
uint64_t member_index;
|
||||
IrInstruction *index_value = instruction->member_index->other;
|
||||
if (!ir_resolve_usize(ira, index_value, &member_index))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (container_type->id == TypeTableEntryIdStruct) {
|
||||
if (member_index >= container_type->data.structure.src_field_count) {
|
||||
ir_add_error(ira, index_value,
|
||||
buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
|
||||
member_index, buf_ptr(&container_type->name), container_type->data.structure.src_field_count));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
TypeStructField *field = &container_type->data.structure.fields[member_index];
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
out_val->data.x_type = field->type_entry;
|
||||
return ira->codegen->builtin_types.entry_type;
|
||||
} else if (container_type->id == TypeTableEntryIdEnum) {
|
||||
if (member_index >= container_type->data.enumeration.src_field_count) {
|
||||
ir_add_error(ira, index_value,
|
||||
buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
|
||||
member_index, buf_ptr(&container_type->name), container_type->data.enumeration.src_field_count));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
TypeEnumField *field = &container_type->data.enumeration.fields[member_index];
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
out_val->data.x_type = field->type_entry;
|
||||
return ira->codegen->builtin_types.entry_type;
|
||||
} else {
|
||||
ir_add_error(ira, container_type_value,
|
||||
buf_sprintf("type '%s' does not support @memberType", buf_ptr(&container_type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstructionMemberName *instruction) {
|
||||
IrInstruction *container_type_value = instruction->container_type->other;
|
||||
TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
|
||||
if (type_is_invalid(container_type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
uint64_t member_index;
|
||||
IrInstruction *index_value = instruction->member_index->other;
|
||||
if (!ir_resolve_usize(ira, index_value, &member_index))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (container_type->id == TypeTableEntryIdStruct) {
|
||||
if (member_index >= container_type->data.structure.src_field_count) {
|
||||
ir_add_error(ira, index_value,
|
||||
buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
|
||||
member_index, buf_ptr(&container_type->name), container_type->data.structure.src_field_count));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
TypeStructField *field = &container_type->data.structure.fields[member_index];
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
init_const_str_lit(ira->codegen, out_val, field->name);
|
||||
return out_val->type;
|
||||
} else if (container_type->id == TypeTableEntryIdEnum) {
|
||||
if (member_index >= container_type->data.enumeration.src_field_count) {
|
||||
ir_add_error(ira, index_value,
|
||||
buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
|
||||
member_index, buf_ptr(&container_type->name), container_type->data.enumeration.src_field_count));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
TypeEnumField *field = &container_type->data.enumeration.fields[member_index];
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
init_const_str_lit(ira->codegen, out_val, field->name);
|
||||
return out_val->type;
|
||||
} else {
|
||||
ir_add_error(ira, container_type_value,
|
||||
buf_sprintf("type '%s' does not support @memberName", buf_ptr(&container_type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstructionBreakpoint *instruction) {
|
||||
ir_build_breakpoint_from(&ira->new_irb, &instruction->base);
|
||||
return ira->codegen->builtin_types.entry_void;
|
||||
@ -15346,6 +15611,35 @@ static TypeTableEntry *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, Ir
|
||||
return ira->codegen->builtin_types.entry_void;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstructionArgType *instruction) {
|
||||
IrInstruction *fn_type_inst = instruction->fn_type->other;
|
||||
TypeTableEntry *fn_type = ir_resolve_type(ira, fn_type_inst);
|
||||
if (type_is_invalid(fn_type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
IrInstruction *arg_index_inst = instruction->arg_index->other;
|
||||
uint64_t arg_index;
|
||||
if (!ir_resolve_usize(ira, arg_index_inst, &arg_index))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (fn_type->id != TypeTableEntryIdFn) {
|
||||
ir_add_error(ira, fn_type_inst, buf_sprintf("expected function, found '%s'", buf_ptr(&fn_type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
|
||||
if (arg_index >= fn_type_id->param_count) {
|
||||
ir_add_error(ira, arg_index_inst,
|
||||
buf_sprintf("arg index %" ZIG_PRI_u64 " out of bounds; '%s' has %" ZIG_PRI_usize " arguments",
|
||||
arg_index, buf_ptr(&fn_type->name), fn_type_id->param_count));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
out_val->data.x_type = fn_type_id->param_info[arg_index].type;
|
||||
return ira->codegen->builtin_types.entry_type;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
|
||||
switch (instruction->id) {
|
||||
case IrInstructionIdInvalid:
|
||||
@ -15480,6 +15774,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
|
||||
return ir_analyze_instruction_slice(ira, (IrInstructionSlice *)instruction);
|
||||
case IrInstructionIdMemberCount:
|
||||
return ir_analyze_instruction_member_count(ira, (IrInstructionMemberCount *)instruction);
|
||||
case IrInstructionIdMemberType:
|
||||
return ir_analyze_instruction_member_type(ira, (IrInstructionMemberType *)instruction);
|
||||
case IrInstructionIdMemberName:
|
||||
return ir_analyze_instruction_member_name(ira, (IrInstructionMemberName *)instruction);
|
||||
case IrInstructionIdBreakpoint:
|
||||
return ir_analyze_instruction_breakpoint(ira, (IrInstructionBreakpoint *)instruction);
|
||||
case IrInstructionIdReturnAddress:
|
||||
@ -15536,6 +15834,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
|
||||
return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction);
|
||||
case IrInstructionIdSetAlignStack:
|
||||
return ir_analyze_instruction_set_align_stack(ira, (IrInstructionSetAlignStack *)instruction);
|
||||
case IrInstructionIdArgType:
|
||||
return ir_analyze_instruction_arg_type(ira, (IrInstructionArgType *)instruction);
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -15687,6 +15987,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
case IrInstructionIdBoolNot:
|
||||
case IrInstructionIdSlice:
|
||||
case IrInstructionIdMemberCount:
|
||||
case IrInstructionIdMemberType:
|
||||
case IrInstructionIdMemberName:
|
||||
case IrInstructionIdAlignOf:
|
||||
case IrInstructionIdReturnAddress:
|
||||
case IrInstructionIdFrameAddress:
|
||||
@ -15716,6 +16018,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
case IrInstructionIdTypeId:
|
||||
case IrInstructionIdAlignCast:
|
||||
case IrInstructionIdOpaqueType:
|
||||
case IrInstructionIdArgType:
|
||||
return false;
|
||||
case IrInstructionIdAsm:
|
||||
{
|
||||
|
||||
@ -658,6 +658,22 @@ static void ir_print_member_count(IrPrint *irp, IrInstructionMemberCount *instru
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_member_type(IrPrint *irp, IrInstructionMemberType *instruction) {
|
||||
fprintf(irp->f, "@memberType(");
|
||||
ir_print_other_instruction(irp, instruction->container_type);
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, instruction->member_index);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_member_name(IrPrint *irp, IrInstructionMemberName *instruction) {
|
||||
fprintf(irp->f, "@memberName(");
|
||||
ir_print_other_instruction(irp, instruction->container_type);
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, instruction->member_index);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_breakpoint(IrPrint *irp, IrInstructionBreakpoint *instruction) {
|
||||
fprintf(irp->f, "@breakpoint()");
|
||||
}
|
||||
@ -954,6 +970,15 @@ static void ir_print_set_align_stack(IrPrint *irp, IrInstructionSetAlignStack *i
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_arg_type(IrPrint *irp, IrInstructionArgType *instruction) {
|
||||
fprintf(irp->f, "@ArgType(");
|
||||
ir_print_other_instruction(irp, instruction->fn_type);
|
||||
fprintf(irp->f, ",");
|
||||
ir_print_other_instruction(irp, instruction->arg_index);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
|
||||
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
ir_print_prefix(irp, instruction);
|
||||
switch (instruction->id) {
|
||||
@ -1139,6 +1164,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdMemberCount:
|
||||
ir_print_member_count(irp, (IrInstructionMemberCount *)instruction);
|
||||
break;
|
||||
case IrInstructionIdMemberType:
|
||||
ir_print_member_type(irp, (IrInstructionMemberType *)instruction);
|
||||
break;
|
||||
case IrInstructionIdMemberName:
|
||||
ir_print_member_name(irp, (IrInstructionMemberName *)instruction);
|
||||
break;
|
||||
case IrInstructionIdBreakpoint:
|
||||
ir_print_breakpoint(irp, (IrInstructionBreakpoint *)instruction);
|
||||
break;
|
||||
@ -1256,6 +1287,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdSetAlignStack:
|
||||
ir_print_set_align_stack(irp, (IrInstructionSetAlignStack *)instruction);
|
||||
break;
|
||||
case IrInstructionIdArgType:
|
||||
ir_print_arg_type(irp, (IrInstructionArgType *)instruction);
|
||||
break;
|
||||
}
|
||||
fprintf(irp->f, "\n");
|
||||
}
|
||||
|
||||
@ -894,7 +894,7 @@ void codegen_link(CodeGen *g, const char *out_file) {
|
||||
Buf *o_file_path = g->link_objects.at(0);
|
||||
int err;
|
||||
if ((err = os_rename(o_file_path, &lj.out_file))) {
|
||||
zig_panic("unable to rename object file into final output: %s", err_str(err));
|
||||
zig_panic("unable to rename object file %s into final output %s: %s", buf_ptr(o_file_path), buf_ptr(&lj.out_file), err_str(err));
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
15
src/main.cpp
15
src/main.cpp
@ -32,6 +32,7 @@ static int usage(const char *arg0) {
|
||||
" --assembly $source add assembly file to build\n"
|
||||
" --cache-dir $path override the cache directory\n"
|
||||
" --color $auto|off|on enable or disable colored error messages\n"
|
||||
" --emit $filetype emit a specific file format as compilation output\n"
|
||||
" --enable-timing-info print timing diagnostics\n"
|
||||
" --libc-include-dir $path directory where libc stdlib.h resides\n"
|
||||
" --name $name override output name\n"
|
||||
@ -269,6 +270,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
char *arg0 = argv[0];
|
||||
Cmd cmd = CmdInvalid;
|
||||
EmitFileType emit_file_type = EmitFileTypeBinary;
|
||||
const char *in_file = nullptr;
|
||||
const char *out_file = nullptr;
|
||||
const char *out_file_h = nullptr;
|
||||
@ -535,6 +537,17 @@ int main(int argc, char **argv) {
|
||||
fprintf(stderr, "--color options are 'auto', 'on', or 'off'\n");
|
||||
return usage(arg0);
|
||||
}
|
||||
} else if (strcmp(arg, "--emit") == 0) {
|
||||
if (strcmp(argv[i], "asm") == 0) {
|
||||
emit_file_type = EmitFileTypeAssembly;
|
||||
} else if (strcmp(argv[i], "bin") == 0) {
|
||||
emit_file_type = EmitFileTypeBinary;
|
||||
} else if (strcmp(argv[i], "llvm-ir") == 0) {
|
||||
emit_file_type = EmitFileTypeLLVMIr;
|
||||
} else {
|
||||
fprintf(stderr, "--emit options are 'asm', 'bin', or 'llvm-ir'\n");
|
||||
return usage(arg0);
|
||||
}
|
||||
} else if (strcmp(arg, "--name") == 0) {
|
||||
out_name = argv[i];
|
||||
} else if (strcmp(arg, "--libc-lib-dir") == 0) {
|
||||
@ -815,6 +828,8 @@ int main(int argc, char **argv) {
|
||||
add_package(g, cur_pkg, g->root_package);
|
||||
|
||||
if (cmd == CmdBuild) {
|
||||
codegen_set_emit_file_type(g, emit_file_type);
|
||||
|
||||
for (size_t i = 0; i < objects.length; i += 1) {
|
||||
codegen_add_object(g, buf_create_from_str(objects.at(i)));
|
||||
}
|
||||
|
||||
@ -581,6 +581,14 @@ const char *target_o_file_ext(ZigTarget *target) {
|
||||
}
|
||||
}
|
||||
|
||||
const char *target_asm_file_ext(ZigTarget *target) {
|
||||
return ".s";
|
||||
}
|
||||
|
||||
const char *target_llvm_ir_file_ext(ZigTarget *target) {
|
||||
return ".ll";
|
||||
}
|
||||
|
||||
const char *target_exe_file_ext(ZigTarget *target) {
|
||||
if (target->os == ZigLLVM_Win32) {
|
||||
return ".exe";
|
||||
|
||||
@ -73,6 +73,8 @@ void resolve_target_object_format(ZigTarget *target);
|
||||
uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id);
|
||||
|
||||
const char *target_o_file_ext(ZigTarget *target);
|
||||
const char *target_asm_file_ext(ZigTarget *target);
|
||||
const char *target_llvm_ir_file_ext(ZigTarget *target);
|
||||
const char *target_exe_file_ext(ZigTarget *target);
|
||||
|
||||
Buf *target_dynamic_linker(ZigTarget *target);
|
||||
|
||||
@ -77,7 +77,7 @@ static const bool assertions_on = false;
|
||||
#endif
|
||||
|
||||
bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
|
||||
const char *filename, LLVMCodeGenFileType file_type, char **error_message, bool is_debug)
|
||||
const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug)
|
||||
{
|
||||
std::error_code EC;
|
||||
raw_fd_ostream dest(filename, EC, sys::fs::F_None);
|
||||
@ -135,18 +135,24 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
|
||||
MPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis()));
|
||||
PMBuilder->populateModulePassManager(MPM);
|
||||
|
||||
// Set output pass.
|
||||
TargetMachine::CodeGenFileType ft;
|
||||
switch (file_type) {
|
||||
case LLVMAssemblyFile:
|
||||
ft = TargetMachine::CGFT_AssemblyFile;
|
||||
break;
|
||||
default:
|
||||
ft = TargetMachine::CGFT_ObjectFile;
|
||||
break;
|
||||
}
|
||||
if (target_machine->addPassesToEmitFile(MPM, dest, ft)) {
|
||||
*error_message = strdup("TargetMachine can't emit a file of this type");
|
||||
return true;
|
||||
if (output_type != ZigLLVM_EmitLLVMIr) {
|
||||
switch (output_type) {
|
||||
case ZigLLVM_EmitAssembly:
|
||||
ft = TargetMachine::CGFT_AssemblyFile;
|
||||
break;
|
||||
case ZigLLVM_EmitBinary:
|
||||
ft = TargetMachine::CGFT_ObjectFile;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
if (target_machine->addPassesToEmitFile(MPM, dest, ft)) {
|
||||
*error_message = strdup("TargetMachine can't emit a file of this type");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// run per function optimization passes
|
||||
@ -158,7 +164,11 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
|
||||
|
||||
MPM.run(*module);
|
||||
|
||||
dest.close();
|
||||
if (output_type == ZigLLVM_EmitLLVMIr) {
|
||||
if (LLVMPrintModuleToFile(module_ref, filename, error_message)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -34,8 +34,16 @@ void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R);
|
||||
char *ZigLLVMGetHostCPUName(void);
|
||||
char *ZigLLVMGetNativeFeatures(void);
|
||||
|
||||
// We use a custom enum here since LLVM does not expose LLVMIr as an emit
|
||||
// output through the same mechanism as assembly/binary.
|
||||
enum ZigLLVM_EmitOutputType {
|
||||
ZigLLVM_EmitAssembly,
|
||||
ZigLLVM_EmitBinary,
|
||||
ZigLLVM_EmitLLVMIr,
|
||||
};
|
||||
|
||||
bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
|
||||
const char *filename, LLVMCodeGenFileType file_type, char **error_message, bool is_debug);
|
||||
const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug);
|
||||
|
||||
LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
|
||||
unsigned NumArgs, unsigned CC, bool always_inline, const char *Name);
|
||||
|
||||
16
std/heap.zig
16
std/heap.zig
@ -17,8 +17,8 @@ pub var c_allocator = Allocator {
|
||||
};
|
||||
|
||||
fn cAlloc(self: &Allocator, n: usize, alignment: usize) -> %[]u8 {
|
||||
if (c.malloc(usize(n))) |mem| {
|
||||
@ptrCast(&u8, mem)[0..n]
|
||||
if (c.malloc(usize(n))) |buf| {
|
||||
@ptrCast(&u8, buf)[0..n]
|
||||
} else {
|
||||
error.OutOfMemory
|
||||
}
|
||||
@ -29,8 +29,8 @@ fn cRealloc(self: &Allocator, old_mem: []u8, new_size: usize, alignment: usize)
|
||||
old_mem[0..new_size]
|
||||
} else {
|
||||
const old_ptr = @ptrCast(&c_void, old_mem.ptr);
|
||||
if (c.realloc(old_ptr, usize(new_size))) |mem| {
|
||||
@ptrCast(&u8, mem)[0..new_size]
|
||||
if (c.realloc(old_ptr, usize(new_size))) |buf| {
|
||||
@ptrCast(&u8, buf)[0..new_size]
|
||||
} else {
|
||||
error.OutOfMemory
|
||||
}
|
||||
@ -136,6 +136,14 @@ pub const IncrementingAllocator = struct {
|
||||
}
|
||||
};
|
||||
|
||||
test "c_allocator" {
|
||||
if (builtin.link_libc) {
|
||||
var slice = c_allocator.alloc(u8, 50) %% return;
|
||||
defer c_allocator.free(slice);
|
||||
slice = c_allocator.realloc(u8, slice, 100) %% return;
|
||||
}
|
||||
}
|
||||
|
||||
test "IncrementingAllocator" {
|
||||
const total_bytes = 100 * 1024 * 1024;
|
||||
var inc_allocator = %%IncrementingAllocator.init(total_bytes);
|
||||
|
||||
@ -308,7 +308,7 @@ pub const InStream = struct {
|
||||
readFn: fn(self: &InStream, buffer: []u8) -> %usize,
|
||||
|
||||
/// Replaces `buffer` contents by reading from the stream until it is finished.
|
||||
/// If `buffer.len()` woould exceed `max_size`, `error.StreamTooLong` is returned and
|
||||
/// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and
|
||||
/// the contents read from the stream are lost.
|
||||
pub fn readAllBuffer(self: &InStream, buffer: &Buffer, max_size: usize) -> %void {
|
||||
%return buffer.resize(0);
|
||||
@ -339,7 +339,7 @@ pub const InStream = struct {
|
||||
var buf = Buffer.initNull(allocator);
|
||||
defer buf.deinit();
|
||||
|
||||
%return self.readAllBuffer(self, &buf, max_size);
|
||||
%return self.readAllBuffer(&buf, max_size);
|
||||
return buf.toOwnedSlice();
|
||||
}
|
||||
|
||||
|
||||
@ -29,6 +29,7 @@ comptime {
|
||||
_ = @import("cases/null.zig");
|
||||
_ = @import("cases/pub_enum/index.zig");
|
||||
_ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
|
||||
_ = @import("cases/reflection.zig");
|
||||
_ = @import("cases/sizeof_and_typeof.zig");
|
||||
_ = @import("cases/slice.zig");
|
||||
_ = @import("cases/struct.zig");
|
||||
|
||||
70
test/cases/reflection.zig
Normal file
70
test/cases/reflection.zig
Normal file
@ -0,0 +1,70 @@
|
||||
const assert = @import("std").debug.assert;
|
||||
const mem = @import("std").mem;
|
||||
|
||||
test "reflection: array, pointer, nullable, error union type child" {
|
||||
comptime {
|
||||
assert(([10]u8).Child == u8);
|
||||
assert((&u8).Child == u8);
|
||||
assert((%u8).Child == u8);
|
||||
assert((?u8).Child == u8);
|
||||
}
|
||||
}
|
||||
|
||||
test "reflection: function return type, var args, and param types" {
|
||||
comptime {
|
||||
assert(@typeOf(dummy).ReturnType == i32);
|
||||
assert(!@typeOf(dummy).is_var_args);
|
||||
assert(@typeOf(dummy_varargs).is_var_args);
|
||||
assert(@typeOf(dummy).arg_count == 3);
|
||||
assert(@ArgType(@typeOf(dummy), 0) == bool);
|
||||
assert(@ArgType(@typeOf(dummy), 1) == i32);
|
||||
assert(@ArgType(@typeOf(dummy), 2) == f32);
|
||||
}
|
||||
}
|
||||
|
||||
fn dummy(a: bool, b: i32, c: f32) -> i32 { 1234 }
|
||||
fn dummy_varargs(args: ...) {}
|
||||
|
||||
test "reflection: struct member types and names" {
|
||||
comptime {
|
||||
assert(@memberCount(Foo) == 3);
|
||||
|
||||
assert(@memberType(Foo, 0) == i32);
|
||||
assert(@memberType(Foo, 1) == bool);
|
||||
assert(@memberType(Foo, 2) == void);
|
||||
|
||||
assert(mem.eql(u8, @memberName(Foo, 0), "one"));
|
||||
assert(mem.eql(u8, @memberName(Foo, 1), "two"));
|
||||
assert(mem.eql(u8, @memberName(Foo, 2), "three"));
|
||||
}
|
||||
}
|
||||
|
||||
test "reflection: enum member types and names" {
|
||||
comptime {
|
||||
assert(@memberCount(Bar) == 4);
|
||||
|
||||
assert(@memberType(Bar, 0) == void);
|
||||
assert(@memberType(Bar, 1) == i32);
|
||||
assert(@memberType(Bar, 2) == bool);
|
||||
assert(@memberType(Bar, 3) == f64);
|
||||
|
||||
assert(mem.eql(u8, @memberName(Bar, 0), "One"));
|
||||
assert(mem.eql(u8, @memberName(Bar, 1), "Two"));
|
||||
assert(mem.eql(u8, @memberName(Bar, 2), "Three"));
|
||||
assert(mem.eql(u8, @memberName(Bar, 3), "Four"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const Foo = struct {
|
||||
one: i32,
|
||||
two: bool,
|
||||
three: void,
|
||||
};
|
||||
|
||||
const Bar = enum {
|
||||
One,
|
||||
Two: i32,
|
||||
Three: bool,
|
||||
Four: f64,
|
||||
};
|
||||
@ -2275,4 +2275,64 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
,
|
||||
".tmp_source.zig:2:1: error: invalid character: '\\t'");
|
||||
|
||||
cases.add("@ArgType given non function parameter",
|
||||
\\comptime {
|
||||
\\ _ = @ArgType(i32, 3);
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:2:18: error: expected function, found 'i32'");
|
||||
|
||||
cases.add("@ArgType arg index out of bounds",
|
||||
\\comptime {
|
||||
\\ _ = @ArgType(@typeOf(add), 2);
|
||||
\\}
|
||||
\\fn add(a: i32, b: i32) -> i32 { return a + b; }
|
||||
,
|
||||
".tmp_source.zig:2:32: error: arg index 2 out of bounds; 'fn(i32, i32) -> i32' has 2 arguments");
|
||||
|
||||
cases.add("@memberType on unsupported type",
|
||||
\\comptime {
|
||||
\\ _ = @memberType(i32, 0);
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:2:21: error: type 'i32' does not support @memberType");
|
||||
|
||||
cases.add("@memberType struct out of bounds",
|
||||
\\comptime {
|
||||
\\ _ = @memberType(Foo, 0);
|
||||
\\}
|
||||
\\const Foo = struct {};
|
||||
,
|
||||
".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
|
||||
|
||||
cases.add("@memberType enum out of bounds",
|
||||
\\comptime {
|
||||
\\ _ = @memberType(Foo, 0);
|
||||
\\}
|
||||
\\const Foo = enum {};
|
||||
,
|
||||
".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
|
||||
|
||||
cases.add("@memberName on unsupported type",
|
||||
\\comptime {
|
||||
\\ _ = @memberName(i32, 0);
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:2:21: error: type 'i32' does not support @memberName");
|
||||
|
||||
cases.add("@memberName struct out of bounds",
|
||||
\\comptime {
|
||||
\\ _ = @memberName(Foo, 0);
|
||||
\\}
|
||||
\\const Foo = struct {};
|
||||
,
|
||||
".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
|
||||
|
||||
cases.add("@memberName enum out of bounds",
|
||||
\\comptime {
|
||||
\\ _ = @memberName(Foo, 0);
|
||||
\\}
|
||||
\\const Foo = enum {};
|
||||
,
|
||||
".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user