Commit c9ae30d27e
Changed files (10)
doc
std
test
doc/langref.md
@@ -295,19 +295,6 @@ has a terminating null byte.
Built-in functions are prefixed with `@`. Remember that the `comptime` keyword on
a parameter means that the parameter must be known at compile time.
-### @alloca(comptime T: type, count: usize) -> []T
-
-Allocates memory in the stack frame of the caller. This temporary space is
-automatically freed when the function that called alloca returns to its caller,
-just like other stack variables.
-
-When using this function to allocate memory, you should know the upper bound
-of `count`. Consider putting a constant array on the stack with the upper bound
-instead of using alloca. If you do use alloca it is to save a few bytes off
-the memory size given that you didn't actually hit your upper bound.
-
-The allocated memory contents are undefined.
-
### @typeOf(expression) -> type
This function returns a compile-time constant, which is the type of the
src/all_types.hpp
@@ -1190,7 +1190,6 @@ enum BuiltinFnId {
BuiltinFnIdTruncate,
BuiltinFnIdIntType,
BuiltinFnIdSetDebugSafety,
- BuiltinFnIdAlloca,
BuiltinFnIdTypeName,
BuiltinFnIdIsInteger,
BuiltinFnIdIsFloat,
@@ -1706,7 +1705,6 @@ enum IrInstructionId {
IrInstructionIdTruncate,
IrInstructionIdIntType,
IrInstructionIdBoolNot,
- IrInstructionIdAlloca,
IrInstructionIdMemset,
IrInstructionIdMemcpy,
IrInstructionIdSlice,
@@ -2234,14 +2232,6 @@ struct IrInstructionBoolNot {
IrInstruction *value;
};
-struct IrInstructionAlloca {
- IrInstruction base;
-
- IrInstruction *type_value;
- IrInstruction *count;
- LLVMValueRef tmp_ptr;
-};
-
struct IrInstructionMemset {
IrInstruction base;
src/codegen.cpp
@@ -2190,26 +2190,6 @@ static LLVMValueRef ir_render_truncate(CodeGen *g, IrExecutable *executable, IrI
}
}
-static LLVMValueRef ir_render_alloca(CodeGen *g, IrExecutable *executable, IrInstructionAlloca *instruction) {
- TypeTableEntry *slice_type = get_underlying_type(instruction->base.value.type);
- TypeTableEntry *ptr_type = slice_type->data.structure.fields[slice_ptr_index].type_entry;
- TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
- LLVMValueRef size_val = ir_llvm_value(g, instruction->count);
- LLVMValueRef ptr_val = LLVMBuildArrayAlloca(g->builder, child_type->type_ref, size_val, "");
-
- // TODO in debug mode, initialize all the bytes to 0xaa
-
- // store the freshly allocated pointer in the slice
- LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, slice_ptr_index, "");
- LLVMBuildStore(g->builder, ptr_val, ptr_field_ptr);
-
- // store the size in the len field
- LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, slice_len_index, "");
- LLVMBuildStore(g->builder, size_val, len_field_ptr);
-
- return instruction->tmp_ptr;
-}
-
static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutable *executable, IrInstructionMemset *instruction) {
LLVMValueRef dest_ptr = ir_llvm_value(g, instruction->dest_ptr);
LLVMValueRef char_val = ir_llvm_value(g, instruction->byte);
@@ -2548,7 +2528,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
assert(instruction->tmp_ptr);
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
- assert(child_type == instruction->value->value.type);
+ // child_type and instruction->value->value.type may differ by constness
gen_assign_raw(g, val_ptr, payload_val, child_type);
LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");
LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);
@@ -2796,8 +2776,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_truncate(g, executable, (IrInstructionTruncate *)instruction);
case IrInstructionIdBoolNot:
return ir_render_bool_not(g, executable, (IrInstructionBoolNot *)instruction);
- case IrInstructionIdAlloca:
- return ir_render_alloca(g, executable, (IrInstructionAlloca *)instruction);
case IrInstructionIdMemset:
return ir_render_memset(g, executable, (IrInstructionMemset *)instruction);
case IrInstructionIdMemcpy:
@@ -3648,9 +3626,6 @@ static void do_code_gen(CodeGen *g) {
} else if (instruction->id == IrInstructionIdCall) {
IrInstructionCall *call_instruction = (IrInstructionCall *)instruction;
slot = &call_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdAlloca) {
- IrInstructionAlloca *alloca_instruction = (IrInstructionAlloca *)instruction;
- slot = &alloca_instruction->tmp_ptr;
} else if (instruction->id == IrInstructionIdSlice) {
IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction;
slot = &slice_instruction->tmp_ptr;
@@ -4326,7 +4301,6 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
create_builtin_fn(g, BuiltinFnIdIntType, "intType", 2);
create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);
- create_builtin_fn(g, BuiltinFnIdAlloca, "alloca", 2);
create_builtin_fn(g, BuiltinFnIdSetGlobalAlign, "setGlobalAlign", 2);
create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2);
create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2);
src/ir.cpp
@@ -404,10 +404,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) {
return IrInstructionIdBoolNot;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionAlloca *) {
- return IrInstructionIdAlloca;
-}
-
static constexpr IrInstructionId ir_instruction_id(IrInstructionMemset *) {
return IrInstructionIdMemset;
}
@@ -1668,27 +1664,6 @@ static IrInstruction *ir_build_bool_not_from(IrBuilder *irb, IrInstruction *old_
return new_instruction;
}
-static IrInstruction *ir_build_alloca(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *type_value, IrInstruction *count)
-{
- IrInstructionAlloca *instruction = ir_build_instruction<IrInstructionAlloca>(irb, scope, source_node);
- instruction->type_value = type_value;
- instruction->count = count;
-
- ir_ref_instruction(type_value, irb->current_basic_block);
- ir_ref_instruction(count, irb->current_basic_block);
-
- return &instruction->base;
-}
-
-static IrInstruction *ir_build_alloca_from(IrBuilder *irb, IrInstruction *old_instruction,
- IrInstruction *type_value, IrInstruction *count)
-{
- IrInstruction *new_instruction = ir_build_alloca(irb, old_instruction->scope, old_instruction->source_node, type_value, count);
- ir_link_new_instruction(new_instruction, old_instruction);
- return new_instruction;
-}
-
static IrInstruction *ir_build_memset(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *dest_ptr, IrInstruction *byte, IrInstruction *count)
{
@@ -2567,14 +2542,6 @@ static IrInstruction *ir_instruction_boolnot_get_dep(IrInstructionBoolNot *instr
}
}
-static IrInstruction *ir_instruction_alloca_get_dep(IrInstructionAlloca *instruction, size_t index) {
- switch (index) {
- case 0: return instruction->type_value;
- case 1: return instruction->count;
- default: return nullptr;
- }
-}
-
static IrInstruction *ir_instruction_memset_get_dep(IrInstructionMemset *instruction, size_t index) {
switch (index) {
case 0: return instruction->dest_ptr;
@@ -2938,8 +2905,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_inttype_get_dep((IrInstructionIntType *) instruction, index);
case IrInstructionIdBoolNot:
return ir_instruction_boolnot_get_dep((IrInstructionBoolNot *) instruction, index);
- case IrInstructionIdAlloca:
- return ir_instruction_alloca_get_dep((IrInstructionAlloca *) instruction, index);
case IrInstructionIdMemset:
return ir_instruction_memset_get_dep((IrInstructionMemset *) instruction, index);
case IrInstructionIdMemcpy:
@@ -4100,20 +4065,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_build_int_type(irb, scope, node, arg0_value, arg1_value);
}
- case BuiltinFnIdAlloca:
- {
- 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_alloca(irb, scope, node, arg0_value, arg1_value);
- }
case BuiltinFnIdMemcpy:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
@@ -11461,31 +11412,6 @@ static TypeTableEntry *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstruc
return bool_type;
}
-static TypeTableEntry *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructionAlloca *instruction) {
- IrInstruction *type_value = instruction->type_value->other;
- if (type_is_invalid(type_value->value.type))
- return ira->codegen->builtin_types.entry_invalid;
-
- IrInstruction *count_value = instruction->count->other;
- if (type_is_invalid(count_value->value.type))
- return ira->codegen->builtin_types.entry_invalid;
-
- TypeTableEntry *child_type = ir_resolve_type(ira, type_value);
-
- if (type_requires_comptime(child_type)) {
- ir_add_error(ira, type_value,
- buf_sprintf("invalid alloca type '%s'", buf_ptr(&child_type->name)));
- // TODO if this is a typedecl, add error note showing the declaration of the type decl
- return ira->codegen->builtin_types.entry_invalid;
- } else {
- TypeTableEntry *slice_type = get_slice_type(ira->codegen, child_type, false);
- IrInstruction *new_instruction = ir_build_alloca_from(&ira->new_irb, &instruction->base, type_value, count_value);
- ir_add_alloca(ira, new_instruction, slice_type);
- return slice_type;
- }
- zig_unreachable();
-}
-
static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructionMemset *instruction) {
IrInstruction *dest_ptr = instruction->dest_ptr->other;
if (type_is_invalid(dest_ptr->value.type))
@@ -12550,8 +12476,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);
case IrInstructionIdBoolNot:
return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);
- case IrInstructionIdAlloca:
- return ir_analyze_instruction_alloca(ira, (IrInstructionAlloca *)instruction);
case IrInstructionIdMemset:
return ir_analyze_instruction_memset(ira, (IrInstructionMemset *)instruction);
case IrInstructionIdMemcpy:
@@ -12749,7 +12673,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdTruncate:
case IrInstructionIdIntType:
case IrInstructionIdBoolNot:
- case IrInstructionIdAlloca:
case IrInstructionIdSlice:
case IrInstructionIdMemberCount:
case IrInstructionIdAlignOf:
src/ir_print.cpp
@@ -601,14 +601,6 @@ static void ir_print_truncate(IrPrint *irp, IrInstructionTruncate *instruction)
fprintf(irp->f, ")");
}
-static void ir_print_alloca(IrPrint *irp, IrInstructionAlloca *instruction) {
- fprintf(irp->f, "@alloca(");
- ir_print_other_instruction(irp, instruction->type_value);
- fprintf(irp->f, ", ");
- ir_print_other_instruction(irp, instruction->count);
- fprintf(irp->f, ")");
-}
-
static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) {
fprintf(irp->f, "@intType(");
ir_print_other_instruction(irp, instruction->is_signed);
@@ -1049,9 +1041,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdTruncate:
ir_print_truncate(irp, (IrInstructionTruncate *)instruction);
break;
- case IrInstructionIdAlloca:
- ir_print_alloca(irp, (IrInstructionAlloca *)instruction);
- break;
case IrInstructionIdIntType:
ir_print_int_type(irp, (IrInstructionIntType *)instruction);
break;
std/os/index.zig
@@ -21,6 +21,8 @@ const mem = @import("../mem.zig");
const Allocator = mem.Allocator;
const io = @import("../io.zig");
+const HashMap = @import("../hash_map.zig").HashMap;
+const cstr = @import("../cstr.zig");
error Unexpected;
error SysResources;
@@ -284,12 +286,12 @@ pub const ChildProcess = struct {
Close,
};
- pub fn spawn(exe_path: []const u8, args: []const []const u8, env: []const EnvPair,
+ pub fn spawn(exe_path: []const u8, args: []const []const u8, env_map: &const EnvMap,
stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
{
switch (@compileVar("os")) {
Os.linux, Os.macosx, Os.ios, Os.darwin => {
- return spawnPosix(exe_path, args, env, stdin, stdout, stderr, allocator);
+ return spawnPosix(exe_path, args, env_map, stdin, stdout, stderr, allocator);
},
else => @compileError("Unsupported OS"),
}
@@ -351,7 +353,7 @@ pub const ChildProcess = struct {
};
}
- fn spawnPosix(exe_path: []const u8, args: []const []const u8, env: []const EnvPair,
+ fn spawnPosix(exe_path: []const u8, args: []const []const u8, env_map: &const EnvMap,
stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
{
// TODO issue #295
@@ -408,7 +410,7 @@ pub const ChildProcess = struct {
setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %%
|err| forkChildErrReport(err_pipe[1], err);
- const err = posix.getErrno(%return execve(exe_path, args, env, allocator));
+ const err = posix.getErrno(%return execve(exe_path, args, env_map, allocator));
assert(err > 0);
forkChildErrReport(err_pipe[1], switch (err) {
errno.EFAULT => unreachable,
@@ -473,7 +475,7 @@ pub const ChildProcess = struct {
/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
/// pointers after the args and after the environment variables.
/// Also make the first arg equal to path.
-fn execve(path: []const u8, argv: []const []const u8, envp: []const EnvPair, allocator: &Allocator) -> %usize {
+fn execve(path: []const u8, argv: []const []const u8, env_map: &const EnvMap, allocator: &Allocator) -> %usize {
const path_buf = %return allocator.alloc(u8, path.len + 1);
defer allocator.free(path_buf);
@memcpy(&path_buf[0], &path[0], path.len);
@@ -505,39 +507,149 @@ fn execve(path: []const u8, argv: []const []const u8, envp: []const EnvPair, all
}
argv_buf[argv.len + 1] = null;
- const envp_buf = %return allocator.alloc(?&const u8, envp.len + 1);
+ const envp_count = env_map.count();
+ const envp_buf = %return allocator.alloc(?&const u8, envp_count + 1);
mem.set(?&const u8, envp_buf, null);
defer {
for (envp_buf) |env, i| {
- const env_buf = if (const ptr ?= env) ptr[0...envp[i].key.len + envp[i].value.len + 2] else break;
+ const env_buf = if (const ptr ?= env) ptr[0...cstr.len(ptr)] else break;
allocator.free(env_buf);
}
allocator.free(envp_buf);
}
- for (envp) |pair, i| {
- const env_buf = %return allocator.alloc(u8, pair.key.len + pair.value.len + 2);
- @memcpy(&env_buf[0], pair.key.ptr, pair.key.len);
- env_buf[pair.key.len] = '=';
- @memcpy(&env_buf[pair.key.len + 1], pair.value.ptr, pair.value.len);
- env_buf[env_buf.len - 1] = 0;
-
- envp_buf[i] = env_buf.ptr;
+ {
+ var it = env_map.iterator();
+ var i: usize = 0;
+ while (true; i += 1) {
+ const pair = it.next() ?? break;
+
+ const env_buf = %return allocator.alloc(u8, pair.key.len + pair.value.len + 2);
+ @memcpy(&env_buf[0], pair.key.ptr, pair.key.len);
+ env_buf[pair.key.len] = '=';
+ @memcpy(&env_buf[pair.key.len + 1], pair.value.ptr, pair.value.len);
+ env_buf[env_buf.len - 1] = 0;
+
+ envp_buf[i] = env_buf.ptr;
+ }
+ assert(i == envp_count);
}
- envp_buf[envp.len] = null;
+ envp_buf[envp_count] = null;
return posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr);
}
-pub const EnvPair = struct {
- key: []const u8,
- value: []const u8,
+pub var environ_raw: []&u8 = undefined;
+
+pub const EnvMap = struct {
+ hash_map: EnvHashMap,
+
+ const EnvHashMap = HashMap([]const u8, []const u8, hash_slice_u8, eql_slice_u8);
+
+ pub fn init(allocator: &Allocator) -> EnvMap {
+ var self = EnvMap {
+ .hash_map = undefined,
+ };
+ self.hash_map.init(allocator);
+ return self;
+ }
+
+ pub fn deinit(self: &EnvMap) {
+ var it = self.hash_map.entryIterator();
+ while (true) {
+ const entry = it.next() ?? break;
+ self.free(entry.key);
+ self.free(entry.value);
+ }
+
+ self.hash_map.deinit();
+ }
+
+ pub fn set(self: &EnvMap, key: []const u8, value: []const u8) -> %void {
+ if (const entry ?= self.hash_map.get(key)) {
+ const value_copy = %return self.copy(value);
+ %defer self.free(value_copy);
+ %return self.hash_map.put(key, value_copy);
+ self.free(entry.value);
+ } else {
+ const key_copy = %return self.copy(key);
+ %defer self.free(key_copy);
+ const value_copy = %return self.copy(value);
+ %defer self.free(value_copy);
+ %return self.hash_map.put(key_copy, value_copy);
+ }
+ }
+
+ pub fn delete(self: &EnvMap, key: []const u8) {
+ const entry = self.hash_map.remove(key) ?? return;
+ self.free(entry.key);
+ self.free(entry.value);
+ }
+
+ pub fn count(self: &const EnvMap) -> usize {
+ return self.hash_map.size;
+ }
+
+ pub fn iterator(self: &const EnvMap) -> EnvHashMap.Iterator {
+ return self.hash_map.entryIterator();
+ }
+
+ fn free(self: &EnvMap, value: []const u8) {
+ // remove the const
+ const mut_value = @ptrcast(&u8, value.ptr)[0...value.len];
+ self.hash_map.allocator.free(mut_value);
+ }
+
+ fn copy(self: &EnvMap, value: []const u8) -> %[]const u8 {
+ const result = %return self.hash_map.allocator.alloc(u8, value.len);
+ mem.copy(u8, result, value);
+ return result;
+ }
};
-pub var environ: []const EnvPair = undefined;
+
+pub fn getEnvMap(allocator: &Allocator) -> %EnvMap {
+ var result = EnvMap.init(allocator);
+ %defer result.deinit();
+
+ for (environ_raw) |ptr| {
+ var line_i: usize = 0;
+ while (ptr[line_i] != 0 and ptr[line_i] != '='; line_i += 1) {}
+ const key = ptr[0...line_i];
+
+ var end_i: usize = line_i;
+ while (ptr[end_i] != 0; end_i += 1) {}
+ const value = ptr[line_i + 1...end_i];
+
+ %return result.set(key, value);
+ }
+ return result;
+}
pub fn getEnv(key: []const u8) -> ?[]const u8 {
- for (environ) |pair| {
- if (mem.eql(u8, pair.key, key))
- return pair.value;
+ for (environ_raw) |ptr| {
+ var line_i: usize = 0;
+ while (ptr[line_i] != 0 and ptr[line_i] != '='; line_i += 1) {}
+ const this_key = ptr[0...line_i];
+ if (!mem.eql(u8, key, this_key))
+ continue;
+
+ var end_i: usize = line_i;
+ while (ptr[end_i] != 0; end_i += 1) {}
+ const this_value = ptr[line_i + 1...end_i];
+
+ return this_value;
}
return null;
}
+
+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;
+}
+
+fn eql_slice_u8(a: []const u8, b: []const u8) -> bool {
+ return mem.eql(u8, a, b);
+}
std/special/bootstrap.zig
@@ -9,8 +9,7 @@ const want_start_symbol = !want_main_symbol;
const exit = std.os.posix.exit;
-var argc: usize = undefined;
-var argv: &&u8 = undefined;
+var argc_ptr: &usize = undefined;
export nakedcc fn _start() -> noreturn {
@setGlobalLinkage(_start, if (want_start_symbol) GlobalLinkage.Strong else GlobalLinkage.Internal);
@@ -20,21 +19,28 @@ export nakedcc fn _start() -> noreturn {
switch (@compileVar("arch")) {
Arch.x86_64 => {
- argc = asm("mov %[argc], [rsp]": [argc] "=r" (-> usize));
- argv = asm("lea %[argv], [rsp + 8h]": [argv] "=r" (-> &&u8));
+ argc_ptr = asm("lea %[argc], [rsp]": [argc] "=r" (-> &usize));
},
Arch.i386 => {
- argc = asm("mov %[argc], [esp]": [argc] "=r" (-> usize));
- argv = asm("lea %[argv], [esp + 4h]": [argv] "=r" (-> &&u8));
+ argc_ptr = asm("lea %[argc], [esp]": [argc] "=r" (-> &usize));
},
else => @compileError("unsupported arch"),
}
callMainAndExit()
}
-fn callMain(envp: &?&u8) -> %void {
- // TODO issue #225
- const args = @alloca([]u8, argc);
+fn callMainAndExit() -> noreturn {
+ const argc = *argc_ptr;
+ const argv = @ptrcast(&&u8, &argc_ptr[1]);
+ const envp = @ptrcast(&?&u8, &argv[argc + 1]);
+ callMain(argc, argv, envp) %% exit(1);
+ exit(0);
+}
+
+var args_data: [32][]u8 = undefined;
+fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {
+ // TODO create args API to make it work with > 32 args
+ const args = args_data[0...argc];
for (args) |_, i| {
const ptr = argv[i];
args[i] = ptr[0...std.cstr.len(ptr)];
@@ -42,41 +48,17 @@ fn callMain(envp: &?&u8) -> %void {
var env_count: usize = 0;
while (envp[env_count] != null; env_count += 1) {}
- // TODO issue #225
- const environ = @alloca(std.os.EnvPair, env_count);
- for (environ) |_, env_i| {
- const ptr = ??envp[env_i];
-
- var line_i: usize = 0;
- while (ptr[line_i] != 0 and ptr[line_i] != '='; line_i += 1) {}
-
- var end_i: usize = line_i;
- while (ptr[end_i] != 0; end_i += 1) {}
-
- environ[env_i] = std.os.EnvPair {
- .key = ptr[0...line_i],
- .value = ptr[line_i + 1...end_i],
- };
- }
- std.os.environ = environ;
+ std.os.environ_raw = @ptrcast(&&u8, envp)[0...env_count];
return root.main(args);
}
-fn callMainAndExit() -> noreturn {
- const envp = @ptrcast(&?&u8, &argv[argc + 1]);
- callMain(envp) %% exit(1);
- exit(0);
-}
-
export fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 {
@setGlobalLinkage(main, if (want_main_symbol) GlobalLinkage.Strong else GlobalLinkage.Internal);
if (!want_main_symbol) {
unreachable;
}
- argc = usize(c_argc);
- argv = c_argv;
- callMain(c_envp) %% return 1;
+ callMain(usize(c_argc), c_argv, c_envp) %% return 1;
return 0;
}
std/build.zig
@@ -40,6 +40,8 @@ pub const Builder = struct {
}
pub fn make(self: &Builder, cli_args: []const []const u8) -> %void {
+ var env_map = %return os.getEnvMap(self.allocator);
+
var verbose = false;
for (cli_args) |arg| {
if (mem.eql(u8, arg, "--verbose")) {
@@ -93,7 +95,7 @@ pub const Builder = struct {
}
printInvocation(self.zig_exe, zig_args);
- var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), os.environ,
+ var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), env_map,
StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator);
const term = %return child.wait();
switch (term) {
std/hash_map.zig
@@ -29,7 +29,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
};
pub const Iterator = struct {
- hm: &Self,
+ hm: &const Self,
// how many items have we returned
count: usize,
// iterator through the entry array
@@ -99,17 +99,21 @@ pub fn HashMap(comptime K: type, comptime V: type,
}
pub fn get(hm: &Self, key: K) -> ?&Entry {
+ if (hm.entries.len == 0) {
+ return null;
+ }
return hm.internalGet(key);
}
- pub fn remove(hm: &Self, key: K) {
+ pub fn remove(hm: &Self, key: K) -> ?&Entry {
hm.incrementModificationCount();
const start_index = hm.keyToIndex(key);
{var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index; roll_over += 1) {
const index = (start_index + roll_over) % hm.entries.len;
var entry = &hm.entries[index];
- assert(entry.used); // key not found
+ if (!entry.used)
+ return null;
if (!eql(entry.key, key)) continue;
@@ -119,7 +123,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
if (!next_entry.used or next_entry.distance_from_start_index == 0) {
entry.used = false;
hm.size -= 1;
- return;
+ return entry;
}
*entry = *next_entry;
entry.distance_from_start_index -= 1;
@@ -127,10 +131,10 @@ pub fn HashMap(comptime K: type, comptime V: type,
}
unreachable // shifting everything in the table
}}
- unreachable // key not found
+ return null;
}
- pub fn entryIterator(hm: &Self) -> Iterator {
+ pub fn entryIterator(hm: &const Self) -> Iterator {
return Iterator {
.hm = hm,
.count = 0,
@@ -231,7 +235,8 @@ test "basicHashMapTest" {
%%map.put(5, 55);
assert((??map.get(2)).value == 22);
- map.remove(2);
+ _ = map.remove(2);
+ assert(map.remove(2) == null);
assert(if (const entry ?= map.get(2)) false else true);
}
test/cases/const_slice_child.zig
@@ -1,4 +1,5 @@
-const assert = @import("std").debug.assert;
+const debug = @import("std").debug;
+const assert = debug.assert;
var argv: &const &const u8 = undefined;
@@ -20,7 +21,7 @@ fn foo(args: [][]const u8) {
}
fn bar(argc: usize) {
- const args = @alloca([]u8, argc);
+ const args = %%debug.global_allocator.alloc([]u8, argc);
for (args) |_, i| {
const ptr = argv[i];
args[i] = ptr[0...strlen(ptr)];