mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
Merge remote-tracking branch 'upstream/master' into arm-support-improvement
This commit is contained in:
commit
5308eb7045
@ -23,14 +23,18 @@ find_program(GIT_EXE NAMES git)
|
||||
if(GIT_EXE)
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXE} -C ${CMAKE_SOURCE_DIR} name-rev HEAD --tags --name-only --no-undefined --always
|
||||
RESULT_VARIABLE EXIT_STATUS
|
||||
OUTPUT_VARIABLE ZIG_GIT_REV
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(ZIG_GIT_REV MATCHES "\\^0$")
|
||||
if(NOT("${ZIG_GIT_REV}" STREQUAL "${ZIG_VERSION}^0"))
|
||||
message("WARNING: Tag does not match configured Zig version")
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET)
|
||||
if(EXIT_STATUS EQUAL "0")
|
||||
if(ZIG_GIT_REV MATCHES "\\^0$")
|
||||
if(NOT("${ZIG_GIT_REV}" STREQUAL "${ZIG_VERSION}^0"))
|
||||
message("WARNING: Tag does not match configured Zig version")
|
||||
endif()
|
||||
else()
|
||||
set(ZIG_VERSION "${ZIG_VERSION}+${ZIG_GIT_REV}")
|
||||
endif()
|
||||
else()
|
||||
set(ZIG_VERSION "${ZIG_VERSION}+${ZIG_GIT_REV}")
|
||||
endif()
|
||||
endif()
|
||||
message("Configuring zig version ${ZIG_VERSION}")
|
||||
|
||||
@ -138,12 +138,13 @@ pub fn build(b: *Builder) !void {
|
||||
|
||||
test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
|
||||
test_step.dependOn(tests.addStandaloneTests(b, test_filter, modes));
|
||||
test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
|
||||
test_step.dependOn(tests.addCliTests(b, test_filter, modes));
|
||||
test_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes));
|
||||
test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
|
||||
test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));
|
||||
test_step.dependOn(tests.addTranslateCTests(b, test_filter));
|
||||
test_step.dependOn(tests.addGenHTests(b, test_filter));
|
||||
test_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes));
|
||||
test_step.dependOn(docs_step);
|
||||
}
|
||||
|
||||
|
||||
@ -307,7 +307,7 @@ const Node = union(enum) {
|
||||
const Toc = struct {
|
||||
nodes: []Node,
|
||||
toc: []u8,
|
||||
urls: std.HashMap([]const u8, Token, mem.hash_slice_u8, mem.eql_slice_u8),
|
||||
urls: std.StringHashMap(Token),
|
||||
};
|
||||
|
||||
const Action = enum {
|
||||
@ -316,7 +316,7 @@ const Action = enum {
|
||||
};
|
||||
|
||||
fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
|
||||
var urls = std.HashMap([]const u8, Token, mem.hash_slice_u8, mem.eql_slice_u8).init(allocator);
|
||||
var urls = std.StringHashMap(Token).init(allocator);
|
||||
errdefer urls.deinit();
|
||||
|
||||
var header_stack_size: usize = 0;
|
||||
|
||||
@ -5,7 +5,7 @@ const mem = std.mem;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const ArrayList = std.ArrayList;
|
||||
const HashMap = std.HashMap;
|
||||
const StringHashMap = std.StringHashMap;
|
||||
|
||||
fn trimStart(slice: []const u8, ch: u8) []const u8 {
|
||||
var i: usize = 0;
|
||||
@ -73,7 +73,7 @@ fn readFlagArguments(allocator: *Allocator, args: []const []const u8, required:
|
||||
}
|
||||
}
|
||||
|
||||
const HashMapFlags = HashMap([]const u8, FlagArg, std.hash.Fnv1a_32.hash, mem.eql_slice_u8);
|
||||
const HashMapFlags = StringHashMap(FlagArg);
|
||||
|
||||
// A store for querying found flags and positional arguments.
|
||||
pub const Args = struct {
|
||||
|
||||
@ -249,7 +249,7 @@ pub const Compilation = struct {
|
||||
const ArrayTypeTable = std.HashMap(*const Type.Array.Key, *Type.Array, Type.Array.Key.hash, Type.Array.Key.eql);
|
||||
const PtrTypeTable = std.HashMap(*const Type.Pointer.Key, *Type.Pointer, Type.Pointer.Key.hash, Type.Pointer.Key.eql);
|
||||
const FnTypeTable = std.HashMap(*const Type.Fn.Key, *Type.Fn, Type.Fn.Key.hash, Type.Fn.Key.eql);
|
||||
const TypeTable = std.HashMap([]const u8, *Type, mem.hash_slice_u8, mem.eql_slice_u8);
|
||||
const TypeTable = std.StringHashMap(*Type);
|
||||
|
||||
const CompileErrList = std.ArrayList(*Msg);
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ pub const Decl = struct {
|
||||
// TODO when we destroy the decl, deref the tree scope
|
||||
tree_scope: *Scope.AstTree,
|
||||
|
||||
pub const Table = std.HashMap([]const u8, *Decl, mem.hash_slice_u8, mem.eql_slice_u8);
|
||||
pub const Table = std.StringHashMap(*Decl);
|
||||
|
||||
pub fn cast(base: *Decl, comptime T: type) ?*T {
|
||||
if (base.id != @field(Id, @typeName(T))) return null;
|
||||
|
||||
@ -541,7 +541,7 @@ const Fmt = struct {
|
||||
color: errmsg.Color,
|
||||
loop: *event.Loop,
|
||||
|
||||
const SeenMap = std.HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8);
|
||||
const SeenMap = std.StringHashMap(void);
|
||||
};
|
||||
|
||||
fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_file: []const u8) void {
|
||||
|
||||
@ -10,7 +10,7 @@ pub const Package = struct {
|
||||
/// relative to root_src_dir
|
||||
table: Table,
|
||||
|
||||
pub const Table = std.HashMap([]const u8, *Package, mem.hash_slice_u8, mem.eql_slice_u8);
|
||||
pub const Table = std.StringHashMap(*Package);
|
||||
|
||||
/// makes internal copies of root_src_dir and root_src_path
|
||||
/// allocator should be an arena allocator because Package never frees anything
|
||||
|
||||
@ -343,7 +343,7 @@ const Fmt = struct {
|
||||
color: errmsg.Color,
|
||||
allocator: *mem.Allocator,
|
||||
|
||||
const SeenMap = std.HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8);
|
||||
const SeenMap = std.StringHashMap(void);
|
||||
};
|
||||
|
||||
fn printErrMsgToFile(
|
||||
@ -376,7 +376,7 @@ fn printErrMsgToFile(
|
||||
const text = text_buf.toOwnedSlice();
|
||||
|
||||
const stream = &file.outStream().stream;
|
||||
try stream.print( "{}:{}:{}: error: {}\n", path, start_loc.line + 1, start_loc.column + 1, text);
|
||||
try stream.print("{}:{}:{}: error: {}\n", path, start_loc.line + 1, start_loc.column + 1, text);
|
||||
|
||||
if (!color_on) return;
|
||||
|
||||
|
||||
@ -1989,6 +1989,7 @@ struct CodeGen {
|
||||
bool system_linker_hack;
|
||||
bool reported_bad_link_libc_error;
|
||||
bool is_dynamic; // shared library rather than static library. dynamic musl rather than static musl.
|
||||
bool need_frame_size_prefix_data;
|
||||
|
||||
//////////////////////////// Participates in Input Parameter Cache Hash
|
||||
/////// Note: there is a separate cache hash for builtin.zig, when adding fields,
|
||||
@ -2003,6 +2004,7 @@ struct CodeGen {
|
||||
ZigList<Buf *> assembly_files;
|
||||
ZigList<CFile *> c_source_files;
|
||||
ZigList<const char *> lib_dirs;
|
||||
ZigList<const char *> framework_dirs;
|
||||
|
||||
ZigLibCInstallation *libc;
|
||||
|
||||
|
||||
@ -2671,6 +2671,10 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!type_has_bits(struct_type)) {
|
||||
assert(struct_type->abi_align == 0);
|
||||
}
|
||||
|
||||
struct_type->data.structure.resolve_loop_flag_other = false;
|
||||
|
||||
if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) {
|
||||
@ -4191,7 +4195,7 @@ bool fn_is_async(ZigFn *fn) {
|
||||
return fn->inferred_async_node != inferred_async_none;
|
||||
}
|
||||
|
||||
static void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {
|
||||
void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn) {
|
||||
assert(fn->inferred_async_node != nullptr);
|
||||
assert(fn->inferred_async_node != inferred_async_checking);
|
||||
assert(fn->inferred_async_node != inferred_async_none);
|
||||
@ -7687,8 +7691,13 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta
|
||||
ZigType *tag_type = union_type->data.unionation.tag_type;
|
||||
uint32_t gen_field_count = union_type->data.unionation.gen_field_count;
|
||||
if (gen_field_count == 0) {
|
||||
union_type->llvm_type = get_llvm_type(g, tag_type);
|
||||
union_type->llvm_di_type = get_llvm_di_type(g, tag_type);
|
||||
if (tag_type == nullptr) {
|
||||
union_type->llvm_type = g->builtin_types.entry_void->llvm_type;
|
||||
union_type->llvm_di_type = g->builtin_types.entry_void->llvm_di_type;
|
||||
} else {
|
||||
union_type->llvm_type = get_llvm_type(g, tag_type);
|
||||
union_type->llvm_di_type = get_llvm_di_type(g, tag_type);
|
||||
}
|
||||
union_type->data.unionation.resolve_status = ResolveStatusLLVMFull;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -256,4 +256,6 @@ Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *
|
||||
ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field);
|
||||
ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field);
|
||||
|
||||
void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn);
|
||||
|
||||
#endif
|
||||
|
||||
@ -3522,6 +3522,15 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir
|
||||
assert(ptr_type->id == ZigTypeIdPointer);
|
||||
if (!type_has_bits(ptr_type))
|
||||
return nullptr;
|
||||
if (instruction->ptr->ref_count == 0) {
|
||||
// In this case, this StorePtr instruction should be elided. Something happened like this:
|
||||
// var t = true;
|
||||
// const x = if (t) Num.Two else unreachable;
|
||||
// The if condition is a runtime value, so the StorePtr for `x = Num.Two` got generated
|
||||
// (this instruction being rendered) but because of `else unreachable` the result ended
|
||||
// up being a comptime const value.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool have_init_expr = !value_is_all_undef(&instruction->value->value);
|
||||
if (have_init_expr) {
|
||||
@ -3766,6 +3775,7 @@ static void render_async_var_decls(CodeGen *g, Scope *scope) {
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) {
|
||||
assert(g->need_frame_size_prefix_data);
|
||||
LLVMTypeRef usize_llvm_type = g->builtin_types.entry_usize->llvm_type;
|
||||
LLVMTypeRef ptr_usize_llvm_type = LLVMPointerType(usize_llvm_type, 0);
|
||||
LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, "");
|
||||
@ -4103,6 +4113,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
||||
static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executable,
|
||||
IrInstructionStructFieldPtr *instruction)
|
||||
{
|
||||
Error err;
|
||||
|
||||
if (instruction->base.value.special != ConstValSpecialRuntime)
|
||||
return nullptr;
|
||||
|
||||
@ -4120,6 +4132,11 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa
|
||||
return struct_ptr;
|
||||
}
|
||||
|
||||
ZigType *struct_type = (struct_ptr_type->id == ZigTypeIdPointer) ?
|
||||
struct_ptr_type->data.pointer.child_type : struct_ptr_type;
|
||||
if ((err = type_resolve(g, struct_type, ResolveStatusLLVMFull)))
|
||||
report_errors_and_exit(g);
|
||||
|
||||
assert(field->gen_index != SIZE_MAX);
|
||||
return LLVMBuildStructGEP(g->builder, struct_ptr, (unsigned)field->gen_index, "");
|
||||
}
|
||||
@ -7199,7 +7216,9 @@ static void do_code_gen(CodeGen *g) {
|
||||
|
||||
LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
|
||||
LLVMValueRef size_val = LLVMConstInt(usize_type_ref, fn_table_entry->frame_type->abi_size, false);
|
||||
ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val);
|
||||
if (g->need_frame_size_prefix_data) {
|
||||
ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val);
|
||||
}
|
||||
|
||||
if (!g->strip_debug_symbols) {
|
||||
AstNode *source_node = fn_table_entry->proto_node;
|
||||
@ -8445,8 +8464,21 @@ static void init(CodeGen *g) {
|
||||
Buf *producer = buf_sprintf("zig %d.%d.%d", ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH);
|
||||
const char *flags = "";
|
||||
unsigned runtime_version = 0;
|
||||
|
||||
// For macOS stack traces, we want to avoid having to parse the compilation unit debug
|
||||
// info. As long as each debug info file has a path independent of the compilation unit
|
||||
// directory (DW_AT_comp_dir), then we never have to look at the compilation unit debug
|
||||
// info. If we provide an absolute path to LLVM here for the compilation unit debug info,
|
||||
// LLVM will emit DWARF info that depends on DW_AT_comp_dir. To avoid this, we pass "."
|
||||
// for the compilation unit directory. This forces each debug file to have a directory
|
||||
// rather than be relative to DW_AT_comp_dir. According to DWARF 5, debug files will
|
||||
// no longer reference DW_AT_comp_dir, for the purpose of being able to support the
|
||||
// common practice of stripping all but the line number sections from an executable.
|
||||
const char *compile_unit_dir = target_os_is_darwin(g->zig_target->os) ? "." :
|
||||
buf_ptr(&g->root_package->root_src_dir);
|
||||
|
||||
ZigLLVMDIFile *compile_unit_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(g->root_out_name),
|
||||
buf_ptr(&g->root_package->root_src_dir));
|
||||
compile_unit_dir);
|
||||
g->compile_unit = ZigLLVMCreateCompileUnit(g->dbuilder, ZigLLVMLang_DW_LANG_C99(),
|
||||
compile_unit_file, buf_ptr(producer), is_optimized, flags, runtime_version,
|
||||
"", 0, !g->strip_debug_symbols);
|
||||
@ -8873,6 +8905,15 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
|
||||
for (size_t i = 0; i < g->test_fns.length; i += 1) {
|
||||
ZigFn *test_fn_entry = g->test_fns.at(i);
|
||||
|
||||
if (fn_is_async(test_fn_entry)) {
|
||||
ErrorMsg *msg = add_node_error(g, test_fn_entry->proto_node,
|
||||
buf_create_from_str("test functions cannot be async"));
|
||||
add_error_note(g, msg, test_fn_entry->proto_node,
|
||||
buf_sprintf("this restriction may be lifted in the future. See https://github.com/ziglang/zig/issues/3117 for more details"));
|
||||
add_async_error_notes(g, msg, test_fn_entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
ConstExprValue *this_val = &test_fn_array->data.x_array.data.s_none.elements[i];
|
||||
this_val->special = ConstValSpecialStatic;
|
||||
this_val->type = struct_type;
|
||||
@ -8892,6 +8933,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
|
||||
fn_field->data.x_ptr.mut = ConstPtrMutComptimeConst;
|
||||
fn_field->data.x_ptr.data.fn.fn_entry = test_fn_entry;
|
||||
}
|
||||
report_errors_and_maybe_exit(g);
|
||||
|
||||
ConstExprValue *test_fn_slice = create_const_slice(g, test_fn_array, 0, g->test_fns.length, true);
|
||||
|
||||
@ -9803,6 +9845,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
|
||||
cache_list_of_str(ch, g->llvm_argv, g->llvm_argv_len);
|
||||
cache_list_of_str(ch, g->clang_argv, g->clang_argv_len);
|
||||
cache_list_of_str(ch, g->lib_dirs.items, g->lib_dirs.length);
|
||||
cache_list_of_str(ch, g->framework_dirs.items, g->framework_dirs.length);
|
||||
if (g->libc) {
|
||||
cache_buf(ch, &g->libc->include_dir);
|
||||
cache_buf(ch, &g->libc->sys_include_dir);
|
||||
|
||||
98
src/ir.cpp
98
src/ir.cpp
@ -330,6 +330,8 @@ static bool ir_should_inline(IrExecutable *exec, Scope *scope) {
|
||||
while (scope != nullptr) {
|
||||
if (scope->id == ScopeIdCompTime)
|
||||
return true;
|
||||
if (scope->id == ScopeIdTypeOf)
|
||||
return false;
|
||||
if (scope->id == ScopeIdFnDef)
|
||||
break;
|
||||
scope = scope->parent;
|
||||
@ -14837,6 +14839,12 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in
|
||||
if (align != 0) {
|
||||
if ((err = type_resolve(ira->codegen, var_type, ResolveStatusAlignmentKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (!type_has_bits(var_type)) {
|
||||
ir_add_error(ira, source_inst,
|
||||
buf_sprintf("variable '%s' of zero-bit type '%s' has no in-memory representation, it cannot be aligned",
|
||||
name_hint, buf_ptr(&var_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
}
|
||||
assert(result->base.value.data.x_ptr.special != ConstPtrSpecialInvalid);
|
||||
|
||||
@ -15648,6 +15656,32 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
|
||||
return &store_ptr->base;
|
||||
}
|
||||
|
||||
static IrInstruction *analyze_casted_new_stack(IrAnalyze *ira, IrInstructionCallSrc *call_instruction,
|
||||
ZigFn *fn_entry)
|
||||
{
|
||||
if (call_instruction->new_stack == nullptr)
|
||||
return nullptr;
|
||||
|
||||
IrInstruction *new_stack = call_instruction->new_stack->child;
|
||||
if (type_is_invalid(new_stack->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (call_instruction->is_async_call_builtin &&
|
||||
fn_entry != nullptr && new_stack->value.type->id == ZigTypeIdPointer &&
|
||||
new_stack->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)
|
||||
{
|
||||
ZigType *needed_frame_type = get_pointer_to_type(ira->codegen,
|
||||
get_fn_frame_type(ira->codegen, fn_entry), false);
|
||||
return ir_implicit_cast(ira, new_stack, needed_frame_type);
|
||||
} else {
|
||||
ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false);
|
||||
ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr);
|
||||
ira->codegen->need_frame_size_prefix_data = true;
|
||||
return ir_implicit_cast(ira, new_stack, u8_slice);
|
||||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction,
|
||||
ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref,
|
||||
IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline)
|
||||
@ -15826,31 +15860,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
||||
return ir_finish_anal(ira, new_instruction);
|
||||
}
|
||||
|
||||
IrInstruction *casted_new_stack = nullptr;
|
||||
if (call_instruction->new_stack != nullptr) {
|
||||
IrInstruction *new_stack = call_instruction->new_stack->child;
|
||||
if (type_is_invalid(new_stack->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (call_instruction->is_async_call_builtin &&
|
||||
fn_entry != nullptr && new_stack->value.type->id == ZigTypeIdPointer &&
|
||||
new_stack->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame)
|
||||
{
|
||||
ZigType *needed_frame_type = get_pointer_to_type(ira->codegen,
|
||||
get_fn_frame_type(ira->codegen, fn_entry), false);
|
||||
casted_new_stack = ir_implicit_cast(ira, new_stack, needed_frame_type);
|
||||
if (type_is_invalid(casted_new_stack->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
} else {
|
||||
ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false);
|
||||
ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr);
|
||||
casted_new_stack = ir_implicit_cast(ira, new_stack, u8_slice);
|
||||
if (type_is_invalid(casted_new_stack->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
}
|
||||
|
||||
if (fn_type->data.fn.is_generic) {
|
||||
if (!fn_entry) {
|
||||
ir_add_error(ira, call_instruction->fn_ref,
|
||||
@ -16063,6 +16072,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
||||
parent_fn_entry->calls_or_awaits_errorable_fn = true;
|
||||
}
|
||||
|
||||
IrInstruction *casted_new_stack = analyze_casted_new_stack(ira, call_instruction, impl_fn);
|
||||
if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
size_t impl_param_count = impl_fn_type_id->param_count;
|
||||
if (call_instruction->is_async) {
|
||||
IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry,
|
||||
@ -16071,11 +16084,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
||||
}
|
||||
|
||||
IrInstruction *result_loc;
|
||||
if (call_instruction->is_async_call_builtin) {
|
||||
result_loc = get_async_call_result_loc(ira, call_instruction, impl_fn_type_id->return_type);
|
||||
if (result_loc != nullptr && type_is_invalid(result_loc->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
} else if (handle_is_ptr(impl_fn_type_id->return_type)) {
|
||||
if (handle_is_ptr(impl_fn_type_id->return_type)) {
|
||||
result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
|
||||
impl_fn_type_id->return_type, nullptr, true, true, false);
|
||||
if (result_loc != nullptr) {
|
||||
@ -16087,6 +16096,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
||||
result_loc = nullptr;
|
||||
}
|
||||
}
|
||||
} else if (call_instruction->is_async_call_builtin) {
|
||||
result_loc = get_async_call_result_loc(ira, call_instruction, impl_fn_type_id->return_type);
|
||||
if (result_loc != nullptr && type_is_invalid(result_loc->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
} else {
|
||||
result_loc = nullptr;
|
||||
}
|
||||
@ -16211,6 +16224,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
IrInstruction *casted_new_stack = analyze_casted_new_stack(ira, call_instruction, fn_entry);
|
||||
if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (call_instruction->is_async) {
|
||||
IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref,
|
||||
casted_args, call_param_count, casted_new_stack);
|
||||
@ -16223,11 +16240,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
||||
}
|
||||
|
||||
IrInstruction *result_loc;
|
||||
if (call_instruction->is_async_call_builtin) {
|
||||
result_loc = get_async_call_result_loc(ira, call_instruction, return_type);
|
||||
if (result_loc != nullptr && type_is_invalid(result_loc->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
} else if (handle_is_ptr(return_type)) {
|
||||
if (handle_is_ptr(return_type)) {
|
||||
result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc,
|
||||
return_type, nullptr, true, true, false);
|
||||
if (result_loc != nullptr) {
|
||||
@ -16239,6 +16252,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
|
||||
result_loc = nullptr;
|
||||
}
|
||||
}
|
||||
} else if (call_instruction->is_async_call_builtin) {
|
||||
result_loc = get_async_call_result_loc(ira, call_instruction, return_type);
|
||||
if (result_loc != nullptr && type_is_invalid(result_loc->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
} else {
|
||||
result_loc = nullptr;
|
||||
}
|
||||
@ -17453,7 +17470,12 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
|
||||
return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
|
||||
source_instr, container_ptr, container_type);
|
||||
}
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry,
|
||||
|
||||
ZigType *field_type = resolve_union_field_type(ira->codegen, field);
|
||||
if (field_type == nullptr)
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type,
|
||||
is_const, is_volatile, PtrLenSingle, 0, 0, 0, false);
|
||||
if (instr_is_comptime(container_ptr)) {
|
||||
ConstExprValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad);
|
||||
@ -17470,7 +17492,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
|
||||
if (initializing) {
|
||||
ConstExprValue *payload_val = create_const_vals(1);
|
||||
payload_val->special = ConstValSpecialUndef;
|
||||
payload_val->type = field->type_entry;
|
||||
payload_val->type = field_type;
|
||||
payload_val->parent.id = ConstParentIdUnion;
|
||||
payload_val->parent.data.p_union.union_val = union_val;
|
||||
|
||||
@ -22523,6 +22545,8 @@ static IrInstruction *ir_analyze_instruction_frame_size(IrAnalyze *ira, IrInstru
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
ira->codegen->need_frame_size_prefix_data = true;
|
||||
|
||||
IrInstruction *result = ir_build_frame_size_gen(&ira->new_irb, instruction->base.scope,
|
||||
instruction->base.source_node, fn);
|
||||
result->value.type = ira->codegen->builtin_types.entry_usize;
|
||||
|
||||
@ -2510,6 +2510,12 @@ static void construct_linker_job_macho(LinkJob *lj) {
|
||||
lj->args.append("dynamic_lookup");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < g->framework_dirs.length; i += 1) {
|
||||
const char *framework_dir = g->framework_dirs.at(i);
|
||||
lj->args.append("-F");
|
||||
lj->args.append(framework_dir);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < g->darwin_frameworks.length; i += 1) {
|
||||
lj->args.append("-framework");
|
||||
lj->args.append(buf_ptr(g->darwin_frameworks.at(i)));
|
||||
|
||||
@ -104,6 +104,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
|
||||
" -rdynamic add all symbols to the dynamic symbol table\n"
|
||||
" -rpath [path] add directory to the runtime library search path\n"
|
||||
" --subsystem [subsystem] (windows) /SUBSYSTEM:<subsystem> to the linker\n"
|
||||
" -F[dir] (darwin) add search path for frameworks\n"
|
||||
" -framework [name] (darwin) link against framework\n"
|
||||
" -mios-version-min [ver] (darwin) set iOS deployment target\n"
|
||||
" -mmacosx-version-min [ver] (darwin) set Mac OS X deployment target\n"
|
||||
@ -454,6 +455,7 @@ int main(int argc, char **argv) {
|
||||
ZigList<const char *> lib_dirs = {0};
|
||||
ZigList<const char *> link_libs = {0};
|
||||
ZigList<const char *> forbidden_link_libs = {0};
|
||||
ZigList<const char *> framework_dirs = {0};
|
||||
ZigList<const char *> frameworks = {0};
|
||||
bool have_libc = false;
|
||||
const char *target_string = nullptr;
|
||||
@ -686,6 +688,8 @@ int main(int argc, char **argv) {
|
||||
} else if (arg[1] == 'L' && arg[2] != 0) {
|
||||
// alias for --library-path
|
||||
lib_dirs.append(&arg[2]);
|
||||
} else if (arg[1] == 'F' && arg[2] != 0) {
|
||||
framework_dirs.append(&arg[2]);
|
||||
} else if (strcmp(arg, "--pkg-begin") == 0) {
|
||||
if (i + 2 >= argc) {
|
||||
fprintf(stderr, "Expected 2 arguments after --pkg-begin\n");
|
||||
@ -772,6 +776,8 @@ int main(int argc, char **argv) {
|
||||
main_pkg_path = buf_create_from_str(argv[i]);
|
||||
} else if (strcmp(arg, "--library-path") == 0 || strcmp(arg, "-L") == 0) {
|
||||
lib_dirs.append(argv[i]);
|
||||
} else if (strcmp(arg, "-F") == 0) {
|
||||
framework_dirs.append(argv[i]);
|
||||
} else if (strcmp(arg, "--library") == 0) {
|
||||
if (strcmp(argv[i], "c") == 0)
|
||||
have_libc = true;
|
||||
@ -1153,6 +1159,9 @@ int main(int argc, char **argv) {
|
||||
for (size_t i = 0; i < lib_dirs.length; i += 1) {
|
||||
codegen_add_lib_dir(g, lib_dirs.at(i));
|
||||
}
|
||||
for (size_t i = 0; i < framework_dirs.length; i += 1) {
|
||||
g->framework_dirs.append(framework_dirs.at(i));
|
||||
}
|
||||
for (size_t i = 0; i < link_libs.length; i += 1) {
|
||||
LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i)));
|
||||
link_lib->provided_explicitly = true;
|
||||
|
||||
@ -842,6 +842,7 @@ const char *ZigLLVMGetSubArchTypeName(ZigLLVM_SubArchType sub_arch) {
|
||||
|
||||
void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module) {
|
||||
unwrap(module)->addModuleFlag(Module::Warning, "Debug Info Version", DEBUG_METADATA_VERSION);
|
||||
unwrap(module)->addModuleFlag(Module::Warning, "Dwarf Version", 4);
|
||||
}
|
||||
|
||||
void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
const std = @import("std.zig");
|
||||
const HashMap = std.HashMap;
|
||||
const StringHashMap = std.StringHashMap;
|
||||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
const testing = std.testing;
|
||||
@ -9,7 +9,7 @@ const testing = std.testing;
|
||||
pub const BufMap = struct {
|
||||
hash_map: BufMapHashMap,
|
||||
|
||||
const BufMapHashMap = HashMap([]const u8, []const u8, mem.hash_slice_u8, mem.eql_slice_u8);
|
||||
const BufMapHashMap = StringHashMap([]const u8);
|
||||
|
||||
pub fn init(allocator: *Allocator) BufMap {
|
||||
var self = BufMap{ .hash_map = BufMapHashMap.init(allocator) };
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
const std = @import("std.zig");
|
||||
const HashMap = @import("hash_map.zig").HashMap;
|
||||
const StringHashMap = std.StringHashMap;
|
||||
const mem = @import("mem.zig");
|
||||
const Allocator = mem.Allocator;
|
||||
const testing = std.testing;
|
||||
@ -7,7 +7,7 @@ const testing = std.testing;
|
||||
pub const BufSet = struct {
|
||||
hash_map: BufSetHashMap,
|
||||
|
||||
const BufSetHashMap = HashMap([]const u8, void, mem.hash_slice_u8, mem.eql_slice_u8);
|
||||
const BufSetHashMap = StringHashMap(void);
|
||||
|
||||
pub fn init(a: *Allocator) BufSet {
|
||||
var self = BufSet{ .hash_map = BufSetHashMap.init(a) };
|
||||
|
||||
@ -4,10 +4,11 @@ const io = std.io;
|
||||
const fs = std.fs;
|
||||
const mem = std.mem;
|
||||
const debug = std.debug;
|
||||
const panic = std.debug.panic;
|
||||
const assert = debug.assert;
|
||||
const warn = std.debug.warn;
|
||||
const ArrayList = std.ArrayList;
|
||||
const HashMap = std.HashMap;
|
||||
const StringHashMap = std.StringHashMap;
|
||||
const Allocator = mem.Allocator;
|
||||
const process = std.process;
|
||||
const BufSet = std.BufSet;
|
||||
@ -42,8 +43,8 @@ pub const Builder = struct {
|
||||
top_level_steps: ArrayList(*TopLevelStep),
|
||||
install_prefix: ?[]const u8,
|
||||
dest_dir: ?[]const u8,
|
||||
lib_dir: ?[]const u8,
|
||||
exe_dir: ?[]const u8,
|
||||
lib_dir: []const u8,
|
||||
exe_dir: []const u8,
|
||||
install_path: []const u8,
|
||||
search_prefixes: ArrayList([]const u8),
|
||||
installed_files: ArrayList(InstalledFile),
|
||||
@ -60,8 +61,8 @@ pub const Builder = struct {
|
||||
C11,
|
||||
};
|
||||
|
||||
const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);
|
||||
const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);
|
||||
const UserInputOptionsMap = StringHashMap(UserInputOption);
|
||||
const AvailableOptionsMap = StringHashMap(AvailableOption);
|
||||
|
||||
const AvailableOption = struct {
|
||||
name: []const u8,
|
||||
@ -129,8 +130,8 @@ pub const Builder = struct {
|
||||
.env_map = env_map,
|
||||
.search_prefixes = ArrayList([]const u8).init(allocator),
|
||||
.install_prefix = null,
|
||||
.lib_dir = null,
|
||||
.exe_dir = null,
|
||||
.lib_dir = undefined,
|
||||
.exe_dir = undefined,
|
||||
.dest_dir = env_map.get("DESTDIR"),
|
||||
.installed_files = ArrayList(InstalledFile).init(allocator),
|
||||
.install_tls = TopLevelStep{
|
||||
@ -163,11 +164,13 @@ pub const Builder = struct {
|
||||
self.allocator.destroy(self);
|
||||
}
|
||||
|
||||
/// This function is intended to be called by std/special/build_runner.zig, not a build.zig file.
|
||||
pub fn setInstallPrefix(self: *Builder, optional_prefix: ?[]const u8) void {
|
||||
self.install_prefix = optional_prefix;
|
||||
}
|
||||
|
||||
fn resolveInstallPrefix(self: *Builder) void {
|
||||
/// This function is intended to be called by std/special/build_runner.zig, not a build.zig file.
|
||||
pub fn resolveInstallPrefix(self: *Builder) void {
|
||||
if (self.dest_dir) |dest_dir| {
|
||||
const install_prefix = self.install_prefix orelse "/usr";
|
||||
self.install_path = fs.path.join(self.allocator, [_][]const u8{ dest_dir, install_prefix }) catch unreachable;
|
||||
@ -437,7 +440,7 @@ pub const Builder = struct {
|
||||
.description = description,
|
||||
};
|
||||
if ((self.available_options_map.put(name, available_option) catch unreachable) != null) {
|
||||
debug.panic("Option '{}' declared twice", name);
|
||||
panic("Option '{}' declared twice", name);
|
||||
}
|
||||
self.available_options_list.append(available_option) catch unreachable;
|
||||
|
||||
@ -463,8 +466,8 @@ pub const Builder = struct {
|
||||
return null;
|
||||
},
|
||||
},
|
||||
TypeId.Int => debug.panic("TODO integer options to build script"),
|
||||
TypeId.Float => debug.panic("TODO float options to build script"),
|
||||
TypeId.Int => panic("TODO integer options to build script"),
|
||||
TypeId.Float => panic("TODO float options to build script"),
|
||||
TypeId.String => switch (entry.value.value) {
|
||||
UserValue.Flag => {
|
||||
warn("Expected -D{} to be a string, but received a boolean.\n", name);
|
||||
@ -478,7 +481,7 @@ pub const Builder = struct {
|
||||
},
|
||||
UserValue.Scalar => |s| return s,
|
||||
},
|
||||
TypeId.List => debug.panic("TODO list options to build script"),
|
||||
TypeId.List => panic("TODO list options to build script"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -644,8 +647,6 @@ pub const Builder = struct {
|
||||
}
|
||||
|
||||
pub fn validateUserInputDidItFail(self: *Builder) bool {
|
||||
self.resolveInstallPrefix();
|
||||
|
||||
// make sure all args are used
|
||||
var it = self.user_input_options.iterator();
|
||||
while (true) {
|
||||
@ -855,7 +856,7 @@ pub const Builder = struct {
|
||||
var stdout_file_in_stream = child.stdout.?.inStream();
|
||||
try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
|
||||
|
||||
const term = child.wait() catch |err| std.debug.panic("unable to spawn {}: {}", argv[0], err);
|
||||
const term = child.wait() catch |err| panic("unable to spawn {}: {}", argv[0], err);
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
if (code != 0) {
|
||||
@ -882,8 +883,8 @@ pub const Builder = struct {
|
||||
fn getInstallPath(self: *Builder, dir: InstallDir, dest_rel_path: []const u8) []const u8 {
|
||||
const base_dir = switch (dir) {
|
||||
.Prefix => self.install_path,
|
||||
.Bin => self.exe_dir.?,
|
||||
.Lib => self.lib_dir.?,
|
||||
.Bin => self.exe_dir,
|
||||
.Lib => self.lib_dir,
|
||||
};
|
||||
return fs.path.resolve(
|
||||
self.allocator,
|
||||
@ -1228,6 +1229,7 @@ pub const LibExeObjStep = struct {
|
||||
name_only_filename: []const u8,
|
||||
strip: bool,
|
||||
lib_paths: ArrayList([]const u8),
|
||||
framework_dirs: ArrayList([]const u8),
|
||||
frameworks: BufSet,
|
||||
verbose_link: bool,
|
||||
verbose_cc: bool,
|
||||
@ -1317,6 +1319,9 @@ pub const LibExeObjStep = struct {
|
||||
}
|
||||
|
||||
fn initExtraArgs(builder: *Builder, name: []const u8, root_src: ?[]const u8, kind: Kind, is_dynamic: bool, ver: Version) LibExeObjStep {
|
||||
if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) {
|
||||
panic("invalid name: '{}'. It looks like a file path, but it is supposed to be the library or application name.", name);
|
||||
}
|
||||
var self = LibExeObjStep{
|
||||
.strip = false,
|
||||
.builder = builder,
|
||||
@ -1341,6 +1346,7 @@ pub const LibExeObjStep = struct {
|
||||
.include_dirs = ArrayList(IncludeDir).init(builder.allocator),
|
||||
.link_objects = ArrayList(LinkObject).init(builder.allocator),
|
||||
.lib_paths = ArrayList([]const u8).init(builder.allocator),
|
||||
.framework_dirs = ArrayList([]const u8).init(builder.allocator),
|
||||
.object_src = undefined,
|
||||
.build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,
|
||||
.c_std = Builder.CStd.C99,
|
||||
@ -1614,6 +1620,10 @@ pub const LibExeObjStep = struct {
|
||||
self.lib_paths.append(path) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn addFrameworkDir(self: *LibExeObjStep, dir_path: []const u8) void {
|
||||
self.framework_dirs.append(dir_path) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn addPackagePath(self: *LibExeObjStep, name: []const u8, pkg_index_path: []const u8) void {
|
||||
self.packages.append(Pkg{
|
||||
.name = name,
|
||||
@ -1860,8 +1870,8 @@ pub const LibExeObjStep = struct {
|
||||
}
|
||||
|
||||
for (self.lib_paths.toSliceConst()) |lib_path| {
|
||||
zig_args.append("--library-path") catch unreachable;
|
||||
zig_args.append(lib_path) catch unreachable;
|
||||
try zig_args.append("-L");
|
||||
try zig_args.append(lib_path);
|
||||
}
|
||||
|
||||
if (self.need_system_paths and self.target == Target.Native) {
|
||||
@ -1882,6 +1892,11 @@ pub const LibExeObjStep = struct {
|
||||
}
|
||||
|
||||
if (self.target.isDarwin()) {
|
||||
for (self.framework_dirs.toSliceConst()) |dir| {
|
||||
try zig_args.append("-F");
|
||||
try zig_args.append(dir);
|
||||
}
|
||||
|
||||
var it = self.frameworks.iterator();
|
||||
while (it.next()) |entry| {
|
||||
zig_args.append("-framework") catch unreachable;
|
||||
|
||||
@ -110,9 +110,7 @@ fn convertRepr(comptime T: type, n: FloatRepr) T {
|
||||
q.shiftLeft1(s); // q = p << 1
|
||||
r.shiftLeft1(q); // r = p << 2
|
||||
s.shiftLeft1(r); // p = p << 3
|
||||
q.add(s); // p = (p << 3) + (p << 1)
|
||||
|
||||
exp -= 1;
|
||||
s.add(q); // p = (p << 3) + (p << 1)
|
||||
|
||||
while (s.d2 & mask28 != 0) {
|
||||
q.shiftRight1(s);
|
||||
@ -402,6 +400,13 @@ test "fmt.parseFloat" {
|
||||
expectEqual((try parseFloat(T, "+0")), 0.0);
|
||||
expectEqual((try parseFloat(T, "-0")), 0.0);
|
||||
|
||||
expectEqual((try parseFloat(T, "0e0")), 0);
|
||||
expectEqual((try parseFloat(T, "2e3")), 2000.0);
|
||||
expectEqual((try parseFloat(T, "1e0")), 1.0);
|
||||
expectEqual((try parseFloat(T, "-2e3")), -2000.0);
|
||||
expectEqual((try parseFloat(T, "-1e0")), -1.0);
|
||||
expectEqual((try parseFloat(T, "1.234e3")), 1234);
|
||||
|
||||
expect(approxEq(T, try parseFloat(T, "3.141"), 3.141, epsilon));
|
||||
expect(approxEq(T, try parseFloat(T, "-3.141"), -3.141, epsilon));
|
||||
|
||||
@ -413,6 +418,9 @@ test "fmt.parseFloat" {
|
||||
expectEqual((try parseFloat(T, "-INF")), -std.math.inf(T));
|
||||
|
||||
if (T != f16) {
|
||||
expect(approxEq(T, try parseFloat(T, "1e-2"), 0.01, epsilon));
|
||||
expect(approxEq(T, try parseFloat(T, "1234e-2"), 12.34, epsilon));
|
||||
|
||||
expect(approxEq(T, try parseFloat(T, "123142.1"), 123142.1, epsilon));
|
||||
expect(approxEq(T, try parseFloat(T, "-123142.1124"), T(-123142.1124), epsilon));
|
||||
expect(approxEq(T, try parseFloat(T, "0.7062146892655368"), T(0.7062146892655368), epsilon));
|
||||
|
||||
@ -23,9 +23,7 @@ pub fn StringHashMap(comptime V: type) type {
|
||||
}
|
||||
|
||||
pub fn eqlString(a: []const u8, b: []const u8) bool {
|
||||
if (a.len != b.len) return false;
|
||||
if (a.ptr == b.ptr) return true;
|
||||
return mem.compare(u8, a, b) == .Equal;
|
||||
return mem.eql(u8, a, b);
|
||||
}
|
||||
|
||||
pub fn hashString(s: []const u8) u32 {
|
||||
|
||||
@ -989,7 +989,7 @@ test "json.validate" {
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||
const ArrayList = std.ArrayList;
|
||||
const HashMap = std.HashMap;
|
||||
const StringHashMap = std.StringHashMap;
|
||||
|
||||
pub const ValueTree = struct {
|
||||
arena: ArenaAllocator,
|
||||
@ -1000,7 +1000,7 @@ pub const ValueTree = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const ObjectMap = HashMap([]const u8, Value, mem.hash_slice_u8, mem.eql_slice_u8);
|
||||
pub const ObjectMap = StringHashMap(Value);
|
||||
|
||||
pub const Value = union(enum) {
|
||||
Null,
|
||||
|
||||
38
std/mem.zig
38
std/mem.zig
@ -339,6 +339,7 @@ test "mem.lessThan" {
|
||||
/// Compares two slices and returns whether they are equal.
|
||||
pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
|
||||
if (a.len != b.len) return false;
|
||||
if (a.ptr == b.ptr) return true;
|
||||
for (a) |item, index| {
|
||||
if (b[index] != item) return false;
|
||||
}
|
||||
@ -738,47 +739,34 @@ test "writeIntBig and writeIntLittle" {
|
||||
var buf9: [9]u8 = undefined;
|
||||
|
||||
writeIntBig(u0, &buf0, 0x0);
|
||||
testing.expect(eql_slice_u8(buf0[0..], [_]u8{}));
|
||||
testing.expect(eql(u8, buf0[0..], [_]u8{}));
|
||||
writeIntLittle(u0, &buf0, 0x0);
|
||||
testing.expect(eql_slice_u8(buf0[0..], [_]u8{}));
|
||||
testing.expect(eql(u8, buf0[0..], [_]u8{}));
|
||||
|
||||
writeIntBig(u8, &buf1, 0x12);
|
||||
testing.expect(eql_slice_u8(buf1[0..], [_]u8{0x12}));
|
||||
testing.expect(eql(u8, buf1[0..], [_]u8{0x12}));
|
||||
writeIntLittle(u8, &buf1, 0x34);
|
||||
testing.expect(eql_slice_u8(buf1[0..], [_]u8{0x34}));
|
||||
testing.expect(eql(u8, buf1[0..], [_]u8{0x34}));
|
||||
|
||||
writeIntBig(u16, &buf2, 0x1234);
|
||||
testing.expect(eql_slice_u8(buf2[0..], [_]u8{ 0x12, 0x34 }));
|
||||
testing.expect(eql(u8, buf2[0..], [_]u8{ 0x12, 0x34 }));
|
||||
writeIntLittle(u16, &buf2, 0x5678);
|
||||
testing.expect(eql_slice_u8(buf2[0..], [_]u8{ 0x78, 0x56 }));
|
||||
testing.expect(eql(u8, buf2[0..], [_]u8{ 0x78, 0x56 }));
|
||||
|
||||
writeIntBig(u72, &buf9, 0x123456789abcdef024);
|
||||
testing.expect(eql_slice_u8(buf9[0..], [_]u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }));
|
||||
testing.expect(eql(u8, buf9[0..], [_]u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }));
|
||||
writeIntLittle(u72, &buf9, 0xfedcba9876543210ec);
|
||||
testing.expect(eql_slice_u8(buf9[0..], [_]u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }));
|
||||
testing.expect(eql(u8, buf9[0..], [_]u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }));
|
||||
|
||||
writeIntBig(i8, &buf1, -1);
|
||||
testing.expect(eql_slice_u8(buf1[0..], [_]u8{0xff}));
|
||||
testing.expect(eql(u8, buf1[0..], [_]u8{0xff}));
|
||||
writeIntLittle(i8, &buf1, -2);
|
||||
testing.expect(eql_slice_u8(buf1[0..], [_]u8{0xfe}));
|
||||
testing.expect(eql(u8, buf1[0..], [_]u8{0xfe}));
|
||||
|
||||
writeIntBig(i16, &buf2, -3);
|
||||
testing.expect(eql_slice_u8(buf2[0..], [_]u8{ 0xff, 0xfd }));
|
||||
testing.expect(eql(u8, buf2[0..], [_]u8{ 0xff, 0xfd }));
|
||||
writeIntLittle(i16, &buf2, -4);
|
||||
testing.expect(eql_slice_u8(buf2[0..], [_]u8{ 0xfc, 0xff }));
|
||||
}
|
||||
|
||||
pub fn hash_slice_u8(k: []const u8) u32 {
|
||||
// FNV 32-bit hash
|
||||
var h: u32 = 2166136261;
|
||||
for (k) |b| {
|
||||
h = (h ^ b) *% 16777619;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
pub fn eql_slice_u8(a: []const u8, b: []const u8) bool {
|
||||
return eql(u8, a, b);
|
||||
testing.expect(eql(u8, buf2[0..], [_]u8{ 0xfc, 0xff }));
|
||||
}
|
||||
|
||||
/// Returns an iterator that iterates over the slices of `buffer` that are not
|
||||
|
||||
@ -123,6 +123,7 @@ pub fn main() !void {
|
||||
}
|
||||
}
|
||||
|
||||
builder.resolveInstallPrefix();
|
||||
try runBuild(builder);
|
||||
|
||||
if (builder.validateUserInputDidItFail())
|
||||
@ -151,6 +152,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
|
||||
// run the build script to collect the options
|
||||
if (!already_ran_build) {
|
||||
builder.setInstallPrefix(null);
|
||||
builder.resolveInstallPrefix();
|
||||
try runBuild(builder);
|
||||
}
|
||||
|
||||
|
||||
@ -2419,6 +2419,94 @@ test "zig fmt: comment after empty comment" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: line comment in array" {
|
||||
try testTransform(
|
||||
\\test "a" {
|
||||
\\ var arr = [_]u32{
|
||||
\\ 0
|
||||
\\ // 1,
|
||||
\\ // 2,
|
||||
\\ };
|
||||
\\}
|
||||
\\
|
||||
,
|
||||
\\test "a" {
|
||||
\\ var arr = [_]u32{
|
||||
\\ 0, // 1,
|
||||
\\ // 2,
|
||||
\\ };
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
try testCanonical(
|
||||
\\test "a" {
|
||||
\\ var arr = [_]u32{
|
||||
\\ 0,
|
||||
\\ // 1,
|
||||
\\ // 2,
|
||||
\\ };
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: comment after params" {
|
||||
try testTransform(
|
||||
\\fn a(
|
||||
\\ b: u32
|
||||
\\ // c: u32,
|
||||
\\ // d: u32,
|
||||
\\) void {}
|
||||
\\
|
||||
,
|
||||
\\fn a(
|
||||
\\ b: u32, // c: u32,
|
||||
\\ // d: u32,
|
||||
\\) void {}
|
||||
\\
|
||||
);
|
||||
try testCanonical(
|
||||
\\fn a(
|
||||
\\ b: u32,
|
||||
\\ // c: u32,
|
||||
\\ // d: u32,
|
||||
\\) void {}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: comment in array initializer/access" {
|
||||
try testCanonical(
|
||||
\\test "a" {
|
||||
\\ var a = x{ //aa
|
||||
\\ //bb
|
||||
\\ };
|
||||
\\ var a = []x{ //aa
|
||||
\\ //bb
|
||||
\\ };
|
||||
\\ var b = [ //aa
|
||||
\\ _
|
||||
\\ ]x{ //aa
|
||||
\\ //bb
|
||||
\\ 9,
|
||||
\\ };
|
||||
\\ var c = b[ //aa
|
||||
\\ 0
|
||||
\\ ];
|
||||
\\ var d = [_
|
||||
\\ //aa
|
||||
\\ ]x{ //aa
|
||||
\\ //bb
|
||||
\\ 9,
|
||||
\\ };
|
||||
\\ var e = d[0
|
||||
\\ //aa
|
||||
\\ ];
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: comments at several places in struct init" {
|
||||
try testTransform(
|
||||
\\var bar = Bar{
|
||||
|
||||
@ -483,9 +483,23 @@ fn renderExpression(
|
||||
},
|
||||
|
||||
ast.Node.PrefixOp.Op.ArrayType => |array_index| {
|
||||
try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None); // [
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, array_index, Space.None);
|
||||
try renderToken(tree, stream, tree.nextToken(array_index.lastToken()), indent, start_col, Space.None); // ]
|
||||
const lbracket = prefix_op_node.op_token;
|
||||
const rbracket = tree.nextToken(array_index.lastToken());
|
||||
|
||||
try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
|
||||
|
||||
const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment;
|
||||
const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment;
|
||||
const new_indent = if (ends_with_comment) indent + indent_delta else indent;
|
||||
const new_space = if (ends_with_comment) Space.Newline else Space.None;
|
||||
try renderExpression(allocator, stream, tree, new_indent, start_col, array_index, new_space);
|
||||
if (starts_with_comment) {
|
||||
try stream.writeByte('\n');
|
||||
}
|
||||
if (ends_with_comment or starts_with_comment) {
|
||||
try stream.writeByteNTimes(' ', indent);
|
||||
}
|
||||
try renderToken(tree, stream, rbracket, indent, start_col, Space.None); // ]
|
||||
},
|
||||
ast.Node.PrefixOp.Op.BitNot,
|
||||
ast.Node.PrefixOp.Op.BoolNot,
|
||||
@ -580,7 +594,18 @@ fn renderExpression(
|
||||
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
|
||||
try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, index_expr, Space.None);
|
||||
|
||||
const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment;
|
||||
const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment;
|
||||
const new_indent = if (ends_with_comment) indent + indent_delta else indent;
|
||||
const new_space = if (ends_with_comment) Space.Newline else Space.None;
|
||||
try renderExpression(allocator, stream, tree, new_indent, start_col, index_expr, new_space);
|
||||
if (starts_with_comment) {
|
||||
try stream.writeByte('\n');
|
||||
}
|
||||
if (ends_with_comment or starts_with_comment) {
|
||||
try stream.writeByteNTimes(' ', indent);
|
||||
}
|
||||
return renderToken(tree, stream, rbracket, indent, start_col, space); // ]
|
||||
},
|
||||
|
||||
@ -615,7 +640,7 @@ fn renderExpression(
|
||||
|
||||
if (field_inits.len == 0) {
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
|
||||
try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
|
||||
try renderToken(tree, stream, lbrace, indent + indent_delta, start_col, Space.None);
|
||||
return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
|
||||
}
|
||||
|
||||
@ -714,7 +739,7 @@ fn renderExpression(
|
||||
try renderToken(tree, stream, lbrace, indent, start_col, Space.None);
|
||||
return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space);
|
||||
}
|
||||
if (exprs.len == 1) {
|
||||
if (exprs.len == 1 and tree.tokens.at(exprs.at(0).*.lastToken() + 1).id == .RBrace) {
|
||||
const expr = exprs.at(0).*;
|
||||
|
||||
try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
|
||||
@ -775,7 +800,7 @@ fn renderExpression(
|
||||
while (it.next()) |expr| : (i += 1) {
|
||||
counting_stream.bytes_written = 0;
|
||||
var dummy_col: usize = 0;
|
||||
try renderExpression(allocator, &counting_stream.stream, tree, 0, &dummy_col, expr.*, Space.None);
|
||||
try renderExpression(allocator, &counting_stream.stream, tree, indent, &dummy_col, expr.*, Space.None);
|
||||
const width = @intCast(usize, counting_stream.bytes_written);
|
||||
const col = i % row_size;
|
||||
column_widths[col] = std.math.max(column_widths[col], width);
|
||||
@ -1191,8 +1216,8 @@ fn renderExpression(
|
||||
});
|
||||
|
||||
const src_params_trailing_comma = blk: {
|
||||
const maybe_comma = tree.prevToken(rparen);
|
||||
break :blk tree.tokens.at(maybe_comma).id == Token.Id.Comma;
|
||||
const maybe_comma = tree.tokens.at(rparen - 1).id;
|
||||
break :blk maybe_comma == .Comma or maybe_comma == .LineComment;
|
||||
};
|
||||
|
||||
if (!src_params_trailing_comma) {
|
||||
|
||||
@ -6462,4 +6462,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
"tmp.zig:5:30: error: expression value is ignored",
|
||||
"tmp.zig:9:30: error: expression value is ignored",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
"aligned variable of zero-bit type",
|
||||
\\export fn f() void {
|
||||
\\ var s: struct {} align(4) = undefined;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:2:5: error: variable 's' of zero-bit type 'struct:2:12' has no in-memory representation, it cannot be aligned",
|
||||
);
|
||||
}
|
||||
|
||||
274
test/stack_traces.zig
Normal file
274
test/stack_traces.zig
Normal file
@ -0,0 +1,274 @@
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
const os = std.os;
|
||||
const tests = @import("tests.zig");
|
||||
|
||||
pub fn addCases(cases: *tests.StackTracesContext) void {
|
||||
const source_return =
|
||||
\\const std = @import("std");
|
||||
\\
|
||||
\\pub fn main() !void {
|
||||
\\ return error.TheSkyIsFalling;
|
||||
\\}
|
||||
;
|
||||
const source_try_return =
|
||||
\\const std = @import("std");
|
||||
\\
|
||||
\\fn foo() !void {
|
||||
\\ return error.TheSkyIsFalling;
|
||||
\\}
|
||||
\\
|
||||
\\pub fn main() !void {
|
||||
\\ try foo();
|
||||
\\}
|
||||
;
|
||||
const source_try_try_return_return =
|
||||
\\const std = @import("std");
|
||||
\\
|
||||
\\fn foo() !void {
|
||||
\\ try bar();
|
||||
\\}
|
||||
\\
|
||||
\\fn bar() !void {
|
||||
\\ return make_error();
|
||||
\\}
|
||||
\\
|
||||
\\fn make_error() !void {
|
||||
\\ return error.TheSkyIsFalling;
|
||||
\\}
|
||||
\\
|
||||
\\pub fn main() !void {
|
||||
\\ try foo();
|
||||
\\}
|
||||
;
|
||||
switch (builtin.os) {
|
||||
.linux => {
|
||||
cases.addCase(
|
||||
"return",
|
||||
source_return,
|
||||
[_][]const u8{
|
||||
// debug
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:4:5: [address] in main (test)
|
||||
\\
|
||||
,
|
||||
// release-safe
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:4:5: [address] in std.special.posixCallMainAndExit (test)
|
||||
\\
|
||||
,
|
||||
// release-fast
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
,
|
||||
// release-small
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
},
|
||||
);
|
||||
cases.addCase(
|
||||
"try return",
|
||||
source_try_return,
|
||||
[_][]const u8{
|
||||
// debug
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:4:5: [address] in foo (test)
|
||||
\\source.zig:8:5: [address] in main (test)
|
||||
\\
|
||||
,
|
||||
// release-safe
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:4:5: [address] in std.special.posixCallMainAndExit (test)
|
||||
\\source.zig:8:5: [address] in std.special.posixCallMainAndExit (test)
|
||||
\\
|
||||
,
|
||||
// release-fast
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
,
|
||||
// release-small
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
},
|
||||
);
|
||||
cases.addCase(
|
||||
"try try return return",
|
||||
source_try_try_return_return,
|
||||
[_][]const u8{
|
||||
// debug
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:12:5: [address] in make_error (test)
|
||||
\\source.zig:8:5: [address] in bar (test)
|
||||
\\source.zig:4:5: [address] in foo (test)
|
||||
\\source.zig:16:5: [address] in main (test)
|
||||
\\
|
||||
,
|
||||
// release-safe
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:12:5: [address] in std.special.posixCallMainAndExit (test)
|
||||
\\source.zig:8:5: [address] in std.special.posixCallMainAndExit (test)
|
||||
\\source.zig:4:5: [address] in std.special.posixCallMainAndExit (test)
|
||||
\\source.zig:16:5: [address] in std.special.posixCallMainAndExit (test)
|
||||
\\
|
||||
,
|
||||
// release-fast
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
,
|
||||
// release-small
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
},
|
||||
);
|
||||
},
|
||||
.macosx => {
|
||||
cases.addCase(
|
||||
"return",
|
||||
source_return,
|
||||
[_][]const u8{
|
||||
// debug
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:4:5: [address] in _main.0 (test.o)
|
||||
\\
|
||||
,
|
||||
// release-safe
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:4:5: [address] in _main (test.o)
|
||||
\\
|
||||
,
|
||||
// release-fast
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
,
|
||||
// release-small
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
},
|
||||
);
|
||||
cases.addCase(
|
||||
"try return",
|
||||
source_try_return,
|
||||
[_][]const u8{
|
||||
// debug
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:4:5: [address] in _foo (test.o)
|
||||
\\source.zig:8:5: [address] in _main.0 (test.o)
|
||||
\\
|
||||
,
|
||||
// release-safe
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:4:5: [address] in _main (test.o)
|
||||
\\source.zig:8:5: [address] in _main (test.o)
|
||||
\\
|
||||
,
|
||||
// release-fast
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
,
|
||||
// release-small
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
},
|
||||
);
|
||||
cases.addCase(
|
||||
"try try return return",
|
||||
source_try_try_return_return,
|
||||
[_][]const u8{
|
||||
// debug
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:12:5: [address] in _make_error (test.o)
|
||||
\\source.zig:8:5: [address] in _bar (test.o)
|
||||
\\source.zig:4:5: [address] in _foo (test.o)
|
||||
\\source.zig:16:5: [address] in _main.0 (test.o)
|
||||
\\
|
||||
,
|
||||
// release-safe
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:12:5: [address] in _main (test.o)
|
||||
\\source.zig:8:5: [address] in _main (test.o)
|
||||
\\source.zig:4:5: [address] in _main (test.o)
|
||||
\\source.zig:16:5: [address] in _main (test.o)
|
||||
\\
|
||||
,
|
||||
// release-fast
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
,
|
||||
// release-small
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
},
|
||||
);
|
||||
},
|
||||
.windows => {
|
||||
cases.addCase(
|
||||
"return",
|
||||
source_return,
|
||||
[_][]const u8{
|
||||
// debug
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:4:5: [address] in main (test.obj)
|
||||
\\
|
||||
,
|
||||
// release-safe
|
||||
// --disabled-- results in segmenetation fault
|
||||
"",
|
||||
// release-fast
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
,
|
||||
// release-small
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
},
|
||||
);
|
||||
cases.addCase(
|
||||
"try return",
|
||||
source_try_return,
|
||||
[_][]const u8{
|
||||
// debug
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:4:5: [address] in foo (test.obj)
|
||||
\\source.zig:8:5: [address] in main (test.obj)
|
||||
\\
|
||||
,
|
||||
// release-safe
|
||||
// --disabled-- results in segmenetation fault
|
||||
"",
|
||||
// release-fast
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
,
|
||||
// release-small
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
},
|
||||
);
|
||||
cases.addCase(
|
||||
"try try return return",
|
||||
source_try_try_return_return,
|
||||
[_][]const u8{
|
||||
// debug
|
||||
\\error: TheSkyIsFalling
|
||||
\\source.zig:12:5: [address] in make_error (test.obj)
|
||||
\\source.zig:8:5: [address] in bar (test.obj)
|
||||
\\source.zig:4:5: [address] in foo (test.obj)
|
||||
\\source.zig:16:5: [address] in main (test.obj)
|
||||
\\
|
||||
,
|
||||
// release-safe
|
||||
// --disabled-- results in segmenetation fault
|
||||
"",
|
||||
// release-fast
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
,
|
||||
// release-small
|
||||
\\error: TheSkyIsFalling
|
||||
\\
|
||||
},
|
||||
);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
@ -30,6 +30,7 @@ comptime {
|
||||
_ = @import("behavior/bugs/2114.zig");
|
||||
_ = @import("behavior/bugs/2346.zig");
|
||||
_ = @import("behavior/bugs/2578.zig");
|
||||
_ = @import("behavior/bugs/2692.zig");
|
||||
_ = @import("behavior/bugs/3112.zig");
|
||||
_ = @import("behavior/bugs/394.zig");
|
||||
_ = @import("behavior/bugs/421.zig");
|
||||
|
||||
@ -1031,3 +1031,64 @@ test "@typeOf an async function call of generic fn with error union type" {
|
||||
};
|
||||
_ = async S.func(i32);
|
||||
}
|
||||
|
||||
test "using @typeOf on a generic function call" {
|
||||
const S = struct {
|
||||
var global_frame: anyframe = undefined;
|
||||
var global_ok = false;
|
||||
|
||||
var buf: [100]u8 align(16) = undefined;
|
||||
|
||||
fn amain(x: var) void {
|
||||
if (x == 0) {
|
||||
global_ok = true;
|
||||
return;
|
||||
}
|
||||
suspend {
|
||||
global_frame = @frame();
|
||||
}
|
||||
const F = @typeOf(async amain(x - 1));
|
||||
const frame = @intToPtr(*F, @ptrToInt(&buf));
|
||||
return await @asyncCall(frame, {}, amain, x - 1);
|
||||
}
|
||||
};
|
||||
_ = async S.amain(u32(1));
|
||||
resume S.global_frame;
|
||||
expect(S.global_ok);
|
||||
}
|
||||
|
||||
test "recursive call of await @asyncCall with struct return type" {
|
||||
const S = struct {
|
||||
var global_frame: anyframe = undefined;
|
||||
var global_ok = false;
|
||||
|
||||
var buf: [100]u8 align(16) = undefined;
|
||||
|
||||
fn amain(x: var) Foo {
|
||||
if (x == 0) {
|
||||
global_ok = true;
|
||||
return Foo{ .x = 1, .y = 2, .z = 3 };
|
||||
}
|
||||
suspend {
|
||||
global_frame = @frame();
|
||||
}
|
||||
const F = @typeOf(async amain(x - 1));
|
||||
const frame = @intToPtr(*F, @ptrToInt(&buf));
|
||||
return await @asyncCall(frame, {}, amain, x - 1);
|
||||
}
|
||||
|
||||
const Foo = struct {
|
||||
x: u64,
|
||||
y: u64,
|
||||
z: u64,
|
||||
};
|
||||
};
|
||||
var res: S.Foo = undefined;
|
||||
var frame: @typeOf(async S.amain(u32(1))) = undefined;
|
||||
_ = @asyncCall(&frame, &res, S.amain, u32(1));
|
||||
resume S.global_frame;
|
||||
expect(S.global_ok);
|
||||
expect(res.x == 1);
|
||||
expect(res.y == 2);
|
||||
expect(res.z == 3);
|
||||
}
|
||||
|
||||
6
test/stage1/behavior/bugs/2692.zig
Normal file
6
test/stage1/behavior/bugs/2692.zig
Normal file
@ -0,0 +1,6 @@
|
||||
fn foo(a: []u8) void {}
|
||||
|
||||
test "address of 0 length array" {
|
||||
var pt: [0]u8 = undefined;
|
||||
foo(&pt);
|
||||
}
|
||||
@ -63,3 +63,14 @@ test "labeled break inside comptime if inside runtime if" {
|
||||
}
|
||||
expect(answer == 42);
|
||||
}
|
||||
|
||||
test "const result loc, runtime if cond, else unreachable" {
|
||||
const Num = enum {
|
||||
One,
|
||||
Two,
|
||||
};
|
||||
|
||||
var t = true;
|
||||
const x = if (t) Num.Two else unreachable;
|
||||
if (x != .Two) @compileError("bad");
|
||||
}
|
||||
|
||||
@ -599,3 +599,36 @@ test "extern fn returns struct by value" {
|
||||
S.entry();
|
||||
comptime S.entry();
|
||||
}
|
||||
|
||||
test "for loop over pointers to struct, getting field from struct pointer" {
|
||||
const S = struct {
|
||||
const Foo = struct {
|
||||
name: []const u8,
|
||||
};
|
||||
|
||||
var ok = true;
|
||||
|
||||
fn eql(a: []const u8) bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
const ArrayList = struct {
|
||||
fn toSlice(self: *ArrayList) []*Foo {
|
||||
return ([*]*Foo)(undefined)[0..0];
|
||||
}
|
||||
};
|
||||
|
||||
fn doTheTest() void {
|
||||
var objects: ArrayList = undefined;
|
||||
|
||||
for (objects.toSlice()) |obj| {
|
||||
if (eql(obj.name)) {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
expect(ok);
|
||||
}
|
||||
};
|
||||
S.doTheTest();
|
||||
}
|
||||
|
||||
@ -457,3 +457,13 @@ test "@unionInit can modify a pointer value" {
|
||||
value_ptr.* = @unionInit(UnionInitEnum, "Byte", 2);
|
||||
expect(value.Byte == 2);
|
||||
}
|
||||
|
||||
test "union no tag with struct member" {
|
||||
const Struct = struct {};
|
||||
const Union = union {
|
||||
s: Struct,
|
||||
pub fn foo(self: *@This()) void {}
|
||||
};
|
||||
var u = Union{ .s = Struct{} };
|
||||
u.foo();
|
||||
}
|
||||
|
||||
210
test/tests.zig
210
test/tests.zig
@ -16,6 +16,7 @@ const LibExeObjStep = build.LibExeObjStep;
|
||||
|
||||
const compare_output = @import("compare_output.zig");
|
||||
const standalone = @import("standalone.zig");
|
||||
const stack_traces = @import("stack_traces.zig");
|
||||
const compile_errors = @import("compile_errors.zig");
|
||||
const assemble_and_link = @import("assemble_and_link.zig");
|
||||
const runtime_safety = @import("runtime_safety.zig");
|
||||
@ -57,6 +58,21 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8, modes:
|
||||
return cases.step;
|
||||
}
|
||||
|
||||
pub fn addStackTraceTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
|
||||
const cases = b.allocator.create(StackTracesContext) catch unreachable;
|
||||
cases.* = StackTracesContext{
|
||||
.b = b,
|
||||
.step = b.step("test-stack-traces", "Run the stack trace tests"),
|
||||
.test_index = 0,
|
||||
.test_filter = test_filter,
|
||||
.modes = modes,
|
||||
};
|
||||
|
||||
stack_traces.addCases(cases);
|
||||
|
||||
return cases.step;
|
||||
}
|
||||
|
||||
pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const Mode) *build.Step {
|
||||
const cases = b.allocator.create(CompareOutputContext) catch unreachable;
|
||||
cases.* = CompareOutputContext{
|
||||
@ -549,6 +565,200 @@ pub const CompareOutputContext = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const StackTracesContext = struct {
|
||||
b: *build.Builder,
|
||||
step: *build.Step,
|
||||
test_index: usize,
|
||||
test_filter: ?[]const u8,
|
||||
modes: []const Mode,
|
||||
|
||||
const Expect = [@typeInfo(Mode).Enum.fields.len][]const u8;
|
||||
|
||||
pub fn addCase(
|
||||
self: *StackTracesContext,
|
||||
name: []const u8,
|
||||
source: []const u8,
|
||||
expect: Expect,
|
||||
) void {
|
||||
const b = self.b;
|
||||
|
||||
const source_pathname = fs.path.join(
|
||||
b.allocator,
|
||||
[_][]const u8{ b.cache_root, "source.zig" },
|
||||
) catch unreachable;
|
||||
|
||||
for (self.modes) |mode| {
|
||||
const expect_for_mode = expect[@enumToInt(mode)];
|
||||
if (expect_for_mode.len == 0) continue;
|
||||
|
||||
const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})", "stack-trace", name, @tagName(mode)) catch unreachable;
|
||||
if (self.test_filter) |filter| {
|
||||
if (mem.indexOf(u8, annotated_case_name, filter) == null) continue;
|
||||
}
|
||||
|
||||
const exe = b.addExecutable("test", source_pathname);
|
||||
exe.setBuildMode(mode);
|
||||
|
||||
const write_source = b.addWriteFile(source_pathname, source);
|
||||
exe.step.dependOn(&write_source.step);
|
||||
|
||||
const run_and_compare = RunAndCompareStep.create(
|
||||
self,
|
||||
exe,
|
||||
annotated_case_name,
|
||||
mode,
|
||||
expect_for_mode,
|
||||
);
|
||||
|
||||
self.step.dependOn(&run_and_compare.step);
|
||||
}
|
||||
}
|
||||
|
||||
const RunAndCompareStep = struct {
|
||||
step: build.Step,
|
||||
context: *StackTracesContext,
|
||||
exe: *LibExeObjStep,
|
||||
name: []const u8,
|
||||
mode: Mode,
|
||||
expect_output: []const u8,
|
||||
test_index: usize,
|
||||
|
||||
pub fn create(
|
||||
context: *StackTracesContext,
|
||||
exe: *LibExeObjStep,
|
||||
name: []const u8,
|
||||
mode: Mode,
|
||||
expect_output: []const u8,
|
||||
) *RunAndCompareStep {
|
||||
const allocator = context.b.allocator;
|
||||
const ptr = allocator.create(RunAndCompareStep) catch unreachable;
|
||||
ptr.* = RunAndCompareStep{
|
||||
.step = build.Step.init("StackTraceCompareOutputStep", allocator, make),
|
||||
.context = context,
|
||||
.exe = exe,
|
||||
.name = name,
|
||||
.mode = mode,
|
||||
.expect_output = expect_output,
|
||||
.test_index = context.test_index,
|
||||
};
|
||||
ptr.step.dependOn(&exe.step);
|
||||
context.test_index += 1;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
fn make(step: *build.Step) !void {
|
||||
const self = @fieldParentPtr(RunAndCompareStep, "step", step);
|
||||
const b = self.context.b;
|
||||
|
||||
const full_exe_path = self.exe.getOutputPath();
|
||||
var args = ArrayList([]const u8).init(b.allocator);
|
||||
defer args.deinit();
|
||||
args.append(full_exe_path) catch unreachable;
|
||||
|
||||
warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name);
|
||||
|
||||
const child = std.ChildProcess.init(args.toSliceConst(), b.allocator) catch unreachable;
|
||||
defer child.deinit();
|
||||
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Pipe;
|
||||
child.stderr_behavior = .Pipe;
|
||||
child.env_map = b.env_map;
|
||||
|
||||
child.spawn() catch |err| debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
|
||||
|
||||
var stdout = Buffer.initNull(b.allocator);
|
||||
var stderr = Buffer.initNull(b.allocator);
|
||||
|
||||
var stdout_file_in_stream = child.stdout.?.inStream();
|
||||
var stderr_file_in_stream = child.stderr.?.inStream();
|
||||
|
||||
stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable;
|
||||
stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable;
|
||||
|
||||
const term = child.wait() catch |err| {
|
||||
debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
|
||||
};
|
||||
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
const expect_code: u32 = 1;
|
||||
if (code != expect_code) {
|
||||
warn("Process {} exited with error code {} but expected code {}\n", full_exe_path, code, expect_code);
|
||||
printInvocation(args.toSliceConst());
|
||||
return error.TestFailed;
|
||||
}
|
||||
},
|
||||
.Signal => |signum| {
|
||||
warn("Process {} terminated on signal {}\n", full_exe_path, signum);
|
||||
printInvocation(args.toSliceConst());
|
||||
return error.TestFailed;
|
||||
},
|
||||
.Stopped => |signum| {
|
||||
warn("Process {} stopped on signal {}\n", full_exe_path, signum);
|
||||
printInvocation(args.toSliceConst());
|
||||
return error.TestFailed;
|
||||
},
|
||||
.Unknown => |code| {
|
||||
warn("Process {} terminated unexpectedly with error code {}\n", full_exe_path, code);
|
||||
printInvocation(args.toSliceConst());
|
||||
return error.TestFailed;
|
||||
},
|
||||
}
|
||||
|
||||
// process result
|
||||
// - keep only basename of source file path
|
||||
// - replace address with symbolic string
|
||||
// - skip empty lines
|
||||
const got: []const u8 = got_result: {
|
||||
var buf = try Buffer.initSize(b.allocator, 0);
|
||||
defer buf.deinit();
|
||||
var bytes = stderr.toSliceConst();
|
||||
if (bytes.len != 0 and bytes[bytes.len - 1] == '\n') bytes = bytes[0 .. bytes.len - 1];
|
||||
var it = mem.separate(bytes, "\n");
|
||||
process_lines: while (it.next()) |line| {
|
||||
if (line.len == 0) continue;
|
||||
const delims = [_][]const u8{ ":", ":", ":", " in " };
|
||||
var marks = [_]usize{0} ** 4;
|
||||
// offset search past `[drive]:` on windows
|
||||
var pos: usize = if (builtin.os == .windows) 2 else 0;
|
||||
for (delims) |delim, i| {
|
||||
marks[i] = mem.indexOfPos(u8, line, pos, delim) orelse {
|
||||
try buf.append(line);
|
||||
try buf.append("\n");
|
||||
continue :process_lines;
|
||||
};
|
||||
pos = marks[i] + delim.len;
|
||||
}
|
||||
pos = mem.lastIndexOfScalar(u8, line[0..marks[0]], fs.path.sep) orelse {
|
||||
try buf.append(line);
|
||||
try buf.append("\n");
|
||||
continue :process_lines;
|
||||
};
|
||||
try buf.append(line[pos + 1 .. marks[2] + delims[2].len]);
|
||||
try buf.append(" [address]");
|
||||
try buf.append(line[marks[3]..]);
|
||||
try buf.append("\n");
|
||||
}
|
||||
break :got_result buf.toOwnedSlice();
|
||||
};
|
||||
|
||||
if (!mem.eql(u8, self.expect_output, got)) {
|
||||
warn(
|
||||
\\
|
||||
\\========= Expected this output: =========
|
||||
\\{}
|
||||
\\================================================
|
||||
\\{}
|
||||
\\
|
||||
, self.expect_output, got);
|
||||
return error.TestFailed;
|
||||
}
|
||||
warn("OK\n");
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
pub const CompileErrorContext = struct {
|
||||
b: *build.Builder,
|
||||
step: *build.Step,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user