diff --git a/doc/langref.html.in b/doc/langref.html.in
index 814de721a694..b32c8165e228 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -2797,39 +2797,30 @@ fn foo() void { }
{#code_end#}
{#header_open|Pass-by-value Parameters#}
- In Zig, structs, unions, and enums with payloads cannot be passed by value
- to a function.
+ In Zig, structs, unions, and enums with payloads can be passed directly to a function:
- {#code_begin|test_err|not copyable; cannot pass by value#}
-const Foo = struct {
+ {#code_begin|test#}
+const Point = struct {
x: i32,
+ y: i32,
};
-fn bar(foo: Foo) void {}
-
-test "pass aggregate type by value to function" {
- bar(Foo {.x = 12,});
+fn foo(point: Point) i32 {
+ return point.x + point.y;
}
- {#code_end#}
-
- Instead, one must use *const
. Zig allows implicitly casting something
- to a const pointer to it:
-
- {#code_begin|test#}
-const Foo = struct {
- x: i32,
-};
-fn bar(foo: *const Foo) void {}
+const assert = @import("std").debug.assert;
-test "implicitly cast to const pointer" {
- bar(Foo {.x = 12,});
+test "pass aggregate type by non-copy value to function" {
+ assert(foo(Point{ .x = 1, .y = 2 }) == 3);
}
{#code_end#}
- However,
- the C ABI does allow passing structs and unions by value. So functions which
- use the C calling convention may pass structs and unions by value.
+ In this case, the value may be passed by reference, or by value, whichever way
+ Zig decides will be faster.
+
+
+ For extern functions, Zig follows the C ABI for passing structs and unions by value.
{#header_close#}
{#header_open|Function Reflection#}
diff --git a/src/analyze.cpp b/src/analyze.cpp
index cbeac7bc212e..758bc1a045b5 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -1135,7 +1135,10 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
gen_param_info->src_index = i;
gen_param_info->gen_index = SIZE_MAX;
- type_ensure_zero_bits_known(g, type_entry);
+ ensure_complete_type(g, type_entry);
+ if (type_is_invalid(type_entry))
+ return g->builtin_types.entry_invalid;
+
if (type_has_bits(type_entry)) {
TypeTableEntry *gen_type;
if (handle_is_ptr(type_entry)) {
@@ -1546,12 +1549,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
case TypeTableEntryIdPromise:
- ensure_complete_type(g, type_entry);
- if (calling_convention_allows_zig_types(fn_type_id.cc) && !type_is_copyable(g, type_entry)) {
- add_node_error(g, param_node->data.param_decl.type,
- buf_sprintf("type '%s' is not copyable; cannot pass by value", buf_ptr(&type_entry->name)));
- return g->builtin_types.entry_invalid;
- }
break;
}
FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
diff --git a/src/codegen.cpp b/src/codegen.cpp
index fedfcfa7440f..425cdac0249f 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -326,13 +326,6 @@ static void addLLVMArgAttr(LLVMValueRef arg_val, unsigned param_index, const cha
return addLLVMAttr(arg_val, param_index + 1, attr_name);
}
-static void addLLVMCallsiteAttr(LLVMValueRef call_instr, unsigned param_index, const char *attr_name) {
- unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name));
- assert(kind_id != 0);
- LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(LLVMGetGlobalContext(), kind_id, 0);
- LLVMAddCallSiteAttribute(call_instr, param_index + 1, llvm_attr);
-}
-
static bool is_symbol_available(CodeGen *g, Buf *name) {
return g->exported_symbol_names.maybe_get(name) == nullptr && g->external_prototypes.maybe_get(name) == nullptr;
}
@@ -581,11 +574,6 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
if (param_type->id == TypeTableEntryIdPointer) {
addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "nonnull");
}
- // Note: byval is disabled on windows due to an LLVM bug:
- // https://github.com/ziglang/zig/issues/536
- if (is_byval && g->zig_target.os != OsWindows) {
- addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "byval");
- }
}
uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
@@ -3114,15 +3102,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
}
- for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
- FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
- // Note: byval is disabled on windows due to an LLVM bug:
- // https://github.com/ziglang/zig/issues/536
- if (gen_info->is_byval && g->zig_target.os != OsWindows) {
- addLLVMCallsiteAttr(result, (unsigned)gen_info->gen_index, "byval");
- }
- }
-
if (instruction->is_async) {
LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
LLVMBuildStore(g->builder, result, payload_ptr);
diff --git a/src/ir.cpp b/src/ir.cpp
index e5e8dcbb9dd0..d008ead1132e 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -10463,13 +10463,6 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Typ
zig_unreachable();
}
-static IrInstruction *ir_implicit_byval_const_ref_cast(IrAnalyze *ira, IrInstruction *inst) {
- if (type_is_copyable(ira->codegen, inst->value.type))
- return inst;
- TypeTableEntry *const_ref_type = get_pointer_to_type(ira->codegen, inst->value.type, true);
- return ir_implicit_cast(ira, inst, const_ref_type);
-}
-
static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) {
TypeTableEntry *type_entry = ptr->value.type;
if (type_is_invalid(type_entry)) {
@@ -12283,7 +12276,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
IrInstruction *casted_arg;
if (is_var_args) {
arg_part_of_generic_id = true;
- casted_arg = ir_implicit_byval_const_ref_cast(ira, arg);
+ casted_arg = arg;
} else {
if (param_decl_node->data.param_decl.var_token == nullptr) {
AstNode *param_type_node = param_decl_node->data.param_decl.type;
@@ -12296,7 +12289,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
return false;
} else {
arg_part_of_generic_id = true;
- casted_arg = ir_implicit_byval_const_ref_cast(ira, arg);
+ casted_arg = arg;
}
}
@@ -12515,9 +12508,18 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
size_t next_proto_i = 0;
if (first_arg_ptr) {
- IrInstruction *first_arg;
assert(first_arg_ptr->value.type->id == TypeTableEntryIdPointer);
- if (handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
+
+ bool first_arg_known_bare = false;
+ if (fn_type_id->next_param_index >= 1) {
+ TypeTableEntry *param_type = fn_type_id->param_info[next_proto_i].type;
+ if (type_is_invalid(param_type))
+ return ira->codegen->builtin_types.entry_invalid;
+ first_arg_known_bare = param_type->id != TypeTableEntryIdPointer;
+ }
+
+ IrInstruction *first_arg;
+ if (!first_arg_known_bare && handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
first_arg = first_arg_ptr;
} else {
first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
@@ -12667,9 +12669,18 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
size_t next_proto_i = 0;
if (first_arg_ptr) {
- IrInstruction *first_arg;
assert(first_arg_ptr->value.type->id == TypeTableEntryIdPointer);
- if (handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
+
+ bool first_arg_known_bare = false;
+ if (fn_type_id->next_param_index >= 1) {
+ TypeTableEntry *param_type = fn_type_id->param_info[next_proto_i].type;
+ if (type_is_invalid(param_type))
+ return ira->codegen->builtin_types.entry_invalid;
+ first_arg_known_bare = param_type->id != TypeTableEntryIdPointer;
+ }
+
+ IrInstruction *first_arg;
+ if (!first_arg_known_bare && handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
first_arg = first_arg_ptr;
} else {
first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
@@ -12802,10 +12813,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
return ira->codegen->builtin_types.entry_invalid;
}
if (inst_fn_type_id.async_allocator_type == nullptr) {
- IrInstruction *casted_inst = ir_implicit_byval_const_ref_cast(ira, uncasted_async_allocator_inst);
- if (type_is_invalid(casted_inst->value.type))
- return ira->codegen->builtin_types.entry_invalid;
- inst_fn_type_id.async_allocator_type = casted_inst->value.type;
+ inst_fn_type_id.async_allocator_type = uncasted_async_allocator_inst->value.type;
}
async_allocator_inst = ir_implicit_cast(ira, uncasted_async_allocator_inst, inst_fn_type_id.async_allocator_type);
if (type_is_invalid(async_allocator_inst->value.type))
@@ -12866,9 +12874,16 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
IrInstruction **casted_args = allocate(call_param_count);
size_t next_arg_index = 0;
if (first_arg_ptr) {
- IrInstruction *first_arg;
assert(first_arg_ptr->value.type->id == TypeTableEntryIdPointer);
- if (handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
+
+ TypeTableEntry *param_type = fn_type_id->param_info[next_arg_index].type;
+ if (type_is_invalid(param_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ IrInstruction *first_arg;
+ if (param_type->id == TypeTableEntryIdPointer &&
+ handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type))
+ {
first_arg = first_arg_ptr;
} else {
first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
@@ -12876,10 +12891,6 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
return ira->codegen->builtin_types.entry_invalid;
}
- TypeTableEntry *param_type = fn_type_id->param_info[next_arg_index].type;
- if (type_is_invalid(param_type))
- return ira->codegen->builtin_types.entry_invalid;
-
IrInstruction *casted_arg = ir_implicit_cast(ira, first_arg, param_type);
if (type_is_invalid(casted_arg->value.type))
return ira->codegen->builtin_types.entry_invalid;
diff --git a/std/array_list.zig b/std/array_list.zig
index 1a235d28a354..fd1d5cbe26d9 100644
--- a/std/array_list.zig
+++ b/std/array_list.zig
@@ -29,36 +29,36 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
};
}
- pub fn deinit(self: *const Self) void {
+ pub fn deinit(self: Self) void {
self.allocator.free(self.items);
}
- pub fn toSlice(self: *const Self) []align(A) T {
+ pub fn toSlice(self: Self) []align(A) T {
return self.items[0..self.len];
}
- pub fn toSliceConst(self: *const Self) []align(A) const T {
+ pub fn toSliceConst(self: Self) []align(A) const T {
return self.items[0..self.len];
}
- pub fn at(self: *const Self, n: usize) T {
+ pub fn at(self: Self, n: usize) T {
return self.toSliceConst()[n];
}
/// Sets the value at index `i`, or returns `error.OutOfBounds` if
/// the index is not in range.
- pub fn setOrError(self: *const Self, i: usize, item: *const T) !void {
+ pub fn setOrError(self: Self, i: usize, item: T) !void {
if (i >= self.len) return error.OutOfBounds;
- self.items[i] = item.*;
+ self.items[i] = item;
}
/// Sets the value at index `i`, asserting that the value is in range.
- pub fn set(self: *const Self, i: usize, item: *const T) void {
+ pub fn set(self: *Self, i: usize, item: T) void {
assert(i < self.len);
- self.items[i] = item.*;
+ self.items[i] = item;
}
- pub fn count(self: *const Self) usize {
+ pub fn count(self: Self) usize {
return self.len;
}
@@ -81,12 +81,12 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
return result;
}
- pub fn insert(self: *Self, n: usize, item: *const T) !void {
+ pub fn insert(self: *Self, n: usize, item: T) !void {
try self.ensureCapacity(self.len + 1);
self.len += 1;
mem.copy(T, self.items[n + 1 .. self.len], self.items[n .. self.len - 1]);
- self.items[n] = item.*;
+ self.items[n] = item;
}
pub fn insertSlice(self: *Self, n: usize, items: []align(A) const T) !void {
@@ -97,9 +97,9 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
mem.copy(T, self.items[n .. n + items.len], items);
}
- pub fn append(self: *Self, item: *const T) !void {
+ pub fn append(self: *Self, item: T) !void {
const new_item_ptr = try self.addOne();
- new_item_ptr.* = item.*;
+ new_item_ptr.* = item;
}
pub fn appendSlice(self: *Self, items: []align(A) const T) !void {
diff --git a/std/build.zig b/std/build.zig
index 16ce426bcb96..92454a183ae4 100644
--- a/std/build.zig
+++ b/std/build.zig
@@ -234,7 +234,7 @@ pub const Builder = struct {
defer wanted_steps.deinit();
if (step_names.len == 0) {
- try wanted_steps.append(&self.default_step);
+ try wanted_steps.append(self.default_step);
} else {
for (step_names) |step_name| {
const s = try self.getTopLevelStepByName(step_name);
diff --git a/std/fmt/index.zig b/std/fmt/index.zig
index cfc0948d2cfb..90d3a559c445 100644
--- a/std/fmt/index.zig
+++ b/std/fmt/index.zig
@@ -162,8 +162,6 @@ pub fn formatType(
},
builtin.TypeInfo.Pointer.Size.Many => {
if (ptr_info.child == u8) {
- //This is a bit of a hack, but it made more sense to
- // do this check here than have formatText do it
if (fmt[0] == 's') {
const len = std.cstr.len(value);
return formatText(value[0..len], fmt, context, Errors, output);
@@ -176,6 +174,12 @@ pub fn formatType(
return output(context, casted_value);
},
},
+ builtin.TypeId.Array => |info| {
+ if (info.child == u8) {
+ return formatText(value, fmt, context, Errors, output);
+ }
+ return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
+ },
else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
}
}
diff --git a/std/json.zig b/std/json.zig
index 75ea2eee1c75..8bbee981e387 100644
--- a/std/json.zig
+++ b/std/json.zig
@@ -1326,7 +1326,7 @@ pub const Parser = struct {
},
// Array Parent -> [ ..., , value ]
Value.Array => |*array| {
- try array.append(value);
+ try array.append(value.*);
p.state = State.ArrayValue;
},
else => {
diff --git a/std/math/big/int.zig b/std/math/big/int.zig
index 19af10e69569..5e15cfb895e3 100644
--- a/std/math/big/int.zig
+++ b/std/math/big/int.zig
@@ -18,39 +18,6 @@ comptime {
debug.assert(Limb.is_signed == false);
}
-const wrapped_buffer_size = 512;
-
-// Converts primitive integer values onto a stack-based big integer, or passes through existing
-// Int types with no modifications. This can fail at runtime if using a very large dynamic
-// integer but it is very unlikely and is considered a user error.
-fn wrapInt(allocator: *Allocator, bn: var) *const Int {
- const T = @typeOf(bn);
- switch (@typeInfo(T)) {
- TypeId.Pointer => |info| {
- if (info.child == Int) {
- return bn;
- } else {
- @compileError("cannot set Int using type " ++ @typeName(T));
- }
- },
- else => {
- var s = allocator.create(Int) catch unreachable;
- s.* = Int{
- .allocator = allocator,
- .positive = false,
- .limbs = block: {
- var limbs = allocator.alloc(Limb, Int.default_capacity) catch unreachable;
- limbs[0] = 0;
- break :block limbs;
- },
- .len = 1,
- };
- s.set(bn) catch unreachable;
- return s;
- },
- }
-}
-
pub const Int = struct {
allocator: *Allocator,
positive: bool,
@@ -93,11 +60,11 @@ pub const Int = struct {
self.limbs = try self.allocator.realloc(Limb, self.limbs, capacity);
}
- pub fn deinit(self: *const Int) void {
+ pub fn deinit(self: Int) void {
self.allocator.free(self.limbs);
}
- pub fn clone(other: *const Int) !Int {
+ pub fn clone(other: Int) !Int {
return Int{
.allocator = other.allocator,
.positive = other.positive,
@@ -110,8 +77,8 @@ pub const Int = struct {
};
}
- pub fn copy(self: *Int, other: *const Int) !void {
- if (self == other) {
+ pub fn copy(self: *Int, other: Int) !void {
+ if (self == &other) {
return;
}
@@ -125,7 +92,7 @@ pub const Int = struct {
mem.swap(Int, self, other);
}
- pub fn dump(self: *const Int) void {
+ pub fn dump(self: Int) void {
for (self.limbs) |limb| {
debug.warn("{x} ", limb);
}
@@ -140,20 +107,20 @@ pub const Int = struct {
r.positive = true;
}
- pub fn isOdd(r: *const Int) bool {
+ pub fn isOdd(r: Int) bool {
return r.limbs[0] & 1 != 0;
}
- pub fn isEven(r: *const Int) bool {
+ pub fn isEven(r: Int) bool {
return !r.isOdd();
}
- fn bitcount(self: *const Int) usize {
+ fn bitcount(self: Int) usize {
const u_bit_count = (self.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(self.limbs[self.len - 1]));
return usize(!self.positive) + u_bit_count;
}
- pub fn sizeInBase(self: *const Int, base: usize) usize {
+ pub fn sizeInBase(self: Int, base: usize) usize {
return (self.bitcount() / math.log2(base)) + 1;
}
@@ -219,7 +186,7 @@ pub const Int = struct {
TargetTooSmall,
};
- pub fn to(self: *const Int, comptime T: type) ConvertError!T {
+ pub fn to(self: Int, comptime T: type) ConvertError!T {
switch (@typeId(T)) {
TypeId.Int => {
const UT = if (T.is_signed) @IntType(false, T.bit_count - 1) else T;
@@ -286,16 +253,28 @@ pub const Int = struct {
i += 1;
}
+ // TODO values less than limb size should guarantee non allocating
+ var base_buffer: [512]u8 = undefined;
+ const base_al = &std.heap.FixedBufferAllocator.init(base_buffer[0..]).allocator;
+ const base_ap = try Int.initSet(base_al, base);
+
+ var d_buffer: [512]u8 = undefined;
+ var d_fba = std.heap.FixedBufferAllocator.init(d_buffer[0..]);
+ const d_al = &d_fba.allocator;
+
try self.set(0);
for (value[i..]) |ch| {
const d = try charToDigit(ch, base);
- try self.mul(self, base);
- try self.add(self, d);
+ d_fba.end_index = 0;
+ const d_ap = try Int.initSet(d_al, d);
+
+ try self.mul(self.*, base_ap);
+ try self.add(self.*, d_ap);
}
self.positive = positive;
}
- pub fn toString(self: *const Int, allocator: *Allocator, base: u8) ![]const u8 {
+ pub fn toString(self: Int, allocator: *Allocator, base: u8) ![]const u8 {
if (base < 2 or base > 16) {
return error.InvalidBase;
}
@@ -345,7 +324,7 @@ pub const Int = struct {
var b = try Int.initSet(allocator, limb_base);
while (q.len >= 2) {
- try Int.divTrunc(&q, &r, &q, &b);
+ try Int.divTrunc(&q, &r, q, b);
var r_word = r.limbs[0];
var i: usize = 0;
@@ -378,12 +357,7 @@ pub const Int = struct {
}
// returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.
- pub fn cmpAbs(a: *const Int, bv: var) i8 {
- // TODO: Thread-local buffer.
- var buffer: [wrapped_buffer_size]u8 = undefined;
- var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
- var b = wrapInt(&stack.allocator, bv);
-
+ pub fn cmpAbs(a: Int, b: Int) i8 {
if (a.len < b.len) {
return -1;
}
@@ -408,11 +382,7 @@ pub const Int = struct {
}
// returns -1, 0, 1 if a < b, a == b or a > b respectively.
- pub fn cmp(a: *const Int, bv: var) i8 {
- var buffer: [wrapped_buffer_size]u8 = undefined;
- var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
- var b = wrapInt(&stack.allocator, bv);
-
+ pub fn cmp(a: Int, b: Int) i8 {
if (a.positive != b.positive) {
return if (a.positive) i8(1) else -1;
} else {
@@ -422,17 +392,17 @@ pub const Int = struct {
}
// if a == 0
- pub fn eqZero(a: *const Int) bool {
+ pub fn eqZero(a: Int) bool {
return a.len == 1 and a.limbs[0] == 0;
}
// if |a| == |b|
- pub fn eqAbs(a: *const Int, b: var) bool {
+ pub fn eqAbs(a: Int, b: Int) bool {
return cmpAbs(a, b) == 0;
}
// if a == b
- pub fn eq(a: *const Int, b: var) bool {
+ pub fn eq(a: Int, b: Int) bool {
return cmp(a, b) == 0;
}
@@ -473,12 +443,7 @@ pub const Int = struct {
}
// r = a + b
- pub fn add(r: *Int, av: var, bv: var) Allocator.Error!void {
- var buffer: [2 * wrapped_buffer_size]u8 = undefined;
- var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
- var a = wrapInt(&stack.allocator, av);
- var b = wrapInt(&stack.allocator, bv);
-
+ pub fn add(r: *Int, a: Int, b: Int) Allocator.Error!void {
if (a.eqZero()) {
try r.copy(b);
return;
@@ -547,12 +512,7 @@ pub const Int = struct {
}
// r = a - b
- pub fn sub(r: *Int, av: var, bv: var) !void {
- var buffer: [wrapped_buffer_size]u8 = undefined;
- var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
- var a = wrapInt(&stack.allocator, av);
- var b = wrapInt(&stack.allocator, bv);
-
+ pub fn sub(r: *Int, a: Int, b: Int) !void {
if (a.positive != b.positive) {
if (a.positive) {
// (a) - (-b) => a + b
@@ -632,14 +592,9 @@ pub const Int = struct {
// rma = a * b
//
// For greatest efficiency, ensure rma does not alias a or b.
- pub fn mul(rma: *Int, av: var, bv: var) !void {
- var buffer: [2 * wrapped_buffer_size]u8 = undefined;
- var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
- var a = wrapInt(&stack.allocator, av);
- var b = wrapInt(&stack.allocator, bv);
-
+ pub fn mul(rma: *Int, a: Int, b: Int) !void {
var r = rma;
- var aliased = rma == a or rma == b;
+ var aliased = rma.limbs.ptr == a.limbs.ptr or rma.limbs.ptr == b.limbs.ptr;
var sr: Int = undefined;
if (aliased) {
@@ -714,29 +669,29 @@ pub const Int = struct {
}
}
- pub fn divFloor(q: *Int, r: *Int, a: var, b: var) !void {
+ pub fn divFloor(q: *Int, r: *Int, a: Int, b: Int) !void {
try div(q, r, a, b);
// Trunc -> Floor.
if (!q.positive) {
- try q.sub(q, 1);
- try r.add(q, 1);
+ // TODO values less than limb size should guarantee non allocating
+ var one_buffer: [512]u8 = undefined;
+ const one_al = &std.heap.FixedBufferAllocator.init(one_buffer[0..]).allocator;
+ const one_ap = try Int.initSet(one_al, 1);
+
+ try q.sub(q.*, one_ap);
+ try r.add(q.*, one_ap);
}
r.positive = b.positive;
}
- pub fn divTrunc(q: *Int, r: *Int, a: var, b: var) !void {
+ pub fn divTrunc(q: *Int, r: *Int, a: Int, b: Int) !void {
try div(q, r, a, b);
r.positive = a.positive;
}
// Truncates by default.
- fn div(quo: *Int, rem: *Int, av: var, bv: var) !void {
- var buffer: [2 * wrapped_buffer_size]u8 = undefined;
- var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
- var a = wrapInt(&stack.allocator, av);
- var b = wrapInt(&stack.allocator, bv);
-
+ fn div(quo: *Int, rem: *Int, a: Int, b: Int) !void {
if (b.eqZero()) {
@panic("division by zero");
}
@@ -821,8 +776,8 @@ pub const Int = struct {
// Normalize so y > Limb.bit_count / 2 (i.e. leading bit is set)
const norm_shift = @clz(y.limbs[y.len - 1]);
- try x.shiftLeft(x, norm_shift);
- try y.shiftLeft(y, norm_shift);
+ try x.shiftLeft(x.*, norm_shift);
+ try y.shiftLeft(y.*, norm_shift);
const n = x.len - 1;
const t = y.len - 1;
@@ -832,10 +787,10 @@ pub const Int = struct {
mem.set(Limb, q.limbs[0..q.len], 0);
// 2.
- try tmp.shiftLeft(y, Limb.bit_count * (n - t));
- while (x.cmp(&tmp) >= 0) {
+ try tmp.shiftLeft(y.*, Limb.bit_count * (n - t));
+ while (x.cmp(tmp) >= 0) {
q.limbs[n - t] += 1;
- try x.sub(x, tmp);
+ try x.sub(x.*, tmp);
}
// 3.
@@ -864,7 +819,7 @@ pub const Int = struct {
r.limbs[2] = carry;
r.normN(3);
- if (r.cmpAbs(&tmp) <= 0) {
+ if (r.cmpAbs(tmp) <= 0) {
break;
}
@@ -873,13 +828,13 @@ pub const Int = struct {
// 3.3
try tmp.set(q.limbs[i - t - 1]);
- try tmp.mul(&tmp, y);
- try tmp.shiftLeft(&tmp, Limb.bit_count * (i - t - 1));
- try x.sub(x, &tmp);
+ try tmp.mul(tmp, y.*);
+ try tmp.shiftLeft(tmp, Limb.bit_count * (i - t - 1));
+ try x.sub(x.*, tmp);
if (!x.positive) {
- try tmp.shiftLeft(y, Limb.bit_count * (i - t - 1));
- try x.add(x, &tmp);
+ try tmp.shiftLeft(y.*, Limb.bit_count * (i - t - 1));
+ try x.add(x.*, tmp);
q.limbs[i - t - 1] -= 1;
}
}
@@ -887,16 +842,12 @@ pub const Int = struct {
// Denormalize
q.normN(q.len);
- try r.shiftRight(x, norm_shift);
+ try r.shiftRight(x.*, norm_shift);
r.normN(r.len);
}
// r = a << shift, in other words, r = a * 2^shift
- pub fn shiftLeft(r: *Int, av: var, shift: usize) !void {
- var buffer: [wrapped_buffer_size]u8 = undefined;
- var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
- var a = wrapInt(&stack.allocator, av);
-
+ pub fn shiftLeft(r: *Int, a: Int, shift: usize) !void {
try r.ensureCapacity(a.len + (shift / Limb.bit_count) + 1);
llshl(r.limbs[0..], a.limbs[0..a.len], shift);
r.norm1(a.len + (shift / Limb.bit_count) + 1);
@@ -927,11 +878,7 @@ pub const Int = struct {
}
// r = a >> shift
- pub fn shiftRight(r: *Int, av: var, shift: usize) !void {
- var buffer: [wrapped_buffer_size]u8 = undefined;
- var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
- var a = wrapInt(&stack.allocator, av);
-
+ pub fn shiftRight(r: *Int, a: Int, shift: usize) !void {
if (a.len <= shift / Limb.bit_count) {
r.len = 1;
r.limbs[0] = 0;
@@ -966,12 +913,7 @@ pub const Int = struct {
}
// r = a | b
- pub fn bitOr(r: *Int, av: var, bv: var) !void {
- var buffer: [2 * wrapped_buffer_size]u8 = undefined;
- var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
- var a = wrapInt(&stack.allocator, av);
- var b = wrapInt(&stack.allocator, bv);
-
+ pub fn bitOr(r: *Int, a: Int, b: Int) !void {
if (a.len > b.len) {
try r.ensureCapacity(a.len);
llor(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
@@ -998,12 +940,7 @@ pub const Int = struct {
}
// r = a & b
- pub fn bitAnd(r: *Int, av: var, bv: var) !void {
- var buffer: [2 * wrapped_buffer_size]u8 = undefined;
- var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
- var a = wrapInt(&stack.allocator, av);
- var b = wrapInt(&stack.allocator, bv);
-
+ pub fn bitAnd(r: *Int, a: Int, b: Int) !void {
if (a.len > b.len) {
try r.ensureCapacity(b.len);
lland(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
@@ -1027,12 +964,7 @@ pub const Int = struct {
}
// r = a ^ b
- pub fn bitXor(r: *Int, av: var, bv: var) !void {
- var buffer: [2 * wrapped_buffer_size]u8 = undefined;
- var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
- var a = wrapInt(&stack.allocator, av);
- var b = wrapInt(&stack.allocator, bv);
-
+ pub fn bitXor(r: *Int, a: Int, b: Int) !void {
if (a.len > b.len) {
try r.ensureCapacity(a.len);
llxor(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
@@ -1065,7 +997,7 @@ pub const Int = struct {
// may be untested in some cases.
const u256 = @IntType(false, 256);
-var al = debug.global_allocator;
+const al = debug.global_allocator;
test "big.int comptime_int set" {
comptime var s = 0xefffffff00000001eeeeeeefaaaaaaab;
@@ -1198,7 +1130,7 @@ test "big.int bitcount + sizeInBase" {
debug.assert(a.sizeInBase(2) >= 32);
debug.assert(a.sizeInBase(10) >= 10);
- try a.shiftLeft(&a, 5000);
+ try a.shiftLeft(a, 5000);
debug.assert(a.bitcount() == 5032);
debug.assert(a.sizeInBase(2) >= 5032);
a.positive = false;
@@ -1320,40 +1252,40 @@ test "big.int compare" {
var a = try Int.initSet(al, -11);
var b = try Int.initSet(al, 10);
- debug.assert(a.cmpAbs(&b) == 1);
- debug.assert(a.cmp(&b) == -1);
+ debug.assert(a.cmpAbs(b) == 1);
+ debug.assert(a.cmp(b) == -1);
}
test "big.int compare similar" {
var a = try Int.initSet(al, 0xffffffffeeeeeeeeffffffffeeeeeeee);
var b = try Int.initSet(al, 0xffffffffeeeeeeeeffffffffeeeeeeef);
- debug.assert(a.cmpAbs(&b) == -1);
- debug.assert(b.cmpAbs(&a) == 1);
+ debug.assert(a.cmpAbs(b) == -1);
+ debug.assert(b.cmpAbs(a) == 1);
}
test "big.int compare different limb size" {
var a = try Int.initSet(al, @maxValue(Limb) + 1);
var b = try Int.initSet(al, 1);
- debug.assert(a.cmpAbs(&b) == 1);
- debug.assert(b.cmpAbs(&a) == -1);
+ debug.assert(a.cmpAbs(b) == 1);
+ debug.assert(b.cmpAbs(a) == -1);
}
test "big.int compare multi-limb" {
var a = try Int.initSet(al, -0x7777777799999999ffffeeeeffffeeeeffffeeeef);
var b = try Int.initSet(al, 0x7777777799999999ffffeeeeffffeeeeffffeeeee);
- debug.assert(a.cmpAbs(&b) == 1);
- debug.assert(a.cmp(&b) == -1);
+ debug.assert(a.cmpAbs(b) == 1);
+ debug.assert(a.cmp(b) == -1);
}
test "big.int equality" {
var a = try Int.initSet(al, 0xffffffff1);
var b = try Int.initSet(al, -0xffffffff1);
- debug.assert(a.eqAbs(&b));
- debug.assert(!a.eq(&b));
+ debug.assert(a.eqAbs(b));
+ debug.assert(!a.eq(b));
}
test "big.int abs" {
@@ -1381,7 +1313,7 @@ test "big.int add single-single" {
var b = try Int.initSet(al, 5);
var c = try Int.init(al);
- try c.add(&a, &b);
+ try c.add(a, b);
debug.assert((try c.to(u32)) == 55);
}
@@ -1392,10 +1324,10 @@ test "big.int add multi-single" {
var c = try Int.init(al);
- try c.add(&a, &b);
+ try c.add(a, b);
debug.assert((try c.to(DoubleLimb)) == @maxValue(Limb) + 2);
- try c.add(&b, &a);
+ try c.add(b, a);
debug.assert((try c.to(DoubleLimb)) == @maxValue(Limb) + 2);
}
@@ -1406,7 +1338,7 @@ test "big.int add multi-multi" {
var b = try Int.initSet(al, op2);
var c = try Int.init(al);
- try c.add(&a, &b);
+ try c.add(a, b);
debug.assert((try c.to(u128)) == op1 + op2);
}
@@ -1416,7 +1348,7 @@ test "big.int add zero-zero" {
var b = try Int.initSet(al, 0);
var c = try Int.init(al);
- try c.add(&a, &b);
+ try c.add(a, b);
debug.assert((try c.to(u32)) == 0);
}
@@ -1426,7 +1358,7 @@ test "big.int add alias multi-limb nonzero-zero" {
var a = try Int.initSet(al, op1);
var b = try Int.initSet(al, 0);
- try a.add(&a, &b);
+ try a.add(a, b);
debug.assert((try a.to(u128)) == op1);
}
@@ -1434,16 +1366,21 @@ test "big.int add alias multi-limb nonzero-zero" {
test "big.int add sign" {
var a = try Int.init(al);
- try a.add(1, 2);
+ const one = try Int.initSet(al, 1);
+ const two = try Int.initSet(al, 2);
+ const neg_one = try Int.initSet(al, -1);
+ const neg_two = try Int.initSet(al, -2);
+
+ try a.add(one, two);
debug.assert((try a.to(i32)) == 3);
- try a.add(-1, 2);
+ try a.add(neg_one, two);
debug.assert((try a.to(i32)) == 1);
- try a.add(1, -2);
+ try a.add(one, neg_two);
debug.assert((try a.to(i32)) == -1);
- try a.add(-1, -2);
+ try a.add(neg_one, neg_two);
debug.assert((try a.to(i32)) == -3);
}
@@ -1452,7 +1389,7 @@ test "big.int sub single-single" {
var b = try Int.initSet(al, 5);
var c = try Int.init(al);
- try c.sub(&a, &b);
+ try c.sub(a, b);
debug.assert((try c.to(u32)) == 45);
}
@@ -1462,7 +1399,7 @@ test "big.int sub multi-single" {
var b = try Int.initSet(al, 1);
var c = try Int.init(al);
- try c.sub(&a, &b);
+ try c.sub(a, b);
debug.assert((try c.to(Limb)) == @maxValue(Limb));
}
@@ -1475,7 +1412,7 @@ test "big.int sub multi-multi" {
var b = try Int.initSet(al, op2);
var c = try Int.init(al);
- try c.sub(&a, &b);
+ try c.sub(a, b);
debug.assert((try c.to(u128)) == op1 - op2);
}
@@ -1485,7 +1422,7 @@ test "big.int sub equal" {
var b = try Int.initSet(al, 0x11efefefefefefefefefefefef);
var c = try Int.init(al);
- try c.sub(&a, &b);
+ try c.sub(a, b);
debug.assert((try c.to(u32)) == 0);
}
@@ -1493,19 +1430,24 @@ test "big.int sub equal" {
test "big.int sub sign" {
var a = try Int.init(al);
- try a.sub(1, 2);
+ const one = try Int.initSet(al, 1);
+ const two = try Int.initSet(al, 2);
+ const neg_one = try Int.initSet(al, -1);
+ const neg_two = try Int.initSet(al, -2);
+
+ try a.sub(one, two);
debug.assert((try a.to(i32)) == -1);
- try a.sub(-1, 2);
+ try a.sub(neg_one, two);
debug.assert((try a.to(i32)) == -3);
- try a.sub(1, -2);
+ try a.sub(one, neg_two);
debug.assert((try a.to(i32)) == 3);
- try a.sub(-1, -2);
+ try a.sub(neg_one, neg_two);
debug.assert((try a.to(i32)) == 1);
- try a.sub(-2, -1);
+ try a.sub(neg_two, neg_one);
debug.assert((try a.to(i32)) == -1);
}
@@ -1514,7 +1456,7 @@ test "big.int mul single-single" {
var b = try Int.initSet(al, 5);
var c = try Int.init(al);
- try c.mul(&a, &b);
+ try c.mul(a, b);
debug.assert((try c.to(u64)) == 250);
}
@@ -1524,7 +1466,7 @@ test "big.int mul multi-single" {
var b = try Int.initSet(al, 2);
var c = try Int.init(al);
- try c.mul(&a, &b);
+ try c.mul(a, b);
debug.assert((try c.to(DoubleLimb)) == 2 * @maxValue(Limb));
}
@@ -1536,7 +1478,7 @@ test "big.int mul multi-multi" {
var b = try Int.initSet(al, op2);
var c = try Int.init(al);
- try c.mul(&a, &b);
+ try c.mul(a, b);
debug.assert((try c.to(u256)) == op1 * op2);
}
@@ -1545,7 +1487,7 @@ test "big.int mul alias r with a" {
var a = try Int.initSet(al, @maxValue(Limb));
var b = try Int.initSet(al, 2);
- try a.mul(&a, &b);
+ try a.mul(a, b);
debug.assert((try a.to(DoubleLimb)) == 2 * @maxValue(Limb));
}
@@ -1554,7 +1496,7 @@ test "big.int mul alias r with b" {
var a = try Int.initSet(al, @maxValue(Limb));
var b = try Int.initSet(al, 2);
- try a.mul(&b, &a);
+ try a.mul(b, a);
debug.assert((try a.to(DoubleLimb)) == 2 * @maxValue(Limb));
}
@@ -1562,7 +1504,7 @@ test "big.int mul alias r with b" {
test "big.int mul alias r with a and b" {
var a = try Int.initSet(al, @maxValue(Limb));
- try a.mul(&a, &a);
+ try a.mul(a, a);
debug.assert((try a.to(DoubleLimb)) == @maxValue(Limb) * @maxValue(Limb));
}
@@ -1572,7 +1514,7 @@ test "big.int mul a*0" {
var b = try Int.initSet(al, 0);
var c = try Int.init(al);
- try c.mul(&a, &b);
+ try c.mul(a, b);
debug.assert((try c.to(u32)) == 0);
}
@@ -1582,7 +1524,7 @@ test "big.int mul 0*0" {
var b = try Int.initSet(al, 0);
var c = try Int.init(al);
- try c.mul(&a, &b);
+ try c.mul(a, b);
debug.assert((try c.to(u32)) == 0);
}
@@ -1593,7 +1535,7 @@ test "big.int div single-single no rem" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divTrunc(&q, &r, &a, &b);
+ try Int.divTrunc(&q, &r, a, b);
debug.assert((try q.to(u32)) == 10);
debug.assert((try r.to(u32)) == 0);
@@ -1605,7 +1547,7 @@ test "big.int div single-single with rem" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divTrunc(&q, &r, &a, &b);
+ try Int.divTrunc(&q, &r, a, b);
debug.assert((try q.to(u32)) == 9);
debug.assert((try r.to(u32)) == 4);
@@ -1620,7 +1562,7 @@ test "big.int div multi-single no rem" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divTrunc(&q, &r, &a, &b);
+ try Int.divTrunc(&q, &r, a, b);
debug.assert((try q.to(u64)) == op1 / op2);
debug.assert((try r.to(u64)) == 0);
@@ -1635,7 +1577,7 @@ test "big.int div multi-single with rem" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divTrunc(&q, &r, &a, &b);
+ try Int.divTrunc(&q, &r, a, b);
debug.assert((try q.to(u64)) == op1 / op2);
debug.assert((try r.to(u64)) == 3);
@@ -1650,7 +1592,7 @@ test "big.int div multi>2-single" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divTrunc(&q, &r, &a, &b);
+ try Int.divTrunc(&q, &r, a, b);
debug.assert((try q.to(u128)) == op1 / op2);
debug.assert((try r.to(u32)) == 0x3e4e);
@@ -1662,7 +1604,7 @@ test "big.int div single-single q < r" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divTrunc(&q, &r, &a, &b);
+ try Int.divTrunc(&q, &r, a, b);
debug.assert((try q.to(u64)) == 0);
debug.assert((try r.to(u64)) == 0x0078f432);
@@ -1674,7 +1616,7 @@ test "big.int div single-single q == r" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divTrunc(&q, &r, &a, &b);
+ try Int.divTrunc(&q, &r, a, b);
debug.assert((try q.to(u64)) == 1);
debug.assert((try r.to(u64)) == 0);
@@ -1684,7 +1626,7 @@ test "big.int div q=0 alias" {
var a = try Int.initSet(al, 3);
var b = try Int.initSet(al, 10);
- try Int.divTrunc(&a, &b, &a, &b);
+ try Int.divTrunc(&a, &b, a, b);
debug.assert((try a.to(u64)) == 0);
debug.assert((try b.to(u64)) == 3);
@@ -1698,7 +1640,7 @@ test "big.int div multi-multi q < r" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divTrunc(&q, &r, &a, &b);
+ try Int.divTrunc(&q, &r, a, b);
debug.assert((try q.to(u128)) == 0);
debug.assert((try r.to(u128)) == op1);
@@ -1713,7 +1655,7 @@ test "big.int div trunc single-single +/+" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divTrunc(&q, &r, &a, &b);
+ try Int.divTrunc(&q, &r, a, b);
// n = q * d + r
// 5 = 1 * 3 + 2
@@ -1733,7 +1675,7 @@ test "big.int div trunc single-single -/+" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divTrunc(&q, &r, &a, &b);
+ try Int.divTrunc(&q, &r, a, b);
// n = q * d + r
// -5 = 1 * -3 - 2
@@ -1753,7 +1695,7 @@ test "big.int div trunc single-single +/-" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divTrunc(&q, &r, &a, &b);
+ try Int.divTrunc(&q, &r, a, b);
// n = q * d + r
// 5 = -1 * -3 + 2
@@ -1773,7 +1715,7 @@ test "big.int div trunc single-single -/-" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divTrunc(&q, &r, &a, &b);
+ try Int.divTrunc(&q, &r, a, b);
// n = q * d + r
// -5 = 1 * -3 - 2
@@ -1793,7 +1735,7 @@ test "big.int div floor single-single +/+" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divFloor(&q, &r, &a, &b);
+ try Int.divFloor(&q, &r, a, b);
// n = q * d + r
// 5 = 1 * 3 + 2
@@ -1813,7 +1755,7 @@ test "big.int div floor single-single -/+" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divFloor(&q, &r, &a, &b);
+ try Int.divFloor(&q, &r, a, b);
// n = q * d + r
// -5 = -2 * 3 + 1
@@ -1833,7 +1775,7 @@ test "big.int div floor single-single +/-" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divFloor(&q, &r, &a, &b);
+ try Int.divFloor(&q, &r, a, b);
// n = q * d + r
// 5 = -2 * -3 - 1
@@ -1853,7 +1795,7 @@ test "big.int div floor single-single -/-" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divFloor(&q, &r, &a, &b);
+ try Int.divFloor(&q, &r, a, b);
// n = q * d + r
// -5 = 2 * -3 + 1
@@ -1870,7 +1812,7 @@ test "big.int div multi-multi with rem" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divTrunc(&q, &r, &a, &b);
+ try Int.divTrunc(&q, &r, a, b);
debug.assert((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b);
debug.assert((try r.to(u128)) == 0x28de0acacd806823638);
@@ -1882,7 +1824,7 @@ test "big.int div multi-multi no rem" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divTrunc(&q, &r, &a, &b);
+ try Int.divTrunc(&q, &r, a, b);
debug.assert((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b);
debug.assert((try r.to(u128)) == 0);
@@ -1894,7 +1836,7 @@ test "big.int div multi-multi (2 branch)" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divTrunc(&q, &r, &a, &b);
+ try Int.divTrunc(&q, &r, a, b);
debug.assert((try q.to(u128)) == 0x10000000000000000);
debug.assert((try r.to(u128)) == 0x44444443444444431111111111111111);
@@ -1906,7 +1848,7 @@ test "big.int div multi-multi (3.1/3.3 branch)" {
var q = try Int.init(al);
var r = try Int.init(al);
- try Int.divTrunc(&q, &r, &a, &b);
+ try Int.divTrunc(&q, &r, a, b);
debug.assert((try q.to(u128)) == 0xfffffffffffffffffff);
debug.assert((try r.to(u256)) == 0x1111111111111111111110b12222222222222222282);
@@ -1943,17 +1885,17 @@ test "big.int shift-left multi" {
test "big.int shift-right negative" {
var a = try Int.init(al);
- try a.shiftRight(-20, 2);
+ try a.shiftRight(try Int.initSet(al, -20), 2);
debug.assert((try a.to(i32)) == -20 >> 2);
- try a.shiftRight(-5, 10);
+ try a.shiftRight(try Int.initSet(al, -5), 10);
debug.assert((try a.to(i32)) == -5 >> 10);
}
test "big.int shift-left negative" {
var a = try Int.init(al);
- try a.shiftRight(-10, 1232);
+ try a.shiftRight(try Int.initSet(al, -10), 1232);
debug.assert((try a.to(i32)) == -10 >> 1232);
}
@@ -1961,7 +1903,7 @@ test "big.int bitwise and simple" {
var a = try Int.initSet(al, 0xffffffff11111111);
var b = try Int.initSet(al, 0xeeeeeeee22222222);
- try a.bitAnd(&a, &b);
+ try a.bitAnd(a, b);
debug.assert((try a.to(u64)) == 0xeeeeeeee00000000);
}
@@ -1970,7 +1912,7 @@ test "big.int bitwise and multi-limb" {
var a = try Int.initSet(al, @maxValue(Limb) + 1);
var b = try Int.initSet(al, @maxValue(Limb));
- try a.bitAnd(&a, &b);
+ try a.bitAnd(a, b);
debug.assert((try a.to(u128)) == 0);
}
@@ -1979,7 +1921,7 @@ test "big.int bitwise xor simple" {
var a = try Int.initSet(al, 0xffffffff11111111);
var b = try Int.initSet(al, 0xeeeeeeee22222222);
- try a.bitXor(&a, &b);
+ try a.bitXor(a, b);
debug.assert((try a.to(u64)) == 0x1111111133333333);
}
@@ -1988,7 +1930,7 @@ test "big.int bitwise xor multi-limb" {
var a = try Int.initSet(al, @maxValue(Limb) + 1);
var b = try Int.initSet(al, @maxValue(Limb));
- try a.bitXor(&a, &b);
+ try a.bitXor(a, b);
debug.assert((try a.to(DoubleLimb)) == (@maxValue(Limb) + 1) ^ @maxValue(Limb));
}
@@ -1997,7 +1939,7 @@ test "big.int bitwise or simple" {
var a = try Int.initSet(al, 0xffffffff11111111);
var b = try Int.initSet(al, 0xeeeeeeee22222222);
- try a.bitOr(&a, &b);
+ try a.bitOr(a, b);
debug.assert((try a.to(u64)) == 0xffffffff33333333);
}
@@ -2006,7 +1948,7 @@ test "big.int bitwise or multi-limb" {
var a = try Int.initSet(al, @maxValue(Limb) + 1);
var b = try Int.initSet(al, @maxValue(Limb));
- try a.bitOr(&a, &b);
+ try a.bitOr(a, b);
// TODO: big.int.cpp or is wrong on multi-limb.
debug.assert((try a.to(DoubleLimb)) == (@maxValue(Limb) + 1) + @maxValue(Limb));
@@ -2015,9 +1957,9 @@ test "big.int bitwise or multi-limb" {
test "big.int var args" {
var a = try Int.initSet(al, 5);
- try a.add(&a, 6);
+ try a.add(a, try Int.initSet(al, 6));
debug.assert((try a.to(u64)) == 11);
- debug.assert(a.cmp(11) == 0);
- debug.assert(a.cmp(14) <= 0);
+ debug.assert(a.cmp(try Int.initSet(al, 11)) == 0);
+ debug.assert(a.cmp(try Int.initSet(al, 14)) <= 0);
}
diff --git a/std/mem.zig b/std/mem.zig
index f961c7862bd5..10b3eb8fef1a 100644
--- a/std/mem.zig
+++ b/std/mem.zig
@@ -40,16 +40,12 @@ pub const Allocator = struct {
/// Call destroy with the result
/// TODO once #733 is solved, this will replace create
- pub fn construct(self: *Allocator, init: var) t: {
- // TODO this is a workaround for type getting parsed as Error!&const T
- const T = @typeOf(init).Child;
- break :t Error!*T;
- } {
- const T = @typeOf(init).Child;
+ pub fn construct(self: *Allocator, init: var) Error!*@typeOf(init) {
+ const T = @typeOf(init);
if (@sizeOf(T) == 0) return &{};
const slice = try self.alloc(T, 1);
const ptr = &slice[0];
- ptr.* = init.*;
+ ptr.* = init;
return ptr;
}
diff --git a/test/behavior.zig b/test/behavior.zig
index eb8b643bb737..096c07b2e026 100644
--- a/test/behavior.zig
+++ b/test/behavior.zig
@@ -13,6 +13,7 @@ comptime {
_ = @import("cases/bugs/656.zig");
_ = @import("cases/bugs/828.zig");
_ = @import("cases/bugs/920.zig");
+ _ = @import("cases/byval_arg_var.zig");
_ = @import("cases/cast.zig");
_ = @import("cases/const_slice_child.zig");
_ = @import("cases/coroutines.zig");
diff --git a/test/cases/byval_arg_var.zig b/test/cases/byval_arg_var.zig
new file mode 100644
index 000000000000..826b9cc9e593
--- /dev/null
+++ b/test/cases/byval_arg_var.zig
@@ -0,0 +1,27 @@
+const std = @import("std");
+
+var result: []const u8 = "wrong";
+
+test "aoeu" {
+ start();
+ blowUpStack(10);
+
+ std.debug.assert(std.mem.eql(u8, result, "string literal"));
+}
+
+fn start() void {
+ foo("string literal");
+}
+
+fn foo(x: var) void {
+ bar(x);
+}
+
+fn bar(x: var) void {
+ result = x;
+}
+
+fn blowUpStack(x: u32) void {
+ if (x == 0) return;
+ blowUpStack(x - 1);
+}
diff --git a/test/cases/cast.zig b/test/cases/cast.zig
index ade1cf78aac7..4c216010eb00 100644
--- a/test/cases/cast.zig
+++ b/test/cases/cast.zig
@@ -318,14 +318,6 @@ fn testCastConstArrayRefToConstSlice() void {
assert(mem.eql(u8, slice, "aoeu"));
}
-test "var args implicitly casts by value arg to const ref" {
- foo("hello");
-}
-
-fn foo(args: ...) void {
- assert(@typeOf(args[0]) == *const [5]u8);
-}
-
test "peer type resolution: error and [N]T" {
// TODO: implicit error!T to error!U where T can implicitly cast to U
//assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
diff --git a/test/cases/fn.zig b/test/cases/fn.zig
index dfb254c6aaa1..12f22bfc356c 100644
--- a/test/cases/fn.zig
+++ b/test/cases/fn.zig
@@ -119,3 +119,60 @@ test "assign inline fn to const variable" {
}
inline fn inlineFn() void {}
+
+test "pass by non-copying value" {
+ assert(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
+}
+
+const Point = struct {
+ x: i32,
+ y: i32,
+};
+
+fn addPointCoords(pt: Point) i32 {
+ return pt.x + pt.y;
+}
+
+test "pass by non-copying value through var arg" {
+ assert(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3);
+}
+
+fn addPointCoordsVar(pt: var) i32 {
+ comptime assert(@typeOf(pt) == Point);
+ return pt.x + pt.y;
+}
+
+test "pass by non-copying value as method" {
+ var pt = Point2{ .x = 1, .y = 2 };
+ assert(pt.addPointCoords() == 3);
+}
+
+const Point2 = struct {
+ x: i32,
+ y: i32,
+
+ fn addPointCoords(self: Point2) i32 {
+ return self.x + self.y;
+ }
+};
+
+test "pass by non-copying value as method, which is generic" {
+ var pt = Point3{ .x = 1, .y = 2 };
+ assert(pt.addPointCoords(i32) == 3);
+}
+
+const Point3 = struct {
+ x: i32,
+ y: i32,
+
+ fn addPointCoords(self: Point3, comptime T: type) i32 {
+ return self.x + self.y;
+ }
+};
+
+test "pass by non-copying value as method, at comptime" {
+ comptime {
+ var pt = Point2{ .x = 1, .y = 2 };
+ assert(pt.addPointCoords() == 3);
+ }
+}
diff --git a/test/cases/var_args.zig b/test/cases/var_args.zig
index 5ef41f52ba6c..3eb6e304486b 100644
--- a/test/cases/var_args.zig
+++ b/test/cases/var_args.zig
@@ -75,18 +75,6 @@ test "array of var args functions" {
assert(!foos[1]());
}
-test "pass array and slice of same array to var args should have same pointers" {
- const array = "hi";
- const slice: []const u8 = array;
- return assertSlicePtrsEql(array, slice);
-}
-
-fn assertSlicePtrsEql(args: ...) void {
- const s1 = ([]const u8)(args[0]);
- const s2 = args[1];
- assert(s1.ptr == s2.ptr);
-}
-
test "pass zero length array to var args param" {
doNothingWithFirstArg("");
}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 06f17a37eedf..ed46e43066b8 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -2215,7 +2215,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ derp.init();
\\}
,
- ".tmp_source.zig:14:5: error: expected type 'i32', found '*const Foo'",
+ ".tmp_source.zig:14:5: error: expected type 'i32', found 'Foo'",
);
cases.add(
@@ -2573,15 +2573,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
break :x tc;
});
- cases.add(
- "pass non-copyable type by value to function",
- \\const Point = struct { x: i32, y: i32, };
- \\fn foo(p: Point) void { }
- \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
- ,
- ".tmp_source.zig:2:11: error: type 'Point' is not copyable; cannot pass by value",
- );
-
cases.add(
"implicit cast from array to mutable slice",
\\var global_array: [10]i32 = undefined;
@@ -4066,20 +4057,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
".tmp_source.zig:3:5: note: field 'A' has type 'i32'",
);
- cases.add(
- "self-referencing function pointer field",
- \\const S = struct {
- \\ f: fn(_: S) void,
- \\};
- \\fn f(_: S) void {
- \\}
- \\export fn entry() void {
- \\ var _ = S { .f = f };
- \\}
- ,
- ".tmp_source.zig:4:9: error: type 'S' is not copyable; cannot pass by value",
- );
-
cases.add(
"taking offset of void field in struct",
\\const Empty = struct {