From 6fd0dddf186f6435f422f2992f44ec9a35e09f20 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Wed, 15 Jan 2020 20:23:49 +0200
Subject: [PATCH 01/37] implement non-exhaustive enums
---
src/all_types.hpp | 2 +
src/analyze.cpp | 18 +++++++-
src/codegen.cpp | 2 +-
src/ir.cpp | 110 ++++++++++++++++++++++++++++++++--------------
4 files changed, 97 insertions(+), 35 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 0fed73f7b2..89af4082d8 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -1383,6 +1383,7 @@ struct ZigTypeEnum {
ContainerLayout layout;
ResolveStatus resolve_status;
+ bool non_exhaustive;
bool resolve_loop_flag;
};
@@ -3665,6 +3666,7 @@ struct IrInstructionCheckSwitchProngs {
IrInstructionCheckSwitchProngsRange *ranges;
size_t range_count;
bool have_else_prong;
+ bool have_underscore_prong;
};
struct IrInstructionCheckStatementIsVoid {
diff --git a/src/analyze.cpp b/src/analyze.cpp
index b7838003c8..a62e0414e0 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -2572,6 +2572,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
enum_type->data.enumeration.src_field_count = field_count;
enum_type->data.enumeration.fields = allocate(field_count);
enum_type->data.enumeration.fields_by_name.init(field_count);
+ enum_type->data.enumeration.non_exhaustive = false;
Scope *scope = &enum_type->data.enumeration.decls_scope->base;
@@ -2648,6 +2649,21 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
buf_sprintf("consider 'union(enum)' here"));
}
+ AstNode *tag_value = field_node->data.struct_field.value;
+
+ if (buf_eql_str(type_enum_field->name, "_")) {
+ if (field_i != field_count - 1) {
+ add_node_error(g, field_node, buf_sprintf("'_' field of non-exhaustive enum must be last"));
+ enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
+ }
+ if (tag_value != nullptr) {
+ add_node_error(g, field_node, buf_sprintf("value assigned to '_' field of non-exhaustive enum"));
+ enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
+ }
+ enum_type->data.enumeration.non_exhaustive = true;
+ continue;
+ }
+
auto field_entry = enum_type->data.enumeration.fields_by_name.put_unique(type_enum_field->name, type_enum_field);
if (field_entry != nullptr) {
ErrorMsg *msg = add_node_error(g, field_node,
@@ -2657,8 +2673,6 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
continue;
}
- AstNode *tag_value = field_node->data.struct_field.value;
-
if (tag_value != nullptr) {
// A user-specified value is available
ZigValue *result = analyze_const_value(g, scope, tag_value, tag_int_type,
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 9bab5fd878..0dc820be51 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -3356,7 +3356,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,
LLVMValueRef tag_int_value = gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
instruction->target->value->type, tag_int_type, target_val);
- if (ir_want_runtime_safety(g, &instruction->base) && wanted_type->data.enumeration.layout != ContainerLayoutExtern) {
+ if (ir_want_runtime_safety(g, &instruction->base) && !wanted_type->data.enumeration.non_exhaustive) {
LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue");
LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue");
size_t field_count = wanted_type->data.enumeration.src_field_count;
diff --git a/src/ir.cpp b/src/ir.cpp
index d871aa27a0..6876214510 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -3451,7 +3451,7 @@ static IrInstruction *ir_build_err_to_int(IrBuilder *irb, Scope *scope, AstNode
static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *target_value, IrInstructionCheckSwitchProngsRange *ranges, size_t range_count,
- bool have_else_prong)
+ bool have_else_prong, bool have_underscore_prong)
{
IrInstructionCheckSwitchProngs *instruction = ir_build_instruction(
irb, scope, source_node);
@@ -3459,6 +3459,7 @@ static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope,
instruction->ranges = ranges;
instruction->range_count = range_count;
instruction->have_else_prong = have_else_prong;
+ instruction->have_underscore_prong = have_underscore_prong;
ir_ref_instruction(target_value, irb->current_basic_block);
for (size_t i = 0; i < range_count; i += 1) {
@@ -8090,34 +8091,11 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);
Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope);
AstNode *else_prong = nullptr;
+ AstNode *underscore_prong = nullptr;
for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) {
AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
size_t prong_item_count = prong_node->data.switch_prong.items.length;
- if (prong_item_count == 0) {
- ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
- if (else_prong) {
- ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
- buf_sprintf("multiple else prongs in switch expression"));
- add_error_note(irb->codegen, msg, else_prong,
- buf_sprintf("previous else prong is here"));
- return irb->codegen->invalid_instruction;
- }
- else_prong = prong_node;
-
- IrBasicBlock *prev_block = irb->current_basic_block;
- if (peer_parent->peers.length > 0) {
- peer_parent->peers.last()->next_bb = else_block;
- }
- peer_parent->peers.append(this_peer_result_loc);
- ir_set_cursor_at_end_and_append_block(irb, else_block);
- if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
- is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, &incoming_blocks, &incoming_values,
- &switch_else_var, LValNone, &this_peer_result_loc->base))
- {
- return irb->codegen->invalid_instruction;
- }
- ir_set_cursor_at_end(irb, prev_block);
- } else if (prong_node->data.switch_prong.any_items_are_range) {
+ if (prong_node->data.switch_prong.any_items_are_range) {
ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
IrInstruction *ok_bit = nullptr;
@@ -8195,6 +8173,59 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
}
ir_set_cursor_at_end_and_append_block(irb, range_block_no);
+ } else {
+ if (prong_item_count == 0) {
+ if (else_prong) {
+ ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
+ buf_sprintf("multiple else prongs in switch expression"));
+ add_error_note(irb->codegen, msg, else_prong,
+ buf_sprintf("previous else prong is here"));
+ return irb->codegen->invalid_instruction;
+ }
+ else_prong = prong_node;
+ if (underscore_prong) {
+ ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
+ buf_sprintf("else and '_' prong in switch expression"));
+ add_error_note(irb->codegen, msg, underscore_prong,
+ buf_sprintf("'_' prong is here"));
+ return irb->codegen->invalid_instruction;
+ }
+ } else if (prong_item_count == 1 &&
+ prong_node->data.switch_prong.items.at(0)->type == NodeTypeSymbol &&
+ buf_eql_str(prong_node->data.switch_prong.items.at(0)->data.symbol_expr.symbol, "_")) {
+ if (underscore_prong) {
+ ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
+ buf_sprintf("multiple '_' prongs in switch expression"));
+ add_error_note(irb->codegen, msg, underscore_prong,
+ buf_sprintf("previous '_' prong is here"));
+ return irb->codegen->invalid_instruction;
+ }
+ underscore_prong = prong_node;
+ if (else_prong) {
+ ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
+ buf_sprintf("else and '_' prong in switch expression"));
+ add_error_note(irb->codegen, msg, else_prong,
+ buf_sprintf("else prong is here"));
+ return irb->codegen->invalid_instruction;
+ }
+ } else {
+ continue;
+ }
+ ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
+
+ IrBasicBlock *prev_block = irb->current_basic_block;
+ if (peer_parent->peers.length > 0) {
+ peer_parent->peers.last()->next_bb = else_block;
+ }
+ peer_parent->peers.append(this_peer_result_loc);
+ ir_set_cursor_at_end_and_append_block(irb, else_block);
+ if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
+ is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, &incoming_blocks, &incoming_values,
+ &switch_else_var, LValNone, &this_peer_result_loc->base))
+ {
+ return irb->codegen->invalid_instruction;
+ }
+ ir_set_cursor_at_end(irb, prev_block);
}
}
@@ -8206,6 +8237,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
continue;
if (prong_node->data.switch_prong.any_items_are_range)
continue;
+ if (underscore_prong == prong_node)
+ continue;
ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
@@ -8249,7 +8282,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
}
IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value,
- check_ranges.items, check_ranges.length, else_prong != nullptr);
+ check_ranges.items, check_ranges.length, else_prong != nullptr, underscore_prong != nullptr);
IrInstruction *br_instruction;
if (cases.length == 0) {
@@ -8269,7 +8302,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
peer_parent->peers.at(i)->base.source_instruction = peer_parent->base.source_instruction;
}
- if (!else_prong) {
+ if (!else_prong && !underscore_prong) {
if (peer_parent->peers.length != 0) {
peer_parent->peers.last()->next_bb = else_block;
}
@@ -12790,7 +12823,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
return ira->codegen->invalid_instruction;
TypeEnumField *field = find_enum_field_by_tag(wanted_type, &val->data.x_bigint);
- if (field == nullptr && wanted_type->data.enumeration.layout != ContainerLayoutExtern) {
+ if (field == nullptr && !wanted_type->data.enumeration.non_exhaustive) {
Buf *val_buf = buf_alloc();
bigint_append_buf(val_buf, &val->data.x_bigint, 10);
ErrorMsg *msg = ir_add_error(ira, source_instr,
@@ -26433,10 +26466,23 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
bigint_incr(&field_index);
}
}
- if (!instruction->have_else_prong) {
- if (switch_type->data.enumeration.layout == ContainerLayoutExtern) {
+ if (switch_type->data.enumeration.non_exhaustive && instruction->have_underscore_prong) {
+ for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) {
+ TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i];
+ if (buf_eql_str(enum_field->name, "_"))
+ continue;
+
+ auto entry = field_prev_uses.maybe_get(enum_field->value);
+ if (!entry) {
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("enumeration value '%s.%s' not handled in switch", buf_ptr(&switch_type->name),
+ buf_ptr(enum_field->name)));
+ }
+ }
+ } else if (!instruction->have_else_prong) {
+ if (switch_type->data.enumeration.non_exhaustive) {
ir_add_error(ira, &instruction->base,
- buf_sprintf("switch on an extern enum must have an else prong"));
+ buf_sprintf("switch on non-exhaustive enum must include `else` or `_` prong"));
}
for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) {
TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i];
From b971c7d0ff1c0ef86ac8d6816eb5e115f0d648fa Mon Sep 17 00:00:00 2001
From: Vexu
Date: Wed, 15 Jan 2020 20:40:56 +0200
Subject: [PATCH 02/37] update tests and translate-c
---
src-self-hosted/translate_c.zig | 27 +++++++++++-----------
test/compile_errors.zig | 41 ++++++++++++++++++---------------
test/stage1/behavior/cast.zig | 1 -
test/stage1/behavior/enum.zig | 40 +++++++++++++++++++++++++-------
test/translate_c.zig | 11 +++++++++
5 files changed, 78 insertions(+), 42 deletions(-)
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index a876b20b68..ad58b6a916 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -440,7 +440,6 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
.PrivateExtern => return failDecl(c, fn_decl_loc, fn_name, "unsupported storage class: private extern", .{}),
.Auto => unreachable, // Not legal on functions
.Register => unreachable, // Not legal on functions
- else => unreachable,
},
};
@@ -953,6 +952,19 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
tld_node.semicolon_token = try appendToken(c, .Semicolon, ";");
try addTopLevelDecl(c, field_name, &tld_node.base);
}
+ // make non exhaustive
+ const field_node = try c.a().create(ast.Node.ContainerField);
+ field_node.* = .{
+ .doc_comments = null,
+ .comptime_token = null,
+ .name_token = try appendIdentifier(c, "_"),
+ .type_expr = null,
+ .value_expr = null,
+ .align_expr = null,
+ };
+
+ try container_node.fields_and_decls.push(&field_node.base);
+ _ = try appendToken(c, .Comma, ",");
container_node.rbrace_token = try appendToken(c, .RBrace, "}");
break :blk &container_node.base;
@@ -1231,18 +1243,6 @@ fn transBinaryOperator(
op_id = .BitOr;
op_token = try appendToken(rp.c, .Pipe, "|");
},
- .Assign,
- .MulAssign,
- .DivAssign,
- .RemAssign,
- .AddAssign,
- .SubAssign,
- .ShlAssign,
- .ShrAssign,
- .AndAssign,
- .XorAssign,
- .OrAssign,
- => unreachable,
else => unreachable,
}
@@ -1678,7 +1678,6 @@ fn transStringLiteral(
"TODO: support string literal kind {}",
.{kind},
),
- else => unreachable,
}
}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 3ce5bd8801..e7ef53452a 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -2,6 +2,28 @@ const tests = @import("tests.zig");
const builtin = @import("builtin");
pub fn addCases(cases: *tests.CompileErrorContext) void {
+ cases.addTest("non-exhaustive enums",
+ \\const E = enum {
+ \\ a,
+ \\ b,
+ \\ _,
+ \\};
+ \\pub export fn entry() void {
+ \\ var e: E = .b;
+ \\ switch (e) { // error: switch not handling the tag `b`
+ \\ .a => {},
+ \\ _ => {},
+ \\ }
+ \\ switch (e) { // error: switch on non-exhaustive enum must include `else` or `_` prong
+ \\ .a => {},
+ \\ .b => {},
+ \\ }
+ \\}
+ , &[_][]const u8{
+ "tmp.zig:8:5: error: enumeration value 'E.b' not handled in switch",
+ "tmp.zig:12:5: error: switch on non-exhaustive enum must include `else` or `_` prong",
+ });
+
cases.addTest("@export with empty name string",
\\pub export fn entry() void { }
\\comptime {
@@ -139,25 +161,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:13: error: pointer type '[*]align(4) u8' requires aligned address",
});
- cases.add("switch on extern enum missing else prong",
- \\const i = extern enum {
- \\ n = 0,
- \\ o = 2,
- \\ p = 4,
- \\ q = 4,
- \\};
- \\pub fn main() void {
- \\ var x = @intToEnum(i, 52);
- \\ switch (x) {
- \\ .n,
- \\ .o,
- \\ .p => unreachable,
- \\ }
- \\}
- , &[_][]const u8{
- "tmp.zig:9:5: error: switch on an extern enum must have an else prong",
- });
-
cases.add("invalid float literal",
\\const std = @import("std");
\\
diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig
index ae2530af61..fe55b445a8 100644
--- a/test/stage1/behavior/cast.zig
+++ b/test/stage1/behavior/cast.zig
@@ -618,7 +618,6 @@ test "peer resolution of string literals" {
.b => "two",
.c => "three",
.d => "four",
- else => unreachable,
};
expect(mem.eql(u8, cmd, "two"));
}
diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig
index d5bb2ddbb2..c888722f27 100644
--- a/test/stage1/behavior/enum.zig
+++ b/test/stage1/behavior/enum.zig
@@ -11,17 +11,41 @@ test "extern enum" {
};
fn doTheTest(y: c_int) void {
var x = i.o;
- expect(@enumToInt(x) == 2);
- x = @intToEnum(i, 12);
- expect(@enumToInt(x) == 12);
- x = @intToEnum(i, y);
- expect(@enumToInt(x) == 52);
switch (x) {
- .n,
- .o,
- .p => unreachable,
+ .n, .p => unreachable,
+ .o => {},
+ }
+ }
+ };
+ S.doTheTest(52);
+ comptime S.doTheTest(52);
+}
+
+test "non-exhaustive enum" {
+ const S = struct {
+ const E = enum(u8) {
+ a,
+ b,
+ _,
+ };
+ fn doTheTest(y: u8) void {
+ var e: E = .b;
+ switch (e) {
+ .a => {},
+ .b => {},
+ _ => {},
+ }
+
+ switch (e) {
+ .a => {},
+ .b => {},
else => {},
}
+ expect(@enumToInt(e) == 1);
+ e = @intToEnum(E, 12);
+ expect(@enumToInt(e) == 12);
+ e = @intToEnum(E, y);
+ expect(@enumToInt(e) == 52);
}
};
S.doTheTest(52);
diff --git a/test/translate_c.zig b/test/translate_c.zig
index 16caa6e323..13779cb2fa 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -629,6 +629,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ VAL21 = 6917529027641081853,
\\ VAL22 = 0,
\\ VAL23 = -1,
+ \\ _,
\\};
});
}
@@ -990,6 +991,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const FOO = @enumToInt(enum_enum_ty.FOO);
\\pub const enum_enum_ty = extern enum {
\\ FOO,
+ \\ _,
\\};
\\pub extern var my_enum: enum_enum_ty;
});
@@ -1106,6 +1108,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ a,
\\ b,
\\ c,
+ \\ _,
\\};
\\pub const d = enum_unnamed_1;
\\pub const e = @enumToInt(enum_unnamed_2.e);
@@ -1115,6 +1118,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ e = 0,
\\ f = 4,
\\ g = 5,
+ \\ _,
\\};
\\pub export var h: enum_unnamed_2 = @intToEnum(enum_unnamed_2, e);
\\pub const i = @enumToInt(enum_unnamed_3.i);
@@ -1124,6 +1128,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ i,
\\ j,
\\ k,
+ \\ _,
\\};
\\pub const struct_Baz = extern struct {
\\ l: enum_unnamed_3,
@@ -1136,6 +1141,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ n,
\\ o,
\\ p,
+ \\ _,
\\};
,
\\pub const Baz = struct_Baz;
@@ -1566,6 +1572,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\const enum_unnamed_1 = extern enum {
\\ One,
\\ Two,
+ \\ _,
\\};
});
@@ -1669,6 +1676,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ A,
\\ B,
\\ C,
+ \\ _,
\\};
\\pub const SomeTypedef = c_int;
\\pub export fn and_or_non_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void) c_int {
@@ -1713,6 +1721,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const enum_Bar = extern enum {
\\ A,
\\ B,
+ \\ _,
\\};
\\pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
,
@@ -1977,6 +1986,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ A,
\\ B,
\\ C,
+ \\ _,
\\};
\\pub export fn if_none_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void, arg_d: enum_SomeEnum) c_int {
\\ var a = arg_a;
@@ -2418,6 +2428,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ A = 2,
\\ B = 5,
\\ @"1" = 6,
+ \\ _,
\\};
,
\\pub const Foo = enum_Foo;
From f3d174aa616401117927988dfc499a1762db01a3 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Wed, 15 Jan 2020 21:38:11 +0200
Subject: [PATCH 03/37] require size for non-exhaustive enums
---
src-self-hosted/translate_c.zig | 63 ++++++++++++++-------------------
src/analyze.cpp | 8 +++++
test/compile_errors.zig | 25 ++++++++++++-
test/translate_c.zig | 20 +++++------
4 files changed, 68 insertions(+), 48 deletions(-)
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index ad58b6a916..c726bf8cbf 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -289,8 +289,7 @@ pub fn translate(
tree.errors = ast.Tree.ErrorList.init(arena);
tree.root_node = try arena.create(ast.Node.Root);
- tree.root_node.* = ast.Node.Root{
- .base = ast.Node{ .id = ast.Node.Id.Root },
+ tree.root_node.* = .{
.decls = ast.Node.Root.DeclList.init(arena),
// initialized with the eof token at the end
.eof_token = undefined,
@@ -876,25 +875,20 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
// types, while that's not ISO-C compliant many compilers allow this and
// default to the usual integer type used for all the enums.
- // TODO only emit this tag type if the enum tag type is not the default.
- // I don't know what the default is, need to figure out how clang is deciding.
- // it appears to at least be different across gcc/msvc
- if (int_type.ptr != null and
- !isCBuiltinType(int_type, .UInt) and
- !isCBuiltinType(int_type, .Int))
- {
- _ = try appendToken(c, .LParen, "(");
- container_node.init_arg_expr = .{
- .Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) {
+ _ = try appendToken(c, .LParen, "(");
+ container_node.init_arg_expr = .{
+ .Type = if (int_type.ptr != null)
+ transQualType(rp, int_type, enum_loc) catch |err| switch (err) {
error.UnsupportedType => {
try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
return null;
},
else => |e| return e,
- },
- };
- _ = try appendToken(c, .RParen, ")");
- }
+ }
+ else
+ try transCreateNodeIdentifier(c, "c_int"),
+ };
+ _ = try appendToken(c, .RParen, ")");
container_node.lbrace_token = try appendToken(c, .LBrace, "{");
@@ -2198,6 +2192,19 @@ fn transDoWhileLoop(
.id = .Loop,
};
+ // if (!cond) break;
+ const if_node = try transCreateNodeIf(rp.c);
+ var cond_scope = Scope{
+ .parent = scope,
+ .id = .Condition,
+ };
+ const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
+ prefix_op.rhs = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true);
+ _ = try appendToken(rp.c, .RParen, ")");
+ if_node.condition = &prefix_op.base;
+ if_node.body = &(try transCreateNodeBreak(rp.c, null)).base;
+ _ = try appendToken(rp.c, .Semicolon, ";");
+
const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: {
// there's already a block in C, so we'll append our condition to it.
// c: do {
@@ -2209,10 +2216,7 @@ fn transDoWhileLoop(
// zig: b;
// zig: if (!cond) break;
// zig: }
- const body = (try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?;
- // if this is used as an expression in Zig it needs to be immediately followed by a semicolon
- _ = try appendToken(rp.c, .Semicolon, ";");
- break :blk body;
+ break :blk (try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?;
} else blk: {
// the C statement is without a block, so we need to create a block to contain it.
// c: do
@@ -2228,19 +2232,6 @@ fn transDoWhileLoop(
break :blk block;
};
- // if (!cond) break;
- const if_node = try transCreateNodeIf(rp.c);
- var cond_scope = Scope{
- .parent = scope,
- .id = .Condition,
- };
- const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
- prefix_op.rhs = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true);
- _ = try appendToken(rp.c, .RParen, ")");
- if_node.condition = &prefix_op.base;
- if_node.body = &(try transCreateNodeBreak(rp.c, null)).base;
- _ = try appendToken(rp.c, .Semicolon, ";");
-
try body_node.statements.push(&if_node.base);
if (new)
body_node.rbrace = try appendToken(rp.c, .RBrace, "}");
@@ -4775,8 +4766,7 @@ fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex {
fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
const token_index = try appendIdentifier(c, name);
const identifier = try c.a().create(ast.Node.Identifier);
- identifier.* = ast.Node.Identifier{
- .base = ast.Node{ .id = ast.Node.Id.Identifier },
+ identifier.* = .{
.token = token_index,
};
return &identifier.base;
@@ -4915,8 +4905,7 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u
const token_index = try appendToken(c, .Keyword_var, "var");
const identifier = try c.a().create(ast.Node.Identifier);
- identifier.* = ast.Node.Identifier{
- .base = ast.Node{ .id = ast.Node.Id.Identifier },
+ identifier.* = .{
.token = token_index,
};
diff --git a/src/analyze.cpp b/src/analyze.cpp
index a62e0414e0..0b2b6ddeaa 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -2652,6 +2652,14 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
AstNode *tag_value = field_node->data.struct_field.value;
if (buf_eql_str(type_enum_field->name, "_")) {
+ if (decl_node->data.container_decl.init_arg_expr == nullptr) {
+ add_node_error(g, field_node, buf_sprintf("non-exhaustive enum must specify size"));
+ enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
+ }
+ if (log2_u64(field_count - 1) == enum_type->size_in_bits) {
+ add_node_error(g, field_node, buf_sprintf("non-exhaustive enum specifies every value"));
+ enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
+ }
if (field_i != field_count - 1) {
add_node_error(g, field_node, buf_sprintf("'_' field of non-exhaustive enum must be last"));
enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index e7ef53452a..9a76319af5 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -3,7 +3,30 @@ const builtin = @import("builtin");
pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.addTest("non-exhaustive enums",
- \\const E = enum {
+ \\const A = enum {
+ \\ a,
+ \\ b,
+ \\ _ = 1,
+ \\};
+ \\const B = enum(u1) {
+ \\ a,
+ \\ b,
+ \\ _,
+ \\ c,
+ \\};
+ \\pub export fn entry() void {
+ \\ _ = A;
+ \\ _ = B;
+ \\}
+ , &[_][]const u8{
+ "tmp.zig:4:5: error: non-exhaustive enum must specify size",
+ "error: value assigned to '_' field of non-exhaustive enum",
+ "error: non-exhaustive enum specifies every value",
+ "error: '_' field of non-exhaustive enum must be last",
+ });
+
+ cases.addTest("switching with non-exhaustive enums",
+ \\const E = enum(u8) {
\\ a,
\\ b,
\\ _,
diff --git a/test/translate_c.zig b/test/translate_c.zig
index 13779cb2fa..adee4c9a4d 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -989,7 +989,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\enum enum_ty { FOO };
, &[_][]const u8{
\\pub const FOO = @enumToInt(enum_enum_ty.FOO);
- \\pub const enum_enum_ty = extern enum {
+ \\pub const enum_enum_ty = extern enum(c_int) {
\\ FOO,
\\ _,
\\};
@@ -1104,7 +1104,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const a = @enumToInt(enum_unnamed_1.a);
\\pub const b = @enumToInt(enum_unnamed_1.b);
\\pub const c = @enumToInt(enum_unnamed_1.c);
- \\const enum_unnamed_1 = extern enum {
+ \\const enum_unnamed_1 = extern enum(c_uint) {
\\ a,
\\ b,
\\ c,
@@ -1114,7 +1114,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const e = @enumToInt(enum_unnamed_2.e);
\\pub const f = @enumToInt(enum_unnamed_2.f);
\\pub const g = @enumToInt(enum_unnamed_2.g);
- \\const enum_unnamed_2 = extern enum {
+ \\const enum_unnamed_2 = extern enum(c_uint) {
\\ e = 0,
\\ f = 4,
\\ g = 5,
@@ -1124,7 +1124,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const i = @enumToInt(enum_unnamed_3.i);
\\pub const j = @enumToInt(enum_unnamed_3.j);
\\pub const k = @enumToInt(enum_unnamed_3.k);
- \\const enum_unnamed_3 = extern enum {
+ \\const enum_unnamed_3 = extern enum(c_uint) {
\\ i,
\\ j,
\\ k,
@@ -1137,7 +1137,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const n = @enumToInt(enum_i.n);
\\pub const o = @enumToInt(enum_i.o);
\\pub const p = @enumToInt(enum_i.p);
- \\pub const enum_i = extern enum {
+ \\pub const enum_i = extern enum(c_uint) {
\\ n,
\\ o,
\\ p,
@@ -1569,7 +1569,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
, &[_][]const u8{
\\pub const One = @enumToInt(enum_unnamed_1.One);
\\pub const Two = @enumToInt(enum_unnamed_1.Two);
- \\const enum_unnamed_1 = extern enum {
+ \\const enum_unnamed_1 = extern enum(c_uint) {
\\ One,
\\ Two,
\\ _,
@@ -1672,7 +1672,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
\\}
, &[_][]const u8{
- \\pub const enum_Foo = extern enum {
+ \\pub const enum_Foo = extern enum(c_uint) {
\\ A,
\\ B,
\\ C,
@@ -1718,7 +1718,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ y: c_int,
\\};
,
- \\pub const enum_Bar = extern enum {
+ \\pub const enum_Bar = extern enum(c_uint) {
\\ A,
\\ B,
\\ _,
@@ -1982,7 +1982,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ return 4;
\\}
, &[_][]const u8{
- \\pub const enum_SomeEnum = extern enum {
+ \\pub const enum_SomeEnum = extern enum(c_uint) {
\\ A,
\\ B,
\\ C,
@@ -2424,7 +2424,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const FooA = @enumToInt(enum_Foo.A);
\\pub const FooB = @enumToInt(enum_Foo.B);
\\pub const Foo1 = @enumToInt(enum_Foo.@"1");
- \\pub const enum_Foo = extern enum {
+ \\pub const enum_Foo = extern enum(c_uint) {
\\ A = 2,
\\ B = 5,
\\ @"1" = 6,
From c57784aa15b50a9f38482154170924babab19c03 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Wed, 15 Jan 2020 21:50:12 +0200
Subject: [PATCH 04/37] add is_exhaustive field to typeinfo
---
lib/std/builtin.zig | 1 +
src/ir.cpp | 7 ++++++-
test/stage1/behavior/enum.zig | 1 +
3 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index dbd19fbadf..4b80b38100 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -253,6 +253,7 @@ pub const TypeInfo = union(enum) {
tag_type: type,
fields: []EnumField,
decls: []Declaration,
+ is_exhaustive: bool,
};
/// This data structure is used by the Zig language code generation and
diff --git a/src/ir.cpp b/src/ir.cpp
index 6876214510..08f80e0647 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -23107,7 +23107,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
result->special = ConstValSpecialStatic;
result->type = ir_type_info_get_type(ira, "Enum", nullptr);
- ZigValue **fields = alloc_const_vals_ptrs(4);
+ ZigValue **fields = alloc_const_vals_ptrs(5);
result->data.x_struct.fields = fields;
// layout: ContainerLayout
@@ -23153,6 +23153,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
{
return err;
}
+ // is_exhaustive: bool
+ ensure_field_index(result->type, "is_exhaustive", 4);
+ fields[4]->special = ConstValSpecialStatic;
+ fields[4]->type = ira->codegen->builtin_types.entry_bool;
+ fields[4]->data.x_bool = !type_entry->data.enumeration.non_exhaustive;
break;
}
diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig
index c888722f27..82e57a3a38 100644
--- a/test/stage1/behavior/enum.zig
+++ b/test/stage1/behavior/enum.zig
@@ -46,6 +46,7 @@ test "non-exhaustive enum" {
expect(@enumToInt(e) == 12);
e = @intToEnum(E, y);
expect(@enumToInt(e) == 52);
+ expect(@typeInfo(E).Enum.is_exhaustive == false);
}
};
S.doTheTest(52);
From 5c2238fc4ad1d10f0620c931d369005b53742eb7 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Wed, 15 Jan 2020 22:09:19 +0200
Subject: [PATCH 05/37] small fixes
* error for '_' prong on exhaustive enum
* todo panic for `@tagName` on non-exhaustive enum
* don't require '_' field on tagged unions
---
src/analyze.cpp | 2 +-
src/codegen.cpp | 2 ++
src/ir.cpp | 8 +++++++-
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 0b2b6ddeaa..7669e0890b 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -3293,7 +3293,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
} else if (enum_type_node != nullptr) {
for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) {
TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i];
- if (!covered_enum_fields[i]) {
+ if (!covered_enum_fields[i] && !buf_eql_str(enum_field->name, "_")) {
AstNode *enum_decl_node = tag_type->data.enumeration.decl_node;
AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i);
ErrorMsg *msg = add_node_error(g, decl_node,
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 0dc820be51..42fd188824 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5065,6 +5065,8 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable
{
ZigType *enum_type = instruction->target->value->type;
assert(enum_type->id == ZigTypeIdEnum);
+ if (enum_type->data.enumeration.non_exhaustive)
+ zig_panic("TODO @tagName on non-exhaustive enum");
LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type);
diff --git a/src/ir.cpp b/src/ir.cpp
index 08f80e0647..7aa3243c34 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -22357,6 +22357,8 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns
if (instr_is_comptime(target)) {
if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_instruction;
+ if (target->value->type->data.enumeration.non_exhaustive)
+ zig_panic("TODO @tagName on non-exhaustive enum");
TypeEnumField *field = find_enum_field_by_tag(target->value->type, &target->value->data.x_bigint);
ZigValue *array_val = create_const_str_lit(ira->codegen, field->name)->data.x_ptr.data.ref.pointee;
IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
@@ -26471,7 +26473,11 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
bigint_incr(&field_index);
}
}
- if (switch_type->data.enumeration.non_exhaustive && instruction->have_underscore_prong) {
+ if (instruction->have_underscore_prong) {
+ if (!switch_type->data.enumeration.non_exhaustive){
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("switch on non-exhaustive enum has `_` prong"));
+ }
for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) {
TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i];
if (buf_eql_str(enum_field->name, "_"))
From 02e5cb1cd4203219ae753e94c7e14cd18a918b49 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Wed, 15 Jan 2020 23:05:52 +0200
Subject: [PATCH 06/37] add non-exhaustive enum to langref
---
doc/langref.html.in | 44 +++++++++++++++++++++++++++++++++++++++++
test/compile_errors.zig | 3 +--
2 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 442e4ac52b..dbe98ce708 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -2893,6 +2893,50 @@ test "switch using enum literals" {
}
{#code_end#}
{#header_close#}
+
+ {#header_open|Non-exhaustive enum#}
+
+ A Non-exhaustive enum can be created by adding a trailing '_' field.
+ It must specify a tag type and cannot consume every enumeration value.
+
+
+ {#link|@intToEnum#} on a non-exhaustive enum cannot fail.
+
+
+ A switch on a non-exhaustive enum can include a '_' prong with the following properties:
+
+ - makes it a compile error if all the known tag names are not handled by the switch
+ - allows omitting {#syntax#}else{#endsyntax#}
+
+
+ {#code_begin|test#}
+const std = @import("std");
+const assert = std.debug.assert;
+
+const Number = enum(u8) {
+ One,
+ Two,
+ Three,
+ _,
+};
+
+test "switch on non-exhaustive enum" {
+ const number = Number.One;
+ const result = switch (number) {
+ .One => true,
+ .Two,
+ .Three => false,
+ _ => false,
+ };
+ assert(result);
+ const is_one = switch (number) {
+ .One => true,
+ else => false,
+ };
+ assert(is_one);
+}
+ {#code_end#}
+ {#header_close#}
{#header_close#}
{#header_open|union#}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 9a76319af5..702cc76524 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -10,9 +10,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\};
\\const B = enum(u1) {
\\ a,
- \\ b,
\\ _,
- \\ c,
+ \\ b,
\\};
\\pub export fn entry() void {
\\ _ = A;
From d84569895c80136d9b081a319301a737f342d251 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Thu, 16 Jan 2020 09:04:11 +0200
Subject: [PATCH 07/37] turn panics into compile errors, require at least 1
field in non-exhaustive enum
---
doc/langref.html.in | 7 ++-----
src/analyze.cpp | 3 ++-
src/codegen.cpp | 7 +++++--
src/ir.cpp | 32 ++++++++++++++++----------------
4 files changed, 25 insertions(+), 24 deletions(-)
diff --git a/doc/langref.html.in b/doc/langref.html.in
index dbe98ce708..cac01c5686 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -2903,11 +2903,8 @@ test "switch using enum literals" {
{#link|@intToEnum#} on a non-exhaustive enum cannot fail.
- A switch on a non-exhaustive enum can include a '_' prong with the following properties:
-
- - makes it a compile error if all the known tag names are not handled by the switch
- - allows omitting {#syntax#}else{#endsyntax#}
-
+ A switch on a non-exhaustive enum can include a '_' prong as an alternative to an {#syntax#}else{#endsyntax#} prong
+ with the difference being that it makes it a compile error if all the known tag names are not handled by the switch.
{#code_begin|test#}
const std = @import("std");
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 7669e0890b..a9aaf74a85 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -2560,7 +2560,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
assert(!enum_type->data.enumeration.fields);
uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length;
- if (field_count == 0) {
+ if (field_count == 0 || (field_count == 1 &&
+ buf_eql_str(decl_node->data.container_decl.fields.at(0)->data.struct_field.name, "_"))) {
add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields"));
enum_type->data.enumeration.src_field_count = field_count;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 42fd188824..030e892d45 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5065,8 +5065,11 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable
{
ZigType *enum_type = instruction->target->value->type;
assert(enum_type->id == ZigTypeIdEnum);
- if (enum_type->data.enumeration.non_exhaustive)
- zig_panic("TODO @tagName on non-exhaustive enum");
+ if (enum_type->data.enumeration.non_exhaustive) {
+ add_node_error(g, instruction->base.source_node,
+ buf_sprintf("TODO @tagName on non-exhaustive enum https://github.com/ziglang/zig/issues/3991"));
+ codegen_report_errors_and_exit(g);
+ }
LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type);
diff --git a/src/ir.cpp b/src/ir.cpp
index 7aa3243c34..43ca01113b 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -8183,13 +8183,6 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
return irb->codegen->invalid_instruction;
}
else_prong = prong_node;
- if (underscore_prong) {
- ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
- buf_sprintf("else and '_' prong in switch expression"));
- add_error_note(irb->codegen, msg, underscore_prong,
- buf_sprintf("'_' prong is here"));
- return irb->codegen->invalid_instruction;
- }
} else if (prong_item_count == 1 &&
prong_node->data.switch_prong.items.at(0)->type == NodeTypeSymbol &&
buf_eql_str(prong_node->data.switch_prong.items.at(0)->data.symbol_expr.symbol, "_")) {
@@ -8201,16 +8194,20 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
return irb->codegen->invalid_instruction;
}
underscore_prong = prong_node;
- if (else_prong) {
- ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
- buf_sprintf("else and '_' prong in switch expression"));
- add_error_note(irb->codegen, msg, else_prong,
- buf_sprintf("else prong is here"));
- return irb->codegen->invalid_instruction;
- }
} else {
continue;
}
+ if (underscore_prong && else_prong) {
+ ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
+ buf_sprintf("else and '_' prong in switch expression"));
+ if (underscore_prong == prong_node)
+ add_error_note(irb->codegen, msg, else_prong,
+ buf_sprintf("else prong is here"));
+ else
+ add_error_note(irb->codegen, msg, underscore_prong,
+ buf_sprintf("'_' prong is here"));
+ return irb->codegen->invalid_instruction;
+ }
ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
IrBasicBlock *prev_block = irb->current_basic_block;
@@ -22357,8 +22354,11 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns
if (instr_is_comptime(target)) {
if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_instruction;
- if (target->value->type->data.enumeration.non_exhaustive)
- zig_panic("TODO @tagName on non-exhaustive enum");
+ if (target->value->type->data.enumeration.non_exhaustive) {
+ add_node_error(ira->codegen, instruction->base.source_node,
+ buf_sprintf("TODO @tagName on non-exhaustive enum https://github.com/ziglang/zig/issues/3991"));
+ return ira->codegen->invalid_instruction;
+ }
TypeEnumField *field = find_enum_field_by_tag(target->value->type, &target->value->data.x_bigint);
ZigValue *array_val = create_const_str_lit(ira->codegen, field->name)->data.x_ptr.data.ref.pointee;
IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
From cb257b4e11768ccce93d7cf11c416fa8e745f206 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Thu, 16 Jan 2020 09:23:26 +0200
Subject: [PATCH 08/37] allow non-exhaustive enums with no fields
---
src/analyze.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index a9aaf74a85..18dc7e032c 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -2560,8 +2560,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
assert(!enum_type->data.enumeration.fields);
uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length;
- if (field_count == 0 || (field_count == 1 &&
- buf_eql_str(decl_node->data.container_decl.fields.at(0)->data.struct_field.name, "_"))) {
+ if (field_count == 0) {
add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields"));
enum_type->data.enumeration.src_field_count = field_count;
@@ -2657,7 +2656,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
add_node_error(g, field_node, buf_sprintf("non-exhaustive enum must specify size"));
enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
}
- if (log2_u64(field_count - 1) == enum_type->size_in_bits) {
+ if (field_count > 1 && log2_u64(field_count - 1) == enum_type->size_in_bits) {
add_node_error(g, field_node, buf_sprintf("non-exhaustive enum specifies every value"));
enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
}
From 6450736c5f9039565802e1f898a8fd402ba12c63 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Thu, 16 Jan 2020 12:50:44 +0200
Subject: [PATCH 09/37] translate-c default enum tag type to c_int
---
src-self-hosted/translate_c.zig | 5 ++++-
test/translate_c.zig | 18 +++++++++---------
2 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig
index c726bf8cbf..2d5774f452 100644
--- a/src-self-hosted/translate_c.zig
+++ b/src-self-hosted/translate_c.zig
@@ -875,9 +875,12 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
// types, while that's not ISO-C compliant many compilers allow this and
// default to the usual integer type used for all the enums.
+ // default to c_int since msvc and gcc default to different types
_ = try appendToken(c, .LParen, "(");
container_node.init_arg_expr = .{
- .Type = if (int_type.ptr != null)
+ .Type = if (int_type.ptr != null and
+ !isCBuiltinType(int_type, .UInt) and
+ !isCBuiltinType(int_type, .Int))
transQualType(rp, int_type, enum_loc) catch |err| switch (err) {
error.UnsupportedType => {
try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
diff --git a/test/translate_c.zig b/test/translate_c.zig
index adee4c9a4d..df33d9b145 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -1104,7 +1104,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const a = @enumToInt(enum_unnamed_1.a);
\\pub const b = @enumToInt(enum_unnamed_1.b);
\\pub const c = @enumToInt(enum_unnamed_1.c);
- \\const enum_unnamed_1 = extern enum(c_uint) {
+ \\const enum_unnamed_1 = extern enum(c_int) {
\\ a,
\\ b,
\\ c,
@@ -1114,7 +1114,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const e = @enumToInt(enum_unnamed_2.e);
\\pub const f = @enumToInt(enum_unnamed_2.f);
\\pub const g = @enumToInt(enum_unnamed_2.g);
- \\const enum_unnamed_2 = extern enum(c_uint) {
+ \\const enum_unnamed_2 = extern enum(c_int) {
\\ e = 0,
\\ f = 4,
\\ g = 5,
@@ -1124,7 +1124,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const i = @enumToInt(enum_unnamed_3.i);
\\pub const j = @enumToInt(enum_unnamed_3.j);
\\pub const k = @enumToInt(enum_unnamed_3.k);
- \\const enum_unnamed_3 = extern enum(c_uint) {
+ \\const enum_unnamed_3 = extern enum(c_int) {
\\ i,
\\ j,
\\ k,
@@ -1137,7 +1137,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const n = @enumToInt(enum_i.n);
\\pub const o = @enumToInt(enum_i.o);
\\pub const p = @enumToInt(enum_i.p);
- \\pub const enum_i = extern enum(c_uint) {
+ \\pub const enum_i = extern enum(c_int) {
\\ n,
\\ o,
\\ p,
@@ -1569,7 +1569,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
, &[_][]const u8{
\\pub const One = @enumToInt(enum_unnamed_1.One);
\\pub const Two = @enumToInt(enum_unnamed_1.Two);
- \\const enum_unnamed_1 = extern enum(c_uint) {
+ \\const enum_unnamed_1 = extern enum(c_int) {
\\ One,
\\ Two,
\\ _,
@@ -1672,7 +1672,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
\\}
, &[_][]const u8{
- \\pub const enum_Foo = extern enum(c_uint) {
+ \\pub const enum_Foo = extern enum(c_int) {
\\ A,
\\ B,
\\ C,
@@ -1718,7 +1718,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ y: c_int,
\\};
,
- \\pub const enum_Bar = extern enum(c_uint) {
+ \\pub const enum_Bar = extern enum(c_int) {
\\ A,
\\ B,
\\ _,
@@ -1982,7 +1982,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ return 4;
\\}
, &[_][]const u8{
- \\pub const enum_SomeEnum = extern enum(c_uint) {
+ \\pub const enum_SomeEnum = extern enum(c_int) {
\\ A,
\\ B,
\\ C,
@@ -2424,7 +2424,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const FooA = @enumToInt(enum_Foo.A);
\\pub const FooB = @enumToInt(enum_Foo.B);
\\pub const Foo1 = @enumToInt(enum_Foo.@"1");
- \\pub const enum_Foo = extern enum(c_uint) {
+ \\pub const enum_Foo = extern enum(c_int) {
\\ A = 2,
\\ B = 5,
\\ @"1" = 6,
From f609ce4f6551d772dcb6480c573ccad7645056cb Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Thu, 16 Jan 2020 11:37:23 +0100
Subject: [PATCH 10/37] Minor changes to the ARM builtin fns
---
lib/std/special/compiler_rt.zig | 2 +-
lib/std/special/compiler_rt/arm.zig | 19 +++++++++----------
2 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig
index 2128883545..cf255804aa 100644
--- a/lib/std/special/compiler_rt.zig
+++ b/lib/std/special/compiler_rt.zig
@@ -147,7 +147,7 @@ comptime {
@export(@import("compiler_rt/negXf2.zig").__negdf2, .{ .name = "__negdf2", .linkage = linkage });
if (is_arm_arch and !is_arm_64 and !is_test) {
- @export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr0, .{ .name = "__aeabi_unwind_cpp_pr0", .linkage = strong_linkage });
+ @export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr0, .{ .name = "__aeabi_unwind_cpp_pr0", .linkage = linkage });
@export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr1, .{ .name = "__aeabi_unwind_cpp_pr1", .linkage = linkage });
@export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr2, .{ .name = "__aeabi_unwind_cpp_pr2", .linkage = linkage });
diff --git a/lib/std/special/compiler_rt/arm.zig b/lib/std/special/compiler_rt/arm.zig
index 9ba423931b..5e718ed4c4 100644
--- a/lib/std/special/compiler_rt/arm.zig
+++ b/lib/std/special/compiler_rt/arm.zig
@@ -1,6 +1,5 @@
// ARM specific builtins
const builtin = @import("builtin");
-const is_test = builtin.is_test;
const __divmodsi4 = @import("int.zig").__divmodsi4;
const __udivmodsi4 = @import("int.zig").__udivmodsi4;
@@ -33,18 +32,14 @@ pub fn __aeabi_memclr(dest: [*]u8, n: usize) callconv(.AAPCS) void {
_ = memset(dest, 0, n);
}
-pub fn __aeabi_unwind_cpp_pr0() callconv(.C) void {
- unreachable;
-}
-pub fn __aeabi_unwind_cpp_pr1() callconv(.C) void {
- unreachable;
-}
-pub fn __aeabi_unwind_cpp_pr2() callconv(.C) void {
- unreachable;
-}
+// Dummy functions to avoid errors during the linking phase
+pub fn __aeabi_unwind_cpp_pr0() callconv(.C) void {}
+pub fn __aeabi_unwind_cpp_pr1() callconv(.C) void {}
+pub fn __aeabi_unwind_cpp_pr2() callconv(.C) void {}
// This function can only clobber r0 according to the ABI
pub fn __aeabi_read_tp() callconv(.Naked) void {
+ @setRuntimeSafety(false);
asm volatile (
\\ mrc p15, 0, r0, c13, c0, 3
\\ bx lr
@@ -56,6 +51,7 @@ pub fn __aeabi_read_tp() callconv(.Naked) void {
// calling convention is always respected
pub fn __aeabi_uidivmod() callconv(.Naked) void {
+ @setRuntimeSafety(false);
// Divide r0 by r1; the quotient goes in r0, the remainder in r1
asm volatile (
\\ push {lr}
@@ -73,6 +69,7 @@ pub fn __aeabi_uidivmod() callconv(.Naked) void {
}
pub fn __aeabi_uldivmod() callconv(.Naked) void {
+ @setRuntimeSafety(false);
// Divide r1:r0 by r3:r2; the quotient goes in r1:r0, the remainder in r3:r2
asm volatile (
\\ push {r4, lr}
@@ -92,6 +89,7 @@ pub fn __aeabi_uldivmod() callconv(.Naked) void {
}
pub fn __aeabi_idivmod() callconv(.Naked) void {
+ @setRuntimeSafety(false);
// Divide r0 by r1; the quotient goes in r0, the remainder in r1
asm volatile (
\\ push {lr}
@@ -109,6 +107,7 @@ pub fn __aeabi_idivmod() callconv(.Naked) void {
}
pub fn __aeabi_ldivmod() callconv(.Naked) void {
+ @setRuntimeSafety(false);
// Divide r1:r0 by r3:r2; the quotient goes in r1:r0, the remainder in r3:r2
asm volatile (
\\ push {r4, lr}
From df03fcf5f07e0d5d16e5b837658265f6c468cbe4 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Thu, 16 Jan 2020 17:12:43 +0200
Subject: [PATCH 11/37] implement `@bitSizeOf`
---
doc/langref.html.in | 15 ++++++++++++++-
src/all_types.hpp | 4 ++++
src/codegen.cpp | 1 +
src/ir.cpp | 12 +++++++++---
src/ir_print.cpp | 5 ++++-
test/stage1/behavior/sizeof_and_typeof.zig | 11 +++++++++++
6 files changed, 43 insertions(+), 5 deletions(-)
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 092e303013..88e6b41983 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -6815,6 +6815,19 @@ async fn func(y: *i32) void {
{#header_close#}
+ {#header_open|@bitSizeOf#}
+ {#syntax#}@bitSizeOf(comptime T: type) comptime_int{#endsyntax#}
+
+ This function returns the number of bits it takes to store {#syntax#}T{#endsyntax#} in memory.
+ The result is a target-specific compile time constant.
+
+
+ This function measures the size at runtime. For types that are disallowed at runtime, such as
+ {#syntax#}comptime_int{#endsyntax#} and {#syntax#}type{#endsyntax#}, the result is {#syntax#}0{#endsyntax#}.
+
+ {#see_also|@sizeOf|@typeInfo#}
+ {#header_close#}
+
{#header_open|@breakpoint#}
{#syntax#}@breakpoint(){#endsyntax#}
@@ -8044,7 +8057,7 @@ test "@setRuntimeSafety" {
This function measures the size at runtime. For types that are disallowed at runtime, such as
{#syntax#}comptime_int{#endsyntax#} and {#syntax#}type{#endsyntax#}, the result is {#syntax#}0{#endsyntax#}.
- {#see_also|@typeInfo#}
+ {#see_also|@bitSizeOf|@typeInfo#}
{#header_close#}
{#header_open|@sliceToBytes#}
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 0fed73f7b2..4d6f68daff 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -358,6 +358,8 @@ struct LazyValueSizeOf {
IrAnalyze *ira;
IrInstruction *target_type;
+
+ bool bit_size;
};
struct LazyValueSliceType {
@@ -1754,6 +1756,7 @@ enum BuiltinFnId {
BuiltinFnIdFrameSize,
BuiltinFnIdAs,
BuiltinFnIdCall,
+ BuiltinFnIdBitSizeof,
};
struct BuiltinFnEntry {
@@ -3146,6 +3149,7 @@ struct IrInstructionAsmGen {
struct IrInstructionSizeOf {
IrInstruction base;
+ bool bit_size;
IrInstruction *type_value;
};
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 95b55675bb..cd009b3bea 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -8299,6 +8299,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdFrameSize, "frameSize", 1);
create_builtin_fn(g, BuiltinFnIdAs, "as", 2);
create_builtin_fn(g, BuiltinFnIdCall, "call", 3);
+ create_builtin_fn(g, BuiltinFnIdBitSizeof, "bitSizeOf", 1);
}
static const char *bool_to_str(bool b) {
diff --git a/src/ir.cpp b/src/ir.cpp
index d871aa27a0..c3ca366456 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -2392,9 +2392,10 @@ static IrInstruction *ir_build_asm_gen(IrAnalyze *ira, Scope *scope, AstNode *so
return &instruction->base;
}
-static IrInstruction *ir_build_size_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) {
+static IrInstruction *ir_build_size_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value, bool bit_size) {
IrInstructionSizeOf *instruction = ir_build_instruction(irb, scope, source_node);
instruction->type_value = type_value;
+ instruction->bit_size = bit_size;
ir_ref_instruction(type_value, irb->current_basic_block);
@@ -5249,13 +5250,14 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_lval_wrap(irb, scope, set_float_mode, lval, result_loc);
}
case BuiltinFnIdSizeof:
+ case BuiltinFnIdBitSizeof:
{
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;
- IrInstruction *size_of = ir_build_size_of(irb, scope, node, arg0_value);
+ IrInstruction *size_of = ir_build_size_of(irb, scope, node, arg0_value, builtin_fn->id == BuiltinFnIdBitSizeof);
return ir_lval_wrap(irb, scope, size_of, lval, result_loc);
}
case BuiltinFnIdImport:
@@ -21065,6 +21067,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, IrInstructi
lazy_size_of->ira = ira; ira_ref(ira);
result->value->data.x_lazy = &lazy_size_of->base;
lazy_size_of->base.id = LazyValueIdSizeOf;
+ lazy_size_of->bit_size = instruction->bit_size;
lazy_size_of->target_type = instruction->type_value->child;
if (ir_resolve_type_lazy(ira, lazy_size_of->target_type) == nullptr)
@@ -29415,7 +29418,10 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
val->special = ConstValSpecialStatic;
assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt);
- bigint_init_unsigned(&val->data.x_bigint, abi_size);
+ if (lazy_size_of->bit_size)
+ bigint_init_unsigned(&val->data.x_bigint, size_in_bits);
+ else
+ bigint_init_unsigned(&val->data.x_bigint, abi_size);
// We can't free the lazy value here, because multiple other ZigValues might be pointing to it.
return ErrorNone;
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 90ab410e4d..24e030f501 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -1039,7 +1039,10 @@ static void ir_print_asm_gen(IrPrint *irp, IrInstructionAsmGen *instruction) {
}
static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) {
- fprintf(irp->f, "@sizeOf(");
+ if (instruction->bit_size)
+ fprintf(irp->f, "@bitSizeOf(");
+ else
+ fprintf(irp->f, "@sizeOf(");
ir_print_other_instruction(irp, instruction->type_value);
fprintf(irp->f, ")");
}
diff --git a/test/stage1/behavior/sizeof_and_typeof.zig b/test/stage1/behavior/sizeof_and_typeof.zig
index d46cdccd0d..a738dbbbf9 100644
--- a/test/stage1/behavior/sizeof_and_typeof.zig
+++ b/test/stage1/behavior/sizeof_and_typeof.zig
@@ -124,3 +124,14 @@ fn fn1(alpha: bool) void {
test "lazy @sizeOf result is checked for definedness" {
const f = fn1;
}
+
+test "@bitSizeOf" {
+ expect(@bitSizeOf(u2) == 2);
+ expect(@bitSizeOf(u8) == @sizeOf(u8) * 8);
+ expect(@bitSizeOf(struct {
+ a: u2
+ }) == 8);
+ expect(@bitSizeOf(packed struct {
+ a: u2
+ }) == 2);
+}
From bac27731e30cbea76997fa3547791b3462ac8697 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Thu, 16 Jan 2020 13:55:39 +0200
Subject: [PATCH 12/37] add struct field default value to typeinfo
---
lib/std/builtin.zig | 1 +
src/ir.cpp | 8 +++++++-
test/stage1/behavior/type_info.zig | 5 ++++-
3 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index dbd19fbadf..65604a5b20 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -205,6 +205,7 @@ pub const TypeInfo = union(enum) {
name: []const u8,
offset: ?comptime_int,
field_type: type,
+ default_value: var,
};
/// This data structure is used by the Zig language code generation and
diff --git a/src/ir.cpp b/src/ir.cpp
index c3ca366456..818644f501 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -23338,7 +23338,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
struct_field_val->special = ConstValSpecialStatic;
struct_field_val->type = type_info_struct_field_type;
- ZigValue **inner_fields = alloc_const_vals_ptrs(3);
+ ZigValue **inner_fields = alloc_const_vals_ptrs(4);
inner_fields[1]->special = ConstValSpecialStatic;
inner_fields[1]->type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_num_lit_int);
@@ -23361,6 +23361,12 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
inner_fields[2]->type = ira->codegen->builtin_types.entry_type;
inner_fields[2]->data.x_type = struct_field->type_entry;
+ // default_value: var
+ inner_fields[3]->special = ConstValSpecialStatic;
+ inner_fields[3]->type = get_optional_type(ira->codegen, struct_field->type_entry);
+ memoize_field_init_val(ira->codegen, type_entry, struct_field);
+ set_optional_payload(inner_fields[3], struct_field->init_val);
+
ZigValue *name = create_const_str_lit(ira->codegen, struct_field->name)->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(struct_field->name), true);
diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig
index d35cc8831f..9d577ec0b4 100644
--- a/test/stage1/behavior/type_info.zig
+++ b/test/stage1/behavior/type_info.zig
@@ -237,9 +237,11 @@ fn testStruct() void {
const struct_info = @typeInfo(TestStruct);
expect(@as(TypeId, struct_info) == TypeId.Struct);
expect(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed);
- expect(struct_info.Struct.fields.len == 3);
+ expect(struct_info.Struct.fields.len == 4);
expect(struct_info.Struct.fields[1].offset == null);
expect(struct_info.Struct.fields[2].field_type == *TestStruct);
+ expect(struct_info.Struct.fields[2].default_value == null);
+ expect(struct_info.Struct.fields[3].default_value.? == 4);
expect(struct_info.Struct.decls.len == 2);
expect(struct_info.Struct.decls[0].is_pub);
expect(!struct_info.Struct.decls[0].data.Fn.is_extern);
@@ -254,6 +256,7 @@ const TestStruct = packed struct {
fieldA: usize,
fieldB: void,
fieldC: *Self,
+ fieldD: u32 = 4,
pub fn foo(self: *const Self) void {}
};
From 6c8f01dcde03380806338758d489c3f2a78e5b5b Mon Sep 17 00:00:00 2001
From: Vexu
Date: Thu, 16 Jan 2020 22:48:01 +0200
Subject: [PATCH 13/37] correct field count
---
src/analyze.cpp | 60 ++++++++++++++++++-----------------
test/compile_errors.zig | 6 ++++
test/stage1/behavior/enum.zig | 1 +
3 files changed, 38 insertions(+), 29 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 18dc7e032c..e064677a09 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -2569,16 +2569,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
return ErrorSemanticAnalyzeFail;
}
- enum_type->data.enumeration.src_field_count = field_count;
- enum_type->data.enumeration.fields = allocate(field_count);
- enum_type->data.enumeration.fields_by_name.init(field_count);
- enum_type->data.enumeration.non_exhaustive = false;
-
Scope *scope = &enum_type->data.enumeration.decls_scope->base;
- HashMap occupied_tag_values = {};
- occupied_tag_values.init(field_count);
-
ZigType *tag_int_type;
if (enum_type->data.enumeration.layout == ContainerLayoutExtern) {
tag_int_type = get_c_int_type(g, CIntTypeInt);
@@ -2620,6 +2612,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
}
}
+ enum_type->data.enumeration.non_exhaustive = false;
enum_type->data.enumeration.tag_int_type = tag_int_type;
enum_type->size_in_bits = tag_int_type->size_in_bits;
enum_type->abi_size = tag_int_type->abi_size;
@@ -2628,6 +2621,31 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
BigInt bi_one;
bigint_init_unsigned(&bi_one, 1);
+ AstNode *last_field_node = decl_node->data.container_decl.fields.at(field_count - 1);
+ if (buf_eql_str(last_field_node->data.struct_field.name, "_")) {
+ field_count -= 1;
+ if (field_count > 1 && log2_u64(field_count) == enum_type->size_in_bits) {
+ add_node_error(g, last_field_node, buf_sprintf("non-exhaustive enum specifies every value"));
+ enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
+ }
+ if (decl_node->data.container_decl.init_arg_expr == nullptr) {
+ add_node_error(g, last_field_node, buf_sprintf("non-exhaustive enum must specify size"));
+ enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
+ }
+ if (last_field_node->data.struct_field.value != nullptr) {
+ add_node_error(g, last_field_node, buf_sprintf("value assigned to '_' field of non-exhaustive enum"));
+ enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
+ }
+ enum_type->data.enumeration.non_exhaustive = true;
+ }
+
+ enum_type->data.enumeration.src_field_count = field_count;
+ enum_type->data.enumeration.fields = allocate(field_count);
+ enum_type->data.enumeration.fields_by_name.init(field_count);
+
+ HashMap occupied_tag_values = {};
+ occupied_tag_values.init(field_count);
+
TypeEnumField *last_enum_field = nullptr;
for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
@@ -2649,27 +2667,9 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
buf_sprintf("consider 'union(enum)' here"));
}
- AstNode *tag_value = field_node->data.struct_field.value;
-
if (buf_eql_str(type_enum_field->name, "_")) {
- if (decl_node->data.container_decl.init_arg_expr == nullptr) {
- add_node_error(g, field_node, buf_sprintf("non-exhaustive enum must specify size"));
- enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
- }
- if (field_count > 1 && log2_u64(field_count - 1) == enum_type->size_in_bits) {
- add_node_error(g, field_node, buf_sprintf("non-exhaustive enum specifies every value"));
- enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
- }
- if (field_i != field_count - 1) {
- add_node_error(g, field_node, buf_sprintf("'_' field of non-exhaustive enum must be last"));
- enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
- }
- if (tag_value != nullptr) {
- add_node_error(g, field_node, buf_sprintf("value assigned to '_' field of non-exhaustive enum"));
- enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
- }
- enum_type->data.enumeration.non_exhaustive = true;
- continue;
+ add_node_error(g, field_node, buf_sprintf("'_' field of non-exhaustive enum must be last"));
+ enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
}
auto field_entry = enum_type->data.enumeration.fields_by_name.put_unique(type_enum_field->name, type_enum_field);
@@ -2681,6 +2681,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
continue;
}
+ AstNode *tag_value = field_node->data.struct_field.value;
+
if (tag_value != nullptr) {
// A user-specified value is available
ZigValue *result = analyze_const_value(g, scope, tag_value, tag_int_type,
@@ -3293,7 +3295,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
} else if (enum_type_node != nullptr) {
for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) {
TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i];
- if (!covered_enum_fields[i] && !buf_eql_str(enum_field->name, "_")) {
+ if (!covered_enum_fields[i]) {
AstNode *enum_decl_node = tag_type->data.enumeration.decl_node;
AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i);
ErrorMsg *msg = add_node_error(g, decl_node,
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 702cc76524..be2a40d74d 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -13,9 +13,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ _,
\\ b,
\\};
+ \\const C = enum(u1) {
+ \\ a,
+ \\ b,
+ \\ _,
+ \\};
\\pub export fn entry() void {
\\ _ = A;
\\ _ = B;
+ \\ _ = C;
\\}
, &[_][]const u8{
"tmp.zig:4:5: error: non-exhaustive enum must specify size",
diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig
index 82e57a3a38..62b7d51c26 100644
--- a/test/stage1/behavior/enum.zig
+++ b/test/stage1/behavior/enum.zig
@@ -41,6 +41,7 @@ test "non-exhaustive enum" {
.b => {},
else => {},
}
+ expect(@typeInfo(E).Enum.fields.len == 2);
expect(@enumToInt(e) == 1);
e = @intToEnum(E, 12);
expect(@enumToInt(e) == 12);
From cd062b08d01cf2c92b05ef3e96b2ff3715f29fd5 Mon Sep 17 00:00:00 2001
From: Michael Dusan
Date: Thu, 16 Jan 2020 18:56:13 -0500
Subject: [PATCH 14/37] cmake: support `make` and `make install`
- `make` or `ninja` will not build but not install
- `make install` or `ninja install` will build __and__ install
Only for build system generator Visual Studio, specify the following
to disable installation of lib files:
ZIG_SKIP_INSTALL_LIB_FILES=ON
---
CMakeLists.txt | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 64aa7d1bd4..47a0cdf578 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -45,7 +45,6 @@ message("Configuring zig version ${ZIG_VERSION}")
set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries")
-set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL "Disable copying lib/ files to install prefix")
set(ZIG_ENABLE_MEM_PROFILE off CACHE BOOL "Activate memory usage instrumentation")
if(ZIG_STATIC)
@@ -608,19 +607,26 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
else()
set(LIBUSERLAND_RELEASE_MODE "true")
endif()
-if(ZIG_SKIP_INSTALL_LIB_FILES)
- set(ZIG_BUILD_INSTALL_STEP "")
-else()
- set(ZIG_BUILD_INSTALL_STEP "install")
-endif()
-add_custom_target(zig_build_libuserland ALL
- COMMAND zig0 build
+
+set(BUILD_LIBUSERLAND_COMMAND zig0 build
--override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
- libuserland ${ZIG_BUILD_INSTALL_STEP}
"-Doutput-dir=${CMAKE_BINARY_DIR}"
"-Drelease=${LIBUSERLAND_RELEASE_MODE}"
"-Dlib-files-only"
--prefix "${CMAKE_INSTALL_PREFIX}"
+ libuserland
+)
+
+# When using Visual Studio build system generator we default to libuserland install.
+if(MSVC)
+ set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL "Disable copying lib/ files to install prefix")
+ if(NOT ZIG_SKIP_INSTALL_LIB_FILES)
+ set(BUILD_LIBUSERLAND_COMMAND ${BUILD_LIBUSERLAND_COMMAND} install)
+ endif()
+endif()
+
+add_custom_target(zig_build_libuserland ALL
+ COMMAND ${BUILD_LIBUSERLAND_COMMAND}
DEPENDS zig0
BYPRODUCTS "${LIBUSERLAND}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
@@ -638,4 +644,9 @@ elseif(MINGW)
target_link_libraries(zig ntdll)
endif()
add_dependencies(zig zig_build_libuserland)
+
install(TARGETS zig DESTINATION bin)
+
+# CODE has no effect with Visual Studio build system generator
+install(CODE "message(\"-- Installing: /opt/zig/lib\")")
+install(CODE "execute_process(COMMAND ${BUILD_LIBUSERLAND_COMMAND} install)")
From 97cca1376aa5d5ed6ae699cc67b3c5e4b97f11bf Mon Sep 17 00:00:00 2001
From: Michael Dusan
Date: Fri, 17 Jan 2020 00:35:34 -0500
Subject: [PATCH 15/37] cmake: fix install lib path message
---
CMakeLists.txt | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 47a0cdf578..bebd59c1e0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -609,12 +609,12 @@ else()
endif()
set(BUILD_LIBUSERLAND_COMMAND zig0 build
- --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
- "-Doutput-dir=${CMAKE_BINARY_DIR}"
- "-Drelease=${LIBUSERLAND_RELEASE_MODE}"
- "-Dlib-files-only"
- --prefix "${CMAKE_INSTALL_PREFIX}"
- libuserland
+ --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
+ "-Doutput-dir=${CMAKE_BINARY_DIR}"
+ "-Drelease=${LIBUSERLAND_RELEASE_MODE}"
+ "-Dlib-files-only"
+ --prefix "${CMAKE_INSTALL_PREFIX}"
+ libuserland
)
# When using Visual Studio build system generator we default to libuserland install.
@@ -647,6 +647,6 @@ add_dependencies(zig zig_build_libuserland)
install(TARGETS zig DESTINATION bin)
-# CODE has no effect with Visual Studio build system generator
-install(CODE "message(\"-- Installing: /opt/zig/lib\")")
+# CODE has no effect with Visual Studio build system generator.
+install(CODE "message(\"-- Installing: ${CMAKE_INSTALL_PREFIX}/lib\")")
install(CODE "execute_process(COMMAND ${BUILD_LIBUSERLAND_COMMAND} install)")
From af9eb7ac13b522c1880357ae7349a0b984b83ab4 Mon Sep 17 00:00:00 2001
From: Michael Dusan
Date: Fri, 17 Jan 2020 00:19:59 -0500
Subject: [PATCH 16/37] doc: update contributing
---
CONTRIBUTING.md | 33 +++++++++++++++++++--------------
1 file changed, 19 insertions(+), 14 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a5aeeb9e21..62b8083222 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -51,23 +51,28 @@ knowledge of Zig internals.**
### Editing Source Code
-First, build the Stage 1 compiler as described in [the Building section](#building).
+First, build the Stage 1 compiler as described in [Building from Source](README.md#Building-from-Source).
-One modification you may want to make is adding `-DZIG_SKIP_INSTALL_LIB_FILES=ON`
-to the cmake line. If you use the build directory as a working directory to run
-tests with, zig will find the lib files in the source directory, and they will not
-be "installed" every time you run `make`. This will allow you to make modifications
-directly to the standard library, for example, and have them effective immediately.
-Note that if you already ran `make` or `make install` with the default cmake
-settings, there will already be a `lib/` directory in your build directory. When
-executed from the build directory, zig will find this instead of the source lib/
-directory. Remove the unwanted directory so that the desired one can be found.
+Zig locates lib files relative to executable path by searching up the
+filesystem tree for a sub-path of `lib/zig/std/std.zig` or `lib/std/std.zig`.
+Typically the former is an install and the latter a git working tree which
+contains the build directory.
+
+During development it is not necessary to perform installs when modifying
+stage1 or userland sources and in fact it is faster and simpler to run,
+test and debug from a git working tree.
+
+- `make` is typically sufficient to build zig during development iterations.
+- `make install` performs a build __and__ install.
+- `msbuild -p:Configuration=Release INSTALL.vcxproj` on Windows performs a
+build and install. To avoid install, pass cmake option `-DZIG_SKIP_INSTALL_LIB_FILES=ON`.
To test changes, do the following from the build directory:
-1. Run `make install` (on POSIX) or
+1. Run `make` (on POSIX) or
`msbuild -p:Configuration=Release INSTALL.vcxproj` (on Windows).
-2. `bin/zig build test` (on POSIX) or `bin\zig.exe build test` (on Windows).
+2. `$BUILD_DIR/zig build test` (on POSIX) or
+ `$BUILD_DIR/Release\zig.exe build test` (on Windows).
That runs the whole test suite, which does a lot of extra testing that you
likely won't always need, and can take upwards of 1 hour. This is what the
@@ -85,8 +90,8 @@ Another example is choosing a different set of things to test. For example,
not the other ones. Combining this suggestion with the previous one, you could
do this:
-`bin/zig build test-std -Dskip-release` (on POSIX) or
-`bin\zig.exe build test-std -Dskip-release` (on Windows).
+`$BUILD_DIR/bin/zig build test-std -Dskip-release` (on POSIX) or
+`$BUILD_DIR/Release\zig.exe build test-std -Dskip-release` (on Windows).
This will run only the standard library tests, in debug mode only, for all
targets (it will cross-compile the tests for non-native targets but not run
From 39f92a9ee4ea109628e1f7d5a65bb53575e53194 Mon Sep 17 00:00:00 2001
From: Vexu
Date: Fri, 17 Jan 2020 09:50:20 +0200
Subject: [PATCH 17/37] improve behavior test
---
test/stage1/behavior/enum.zig | 33 ++++++++++++++++++++++-----------
1 file changed, 22 insertions(+), 11 deletions(-)
diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig
index 62b7d51c26..83ad76b72c 100644
--- a/test/stage1/behavior/enum.zig
+++ b/test/stage1/behavior/enum.zig
@@ -30,19 +30,30 @@ test "non-exhaustive enum" {
};
fn doTheTest(y: u8) void {
var e: E = .b;
- switch (e) {
- .a => {},
- .b => {},
- _ => {},
- }
+ expect(switch (e) {
+ .a => false,
+ .b => true,
+ _ => false,
+ });
+ e = @intToEnum(E, 12);
+ expect(switch (e) {
+ .a => false,
+ .b => false,
+ _ => true,
+ });
+
+ expect(switch (e) {
+ .a => false,
+ .b => false,
+ else => true,
+ });
+ e = .b;
+ expect(switch (e) {
+ .a => false,
+ else => true,
+ });
- switch (e) {
- .a => {},
- .b => {},
- else => {},
- }
expect(@typeInfo(E).Enum.fields.len == 2);
- expect(@enumToInt(e) == 1);
e = @intToEnum(E, 12);
expect(@enumToInt(e) == 12);
e = @intToEnum(E, y);
From d53e8a5751c3d3a65db775598cc1db88c4d92ba9 Mon Sep 17 00:00:00 2001
From: Michael Dusan
Date: Fri, 17 Jan 2020 13:02:44 -0500
Subject: [PATCH 18/37] Revert "cmake: support `make` and `make install`"
This reverts commit cd062b08d01cf2c92b05ef3e96b2ff3715f29fd5.
---
CMakeLists.txt | 35 ++++++++++++-----------------------
CONTRIBUTING.md | 33 ++++++++++++++-------------------
2 files changed, 26 insertions(+), 42 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bebd59c1e0..64aa7d1bd4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -45,6 +45,7 @@ message("Configuring zig version ${ZIG_VERSION}")
set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries")
+set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL "Disable copying lib/ files to install prefix")
set(ZIG_ENABLE_MEM_PROFILE off CACHE BOOL "Activate memory usage instrumentation")
if(ZIG_STATIC)
@@ -607,26 +608,19 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
else()
set(LIBUSERLAND_RELEASE_MODE "true")
endif()
-
-set(BUILD_LIBUSERLAND_COMMAND zig0 build
- --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
- "-Doutput-dir=${CMAKE_BINARY_DIR}"
- "-Drelease=${LIBUSERLAND_RELEASE_MODE}"
- "-Dlib-files-only"
- --prefix "${CMAKE_INSTALL_PREFIX}"
- libuserland
-)
-
-# When using Visual Studio build system generator we default to libuserland install.
-if(MSVC)
- set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL "Disable copying lib/ files to install prefix")
- if(NOT ZIG_SKIP_INSTALL_LIB_FILES)
- set(BUILD_LIBUSERLAND_COMMAND ${BUILD_LIBUSERLAND_COMMAND} install)
- endif()
+if(ZIG_SKIP_INSTALL_LIB_FILES)
+ set(ZIG_BUILD_INSTALL_STEP "")
+else()
+ set(ZIG_BUILD_INSTALL_STEP "install")
endif()
-
add_custom_target(zig_build_libuserland ALL
- COMMAND ${BUILD_LIBUSERLAND_COMMAND}
+ COMMAND zig0 build
+ --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
+ libuserland ${ZIG_BUILD_INSTALL_STEP}
+ "-Doutput-dir=${CMAKE_BINARY_DIR}"
+ "-Drelease=${LIBUSERLAND_RELEASE_MODE}"
+ "-Dlib-files-only"
+ --prefix "${CMAKE_INSTALL_PREFIX}"
DEPENDS zig0
BYPRODUCTS "${LIBUSERLAND}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
@@ -644,9 +638,4 @@ elseif(MINGW)
target_link_libraries(zig ntdll)
endif()
add_dependencies(zig zig_build_libuserland)
-
install(TARGETS zig DESTINATION bin)
-
-# CODE has no effect with Visual Studio build system generator.
-install(CODE "message(\"-- Installing: ${CMAKE_INSTALL_PREFIX}/lib\")")
-install(CODE "execute_process(COMMAND ${BUILD_LIBUSERLAND_COMMAND} install)")
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 62b8083222..a5aeeb9e21 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -51,28 +51,23 @@ knowledge of Zig internals.**
### Editing Source Code
-First, build the Stage 1 compiler as described in [Building from Source](README.md#Building-from-Source).
+First, build the Stage 1 compiler as described in [the Building section](#building).
-Zig locates lib files relative to executable path by searching up the
-filesystem tree for a sub-path of `lib/zig/std/std.zig` or `lib/std/std.zig`.
-Typically the former is an install and the latter a git working tree which
-contains the build directory.
-
-During development it is not necessary to perform installs when modifying
-stage1 or userland sources and in fact it is faster and simpler to run,
-test and debug from a git working tree.
-
-- `make` is typically sufficient to build zig during development iterations.
-- `make install` performs a build __and__ install.
-- `msbuild -p:Configuration=Release INSTALL.vcxproj` on Windows performs a
-build and install. To avoid install, pass cmake option `-DZIG_SKIP_INSTALL_LIB_FILES=ON`.
+One modification you may want to make is adding `-DZIG_SKIP_INSTALL_LIB_FILES=ON`
+to the cmake line. If you use the build directory as a working directory to run
+tests with, zig will find the lib files in the source directory, and they will not
+be "installed" every time you run `make`. This will allow you to make modifications
+directly to the standard library, for example, and have them effective immediately.
+Note that if you already ran `make` or `make install` with the default cmake
+settings, there will already be a `lib/` directory in your build directory. When
+executed from the build directory, zig will find this instead of the source lib/
+directory. Remove the unwanted directory so that the desired one can be found.
To test changes, do the following from the build directory:
-1. Run `make` (on POSIX) or
+1. Run `make install` (on POSIX) or
`msbuild -p:Configuration=Release INSTALL.vcxproj` (on Windows).
-2. `$BUILD_DIR/zig build test` (on POSIX) or
- `$BUILD_DIR/Release\zig.exe build test` (on Windows).
+2. `bin/zig build test` (on POSIX) or `bin\zig.exe build test` (on Windows).
That runs the whole test suite, which does a lot of extra testing that you
likely won't always need, and can take upwards of 1 hour. This is what the
@@ -90,8 +85,8 @@ Another example is choosing a different set of things to test. For example,
not the other ones. Combining this suggestion with the previous one, you could
do this:
-`$BUILD_DIR/bin/zig build test-std -Dskip-release` (on POSIX) or
-`$BUILD_DIR/Release\zig.exe build test-std -Dskip-release` (on Windows).
+`bin/zig build test-std -Dskip-release` (on POSIX) or
+`bin\zig.exe build test-std -Dskip-release` (on Windows).
This will run only the standard library tests, in debug mode only, for all
targets (it will cross-compile the tests for non-native targets but not run
From d9be6e5dc693fcbcb5f4c343a3d2b0b9fc786e25 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C3=ABl=20Larouche?=
Date: Sat, 11 Jan 2020 17:10:00 -0500
Subject: [PATCH 19/37] Port clzsi2 from compiler_rt, required for using
std.fmt.format on some ARM architecture.
---
lib/std/special/compiler_rt.zig | 6 +-
lib/std/special/compiler_rt/clzsi2.zig | 118 ++++++++
lib/std/special/compiler_rt/clzsi2_test.zig | 292 ++++++++++++++++++++
3 files changed, 415 insertions(+), 1 deletion(-)
create mode 100644 lib/std/special/compiler_rt/clzsi2.zig
create mode 100644 lib/std/special/compiler_rt/clzsi2_test.zig
diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig
index cf255804aa..9b225dbad6 100644
--- a/lib/std/special/compiler_rt.zig
+++ b/lib/std/special/compiler_rt.zig
@@ -146,6 +146,8 @@ comptime {
@export(@import("compiler_rt/negXf2.zig").__negsf2, .{ .name = "__negsf2", .linkage = linkage });
@export(@import("compiler_rt/negXf2.zig").__negdf2, .{ .name = "__negdf2", .linkage = linkage });
+ @export(@import("compiler_rt/clzsi2.zig").__clzsi2, .{ .name = "__clzsi2", .linkage = linkage });
+
if (is_arm_arch and !is_arm_64 and !is_test) {
@export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr0, .{ .name = "__aeabi_unwind_cpp_pr0", .linkage = linkage });
@export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr1, .{ .name = "__aeabi_unwind_cpp_pr1", .linkage = linkage });
@@ -177,7 +179,9 @@ comptime {
@export(@import("compiler_rt/arm.zig").__aeabi_memclr, .{ .name = "__aeabi_memclr4", .linkage = linkage });
@export(@import("compiler_rt/arm.zig").__aeabi_memclr, .{ .name = "__aeabi_memclr8", .linkage = linkage });
- @export(@import("compiler_rt/arm.zig").__aeabi_read_tp, .{ .name = "__aeabi_read_tp", .linkage = linkage });
+ if (builtin.os == .linux) {
+ @export(@import("compiler_rt/arm.zig").__aeabi_read_tp, .{ .name = "__aeabi_read_tp", .linkage = linkage });
+ }
@export(@import("compiler_rt/extendXfYf2.zig").__aeabi_f2d, .{ .name = "__aeabi_f2d", .linkage = linkage });
@export(@import("compiler_rt/floatsiXf.zig").__aeabi_i2d, .{ .name = "__aeabi_i2d", .linkage = linkage });
diff --git a/lib/std/special/compiler_rt/clzsi2.zig b/lib/std/special/compiler_rt/clzsi2.zig
new file mode 100644
index 0000000000..0cbfdb8db1
--- /dev/null
+++ b/lib/std/special/compiler_rt/clzsi2.zig
@@ -0,0 +1,118 @@
+// Ported from:
+//
+// https://github.com/llvm-mirror/compiler-rt/blob/f0745e8476f069296a7c71accedd061dce4cdf79/lib/builtins/clzsi2.c
+// https://github.com/llvm-mirror/compiler-rt/blob/f0745e8476f069296a7c71accedd061dce4cdf79/lib/builtins/arm/clzsi2.S
+const builtin = @import("builtin");
+
+// Precondition: a != 0
+fn __clzsi2_generic(a: i32) callconv(.C) i32 {
+ @setRuntimeSafety(builtin.is_test);
+
+ var x = @bitCast(u32, a);
+ var n: i32 = 32;
+
+ // Count first bit set using binary search, from Hacker's Delight
+ var y: u32 = 0;
+ inline for ([_]i32{ 16, 8, 4, 2, 1 }) |shift| {
+ y = x >> shift;
+ if (y != 0) {
+ n = n - shift;
+ x = y;
+ }
+ }
+
+ return n - @bitCast(i32, x);
+}
+
+fn __clzsi2_arm_clz(a: i32) callconv(.Naked) noreturn {
+ asm volatile (
+ \\ clz r0,r0
+ \\ bx lr
+ );
+ unreachable;
+}
+
+fn __clzsi2_arm32(a: i32) callconv(.Naked) noreturn {
+ asm volatile (
+ \\ // Assumption: n != 0
+ \\ // r0: n
+ \\ // r1: count of leading zeros in n + 1
+ \\ // r2: scratch register for shifted r0
+ \\ mov r1, #1
+ \\
+ \\ // Basic block:
+ \\ // if ((r0 >> SHIFT) == 0)
+ \\ // r1 += SHIFT;
+ \\ // else
+ \\ // r0 >>= SHIFT;
+ \\ // for descending powers of two as SHIFT.
+ \\ lsrs r2, r0, #16
+ \\ movne r0, r2
+ \\ addeq r1, #16
+ \\
+ \\ lsrs r2, r0, #8
+ \\ movne r0, r2
+ \\ addeq r1, #8
+ \\
+ \\ lsrs r2, r0, #4
+ \\ movne r0, r2
+ \\ addeq r1, #4
+ \\
+ \\ lsrs r2, r0, #2
+ \\ movne r0, r2
+ \\ addeq r1, #2
+ \\
+ \\ // The basic block invariants at this point are (r0 >> 2) == 0 and
+ \\ // r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
+ \\ //
+ \\ // r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)f
+ \\ // ---+----------------+----------------+------------+--------------
+ \\ // 1 | 1 | 0 | 0 | 1
+ \\ // 2 | 0 | 1 | -1 | 0
+ \\ // 3 | 0 | 1 | -1 | 0
+ \\ //
+ \\ // The r1's initial value of 1 compensates for the 1 here.
+ \\ sub r0, r1, r0, lsr #1
+ \\ bx lr
+ );
+ unreachable;
+}
+
+const can_use_arm_clz = switch (builtin.arch) {
+ .arm, .armeb => |sub_arch| switch (sub_arch) {
+ .v4t => false,
+ .v6m => false,
+ else => true,
+ },
+ .thumb, .thumbeb => |sub_arch| switch (sub_arch) {
+ .v6,
+ .v6k,
+ .v5,
+ .v5te,
+ .v4t,
+ => false,
+ else => true,
+ },
+ else => false,
+};
+
+const is_arm32_no_thumb = switch (builtin.arch) {
+ builtin.Arch.arm,
+ builtin.Arch.armeb,
+ => true,
+ else => false,
+};
+
+pub const __clzsi2 = blk: {
+ if (comptime can_use_arm_clz) {
+ break :blk __clzsi2_arm_clz;
+ } else if (comptime is_arm32_no_thumb) {
+ break :blk __clzsi2_arm32;
+ } else {
+ break :blk __clzsi2_generic;
+ }
+};
+
+test "test clzsi2" {
+ _ = @import("clzsi2_test.zig");
+}
diff --git a/lib/std/special/compiler_rt/clzsi2_test.zig b/lib/std/special/compiler_rt/clzsi2_test.zig
new file mode 100644
index 0000000000..ff94455846
--- /dev/null
+++ b/lib/std/special/compiler_rt/clzsi2_test.zig
@@ -0,0 +1,292 @@
+const clzsi2 = @import("clzsi2.zig");
+const testing = @import("std").testing;
+
+fn test__clzsi2(a: u32, expected: i32) void {
+ var nakedClzsi2 = clzsi2.__clzsi2;
+ var actualClzsi2 = @ptrCast(fn (a: i32) callconv(.C) i32, nakedClzsi2);
+ var x = @intCast(i32, a);
+ var result = actualClzsi2(x);
+ testing.expectEqual(expected, result);
+}
+
+test "clzsi2" {
+ test__clzsi2(0x00800000, 8);
+ test__clzsi2(0x01000000, 7);
+ test__clzsi2(0x02000000, 6);
+ test__clzsi2(0x03000000, 6);
+ test__clzsi2(0x04000000, 5);
+ test__clzsi2(0x05000000, 5);
+ test__clzsi2(0x06000000, 5);
+ test__clzsi2(0x07000000, 5);
+ test__clzsi2(0x08000000, 4);
+ test__clzsi2(0x09000000, 4);
+ test__clzsi2(0x0A000000, 4);
+ test__clzsi2(0x0B000000, 4);
+ test__clzsi2(0x0C000000, 4);
+ test__clzsi2(0x0D000000, 4);
+ test__clzsi2(0x0E000000, 4);
+ test__clzsi2(0x0F000000, 4);
+ test__clzsi2(0x10000000, 3);
+ test__clzsi2(0x11000000, 3);
+ test__clzsi2(0x12000000, 3);
+ test__clzsi2(0x13000000, 3);
+ test__clzsi2(0x14000000, 3);
+ test__clzsi2(0x15000000, 3);
+ test__clzsi2(0x16000000, 3);
+ test__clzsi2(0x17000000, 3);
+ test__clzsi2(0x18000000, 3);
+ test__clzsi2(0x19000000, 3);
+ test__clzsi2(0x1A000000, 3);
+ test__clzsi2(0x1B000000, 3);
+ test__clzsi2(0x1C000000, 3);
+ test__clzsi2(0x1D000000, 3);
+ test__clzsi2(0x1E000000, 3);
+ test__clzsi2(0x1F000000, 3);
+ test__clzsi2(0x20000000, 2);
+ test__clzsi2(0x21000000, 2);
+ test__clzsi2(0x22000000, 2);
+ test__clzsi2(0x23000000, 2);
+ test__clzsi2(0x24000000, 2);
+ test__clzsi2(0x25000000, 2);
+ test__clzsi2(0x26000000, 2);
+ test__clzsi2(0x27000000, 2);
+ test__clzsi2(0x28000000, 2);
+ test__clzsi2(0x29000000, 2);
+ test__clzsi2(0x2A000000, 2);
+ test__clzsi2(0x2B000000, 2);
+ test__clzsi2(0x2C000000, 2);
+ test__clzsi2(0x2D000000, 2);
+ test__clzsi2(0x2E000000, 2);
+ test__clzsi2(0x2F000000, 2);
+ test__clzsi2(0x30000000, 2);
+ test__clzsi2(0x31000000, 2);
+ test__clzsi2(0x32000000, 2);
+ test__clzsi2(0x33000000, 2);
+ test__clzsi2(0x34000000, 2);
+ test__clzsi2(0x35000000, 2);
+ test__clzsi2(0x36000000, 2);
+ test__clzsi2(0x37000000, 2);
+ test__clzsi2(0x38000000, 2);
+ test__clzsi2(0x39000000, 2);
+ test__clzsi2(0x3A000000, 2);
+ test__clzsi2(0x3B000000, 2);
+ test__clzsi2(0x3C000000, 2);
+ test__clzsi2(0x3D000000, 2);
+ test__clzsi2(0x3E000000, 2);
+ test__clzsi2(0x3F000000, 2);
+ test__clzsi2(0x40000000, 1);
+ test__clzsi2(0x41000000, 1);
+ test__clzsi2(0x42000000, 1);
+ test__clzsi2(0x43000000, 1);
+ test__clzsi2(0x44000000, 1);
+ test__clzsi2(0x45000000, 1);
+ test__clzsi2(0x46000000, 1);
+ test__clzsi2(0x47000000, 1);
+ test__clzsi2(0x48000000, 1);
+ test__clzsi2(0x49000000, 1);
+ test__clzsi2(0x4A000000, 1);
+ test__clzsi2(0x4B000000, 1);
+ test__clzsi2(0x4C000000, 1);
+ test__clzsi2(0x4D000000, 1);
+ test__clzsi2(0x4E000000, 1);
+ test__clzsi2(0x4F000000, 1);
+ test__clzsi2(0x50000000, 1);
+ test__clzsi2(0x51000000, 1);
+ test__clzsi2(0x52000000, 1);
+ test__clzsi2(0x53000000, 1);
+ test__clzsi2(0x54000000, 1);
+ test__clzsi2(0x55000000, 1);
+ test__clzsi2(0x56000000, 1);
+ test__clzsi2(0x57000000, 1);
+ test__clzsi2(0x58000000, 1);
+ test__clzsi2(0x59000000, 1);
+ test__clzsi2(0x5A000000, 1);
+ test__clzsi2(0x5B000000, 1);
+ test__clzsi2(0x5C000000, 1);
+ test__clzsi2(0x5D000000, 1);
+ test__clzsi2(0x5E000000, 1);
+ test__clzsi2(0x5F000000, 1);
+ test__clzsi2(0x60000000, 1);
+ test__clzsi2(0x61000000, 1);
+ test__clzsi2(0x62000000, 1);
+ test__clzsi2(0x63000000, 1);
+ test__clzsi2(0x64000000, 1);
+ test__clzsi2(0x65000000, 1);
+ test__clzsi2(0x66000000, 1);
+ test__clzsi2(0x67000000, 1);
+ test__clzsi2(0x68000000, 1);
+ test__clzsi2(0x69000000, 1);
+ test__clzsi2(0x6A000000, 1);
+ test__clzsi2(0x6B000000, 1);
+ test__clzsi2(0x6C000000, 1);
+ test__clzsi2(0x6D000000, 1);
+ test__clzsi2(0x6E000000, 1);
+ test__clzsi2(0x6F000000, 1);
+ test__clzsi2(0x70000000, 1);
+ test__clzsi2(0x71000000, 1);
+ test__clzsi2(0x72000000, 1);
+ test__clzsi2(0x73000000, 1);
+ test__clzsi2(0x74000000, 1);
+ test__clzsi2(0x75000000, 1);
+ test__clzsi2(0x76000000, 1);
+ test__clzsi2(0x77000000, 1);
+ test__clzsi2(0x78000000, 1);
+ test__clzsi2(0x79000000, 1);
+ test__clzsi2(0x7A000000, 1);
+ test__clzsi2(0x7B000000, 1);
+ test__clzsi2(0x7C000000, 1);
+ test__clzsi2(0x7D000000, 1);
+ test__clzsi2(0x7E000000, 1);
+ test__clzsi2(0x7F000000, 1);
+ test__clzsi2(0x80000000, 0);
+ test__clzsi2(0x81000000, 0);
+ test__clzsi2(0x82000000, 0);
+ test__clzsi2(0x83000000, 0);
+ test__clzsi2(0x84000000, 0);
+ test__clzsi2(0x85000000, 0);
+ test__clzsi2(0x86000000, 0);
+ test__clzsi2(0x87000000, 0);
+ test__clzsi2(0x88000000, 0);
+ test__clzsi2(0x89000000, 0);
+ test__clzsi2(0x8A000000, 0);
+ test__clzsi2(0x8B000000, 0);
+ test__clzsi2(0x8C000000, 0);
+ test__clzsi2(0x8D000000, 0);
+ test__clzsi2(0x8E000000, 0);
+ test__clzsi2(0x8F000000, 0);
+ test__clzsi2(0x90000000, 0);
+ test__clzsi2(0x91000000, 0);
+ test__clzsi2(0x92000000, 0);
+ test__clzsi2(0x93000000, 0);
+ test__clzsi2(0x94000000, 0);
+ test__clzsi2(0x95000000, 0);
+ test__clzsi2(0x96000000, 0);
+ test__clzsi2(0x97000000, 0);
+ test__clzsi2(0x98000000, 0);
+ test__clzsi2(0x99000000, 0);
+ test__clzsi2(0x9A000000, 0);
+ test__clzsi2(0x9B000000, 0);
+ test__clzsi2(0x9C000000, 0);
+ test__clzsi2(0x9D000000, 0);
+ test__clzsi2(0x9E000000, 0);
+ test__clzsi2(0x9F000000, 0);
+ test__clzsi2(0xA0000000, 0);
+ test__clzsi2(0xA1000000, 0);
+ test__clzsi2(0xA2000000, 0);
+ test__clzsi2(0xA3000000, 0);
+ test__clzsi2(0xA4000000, 0);
+ test__clzsi2(0xA5000000, 0);
+ test__clzsi2(0xA6000000, 0);
+ test__clzsi2(0xA7000000, 0);
+ test__clzsi2(0xA8000000, 0);
+ test__clzsi2(0xA9000000, 0);
+ test__clzsi2(0xAA000000, 0);
+ test__clzsi2(0xAB000000, 0);
+ test__clzsi2(0xAC000000, 0);
+ test__clzsi2(0xAD000000, 0);
+ test__clzsi2(0xAE000000, 0);
+ test__clzsi2(0xAF000000, 0);
+ test__clzsi2(0xB0000000, 0);
+ test__clzsi2(0xB1000000, 0);
+ test__clzsi2(0xB2000000, 0);
+ test__clzsi2(0xB3000000, 0);
+ test__clzsi2(0xB4000000, 0);
+ test__clzsi2(0xB5000000, 0);
+ test__clzsi2(0xB6000000, 0);
+ test__clzsi2(0xB7000000, 0);
+ test__clzsi2(0xB8000000, 0);
+ test__clzsi2(0xB9000000, 0);
+ test__clzsi2(0xBA000000, 0);
+ test__clzsi2(0xBB000000, 0);
+ test__clzsi2(0xBC000000, 0);
+ test__clzsi2(0xBD000000, 0);
+ test__clzsi2(0xBE000000, 0);
+ test__clzsi2(0xBF000000, 0);
+ test__clzsi2(0xC0000000, 0);
+ test__clzsi2(0xC1000000, 0);
+ test__clzsi2(0xC2000000, 0);
+ test__clzsi2(0xC3000000, 0);
+ test__clzsi2(0xC4000000, 0);
+ test__clzsi2(0xC5000000, 0);
+ test__clzsi2(0xC6000000, 0);
+ test__clzsi2(0xC7000000, 0);
+ test__clzsi2(0xC8000000, 0);
+ test__clzsi2(0xC9000000, 0);
+ test__clzsi2(0xCA000000, 0);
+ test__clzsi2(0xCB000000, 0);
+ test__clzsi2(0xCC000000, 0);
+ test__clzsi2(0xCD000000, 0);
+ test__clzsi2(0xCE000000, 0);
+ test__clzsi2(0xCF000000, 0);
+ test__clzsi2(0xD0000000, 0);
+ test__clzsi2(0xD1000000, 0);
+ test__clzsi2(0xD2000000, 0);
+ test__clzsi2(0xD3000000, 0);
+ test__clzsi2(0xD4000000, 0);
+ test__clzsi2(0xD5000000, 0);
+ test__clzsi2(0xD6000000, 0);
+ test__clzsi2(0xD7000000, 0);
+ test__clzsi2(0xD8000000, 0);
+ test__clzsi2(0xD9000000, 0);
+ test__clzsi2(0xDA000000, 0);
+ test__clzsi2(0xDB000000, 0);
+ test__clzsi2(0xDC000000, 0);
+ test__clzsi2(0xDD000000, 0);
+ test__clzsi2(0xDE000000, 0);
+ test__clzsi2(0xDF000000, 0);
+ test__clzsi2(0xE0000000, 0);
+ test__clzsi2(0xE1000000, 0);
+ test__clzsi2(0xE2000000, 0);
+ test__clzsi2(0xE3000000, 0);
+ test__clzsi2(0xE4000000, 0);
+ test__clzsi2(0xE5000000, 0);
+ test__clzsi2(0xE6000000, 0);
+ test__clzsi2(0xE7000000, 0);
+ test__clzsi2(0xE8000000, 0);
+ test__clzsi2(0xE9000000, 0);
+ test__clzsi2(0xEA000000, 0);
+ test__clzsi2(0xEB000000, 0);
+ test__clzsi2(0xEC000000, 0);
+ test__clzsi2(0xED000000, 0);
+ test__clzsi2(0xEE000000, 0);
+ test__clzsi2(0xEF000000, 0);
+ test__clzsi2(0xF0000000, 0);
+ test__clzsi2(0xF1000000, 0);
+ test__clzsi2(0xF2000000, 0);
+ test__clzsi2(0xF3000000, 0);
+ test__clzsi2(0xF4000000, 0);
+ test__clzsi2(0xF5000000, 0);
+ test__clzsi2(0xF6000000, 0);
+ test__clzsi2(0xF7000000, 0);
+ test__clzsi2(0xF8000000, 0);
+ test__clzsi2(0xF9000000, 0);
+ test__clzsi2(0xFA000000, 0);
+ test__clzsi2(0xFB000000, 0);
+ test__clzsi2(0xFC000000, 0);
+ test__clzsi2(0xFD000000, 0);
+ test__clzsi2(0xFE000000, 0);
+ test__clzsi2(0xFF000000, 0);
+ test__clzsi2(0x00000001, 31);
+ test__clzsi2(0x00000002, 30);
+ test__clzsi2(0x00000004, 29);
+ test__clzsi2(0x00000008, 28);
+ test__clzsi2(0x00000010, 27);
+ test__clzsi2(0x00000020, 26);
+ test__clzsi2(0x00000040, 25);
+ test__clzsi2(0x00000080, 24);
+ test__clzsi2(0x00000100, 23);
+ test__clzsi2(0x00000200, 22);
+ test__clzsi2(0x00000400, 21);
+ test__clzsi2(0x00000800, 20);
+ test__clzsi2(0x00001000, 19);
+ test__clzsi2(0x00002000, 18);
+ test__clzsi2(0x00004000, 17);
+ test__clzsi2(0x00008000, 16);
+ test__clzsi2(0x00010000, 15);
+ test__clzsi2(0x00020000, 14);
+ test__clzsi2(0x00040000, 13);
+ test__clzsi2(0x00080000, 12);
+ test__clzsi2(0x00100000, 11);
+ test__clzsi2(0x00200000, 10);
+ test__clzsi2(0x00400000, 9);
+}
From b9f4ac86efc8bd1e53c75d204aa6f08c2df58be3 Mon Sep 17 00:00:00 2001
From: Michael Dusan
Date: Fri, 17 Jan 2020 19:39:43 -0500
Subject: [PATCH 20/37] cmake: support `make` and `make install`
(2nd attempt to get this right)
---
CMakeLists.txt | 41 +++++++++++++++++++++++++++++------------
CONTRIBUTING.md | 33 +++++++++++++++++++--------------
cmake/install.cmake | 37 +++++++++++++++++++++++++++++++++++++
3 files changed, 85 insertions(+), 26 deletions(-)
create mode 100644 cmake/install.cmake
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 64aa7d1bd4..2695412028 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -45,7 +45,6 @@ message("Configuring zig version ${ZIG_VERSION}")
set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries")
-set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL "Disable copying lib/ files to install prefix")
set(ZIG_ENABLE_MEM_PROFILE off CACHE BOOL "Activate memory usage instrumentation")
if(ZIG_STATIC)
@@ -608,19 +607,26 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
else()
set(LIBUSERLAND_RELEASE_MODE "true")
endif()
-if(ZIG_SKIP_INSTALL_LIB_FILES)
- set(ZIG_BUILD_INSTALL_STEP "")
-else()
- set(ZIG_BUILD_INSTALL_STEP "install")
+
+set(BUILD_LIBUSERLAND_ARGS "build"
+ --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
+ "-Doutput-dir=${CMAKE_BINARY_DIR}"
+ "-Drelease=${LIBUSERLAND_RELEASE_MODE}"
+ "-Dlib-files-only"
+ --prefix "${CMAKE_INSTALL_PREFIX}"
+ libuserland
+)
+
+# When using Visual Studio build system generator we default to libuserland install.
+if(MSVC)
+ set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL "Disable copying lib/ files to install prefix")
+ if(NOT ZIG_SKIP_INSTALL_LIB_FILES)
+ set(BUILD_LIBUSERLAND_ARGS ${BUILD_LIBUSERLAND_ARGS} install)
+ endif()
endif()
+
add_custom_target(zig_build_libuserland ALL
- COMMAND zig0 build
- --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
- libuserland ${ZIG_BUILD_INSTALL_STEP}
- "-Doutput-dir=${CMAKE_BINARY_DIR}"
- "-Drelease=${LIBUSERLAND_RELEASE_MODE}"
- "-Dlib-files-only"
- --prefix "${CMAKE_INSTALL_PREFIX}"
+ COMMAND zig0 ${BUILD_LIBUSERLAND_ARGS}
DEPENDS zig0
BYPRODUCTS "${LIBUSERLAND}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
@@ -638,4 +644,15 @@ elseif(MINGW)
target_link_libraries(zig ntdll)
endif()
add_dependencies(zig zig_build_libuserland)
+
install(TARGETS zig DESTINATION bin)
+
+# CODE has no effect with Visual Studio build system generator.
+if(NOT MSVC)
+ get_target_property(zig0_BINARY_DIR zig0 BINARY_DIR)
+ install(CODE "set(zig0_EXE \"${zig0_BINARY_DIR}/zig0\")")
+ install(CODE "set(INSTALL_LIBUSERLAND_ARGS \"${BUILD_LIBUSERLAND_ARGS}\" install)")
+ install(CODE "set(BUILD_LIBUSERLAND_ARGS \"${BUILD_LIBUSERLAND_ARGS}\")")
+ install(CODE "set(CMAKE_SOURCE_DIR \"${CMAKE_SOURCE_DIR}\")")
+ install(SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/cmake/install.cmake)
+endif()
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a5aeeb9e21..62b8083222 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -51,23 +51,28 @@ knowledge of Zig internals.**
### Editing Source Code
-First, build the Stage 1 compiler as described in [the Building section](#building).
+First, build the Stage 1 compiler as described in [Building from Source](README.md#Building-from-Source).
-One modification you may want to make is adding `-DZIG_SKIP_INSTALL_LIB_FILES=ON`
-to the cmake line. If you use the build directory as a working directory to run
-tests with, zig will find the lib files in the source directory, and they will not
-be "installed" every time you run `make`. This will allow you to make modifications
-directly to the standard library, for example, and have them effective immediately.
-Note that if you already ran `make` or `make install` with the default cmake
-settings, there will already be a `lib/` directory in your build directory. When
-executed from the build directory, zig will find this instead of the source lib/
-directory. Remove the unwanted directory so that the desired one can be found.
+Zig locates lib files relative to executable path by searching up the
+filesystem tree for a sub-path of `lib/zig/std/std.zig` or `lib/std/std.zig`.
+Typically the former is an install and the latter a git working tree which
+contains the build directory.
+
+During development it is not necessary to perform installs when modifying
+stage1 or userland sources and in fact it is faster and simpler to run,
+test and debug from a git working tree.
+
+- `make` is typically sufficient to build zig during development iterations.
+- `make install` performs a build __and__ install.
+- `msbuild -p:Configuration=Release INSTALL.vcxproj` on Windows performs a
+build and install. To avoid install, pass cmake option `-DZIG_SKIP_INSTALL_LIB_FILES=ON`.
To test changes, do the following from the build directory:
-1. Run `make install` (on POSIX) or
+1. Run `make` (on POSIX) or
`msbuild -p:Configuration=Release INSTALL.vcxproj` (on Windows).
-2. `bin/zig build test` (on POSIX) or `bin\zig.exe build test` (on Windows).
+2. `$BUILD_DIR/zig build test` (on POSIX) or
+ `$BUILD_DIR/Release\zig.exe build test` (on Windows).
That runs the whole test suite, which does a lot of extra testing that you
likely won't always need, and can take upwards of 1 hour. This is what the
@@ -85,8 +90,8 @@ Another example is choosing a different set of things to test. For example,
not the other ones. Combining this suggestion with the previous one, you could
do this:
-`bin/zig build test-std -Dskip-release` (on POSIX) or
-`bin\zig.exe build test-std -Dskip-release` (on Windows).
+`$BUILD_DIR/bin/zig build test-std -Dskip-release` (on POSIX) or
+`$BUILD_DIR/Release\zig.exe build test-std -Dskip-release` (on Windows).
This will run only the standard library tests, in debug mode only, for all
targets (it will cross-compile the tests for non-native targets but not run
diff --git a/cmake/install.cmake b/cmake/install.cmake
new file mode 100644
index 0000000000..415a088d6a
--- /dev/null
+++ b/cmake/install.cmake
@@ -0,0 +1,37 @@
+message("-- Installing: ${CMAKE_INSTALL_PREFIX}/lib")
+
+if(NOT EXISTS ${zig0_EXE})
+ message("::")
+ message(":: ERROR: Executable not found")
+ message(":: (execute_process)")
+ message("::")
+ message(":: executable: ${zig0_EXE}")
+ message("::")
+ message(FATAL_ERROR)
+endif()
+
+execute_process(COMMAND ${zig0_EXE} ${INSTALL_LIBUSERLAND_ARGS}
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ RESULT_VARIABLE _result
+)
+if(_result)
+ message("::")
+ message(":: ERROR: ${_result}")
+ message(":: (execute_process)")
+
+ string(REPLACE ";" " " s_INSTALL_LIBUSERLAND_ARGS "${INSTALL_LIBUSERLAND_ARGS}")
+ message("::")
+ message(":: argv: ${zig0_EXE} ${s_INSTALL_LIBUSERLAND_ARGS} install")
+
+ set(_args ${zig0_EXE} ${INSTALL_LIBUSERLAND_ARGS})
+ list(LENGTH _args _len)
+ math(EXPR _len "${_len} - 1")
+ message("::")
+ foreach(_i RANGE 0 ${_len})
+ list(GET _args ${_i} _arg)
+ message(":: argv[${_i}]: ${_arg}")
+ endforeach()
+
+ message("::")
+ message(FATAL_ERROR)
+endif()
From 5f2bac010df0a2cf1e36622d6742baf13f4ffe75 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sat, 18 Jan 2020 09:55:18 +0100
Subject: [PATCH 21/37] Allow @tagName on enum literals
Closes #4214
---
src/ir.cpp | 12 ++++++++++--
test/stage1/behavior/enum.zig | 5 +++++
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 88b4c1a832..7f6a1963c5 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -21389,9 +21389,9 @@ static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source
if (type_is_invalid(value->value->type))
return ira->codegen->invalid_instruction;
- if (value->value->type->id == ZigTypeIdEnum) {
+ if (value->value->type->id == ZigTypeIdEnum ||
+ value->value->type->id == ZigTypeIdEnumLiteral)
return value;
- }
if (value->value->type->id != ZigTypeIdUnion) {
ir_add_error(ira, value,
@@ -22352,6 +22352,14 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns
if (type_is_invalid(target->value->type))
return ira->codegen->invalid_instruction;
+ if (target->value->type->id == ZigTypeIdEnumLiteral) {
+ IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
+ Buf *field_name = target->value->data.x_enum_literal;
+ ZigValue *array_val = create_const_str_lit(ira->codegen, field_name)->data.x_ptr.data.ref.pointee;
+ init_const_slice(ira->codegen, result->value, array_val, 0, buf_len(field_name), true);
+ return result;
+ }
+
assert(target->value->type->id == ZigTypeIdEnum);
if (instr_is_comptime(target)) {
diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig
index 83ad76b72c..5532a3ddf5 100644
--- a/test/stage1/behavior/enum.zig
+++ b/test/stage1/behavior/enum.zig
@@ -1094,3 +1094,8 @@ test "enum with one member default to u0 tag type" {
};
comptime expect(@TagType(E0) == u0);
}
+
+test "tagName on enum literals" {
+ expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
+ comptime expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
+}
From c53d94e5127a8dcfefd906c5be0e6b81eaf3d22c Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sat, 18 Jan 2020 15:13:21 +0100
Subject: [PATCH 22/37] Prevent crash with empty non-exhaustive enum
---
src/analyze.cpp | 2 +-
src/ir.cpp | 2 +-
test/stage1/behavior/enum.zig | 20 ++++++++++++++++++++
3 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index e064677a09..0bbec66a9b 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -8312,7 +8312,7 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type, ResolveStatu
uint32_t field_count = enum_type->data.enumeration.src_field_count;
- assert(enum_type->data.enumeration.fields);
+ assert(field_count == 0 || enum_type->data.enumeration.fields != nullptr);
ZigLLVMDIEnumerator **di_enumerators = allocate(field_count);
for (uint32_t i = 0; i < field_count; i += 1) {
diff --git a/src/ir.cpp b/src/ir.cpp
index 88b4c1a832..ae02ac9cae 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -21631,7 +21631,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
case ZigTypeIdEnum: {
if ((err = type_resolve(ira->codegen, target_type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_instruction;
- if (target_type->data.enumeration.src_field_count < 2) {
+ if (target_type->data.enumeration.src_field_count == 1) {
TypeEnumField *only_field = &target_type->data.enumeration.fields[0];
IrInstruction *result = ir_const(ira, &switch_target_instruction->base, target_type);
bigint_init_bigint(&result->value->data.x_enum_tag, &only_field->value);
diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig
index 83ad76b72c..a478729003 100644
--- a/test/stage1/behavior/enum.zig
+++ b/test/stage1/behavior/enum.zig
@@ -65,6 +65,26 @@ test "non-exhaustive enum" {
comptime S.doTheTest(52);
}
+test "empty non-exhaustive enum" {
+ const S = struct {
+ const E = enum(u8) {
+ _,
+ };
+ fn doTheTest(y: u8) void {
+ var e = @intToEnum(E, y);
+ expect(switch (e) {
+ _ => true,
+ });
+ expect(@enumToInt(e) == y);
+
+ expect(@typeInfo(E).Enum.fields.len == 0);
+ expect(@typeInfo(E).Enum.is_exhaustive == false);
+ }
+ };
+ S.doTheTest(42);
+ comptime S.doTheTest(42);
+}
+
test "enum type" {
const foo1 = Foo{ .One = 13 };
const foo2 = Foo{
From f456b88baecc0a841520035973e6887eb2573319 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sat, 18 Jan 2020 19:24:04 +0100
Subject: [PATCH 23/37] Get rid of some dead logic
---
src/ir.cpp | 25 +++++++------------------
1 file changed, 7 insertions(+), 18 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index 7f6a1963c5..42a5043279 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -6030,8 +6030,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
- IrInstruction *actual_tag = ir_build_union_tag(irb, scope, node, arg0_value);
- IrInstruction *tag_name = ir_build_tag_name(irb, scope, node, actual_tag);
+ IrInstruction *tag_name = ir_build_tag_name(irb, scope, node, arg0_value);
return ir_lval_wrap(irb, scope, tag_name, lval, result_loc);
}
case BuiltinFnIdTagType:
@@ -21389,10 +21388,6 @@ static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source
if (type_is_invalid(value->value->type))
return ira->codegen->invalid_instruction;
- if (value->value->type->id == ZigTypeIdEnum ||
- value->value->type->id == ZigTypeIdEnumLiteral)
- return value;
-
if (value->value->type->id != ZigTypeIdUnion) {
ir_add_error(ira, value,
buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value->type->name)));
@@ -21460,12 +21455,6 @@ static IrInstruction *ir_analyze_instruction_switch_br(IrAnalyze *ira,
if (type_is_invalid(case_value->value->type))
return ir_unreach_error(ira);
- if (case_value->value->type->id == ZigTypeIdEnum) {
- case_value = ir_analyze_union_tag(ira, &switch_br_instruction->base, case_value);
- if (type_is_invalid(case_value->value->type))
- return ir_unreach_error(ira);
- }
-
IrInstruction *casted_case_value = ir_implicit_cast(ira, case_value, target_value->value->type);
if (type_is_invalid(casted_case_value->value->type))
return ir_unreach_error(ira);
@@ -21510,12 +21499,6 @@ static IrInstruction *ir_analyze_instruction_switch_br(IrAnalyze *ira,
if (type_is_invalid(new_value->value->type))
continue;
- if (new_value->value->type->id == ZigTypeIdEnum) {
- new_value = ir_analyze_union_tag(ira, &switch_br_instruction->base, new_value);
- if (type_is_invalid(new_value->value->type))
- continue;
- }
-
IrInstruction *casted_new_value = ir_implicit_cast(ira, new_value, target_value->value->type);
if (type_is_invalid(casted_new_value->value->type))
continue;
@@ -22360,6 +22343,12 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns
return result;
}
+ if (target->value->type->id == ZigTypeIdUnion) {
+ target = ir_analyze_union_tag(ira, &instruction->base, target);
+ if (type_is_invalid(target->value->type))
+ return ira->codegen->invalid_instruction;
+ }
+
assert(target->value->type->id == ZigTypeIdEnum);
if (instr_is_comptime(target)) {
From b0f753e21d6fcaafd0b35dc02fdfe23b14e310d6 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sat, 18 Jan 2020 19:58:05 +0100
Subject: [PATCH 24/37] Fix edge case in tagName handling of unions
Closes #4226
---
src/ir.cpp | 9 +++++++++
test/stage1/behavior/union.zig | 9 +++++++++
2 files changed, 18 insertions(+)
diff --git a/src/ir.cpp b/src/ir.cpp
index ae02ac9cae..ff4b552a9b 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -22354,6 +22354,15 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns
assert(target->value->type->id == ZigTypeIdEnum);
+ if (target->value->type->data.enumeration.src_field_count == 1 &&
+ !target->value->type->data.enumeration.non_exhaustive) {
+ TypeEnumField *only_field = &target->value->type->data.enumeration.fields[0];
+ ZigValue *array_val = create_const_str_lit(ira->codegen, only_field->name)->data.x_ptr.data.ref.pointee;
+ IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
+ init_const_slice(ira->codegen, result->value, array_val, 0, buf_len(only_field->name), true);
+ return result;
+ }
+
if (instr_is_comptime(target)) {
if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_instruction;
diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig
index a24bee03e6..4625b7573a 100644
--- a/test/stage1/behavior/union.zig
+++ b/test/stage1/behavior/union.zig
@@ -629,3 +629,12 @@ test "union initializer generates padding only if needed" {
var v = U{ .A = 532 };
expect(v.A == 532);
}
+
+test "runtime tag name with single field" {
+ const U = union(enum) {
+ A: i32,
+ };
+
+ var v = U{ .A = 42 };
+ expect(std.mem.eql(u8, @tagName(v), "A"));
+}
From 9e6e1e58bb163868db51832e54c323a9ab893329 Mon Sep 17 00:00:00 2001
From: daurnimator
Date: Sat, 18 Jan 2020 11:58:29 +1000
Subject: [PATCH 25/37] std: use non-exhaustive enums from crc module
Un-reverts PR #3118
---
lib/std/hash/benchmark.zig | 4 ++--
lib/std/hash/crc.zig | 27 ++++++++++++++-------------
2 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/lib/std/hash/benchmark.zig b/lib/std/hash/benchmark.zig
index ce9ed75b58..c792013e06 100644
--- a/lib/std/hash/benchmark.zig
+++ b/lib/std/hash/benchmark.zig
@@ -47,11 +47,11 @@ const hashes = [_]Hash{
.name = "adler32",
},
Hash{
- .ty = hash.crc.Crc32WithPoly(hash.crc.Polynomial.IEEE),
+ .ty = hash.crc.Crc32WithPoly(.IEEE),
.name = "crc32-slicing-by-8",
},
Hash{
- .ty = hash.crc.Crc32SmallWithPoly(hash.crc.Polynomial.IEEE),
+ .ty = hash.crc.Crc32SmallWithPoly(.IEEE),
.name = "crc32-half-byte-lookup",
},
Hash{
diff --git a/lib/std/hash/crc.zig b/lib/std/hash/crc.zig
index 6176ded81d..506d8c8aed 100644
--- a/lib/std/hash/crc.zig
+++ b/lib/std/hash/crc.zig
@@ -9,17 +9,18 @@ const std = @import("../std.zig");
const debug = std.debug;
const testing = std.testing;
-pub const Polynomial = struct {
- pub const IEEE = 0xedb88320;
- pub const Castagnoli = 0x82f63b78;
- pub const Koopman = 0xeb31d82e;
+pub const Polynomial = enum(u32) {
+ IEEE = 0xedb88320,
+ Castagnoli = 0x82f63b78,
+ Koopman = 0xeb31d82e,
+ _,
};
// IEEE is by far the most common CRC and so is aliased by default.
-pub const Crc32 = Crc32WithPoly(Polynomial.IEEE);
+pub const Crc32 = Crc32WithPoly(.IEEE);
// slicing-by-8 crc32 implementation.
-pub fn Crc32WithPoly(comptime poly: u32) type {
+pub fn Crc32WithPoly(comptime poly: Polynomial) type {
return struct {
const Self = @This();
const lookup_tables = comptime block: {
@@ -31,7 +32,7 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
var j: usize = 0;
while (j < 8) : (j += 1) {
if (crc & 1 == 1) {
- crc = (crc >> 1) ^ poly;
+ crc = (crc >> 1) ^ @enumToInt(poly);
} else {
crc = (crc >> 1);
}
@@ -100,7 +101,7 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
}
test "crc32 ieee" {
- const Crc32Ieee = Crc32WithPoly(Polynomial.IEEE);
+ const Crc32Ieee = Crc32WithPoly(.IEEE);
testing.expect(Crc32Ieee.hash("") == 0x00000000);
testing.expect(Crc32Ieee.hash("a") == 0xe8b7be43);
@@ -108,7 +109,7 @@ test "crc32 ieee" {
}
test "crc32 castagnoli" {
- const Crc32Castagnoli = Crc32WithPoly(Polynomial.Castagnoli);
+ const Crc32Castagnoli = Crc32WithPoly(.Castagnoli);
testing.expect(Crc32Castagnoli.hash("") == 0x00000000);
testing.expect(Crc32Castagnoli.hash("a") == 0xc1d04330);
@@ -116,7 +117,7 @@ test "crc32 castagnoli" {
}
// half-byte lookup table implementation.
-pub fn Crc32SmallWithPoly(comptime poly: u32) type {
+pub fn Crc32SmallWithPoly(comptime poly: Polynomial) type {
return struct {
const Self = @This();
const lookup_table = comptime block: {
@@ -127,7 +128,7 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {
var j: usize = 0;
while (j < 8) : (j += 1) {
if (crc & 1 == 1) {
- crc = (crc >> 1) ^ poly;
+ crc = (crc >> 1) ^ @enumToInt(poly);
} else {
crc = (crc >> 1);
}
@@ -164,7 +165,7 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {
}
test "small crc32 ieee" {
- const Crc32Ieee = Crc32SmallWithPoly(Polynomial.IEEE);
+ const Crc32Ieee = Crc32SmallWithPoly(.IEEE);
testing.expect(Crc32Ieee.hash("") == 0x00000000);
testing.expect(Crc32Ieee.hash("a") == 0xe8b7be43);
@@ -172,7 +173,7 @@ test "small crc32 ieee" {
}
test "small crc32 castagnoli" {
- const Crc32Castagnoli = Crc32SmallWithPoly(Polynomial.Castagnoli);
+ const Crc32Castagnoli = Crc32SmallWithPoly(.Castagnoli);
testing.expect(Crc32Castagnoli.hash("") == 0x00000000);
testing.expect(Crc32Castagnoli.hash("a") == 0xc1d04330);
From 72ec4456779839d3df4b41055fbaf47a57b69ac8 Mon Sep 17 00:00:00 2001
From: daurnimator
Date: Sat, 18 Jan 2020 12:12:18 +1000
Subject: [PATCH 26/37] std: turn EAI_ constants into a non-exhaustive enum
---
lib/std/c.zig | 6 ++---
lib/std/c/darwin.zig | 61 +++++++++++++++++++++++--------------------
lib/std/c/freebsd.zig | 60 ++++++++++++++++++++++--------------------
lib/std/c/linux.zig | 40 +++++++++++++++-------------
lib/std/net.zig | 24 ++++++++---------
5 files changed, 102 insertions(+), 89 deletions(-)
diff --git a/lib/std/c.zig b/lib/std/c.zig
index 45d0b4db03..c912c72418 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -185,7 +185,7 @@ pub extern "c" fn getaddrinfo(
noalias service: [*:0]const u8,
noalias hints: *const addrinfo,
noalias res: **addrinfo,
-) c_int;
+) EAI;
pub extern "c" fn freeaddrinfo(res: *addrinfo) void;
@@ -197,9 +197,9 @@ pub extern "c" fn getnameinfo(
noalias serv: [*]u8,
servlen: socklen_t,
flags: u32,
-) c_int;
+) EAI;
-pub extern "c" fn gai_strerror(errcode: c_int) [*:0]const u8;
+pub extern "c" fn gai_strerror(errcode: EAI) [*:0]const u8;
pub extern "c" fn poll(fds: [*]pollfd, nfds: nfds_t, timeout: c_int) c_int;
diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig
index bcb5a38ba3..bc58b1fba1 100644
--- a/lib/std/c/darwin.zig
+++ b/lib/std/c/darwin.zig
@@ -70,47 +70,52 @@ pub const AI_NUMERICHOST = 0x00000004;
/// prevent service name resolution
pub const AI_NUMERICSERV = 0x00001000;
-/// address family for hostname not supported
-pub const EAI_ADDRFAMILY = 1;
+pub const EAI = extern enum(c_int) {
+ /// address family for hostname not supported
+ ADDRFAMILY = 1,
-/// temporary failure in name resolution
-pub const EAI_AGAIN = 2;
+ /// temporary failure in name resolution
+ AGAIN = 2,
-/// invalid value for ai_flags
-pub const EAI_BADFLAGS = 3;
+ /// invalid value for ai_flags
+ BADFLAGS = 3,
-/// non-recoverable failure in name resolution
-pub const EAI_FAIL = 4;
+ /// non-recoverable failure in name resolution
+ FAIL = 4,
-/// ai_family not supported
-pub const EAI_FAMILY = 5;
+ /// ai_family not supported
+ FAMILY = 5,
-/// memory allocation failure
-pub const EAI_MEMORY = 6;
+ /// memory allocation failure
+ MEMORY = 6,
-/// no address associated with hostname
-pub const EAI_NODATA = 7;
+ /// no address associated with hostname
+ NODATA = 7,
-/// hostname nor servname provided, or not known
-pub const EAI_NONAME = 8;
+ /// hostname nor servname provided, or not known
+ NONAME = 8,
-/// servname not supported for ai_socktype
-pub const EAI_SERVICE = 9;
+ /// servname not supported for ai_socktype
+ SERVICE = 9,
-/// ai_socktype not supported
-pub const EAI_SOCKTYPE = 10;
+ /// ai_socktype not supported
+ SOCKTYPE = 10,
-/// system error returned in errno
-pub const EAI_SYSTEM = 11;
+ /// system error returned in errno
+ SYSTEM = 11,
-/// invalid value for hints
-pub const EAI_BADHINTS = 12;
+ /// invalid value for hints
+ BADHINTS = 12,
-/// resolved protocol is unknown
-pub const EAI_PROTOCOL = 13;
+ /// resolved protocol is unknown
+ PROTOCOL = 13,
+
+ /// argument buffer overflow
+ OVERFLOW = 14,
+
+ _,
+};
-/// argument buffer overflow
-pub const EAI_OVERFLOW = 14;
pub const EAI_MAX = 15;
pub const pthread_mutex_t = extern struct {
diff --git a/lib/std/c/freebsd.zig b/lib/std/c/freebsd.zig
index 95e27a7d92..4c6614c978 100644
--- a/lib/std/c/freebsd.zig
+++ b/lib/std/c/freebsd.zig
@@ -23,47 +23,51 @@ pub const pthread_attr_t = extern struct {
__align: c_long,
};
-/// address family for hostname not supported
-pub const EAI_ADDRFAMILY = 1;
+pub const EAI = extern enum(c_int) {
+ /// address family for hostname not supported
+ ADDRFAMILY = 1,
-/// name could not be resolved at this time
-pub const EAI_AGAIN = 2;
+ /// name could not be resolved at this time
+ AGAIN = 2,
-/// flags parameter had an invalid value
-pub const EAI_BADFLAGS = 3;
+ /// flags parameter had an invalid value
+ BADFLAGS = 3,
-/// non-recoverable failure in name resolution
-pub const EAI_FAIL = 4;
+ /// non-recoverable failure in name resolution
+ FAIL = 4,
-/// address family not recognized
-pub const EAI_FAMILY = 5;
+ /// address family not recognized
+ FAMILY = 5,
-/// memory allocation failure
-pub const EAI_MEMORY = 6;
+ /// memory allocation failure
+ MEMORY = 6,
-/// no address associated with hostname
-pub const EAI_NODATA = 7;
+ /// no address associated with hostname
+ NODATA = 7,
-/// name does not resolve
-pub const EAI_NONAME = 8;
+ /// name does not resolve
+ NONAME = 8,
-/// service not recognized for socket type
-pub const EAI_SERVICE = 9;
+ /// service not recognized for socket type
+ SERVICE = 9,
-/// intended socket type was not recognized
-pub const EAI_SOCKTYPE = 10;
+ /// intended socket type was not recognized
+ SOCKTYPE = 10,
-/// system error returned in errno
-pub const EAI_SYSTEM = 11;
+ /// system error returned in errno
+ SYSTEM = 11,
-/// invalid value for hints
-pub const EAI_BADHINTS = 12;
+ /// invalid value for hints
+ BADHINTS = 12,
-/// resolved protocol is unknown
-pub const EAI_PROTOCOL = 13;
+ /// resolved protocol is unknown
+ PROTOCOL = 13,
-/// argument buffer overflow
-pub const EAI_OVERFLOW = 14;
+ /// argument buffer overflow
+ OVERFLOW = 14,
+
+ _,
+};
pub const EAI_MAX = 15;
diff --git a/lib/std/c/linux.zig b/lib/std/c/linux.zig
index 9969474097..0f7abaaaa0 100644
--- a/lib/std/c/linux.zig
+++ b/lib/std/c/linux.zig
@@ -32,25 +32,29 @@ pub const NI_NAMEREQD = 0x08;
pub const NI_DGRAM = 0x10;
pub const NI_NUMERICSCOPE = 0x100;
-pub const EAI_BADFLAGS = -1;
-pub const EAI_NONAME = -2;
-pub const EAI_AGAIN = -3;
-pub const EAI_FAIL = -4;
-pub const EAI_FAMILY = -6;
-pub const EAI_SOCKTYPE = -7;
-pub const EAI_SERVICE = -8;
-pub const EAI_MEMORY = -10;
-pub const EAI_SYSTEM = -11;
-pub const EAI_OVERFLOW = -12;
+pub const EAI = extern enum(c_int) {
+ BADFLAGS = -1,
+ NONAME = -2,
+ AGAIN = -3,
+ FAIL = -4,
+ FAMILY = -6,
+ SOCKTYPE = -7,
+ SERVICE = -8,
+ MEMORY = -10,
+ SYSTEM = -11,
+ OVERFLOW = -12,
-pub const EAI_NODATA = -5;
-pub const EAI_ADDRFAMILY = -9;
-pub const EAI_INPROGRESS = -100;
-pub const EAI_CANCELED = -101;
-pub const EAI_NOTCANCELED = -102;
-pub const EAI_ALLDONE = -103;
-pub const EAI_INTR = -104;
-pub const EAI_IDN_ENCODE = -105;
+ NODATA = -5,
+ ADDRFAMILY = -9,
+ INPROGRESS = -100,
+ CANCELED = -101,
+ NOTCANCELED = -102,
+ ALLDONE = -103,
+ INTR = -104,
+ IDN_ENCODE = -105,
+
+ _,
+};
pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize;
pub extern "c" fn sched_getaffinity(pid: c_int, size: usize, set: *cpu_set_t) c_int;
diff --git a/lib/std/net.zig b/lib/std/net.zig
index 47ce95c99f..c113462855 100644
--- a/lib/std/net.zig
+++ b/lib/std/net.zig
@@ -452,18 +452,18 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
};
var res: *os.addrinfo = undefined;
switch (os.system.getaddrinfo(name_c.ptr, @ptrCast([*:0]const u8, port_c.ptr), &hints, &res)) {
- 0 => {},
- c.EAI_ADDRFAMILY => return error.HostLacksNetworkAddresses,
- c.EAI_AGAIN => return error.TemporaryNameServerFailure,
- c.EAI_BADFLAGS => unreachable, // Invalid hints
- c.EAI_FAIL => return error.NameServerFailure,
- c.EAI_FAMILY => return error.AddressFamilyNotSupported,
- c.EAI_MEMORY => return error.OutOfMemory,
- c.EAI_NODATA => return error.HostLacksNetworkAddresses,
- c.EAI_NONAME => return error.UnknownHostName,
- c.EAI_SERVICE => return error.ServiceUnavailable,
- c.EAI_SOCKTYPE => unreachable, // Invalid socket type requested in hints
- c.EAI_SYSTEM => switch (os.errno(-1)) {
+ @intToEnum(os.system.EAI, 0) => {},
+ .ADDRFAMILY => return error.HostLacksNetworkAddresses,
+ .AGAIN => return error.TemporaryNameServerFailure,
+ .BADFLAGS => unreachable, // Invalid hints
+ .FAIL => return error.NameServerFailure,
+ .FAMILY => return error.AddressFamilyNotSupported,
+ .MEMORY => return error.OutOfMemory,
+ .NODATA => return error.HostLacksNetworkAddresses,
+ .NONAME => return error.UnknownHostName,
+ .SERVICE => return error.ServiceUnavailable,
+ .SOCKTYPE => unreachable, // Invalid socket type requested in hints
+ .SYSTEM => switch (os.errno(-1)) {
else => |e| return os.unexpectedErrno(e),
},
else => unreachable,
From 405b8e9eeefda07b16044690471cfd57fc654c75 Mon Sep 17 00:00:00 2001
From: Sebastian
Date: Sat, 18 Jan 2020 22:15:42 +0000
Subject: [PATCH 27/37] fixed typo - "path" lead to undeclared identifier
---
lib/std/dynamic_library.zig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/std/dynamic_library.zig b/lib/std/dynamic_library.zig
index db912ec922..ef64870b8d 100644
--- a/lib/std/dynamic_library.zig
+++ b/lib/std/dynamic_library.zig
@@ -277,7 +277,7 @@ pub const WindowsDynLib = struct {
}
pub fn openC(path_c: [*:0]const u8) !WindowsDynLib {
- const path_w = try windows.cStrToPrefixedFileW(path);
+ const path_w = try windows.cStrToPrefixedFileW(path_c);
return openW(&path_w);
}
From fa52c9e36efde38f6d1c6e280636ba7f6cb6f83a Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sat, 18 Jan 2020 18:11:20 +0100
Subject: [PATCH 28/37] Small cleanups
---
lib/std/os/bits/linux.zig | 2 +-
lib/std/special/compiler_rt/clzsi2.zig | 70 +++++++++++++-------------
lib/std/start.zig | 13 +----
lib/std/target.zig | 38 ++++++++++++++
4 files changed, 75 insertions(+), 48 deletions(-)
diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig
index 51ea49005e..f4024e1f1d 100644
--- a/lib/std/os/bits/linux.zig
+++ b/lib/std/os/bits/linux.zig
@@ -18,7 +18,7 @@ pub usingnamespace switch (builtin.arch) {
else => struct {},
};
-const is_mips = builtin.arch == .mipsel;
+const is_mips = builtin.arch.isMIPS();
pub const pid_t = i32;
pub const fd_t = i32;
diff --git a/lib/std/special/compiler_rt/clzsi2.zig b/lib/std/special/compiler_rt/clzsi2.zig
index 0cbfdb8db1..6a69ae75f1 100644
--- a/lib/std/special/compiler_rt/clzsi2.zig
+++ b/lib/std/special/compiler_rt/clzsi2.zig
@@ -1,10 +1,5 @@
-// Ported from:
-//
-// https://github.com/llvm-mirror/compiler-rt/blob/f0745e8476f069296a7c71accedd061dce4cdf79/lib/builtins/clzsi2.c
-// https://github.com/llvm-mirror/compiler-rt/blob/f0745e8476f069296a7c71accedd061dce4cdf79/lib/builtins/arm/clzsi2.S
const builtin = @import("builtin");
-// Precondition: a != 0
fn __clzsi2_generic(a: i32) callconv(.C) i32 {
@setRuntimeSafety(builtin.is_test);
@@ -24,15 +19,42 @@ fn __clzsi2_generic(a: i32) callconv(.C) i32 {
return n - @bitCast(i32, x);
}
-fn __clzsi2_arm_clz(a: i32) callconv(.Naked) noreturn {
+fn __clzsi2_thumb1() callconv(.Naked) void {
+ @setRuntimeSafety(builtin.is_test);
+
+ // Similar to the generic version with the last two rounds replaced by a LUT
asm volatile (
- \\ clz r0,r0
+ \\ movs r1, #32
+ \\ lsrs r2, r0, #16
+ \\ beq 1f
+ \\ subs r1, #16
+ \\ movs r0, r2
+ \\ 1:
+ \\ lsrs r2, r0, #8
+ \\ beq 1f
+ \\ subs r1, #8
+ \\ movs r0, r2
+ \\ 1:
+ \\ lsrs r2, r0, #4
+ \\ beq 1f
+ \\ subs r1, #4
+ \\ movs r0, r2
+ \\ 1:
+ \\ ldr r3, =LUT
+ \\ ldrb r0, [r3, r0]
+ \\ subs r0, r1, r0
\\ bx lr
+ \\ .p2align 2
+ \\ LUT:
+ \\ .byte 4,3,2,2,1,1,1,1,0,0,0,0,0,0,0,0
);
+
unreachable;
}
-fn __clzsi2_arm32(a: i32) callconv(.Naked) noreturn {
+fn __clzsi2_arm32() callconv(.Naked) void {
+ @setRuntimeSafety(builtin.is_test);
+
asm volatile (
\\ // Assumption: n != 0
\\ // r0: n
@@ -75,39 +97,15 @@ fn __clzsi2_arm32(a: i32) callconv(.Naked) noreturn {
\\ sub r0, r1, r0, lsr #1
\\ bx lr
);
+
unreachable;
}
-const can_use_arm_clz = switch (builtin.arch) {
- .arm, .armeb => |sub_arch| switch (sub_arch) {
- .v4t => false,
- .v6m => false,
- else => true,
- },
- .thumb, .thumbeb => |sub_arch| switch (sub_arch) {
- .v6,
- .v6k,
- .v5,
- .v5te,
- .v4t,
- => false,
- else => true,
- },
- else => false,
-};
-
-const is_arm32_no_thumb = switch (builtin.arch) {
- builtin.Arch.arm,
- builtin.Arch.armeb,
- => true,
- else => false,
-};
-
pub const __clzsi2 = blk: {
- if (comptime can_use_arm_clz) {
- break :blk __clzsi2_arm_clz;
- } else if (comptime is_arm32_no_thumb) {
+ if (builtin.arch.isARM()) {
break :blk __clzsi2_arm32;
+ } else if (builtin.arch.isThumb()) {
+ break :blk __clzsi2_thumb1;
} else {
break :blk __clzsi2_generic;
}
diff --git a/lib/std/start.zig b/lib/std/start.zig
index c3844e4d1e..bf6f61f25f 100644
--- a/lib/std/start.zig
+++ b/lib/std/start.zig
@@ -8,16 +8,7 @@ const uefi = std.os.uefi;
var starting_stack_ptr: [*]usize = undefined;
-const is_wasm = switch (builtin.arch) {
- .wasm32, .wasm64 => true,
- else => false,
-};
-
-const is_mips = switch (builtin.arch) {
- .mips, .mipsel, .mips64, .mips64el => true,
- else => false,
-};
-const start_sym_name = if (is_mips) "__start" else "_start";
+const start_sym_name = if (builtin.arch.isMIPS()) "__start" else "_start";
comptime {
if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) {
@@ -35,7 +26,7 @@ comptime {
}
} else if (builtin.os == .uefi) {
if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" });
- } else if (is_wasm and builtin.os == .freestanding) {
+ } else if (builtin.arch.isWasm() and builtin.os == .freestanding) {
if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name });
} else if (builtin.os != .other and builtin.os != .freestanding) {
if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name });
diff --git a/lib/std/target.zig b/lib/std/target.zig
index 22fea691c4..d62786ff7f 100644
--- a/lib/std/target.zig
+++ b/lib/std/target.zig
@@ -125,6 +125,16 @@ pub const Target = union(enum) {
v5,
v5te,
v4t,
+
+ pub fn version(version: Arm32) comptime_int {
+ return switch (version) {
+ .v8_5a, .v8_4a, .v8_3a, .v8_2a, .v8_1a, .v8, .v8r, .v8m_baseline, .v8m_mainline, .v8_1m_mainline => 8,
+ .v7, .v7em, .v7m, .v7s, .v7k, .v7ve => 7,
+ .v6, .v6m, .v6k, .v6t2 => 6,
+ .v5, .v5te => 5,
+ .v4t => 4,
+ };
+ }
};
pub const Arm64 = enum {
v8_5a,
@@ -146,6 +156,34 @@ pub const Target = union(enum) {
r6,
};
+ pub fn isARM(arch: Arch) bool {
+ return switch (arch) {
+ .arm, .armeb => true,
+ else => false,
+ };
+ }
+
+ pub fn isThumb(arch: Arch) bool {
+ return switch (arch) {
+ .thumb, .thumbeb => true,
+ else => false,
+ };
+ }
+
+ pub fn isWasm(arch: Arch) bool {
+ return switch (arch) {
+ .wasm32, .wasm64 => true,
+ else => false,
+ };
+ }
+
+ pub fn isMIPS(arch: Arch) bool {
+ return switch (arch) {
+ .mips, .mipsel, .mips64, .mips64el => true,
+ else => false,
+ };
+ }
+
pub fn toElfMachine(arch: Arch) std.elf.EM {
return switch (arch) {
.avr => ._AVR,
From 7d94e712f125e10f234338e800953aa4837206ef Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sat, 18 Jan 2020 23:05:17 +0100
Subject: [PATCH 29/37] Remove useless wrappers around f32/f64 aeabi builtins
---
.../special/compiler_rt/arm/aeabi_dcmp.zig | 87 +++----------------
.../special/compiler_rt/arm/aeabi_fcmp.zig | 87 +++----------------
2 files changed, 22 insertions(+), 152 deletions(-)
diff --git a/lib/std/special/compiler_rt/arm/aeabi_dcmp.zig b/lib/std/special/compiler_rt/arm/aeabi_dcmp.zig
index a8ed182901..47e7fac81a 100644
--- a/lib/std/special/compiler_rt/arm/aeabi_dcmp.zig
+++ b/lib/std/special/compiler_rt/arm/aeabi_dcmp.zig
@@ -2,94 +2,29 @@
//
// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/arm/aeabi_dcmp.S
-const ConditionalOperator = enum {
- Eq,
- Lt,
- Le,
- Ge,
- Gt,
-};
+const comparedf2 = @import("../comparedf2.zig");
-pub fn __aeabi_dcmpeq() callconv(.Naked) noreturn {
+pub fn __aeabi_dcmpeq(a: f64, b: f64) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
- @call(.{ .modifier = .always_inline }, aeabi_dcmp, .{.Eq});
- unreachable;
+ return @boolToInt(@call(.{ .modifier = .always_inline }, comparedf2.__eqdf2, .{ a, b }) == 0);
}
-pub fn __aeabi_dcmplt() callconv(.Naked) noreturn {
+pub fn __aeabi_dcmplt(a: f64, b: f64) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
- @call(.{ .modifier = .always_inline }, aeabi_dcmp, .{.Lt});
- unreachable;
+ return @boolToInt(@call(.{ .modifier = .always_inline }, comparedf2.__ltdf2, .{ a, b }) < 0);
}
-pub fn __aeabi_dcmple() callconv(.Naked) noreturn {
+pub fn __aeabi_dcmple(a: f64, b: f64) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
- @call(.{ .modifier = .always_inline }, aeabi_dcmp, .{.Le});
- unreachable;
+ return @boolToInt(@call(.{ .modifier = .always_inline }, comparedf2.__ledf2, .{ a, b }) <= 0);
}
-pub fn __aeabi_dcmpge() callconv(.Naked) noreturn {
+pub fn __aeabi_dcmpge(a: f64, b: f64) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
- @call(.{ .modifier = .always_inline }, aeabi_dcmp, .{.Ge});
- unreachable;
+ return @boolToInt(@call(.{ .modifier = .always_inline }, comparedf2.__gedf2, .{ a, b }) >= 0);
}
-pub fn __aeabi_dcmpgt() callconv(.Naked) noreturn {
+pub fn __aeabi_dcmpgt(a: f64, b: f64) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
- @call(.{ .modifier = .always_inline }, aeabi_dcmp, .{.Gt});
- unreachable;
-}
-
-fn aeabi_dcmp(comptime cond: ConditionalOperator) void {
- @setRuntimeSafety(false);
- asm volatile (
- \\ push { r4, lr }
- );
-
- switch (cond) {
- .Eq => asm volatile (
- \\ bl __eqdf2
- \\ cmp r0, #0
- \\ beq 1f
- \\ movs r0, #0
- \\ pop { r4, pc }
- \\ 1:
- ),
- .Lt => asm volatile (
- \\ bl __ltdf2
- \\ cmp r0, #0
- \\ blt 1f
- \\ movs r0, #0
- \\ pop { r4, pc }
- \\ 1:
- ),
- .Le => asm volatile (
- \\ bl __ledf2
- \\ cmp r0, #0
- \\ ble 1f
- \\ movs r0, #0
- \\ pop { r4, pc }
- \\ 1:
- ),
- .Ge => asm volatile (
- \\ bl __ltdf2
- \\ cmp r0, #0
- \\ bge 1f
- \\ movs r0, #0
- \\ pop { r4, pc }
- \\ 1:
- ),
- .Gt => asm volatile (
- \\ bl __gtdf2
- \\ cmp r0, #0
- \\ bgt 1f
- \\ movs r0, #0
- \\ pop { r4, pc }
- \\ 1:
- ),
- }
- asm volatile (
- \\ movs r0, #1
- \\ pop { r4, pc }
- );
+ return @boolToInt(@call(.{ .modifier = .always_inline }, comparedf2.__gtdf2, .{ a, b }) > 0);
}
diff --git a/lib/std/special/compiler_rt/arm/aeabi_fcmp.zig b/lib/std/special/compiler_rt/arm/aeabi_fcmp.zig
index 0b4c0f0d41..c53643b368 100644
--- a/lib/std/special/compiler_rt/arm/aeabi_fcmp.zig
+++ b/lib/std/special/compiler_rt/arm/aeabi_fcmp.zig
@@ -2,94 +2,29 @@
//
// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/arm/aeabi_fcmp.S
-const ConditionalOperator = enum {
- Eq,
- Lt,
- Le,
- Ge,
- Gt,
-};
+const comparesf2 = @import("../comparesf2.zig");
-pub fn __aeabi_fcmpeq() callconv(.Naked) noreturn {
+pub fn __aeabi_fcmpeq(a: f32, b: f32) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
- @call(.{ .modifier = .always_inline }, aeabi_fcmp, .{.Eq});
- unreachable;
+ return @boolToInt(@call(.{ .modifier = .always_inline }, comparesf2.__eqsf2, .{ a, b }) == 0);
}
-pub fn __aeabi_fcmplt() callconv(.Naked) noreturn {
+pub fn __aeabi_fcmplt(a: f32, b: f32) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
- @call(.{ .modifier = .always_inline }, aeabi_fcmp, .{.Lt});
- unreachable;
+ return @boolToInt(@call(.{ .modifier = .always_inline }, comparesf2.__ltsf2, .{ a, b }) < 0);
}
-pub fn __aeabi_fcmple() callconv(.Naked) noreturn {
+pub fn __aeabi_fcmple(a: f32, b: f32) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
- @call(.{ .modifier = .always_inline }, aeabi_fcmp, .{.Le});
- unreachable;
+ return @boolToInt(@call(.{ .modifier = .always_inline }, comparesf2.__lesf2, .{ a, b }) <= 0);
}
-pub fn __aeabi_fcmpge() callconv(.Naked) noreturn {
+pub fn __aeabi_fcmpge(a: f32, b: f32) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
- @call(.{ .modifier = .always_inline }, aeabi_fcmp, .{.Ge});
- unreachable;
+ return @boolToInt(@call(.{ .modifier = .always_inline }, comparesf2.__gesf2, .{ a, b }) >= 0);
}
-pub fn __aeabi_fcmpgt() callconv(.Naked) noreturn {
+pub fn __aeabi_fcmpgt(a: f32, b: f32) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
- @call(.{ .modifier = .always_inline }, aeabi_fcmp, .{.Gt});
- unreachable;
-}
-
-fn aeabi_fcmp(comptime cond: ConditionalOperator) void {
- @setRuntimeSafety(false);
- asm volatile (
- \\ push { r4, lr }
- );
-
- switch (cond) {
- .Eq => asm volatile (
- \\ bl __eqsf2
- \\ cmp r0, #0
- \\ beq 1f
- \\ movs r0, #0
- \\ pop { r4, pc }
- \\ 1:
- ),
- .Lt => asm volatile (
- \\ bl __ltsf2
- \\ cmp r0, #0
- \\ blt 1f
- \\ movs r0, #0
- \\ pop { r4, pc }
- \\ 1:
- ),
- .Le => asm volatile (
- \\ bl __lesf2
- \\ cmp r0, #0
- \\ ble 1f
- \\ movs r0, #0
- \\ pop { r4, pc }
- \\ 1:
- ),
- .Ge => asm volatile (
- \\ bl __ltsf2
- \\ cmp r0, #0
- \\ bge 1f
- \\ movs r0, #0
- \\ pop { r4, pc }
- \\ 1:
- ),
- .Gt => asm volatile (
- \\ bl __gtsf2
- \\ cmp r0, #0
- \\ bgt 1f
- \\ movs r0, #0
- \\ pop { r4, pc }
- \\ 1:
- ),
- }
- asm volatile (
- \\ movs r0, #1
- \\ pop { r4, pc }
- );
+ return @boolToInt(@call(.{ .modifier = .always_inline }, comparesf2.__gtsf2, .{ a, b }) > 0);
}
From 6b056d1fb93bba68c03bda5039994d4df338ef13 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sat, 18 Jan 2020 23:37:13 +0100
Subject: [PATCH 30/37] Nuke some repeated code
---
lib/std/special/compiler_rt.zig | 52 +++---
lib/std/special/compiler_rt/compareXf2.zig | 201 +++++++++++++++++++++
lib/std/special/compiler_rt/comparedf2.zig | 127 -------------
lib/std/special/compiler_rt/comparesf2.zig | 127 -------------
lib/std/special/compiler_rt/comparetf2.zig | 99 ----------
5 files changed, 227 insertions(+), 379 deletions(-)
create mode 100644 lib/std/special/compiler_rt/compareXf2.zig
delete mode 100644 lib/std/special/compiler_rt/comparedf2.zig
delete mode 100644 lib/std/special/compiler_rt/comparesf2.zig
delete mode 100644 lib/std/special/compiler_rt/comparetf2.zig
diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig
index 9b225dbad6..920707d1c4 100644
--- a/lib/std/special/compiler_rt.zig
+++ b/lib/std/special/compiler_rt.zig
@@ -16,42 +16,42 @@ comptime {
else => {},
}
- @export(@import("compiler_rt/comparesf2.zig").__lesf2, .{ .name = "__lesf2", .linkage = linkage });
- @export(@import("compiler_rt/comparedf2.zig").__ledf2, .{ .name = "__ledf2", .linkage = linkage });
- @export(@import("compiler_rt/comparetf2.zig").__letf2, .{ .name = "__letf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__lesf2, .{ .name = "__lesf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__ledf2, .{ .name = "__ledf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__letf2, .{ .name = "__letf2", .linkage = linkage });
- @export(@import("compiler_rt/comparesf2.zig").__gesf2, .{ .name = "__gesf2", .linkage = linkage });
- @export(@import("compiler_rt/comparedf2.zig").__gedf2, .{ .name = "__gedf2", .linkage = linkage });
- @export(@import("compiler_rt/comparetf2.zig").__getf2, .{ .name = "__getf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__gesf2, .{ .name = "__gesf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__gedf2, .{ .name = "__gedf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__getf2, .{ .name = "__getf2", .linkage = linkage });
if (!is_test) {
- @export(@import("compiler_rt/comparesf2.zig").__lesf2, .{ .name = "__cmpsf2", .linkage = linkage });
- @export(@import("compiler_rt/comparedf2.zig").__ledf2, .{ .name = "__cmpdf2", .linkage = linkage });
- @export(@import("compiler_rt/comparetf2.zig").__letf2, .{ .name = "__cmptf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__lesf2, .{ .name = "__cmpsf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__ledf2, .{ .name = "__cmpdf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__letf2, .{ .name = "__cmptf2", .linkage = linkage });
- @export(@import("compiler_rt/comparesf2.zig").__eqsf2, .{ .name = "__eqsf2", .linkage = linkage });
- @export(@import("compiler_rt/comparedf2.zig").__eqdf2, .{ .name = "__eqdf2", .linkage = linkage });
- @export(@import("compiler_rt/comparetf2.zig").__letf2, .{ .name = "__eqtf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__eqsf2, .{ .name = "__eqsf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__eqdf2, .{ .name = "__eqdf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__letf2, .{ .name = "__eqtf2", .linkage = linkage });
- @export(@import("compiler_rt/comparesf2.zig").__ltsf2, .{ .name = "__ltsf2", .linkage = linkage });
- @export(@import("compiler_rt/comparedf2.zig").__ltdf2, .{ .name = "__ltdf2", .linkage = linkage });
- @export(@import("compiler_rt/comparetf2.zig").__letf2, .{ .name = "__lttf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__ltsf2, .{ .name = "__ltsf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__ltdf2, .{ .name = "__ltdf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__letf2, .{ .name = "__lttf2", .linkage = linkage });
- @export(@import("compiler_rt/comparesf2.zig").__nesf2, .{ .name = "__nesf2", .linkage = linkage });
- @export(@import("compiler_rt/comparedf2.zig").__nedf2, .{ .name = "__nedf2", .linkage = linkage });
- @export(@import("compiler_rt/comparetf2.zig").__letf2, .{ .name = "__netf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__nesf2, .{ .name = "__nesf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__nedf2, .{ .name = "__nedf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__letf2, .{ .name = "__netf2", .linkage = linkage });
- @export(@import("compiler_rt/comparesf2.zig").__gtsf2, .{ .name = "__gtsf2", .linkage = linkage });
- @export(@import("compiler_rt/comparedf2.zig").__gtdf2, .{ .name = "__gtdf2", .linkage = linkage });
- @export(@import("compiler_rt/comparetf2.zig").__getf2, .{ .name = "__gttf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__gtsf2, .{ .name = "__gtsf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__gtdf2, .{ .name = "__gtdf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__getf2, .{ .name = "__gttf2", .linkage = linkage });
@export(@import("compiler_rt/extendXfYf2.zig").__extendhfsf2, .{ .name = "__gnu_h2f_ieee", .linkage = linkage });
@export(@import("compiler_rt/truncXfYf2.zig").__truncsfhf2, .{ .name = "__gnu_f2h_ieee", .linkage = linkage });
}
- @export(@import("compiler_rt/comparesf2.zig").__unordsf2, .{ .name = "__unordsf2", .linkage = linkage });
- @export(@import("compiler_rt/comparedf2.zig").__unorddf2, .{ .name = "__unorddf2", .linkage = linkage });
- @export(@import("compiler_rt/comparetf2.zig").__unordtf2, .{ .name = "__unordtf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__unordsf2, .{ .name = "__unordsf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__unorddf2, .{ .name = "__unorddf2", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__unordtf2, .{ .name = "__unordtf2", .linkage = linkage });
@export(@import("compiler_rt/addXf3.zig").__addsf3, .{ .name = "__addsf3", .linkage = linkage });
@export(@import("compiler_rt/addXf3.zig").__adddf3, .{ .name = "__adddf3", .linkage = linkage });
@@ -231,14 +231,14 @@ comptime {
@export(@import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmple, .{ .name = "__aeabi_fcmple", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmpge, .{ .name = "__aeabi_fcmpge", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmpgt, .{ .name = "__aeabi_fcmpgt", .linkage = linkage });
- @export(@import("compiler_rt/comparesf2.zig").__aeabi_fcmpun, .{ .name = "__aeabi_fcmpun", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__aeabi_fcmpun, .{ .name = "__aeabi_fcmpun", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmpeq, .{ .name = "__aeabi_dcmpeq", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmplt, .{ .name = "__aeabi_dcmplt", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmple, .{ .name = "__aeabi_dcmple", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmpge, .{ .name = "__aeabi_dcmpge", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmpgt, .{ .name = "__aeabi_dcmpgt", .linkage = linkage });
- @export(@import("compiler_rt/comparedf2.zig").__aeabi_dcmpun, .{ .name = "__aeabi_dcmpun", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__aeabi_dcmpun, .{ .name = "__aeabi_dcmpun", .linkage = linkage });
}
if (builtin.os == .windows) {
// Default stack-probe functions emitted by LLVM
diff --git a/lib/std/special/compiler_rt/compareXf2.zig b/lib/std/special/compiler_rt/compareXf2.zig
new file mode 100644
index 0000000000..3253abe871
--- /dev/null
+++ b/lib/std/special/compiler_rt/compareXf2.zig
@@ -0,0 +1,201 @@
+// Ported from:
+//
+// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/comparesf2.c
+
+const std = @import("std");
+const builtin = @import("builtin");
+
+const LE = extern enum(i32) {
+ Less = -1,
+ Equal = 0,
+ Greater = 1,
+ Unordered = 1,
+};
+
+const GE = extern enum(i32) {
+ Less = -1,
+ Equal = 0,
+ Greater = 1,
+ Unordered = -1,
+};
+
+pub fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT {
+ @setRuntimeSafety(builtin.is_test);
+
+ const srep_t = @IntType(true, T.bit_count);
+ const rep_t = @IntType(false, T.bit_count);
+
+ const significandBits = std.math.floatMantissaBits(T);
+ const exponentBits = std.math.floatExponentBits(T);
+ const signBit = (@as(rep_t, 1) << (significandBits + exponentBits));
+ const absMask = signBit - 1;
+ const infRep = @bitCast(rep_t, std.math.inf(T));
+
+ const aInt = @bitCast(srep_t, a);
+ const bInt = @bitCast(srep_t, b);
+ const aAbs = @bitCast(rep_t, aInt) & absMask;
+ const bAbs = @bitCast(rep_t, bInt) & absMask;
+
+ // If either a or b is NaN, they are unordered.
+ if (aAbs > infRep or bAbs > infRep) return .Unordered;
+
+ // If a and b are both zeros, they are equal.
+ if ((aAbs | bAbs) == 0) return .Equal;
+
+ // If at least one of a and b is positive, we get the same result comparing
+ // a and b as signed integers as we would with a fp_ting-point compare.
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt) {
+ return .Less;
+ } else if (aInt == bInt) {
+ return .Equal;
+ } else return .Greater;
+ }
+
+ // Otherwise, both are negative, so we need to flip the sense of the
+ // comparison to get the correct result. (This assumes a twos- or ones-
+ // complement integer representation; if integers are represented in a
+ // sign-magnitude representation, then this flip is incorrect).
+ else {
+ if (aInt > bInt) {
+ return .Less;
+ } else if (aInt == bInt) {
+ return .Equal;
+ } else return .Greater;
+ }
+}
+
+pub fn unordcmp(comptime T: type, a: T, b: T) i32 {
+ @setRuntimeSafety(builtin.is_test);
+
+ const rep_t = @IntType(false, T.bit_count);
+
+ const significandBits = std.math.floatMantissaBits(T);
+ const exponentBits = std.math.floatExponentBits(T);
+ const signBit = (@as(rep_t, 1) << (significandBits + exponentBits));
+ const absMask = signBit - 1;
+ const infRep = @bitCast(rep_t, std.math.inf(T));
+
+ const aAbs: rep_t = @bitCast(rep_t, a) & absMask;
+ const bAbs: rep_t = @bitCast(rep_t, b) & absMask;
+
+ return @boolToInt(aAbs > infRep or bAbs > infRep);
+}
+
+// Comparison between f32
+
+pub fn __lesf2(a: f32, b: f32) callconv(.C) i32 {
+ @setRuntimeSafety(builtin.is_test);
+ return @bitCast(i32, @call(.{ .modifier = .always_inline }, cmp, .{ f32, LE, a, b }));
+}
+
+pub fn __gesf2(a: f32, b: f32) callconv(.C) i32 {
+ @setRuntimeSafety(builtin.is_test);
+ return @bitCast(i32, @call(.{ .modifier = .always_inline }, cmp, .{ f32, GE, a, b }));
+}
+
+pub fn __eqsf2(a: f32, b: f32) callconv(.C) i32 {
+ return __lesf2(a, b);
+}
+
+pub fn __ltsf2(a: f32, b: f32) callconv(.C) i32 {
+ return __lesf2(a, b);
+}
+
+pub fn __nesf2(a: f32, b: f32) callconv(.C) i32 {
+ return __lesf2(a, b);
+}
+
+pub fn __gtsf2(a: f32, b: f32) callconv(.C) i32 {
+ return __gesf2(a, b);
+}
+
+// Comparison between f64
+
+pub fn __ledf2(a: f64, b: f64) callconv(.C) i32 {
+ @setRuntimeSafety(builtin.is_test);
+ return @bitCast(i32, @call(.{ .modifier = .always_inline }, cmp, .{ f64, LE, a, b }));
+}
+
+pub fn __gedf2(a: f64, b: f64) callconv(.C) i32 {
+ @setRuntimeSafety(builtin.is_test);
+ return @bitCast(i32, @call(.{ .modifier = .always_inline }, cmp, .{ f64, GE, a, b }));
+}
+
+pub fn __eqdf2(a: f64, b: f64) callconv(.C) i32 {
+ return __ledf2(a, b);
+}
+
+pub fn __ltdf2(a: f64, b: f64) callconv(.C) i32 {
+ return __ledf2(a, b);
+}
+
+pub fn __nedf2(a: f64, b: f64) callconv(.C) i32 {
+ return __ledf2(a, b);
+}
+
+pub fn __gtdf2(a: f64, b: f64) callconv(.C) i32 {
+ return __gedf2(a, b);
+}
+
+// Comparison between f128
+
+pub fn __letf2(a: f128, b: f128) callconv(.C) i32 {
+ @setRuntimeSafety(builtin.is_test);
+ return @bitCast(i32, @call(.{ .modifier = .always_inline }, cmp, .{ f128, LE, a, b }));
+}
+
+pub fn __getf2(a: f128, b: f128) callconv(.C) i32 {
+ @setRuntimeSafety(builtin.is_test);
+ return @bitCast(i32, @call(.{ .modifier = .always_inline }, cmp, .{ f128, GE, a, b }));
+}
+
+pub fn __eqtf2(a: f128, b: f128) callconv(.C) i32 {
+ return __letf2(a, b);
+}
+
+pub fn __lttf2(a: f128, b: f128) callconv(.C) i32 {
+ return __letf2(a, b);
+}
+
+pub fn __netf2(a: f128, b: f128) callconv(.C) i32 {
+ return __letf2(a, b);
+}
+
+pub fn __gttf2(a: f128, b: f128) callconv(.C) i32 {
+ return __getf2(a, b);
+}
+
+// Unordered comparison between f32/f64/f128
+
+pub fn __unordsf2(a: f32, b: f32) callconv(.C) i32 {
+ @setRuntimeSafety(builtin.is_test);
+ return @call(.{ .modifier = .always_inline }, unordcmp, .{ f32, a, b });
+}
+
+pub fn __unorddf2(a: f64, b: f64) callconv(.C) i32 {
+ @setRuntimeSafety(builtin.is_test);
+ return @call(.{ .modifier = .always_inline }, unordcmp, .{ f64, a, b });
+}
+
+pub fn __unordtf2(a: f128, b: f128) callconv(.C) i32 {
+ @setRuntimeSafety(builtin.is_test);
+ return @call(.{ .modifier = .always_inline }, unordcmp, .{ f128, a, b });
+}
+
+pub fn __aeabi_fcmpun(a: f32, b: f32) callconv(.AAPCS) i32 {
+ @setRuntimeSafety(false);
+ return @call(.{ .modifier = .always_inline }, __unordsf2, .{ a, b });
+}
+
+pub fn __aeabi_dcmpun(a: f64, b: f64) callconv(.AAPCS) i32 {
+ @setRuntimeSafety(false);
+ return @call(.{ .modifier = .always_inline }, __unorddf2, .{ a, b });
+}
+
+test "comparesf2" {
+ _ = @import("comparesf2_test.zig");
+}
+test "comparedf2" {
+ _ = @import("comparedf2_test.zig");
+}
diff --git a/lib/std/special/compiler_rt/comparedf2.zig b/lib/std/special/compiler_rt/comparedf2.zig
deleted file mode 100644
index 98cca106f7..0000000000
--- a/lib/std/special/compiler_rt/comparedf2.zig
+++ /dev/null
@@ -1,127 +0,0 @@
-// Ported from:
-//
-// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/comparedf2.c
-
-const std = @import("std");
-const builtin = @import("builtin");
-const is_test = builtin.is_test;
-
-const fp_t = f64;
-const rep_t = u64;
-const srep_t = i64;
-
-const typeWidth = rep_t.bit_count;
-const significandBits = std.math.floatMantissaBits(fp_t);
-const exponentBits = std.math.floatExponentBits(fp_t);
-const signBit = (@as(rep_t, 1) << (significandBits + exponentBits));
-const absMask = signBit - 1;
-const implicitBit = @as(rep_t, 1) << significandBits;
-const significandMask = implicitBit - 1;
-const exponentMask = absMask ^ significandMask;
-const infRep = @bitCast(rep_t, std.math.inf(fp_t));
-
-// TODO https://github.com/ziglang/zig/issues/641
-// and then make the return types of some of these functions the enum instead of c_int
-const LE_LESS = @as(c_int, -1);
-const LE_EQUAL = @as(c_int, 0);
-const LE_GREATER = @as(c_int, 1);
-const LE_UNORDERED = @as(c_int, 1);
-
-pub fn __ledf2(a: fp_t, b: fp_t) callconv(.C) c_int {
- @setRuntimeSafety(is_test);
- const aInt: srep_t = @bitCast(srep_t, a);
- const bInt: srep_t = @bitCast(srep_t, b);
- const aAbs: rep_t = @bitCast(rep_t, aInt) & absMask;
- const bAbs: rep_t = @bitCast(rep_t, bInt) & absMask;
-
- // If either a or b is NaN, they are unordered.
- if (aAbs > infRep or bAbs > infRep) return LE_UNORDERED;
-
- // If a and b are both zeros, they are equal.
- if ((aAbs | bAbs) == 0) return LE_EQUAL;
-
- // If at least one of a and b is positive, we get the same result comparing
- // a and b as signed integers as we would with a fp_ting-point compare.
- if ((aInt & bInt) >= 0) {
- if (aInt < bInt) {
- return LE_LESS;
- } else if (aInt == bInt) {
- return LE_EQUAL;
- } else return LE_GREATER;
- }
-
- // Otherwise, both are negative, so we need to flip the sense of the
- // comparison to get the correct result. (This assumes a twos- or ones-
- // complement integer representation; if integers are represented in a
- // sign-magnitude representation, then this flip is incorrect).
- else {
- if (aInt > bInt) {
- return LE_LESS;
- } else if (aInt == bInt) {
- return LE_EQUAL;
- } else return LE_GREATER;
- }
-}
-
-// TODO https://github.com/ziglang/zig/issues/641
-// and then make the return types of some of these functions the enum instead of c_int
-const GE_LESS = @as(c_int, -1);
-const GE_EQUAL = @as(c_int, 0);
-const GE_GREATER = @as(c_int, 1);
-const GE_UNORDERED = @as(c_int, -1); // Note: different from LE_UNORDERED
-
-pub fn __gedf2(a: fp_t, b: fp_t) callconv(.C) c_int {
- @setRuntimeSafety(is_test);
- const aInt: srep_t = @bitCast(srep_t, a);
- const bInt: srep_t = @bitCast(srep_t, b);
- const aAbs: rep_t = @bitCast(rep_t, aInt) & absMask;
- const bAbs: rep_t = @bitCast(rep_t, bInt) & absMask;
-
- if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED;
- if ((aAbs | bAbs) == 0) return GE_EQUAL;
- if ((aInt & bInt) >= 0) {
- if (aInt < bInt) {
- return GE_LESS;
- } else if (aInt == bInt) {
- return GE_EQUAL;
- } else return GE_GREATER;
- } else {
- if (aInt > bInt) {
- return GE_LESS;
- } else if (aInt == bInt) {
- return GE_EQUAL;
- } else return GE_GREATER;
- }
-}
-
-pub fn __unorddf2(a: fp_t, b: fp_t) callconv(.C) c_int {
- @setRuntimeSafety(is_test);
- const aAbs: rep_t = @bitCast(rep_t, a) & absMask;
- const bAbs: rep_t = @bitCast(rep_t, b) & absMask;
- return @boolToInt(aAbs > infRep or bAbs > infRep);
-}
-
-pub fn __eqdf2(a: fp_t, b: fp_t) callconv(.C) c_int {
- return __ledf2(a, b);
-}
-
-pub fn __ltdf2(a: fp_t, b: fp_t) callconv(.C) c_int {
- return __ledf2(a, b);
-}
-
-pub fn __nedf2(a: fp_t, b: fp_t) callconv(.C) c_int {
- return __ledf2(a, b);
-}
-
-pub fn __gtdf2(a: fp_t, b: fp_t) callconv(.C) c_int {
- return __gedf2(a, b);
-}
-
-pub fn __aeabi_dcmpun(a: fp_t, b: fp_t) callconv(.AAPCS) c_int {
- @setRuntimeSafety(false);
- return @call(.{ .modifier = .always_inline }, __unorddf2, .{ a, b });
-}
-
-test "import comparedf2" {
- _ = @import("comparedf2_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/comparesf2.zig b/lib/std/special/compiler_rt/comparesf2.zig
deleted file mode 100644
index bd881af2a1..0000000000
--- a/lib/std/special/compiler_rt/comparesf2.zig
+++ /dev/null
@@ -1,127 +0,0 @@
-// Ported from:
-//
-// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/comparesf2.c
-
-const std = @import("std");
-const builtin = @import("builtin");
-const is_test = builtin.is_test;
-
-const fp_t = f32;
-const rep_t = u32;
-const srep_t = i32;
-
-const typeWidth = rep_t.bit_count;
-const significandBits = std.math.floatMantissaBits(fp_t);
-const exponentBits = std.math.floatExponentBits(fp_t);
-const signBit = (@as(rep_t, 1) << (significandBits + exponentBits));
-const absMask = signBit - 1;
-const implicitBit = @as(rep_t, 1) << significandBits;
-const significandMask = implicitBit - 1;
-const exponentMask = absMask ^ significandMask;
-const infRep = @bitCast(rep_t, std.math.inf(fp_t));
-
-// TODO https://github.com/ziglang/zig/issues/641
-// and then make the return types of some of these functions the enum instead of c_int
-const LE_LESS = @as(c_int, -1);
-const LE_EQUAL = @as(c_int, 0);
-const LE_GREATER = @as(c_int, 1);
-const LE_UNORDERED = @as(c_int, 1);
-
-pub fn __lesf2(a: fp_t, b: fp_t) callconv(.C) c_int {
- @setRuntimeSafety(is_test);
- const aInt: srep_t = @bitCast(srep_t, a);
- const bInt: srep_t = @bitCast(srep_t, b);
- const aAbs: rep_t = @bitCast(rep_t, aInt) & absMask;
- const bAbs: rep_t = @bitCast(rep_t, bInt) & absMask;
-
- // If either a or b is NaN, they are unordered.
- if (aAbs > infRep or bAbs > infRep) return LE_UNORDERED;
-
- // If a and b are both zeros, they are equal.
- if ((aAbs | bAbs) == 0) return LE_EQUAL;
-
- // If at least one of a and b is positive, we get the same result comparing
- // a and b as signed integers as we would with a fp_ting-point compare.
- if ((aInt & bInt) >= 0) {
- if (aInt < bInt) {
- return LE_LESS;
- } else if (aInt == bInt) {
- return LE_EQUAL;
- } else return LE_GREATER;
- }
-
- // Otherwise, both are negative, so we need to flip the sense of the
- // comparison to get the correct result. (This assumes a twos- or ones-
- // complement integer representation; if integers are represented in a
- // sign-magnitude representation, then this flip is incorrect).
- else {
- if (aInt > bInt) {
- return LE_LESS;
- } else if (aInt == bInt) {
- return LE_EQUAL;
- } else return LE_GREATER;
- }
-}
-
-// TODO https://github.com/ziglang/zig/issues/641
-// and then make the return types of some of these functions the enum instead of c_int
-const GE_LESS = @as(c_int, -1);
-const GE_EQUAL = @as(c_int, 0);
-const GE_GREATER = @as(c_int, 1);
-const GE_UNORDERED = @as(c_int, -1); // Note: different from LE_UNORDERED
-
-pub fn __gesf2(a: fp_t, b: fp_t) callconv(.C) c_int {
- @setRuntimeSafety(is_test);
- const aInt: srep_t = @bitCast(srep_t, a);
- const bInt: srep_t = @bitCast(srep_t, b);
- const aAbs: rep_t = @bitCast(rep_t, aInt) & absMask;
- const bAbs: rep_t = @bitCast(rep_t, bInt) & absMask;
-
- if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED;
- if ((aAbs | bAbs) == 0) return GE_EQUAL;
- if ((aInt & bInt) >= 0) {
- if (aInt < bInt) {
- return GE_LESS;
- } else if (aInt == bInt) {
- return GE_EQUAL;
- } else return GE_GREATER;
- } else {
- if (aInt > bInt) {
- return GE_LESS;
- } else if (aInt == bInt) {
- return GE_EQUAL;
- } else return GE_GREATER;
- }
-}
-
-pub fn __unordsf2(a: fp_t, b: fp_t) callconv(.C) c_int {
- @setRuntimeSafety(is_test);
- const aAbs: rep_t = @bitCast(rep_t, a) & absMask;
- const bAbs: rep_t = @bitCast(rep_t, b) & absMask;
- return @boolToInt(aAbs > infRep or bAbs > infRep);
-}
-
-pub fn __eqsf2(a: fp_t, b: fp_t) callconv(.C) c_int {
- return __lesf2(a, b);
-}
-
-pub fn __ltsf2(a: fp_t, b: fp_t) callconv(.C) c_int {
- return __lesf2(a, b);
-}
-
-pub fn __nesf2(a: fp_t, b: fp_t) callconv(.C) c_int {
- return __lesf2(a, b);
-}
-
-pub fn __gtsf2(a: fp_t, b: fp_t) callconv(.C) c_int {
- return __gesf2(a, b);
-}
-
-pub fn __aeabi_fcmpun(a: fp_t, b: fp_t) callconv(.AAPCS) c_int {
- @setRuntimeSafety(false);
- return @call(.{ .modifier = .always_inline }, __unordsf2, .{ a, b });
-}
-
-test "import comparesf2" {
- _ = @import("comparesf2_test.zig");
-}
diff --git a/lib/std/special/compiler_rt/comparetf2.zig b/lib/std/special/compiler_rt/comparetf2.zig
deleted file mode 100644
index f2969f2112..0000000000
--- a/lib/std/special/compiler_rt/comparetf2.zig
+++ /dev/null
@@ -1,99 +0,0 @@
-// TODO https://github.com/ziglang/zig/issues/641
-// and then make the return types of some of these functions the enum instead of c_int
-const LE_LESS = @as(c_int, -1);
-const LE_EQUAL = @as(c_int, 0);
-const LE_GREATER = @as(c_int, 1);
-const LE_UNORDERED = @as(c_int, 1);
-
-const rep_t = u128;
-const srep_t = i128;
-
-const typeWidth = rep_t.bit_count;
-const significandBits = 112;
-const exponentBits = (typeWidth - significandBits - 1);
-const signBit = (@as(rep_t, 1) << (significandBits + exponentBits));
-const absMask = signBit - 1;
-const implicitBit = @as(rep_t, 1) << significandBits;
-const significandMask = implicitBit - 1;
-const exponentMask = absMask ^ significandMask;
-const infRep = exponentMask;
-
-const builtin = @import("builtin");
-const is_test = builtin.is_test;
-
-pub fn __letf2(a: f128, b: f128) callconv(.C) c_int {
- @setRuntimeSafety(is_test);
-
- const aInt = @bitCast(rep_t, a);
- const bInt = @bitCast(rep_t, b);
-
- const aAbs: rep_t = aInt & absMask;
- const bAbs: rep_t = bInt & absMask;
-
- // If either a or b is NaN, they are unordered.
- if (aAbs > infRep or bAbs > infRep) return LE_UNORDERED;
-
- // If a and b are both zeros, they are equal.
- if ((aAbs | bAbs) == 0) return LE_EQUAL;
-
- // If at least one of a and b is positive, we get the same result comparing
- // a and b as signed integers as we would with a floating-point compare.
- return if ((aInt & bInt) >= 0)
- if (aInt < bInt)
- LE_LESS
- else if (aInt == bInt)
- LE_EQUAL
- else
- LE_GREATER
- else
- // Otherwise, both are negative, so we need to flip the sense of the
- // comparison to get the correct result. (This assumes a twos- or ones-
- // complement integer representation; if integers are represented in a
- // sign-magnitude representation, then this flip is incorrect).
- if (aInt > bInt)
- LE_LESS
- else if (aInt == bInt)
- LE_EQUAL
- else
- LE_GREATER;
-}
-
-// TODO https://github.com/ziglang/zig/issues/641
-// and then make the return types of some of these functions the enum instead of c_int
-const GE_LESS = @as(c_int, -1);
-const GE_EQUAL = @as(c_int, 0);
-const GE_GREATER = @as(c_int, 1);
-const GE_UNORDERED = @as(c_int, -1); // Note: different from LE_UNORDERED
-
-pub fn __getf2(a: f128, b: f128) callconv(.C) c_int {
- @setRuntimeSafety(is_test);
-
- const aInt = @bitCast(srep_t, a);
- const bInt = @bitCast(srep_t, b);
- const aAbs = @bitCast(rep_t, aInt) & absMask;
- const bAbs = @bitCast(rep_t, bInt) & absMask;
-
- if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED;
- if ((aAbs | bAbs) == 0) return GE_EQUAL;
- return if ((aInt & bInt) >= 0)
- if (aInt < bInt)
- GE_LESS
- else if (aInt == bInt)
- GE_EQUAL
- else
- GE_GREATER
- else if (aInt > bInt)
- GE_LESS
- else if (aInt == bInt)
- GE_EQUAL
- else
- GE_GREATER;
-}
-
-pub fn __unordtf2(a: f128, b: f128) callconv(.C) c_int {
- @setRuntimeSafety(is_test);
-
- const aAbs = @bitCast(rep_t, a) & absMask;
- const bAbs = @bitCast(rep_t, b) & absMask;
- return @boolToInt(aAbs > infRep or bAbs > infRep);
-}
From ae31da9334851dfca226ece1a66457d8df3e4abe Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sat, 18 Jan 2020 23:40:58 +0100
Subject: [PATCH 31/37] Minor cleanup
---
lib/std/special/compiler_rt.zig | 22 +---------------------
1 file changed, 1 insertion(+), 21 deletions(-)
diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig
index 920707d1c4..213348f0d0 100644
--- a/lib/std/special/compiler_rt.zig
+++ b/lib/std/special/compiler_rt.zig
@@ -148,7 +148,7 @@ comptime {
@export(@import("compiler_rt/clzsi2.zig").__clzsi2, .{ .name = "__clzsi2", .linkage = linkage });
- if (is_arm_arch and !is_arm_64 and !is_test) {
+ if (builtin.arch.isARM() and !is_test) {
@export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr0, .{ .name = "__aeabi_unwind_cpp_pr0", .linkage = linkage });
@export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr1, .{ .name = "__aeabi_unwind_cpp_pr1", .linkage = linkage });
@export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr2, .{ .name = "__aeabi_unwind_cpp_pr2", .linkage = linkage });
@@ -324,23 +324,3 @@ extern var __stack_chk_guard: usize = blk: {
buf[@sizeOf(usize) - 2] = '\n';
break :blk @bitCast(usize, buf);
};
-
-const is_arm_64 = switch (builtin.arch) {
- builtin.Arch.aarch64,
- builtin.Arch.aarch64_be,
- => true,
- else => false,
-};
-
-const is_arm_arch = switch (builtin.arch) {
- builtin.Arch.arm,
- builtin.Arch.armeb,
- builtin.Arch.aarch64,
- builtin.Arch.aarch64_be,
- builtin.Arch.thumb,
- builtin.Arch.thumbeb,
- => true,
- else => false,
-};
-
-const is_arm_32 = is_arm_arch and !is_arm_64;
From 3247fd7862bc5277a2c931f56b41f4f7c085611c Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sat, 18 Jan 2020 23:50:00 +0100
Subject: [PATCH 32/37] Export MSVC builtins inconditionally
---
lib/std/special/compiler_rt.zig | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig
index 213348f0d0..0867629091 100644
--- a/lib/std/special/compiler_rt.zig
+++ b/lib/std/special/compiler_rt.zig
@@ -240,6 +240,15 @@ comptime {
@export(@import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmpgt, .{ .name = "__aeabi_dcmpgt", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__aeabi_dcmpun, .{ .name = "__aeabi_dcmpun", .linkage = linkage });
}
+
+ if (builtin.arch == .i386 and builtin.abi == .msvc) {
+ // Don't let LLVM apply the stdcall name mangling on those MSVC builtins
+ @export(@import("compiler_rt/aulldiv.zig")._alldiv, .{ .name = "\x01__alldiv", .linkage = strong_linkage });
+ @export(@import("compiler_rt/aulldiv.zig")._aulldiv, .{ .name = "\x01__aulldiv", .linkage = strong_linkage });
+ @export(@import("compiler_rt/aullrem.zig")._allrem, .{ .name = "\x01__allrem", .linkage = strong_linkage });
+ @export(@import("compiler_rt/aullrem.zig")._aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage });
+ }
+
if (builtin.os == .windows) {
// Default stack-probe functions emitted by LLVM
if (is_mingw) {
@@ -258,13 +267,6 @@ comptime {
switch (builtin.arch) {
.i386 => {
- // Don't let LLVM apply the stdcall name mangling on those MSVC
- // builtin functions
- @export(@import("compiler_rt/aulldiv.zig")._alldiv, .{ .name = "\x01__alldiv", .linkage = strong_linkage });
- @export(@import("compiler_rt/aulldiv.zig")._aulldiv, .{ .name = "\x01__aulldiv", .linkage = strong_linkage });
- @export(@import("compiler_rt/aullrem.zig")._allrem, .{ .name = "\x01__allrem", .linkage = strong_linkage });
- @export(@import("compiler_rt/aullrem.zig")._aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage });
-
@export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage });
@export(@import("compiler_rt/modti3.zig").__modti3, .{ .name = "__modti3", .linkage = linkage });
@export(@import("compiler_rt/multi3.zig").__multi3, .{ .name = "__multi3", .linkage = linkage });
@@ -299,16 +301,12 @@ comptime {
@export(@import("compiler_rt/mulodi4.zig").__mulodi4, .{ .name = "__mulodi4", .linkage = linkage });
}
-const std = @import("std");
-const assert = std.debug.assert;
-const testing = std.testing;
-
// Avoid dragging in the runtime safety mechanisms into this .o file,
// unless we're trying to test this file.
pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
@setCold(true);
if (is_test) {
- std.debug.panic("{}", .{msg});
+ @import("std").debug.panic("{}", .{msg});
} else {
unreachable;
}
From 5fbc1c28121c1030de5ba8ca106a3dd8516cfd87 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sun, 19 Jan 2020 00:10:42 +0100
Subject: [PATCH 33/37] Nuke some more code
---
lib/std/special/compiler_rt.zig | 20 +++----
.../special/compiler_rt/arm/aeabi_dcmp.zig | 30 -----------
.../special/compiler_rt/arm/aeabi_fcmp.zig | 30 -----------
lib/std/special/compiler_rt/compareXf2.zig | 52 +++++++++++++++++++
4 files changed, 62 insertions(+), 70 deletions(-)
delete mode 100644 lib/std/special/compiler_rt/arm/aeabi_dcmp.zig
delete mode 100644 lib/std/special/compiler_rt/arm/aeabi_fcmp.zig
diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig
index 0867629091..90dbf0cdf4 100644
--- a/lib/std/special/compiler_rt.zig
+++ b/lib/std/special/compiler_rt.zig
@@ -226,18 +226,18 @@ comptime {
@export(@import("compiler_rt/divsf3.zig").__aeabi_fdiv, .{ .name = "__aeabi_fdiv", .linkage = linkage });
@export(@import("compiler_rt/divdf3.zig").__aeabi_ddiv, .{ .name = "__aeabi_ddiv", .linkage = linkage });
- @export(@import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmpeq, .{ .name = "__aeabi_fcmpeq", .linkage = linkage });
- @export(@import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmplt, .{ .name = "__aeabi_fcmplt", .linkage = linkage });
- @export(@import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmple, .{ .name = "__aeabi_fcmple", .linkage = linkage });
- @export(@import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmpge, .{ .name = "__aeabi_fcmpge", .linkage = linkage });
- @export(@import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmpgt, .{ .name = "__aeabi_fcmpgt", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__aeabi_fcmpeq, .{ .name = "__aeabi_fcmpeq", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__aeabi_fcmplt, .{ .name = "__aeabi_fcmplt", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__aeabi_fcmple, .{ .name = "__aeabi_fcmple", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__aeabi_fcmpge, .{ .name = "__aeabi_fcmpge", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__aeabi_fcmpgt, .{ .name = "__aeabi_fcmpgt", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__aeabi_fcmpun, .{ .name = "__aeabi_fcmpun", .linkage = linkage });
- @export(@import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmpeq, .{ .name = "__aeabi_dcmpeq", .linkage = linkage });
- @export(@import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmplt, .{ .name = "__aeabi_dcmplt", .linkage = linkage });
- @export(@import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmple, .{ .name = "__aeabi_dcmple", .linkage = linkage });
- @export(@import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmpge, .{ .name = "__aeabi_dcmpge", .linkage = linkage });
- @export(@import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmpgt, .{ .name = "__aeabi_dcmpgt", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__aeabi_dcmpeq, .{ .name = "__aeabi_dcmpeq", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__aeabi_dcmplt, .{ .name = "__aeabi_dcmplt", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__aeabi_dcmple, .{ .name = "__aeabi_dcmple", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__aeabi_dcmpge, .{ .name = "__aeabi_dcmpge", .linkage = linkage });
+ @export(@import("compiler_rt/compareXf2.zig").__aeabi_dcmpgt, .{ .name = "__aeabi_dcmpgt", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__aeabi_dcmpun, .{ .name = "__aeabi_dcmpun", .linkage = linkage });
}
diff --git a/lib/std/special/compiler_rt/arm/aeabi_dcmp.zig b/lib/std/special/compiler_rt/arm/aeabi_dcmp.zig
deleted file mode 100644
index 47e7fac81a..0000000000
--- a/lib/std/special/compiler_rt/arm/aeabi_dcmp.zig
+++ /dev/null
@@ -1,30 +0,0 @@
-// Ported from:
-//
-// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/arm/aeabi_dcmp.S
-
-const comparedf2 = @import("../comparedf2.zig");
-
-pub fn __aeabi_dcmpeq(a: f64, b: f64) callconv(.AAPCS) i32 {
- @setRuntimeSafety(false);
- return @boolToInt(@call(.{ .modifier = .always_inline }, comparedf2.__eqdf2, .{ a, b }) == 0);
-}
-
-pub fn __aeabi_dcmplt(a: f64, b: f64) callconv(.AAPCS) i32 {
- @setRuntimeSafety(false);
- return @boolToInt(@call(.{ .modifier = .always_inline }, comparedf2.__ltdf2, .{ a, b }) < 0);
-}
-
-pub fn __aeabi_dcmple(a: f64, b: f64) callconv(.AAPCS) i32 {
- @setRuntimeSafety(false);
- return @boolToInt(@call(.{ .modifier = .always_inline }, comparedf2.__ledf2, .{ a, b }) <= 0);
-}
-
-pub fn __aeabi_dcmpge(a: f64, b: f64) callconv(.AAPCS) i32 {
- @setRuntimeSafety(false);
- return @boolToInt(@call(.{ .modifier = .always_inline }, comparedf2.__gedf2, .{ a, b }) >= 0);
-}
-
-pub fn __aeabi_dcmpgt(a: f64, b: f64) callconv(.AAPCS) i32 {
- @setRuntimeSafety(false);
- return @boolToInt(@call(.{ .modifier = .always_inline }, comparedf2.__gtdf2, .{ a, b }) > 0);
-}
diff --git a/lib/std/special/compiler_rt/arm/aeabi_fcmp.zig b/lib/std/special/compiler_rt/arm/aeabi_fcmp.zig
deleted file mode 100644
index c53643b368..0000000000
--- a/lib/std/special/compiler_rt/arm/aeabi_fcmp.zig
+++ /dev/null
@@ -1,30 +0,0 @@
-// Ported from:
-//
-// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/arm/aeabi_fcmp.S
-
-const comparesf2 = @import("../comparesf2.zig");
-
-pub fn __aeabi_fcmpeq(a: f32, b: f32) callconv(.AAPCS) i32 {
- @setRuntimeSafety(false);
- return @boolToInt(@call(.{ .modifier = .always_inline }, comparesf2.__eqsf2, .{ a, b }) == 0);
-}
-
-pub fn __aeabi_fcmplt(a: f32, b: f32) callconv(.AAPCS) i32 {
- @setRuntimeSafety(false);
- return @boolToInt(@call(.{ .modifier = .always_inline }, comparesf2.__ltsf2, .{ a, b }) < 0);
-}
-
-pub fn __aeabi_fcmple(a: f32, b: f32) callconv(.AAPCS) i32 {
- @setRuntimeSafety(false);
- return @boolToInt(@call(.{ .modifier = .always_inline }, comparesf2.__lesf2, .{ a, b }) <= 0);
-}
-
-pub fn __aeabi_fcmpge(a: f32, b: f32) callconv(.AAPCS) i32 {
- @setRuntimeSafety(false);
- return @boolToInt(@call(.{ .modifier = .always_inline }, comparesf2.__gesf2, .{ a, b }) >= 0);
-}
-
-pub fn __aeabi_fcmpgt(a: f32, b: f32) callconv(.AAPCS) i32 {
- @setRuntimeSafety(false);
- return @boolToInt(@call(.{ .modifier = .always_inline }, comparesf2.__gtsf2, .{ a, b }) > 0);
-}
diff --git a/lib/std/special/compiler_rt/compareXf2.zig b/lib/std/special/compiler_rt/compareXf2.zig
index 3253abe871..15e49e3cc1 100644
--- a/lib/std/special/compiler_rt/compareXf2.zig
+++ b/lib/std/special/compiler_rt/compareXf2.zig
@@ -183,11 +183,63 @@ pub fn __unordtf2(a: f128, b: f128) callconv(.C) i32 {
return @call(.{ .modifier = .always_inline }, unordcmp, .{ f128, a, b });
}
+// ARM EABI intrinsics
+
+pub fn __aeabi_fcmpeq(a: f32, b: f32) callconv(.AAPCS) i32 {
+ @setRuntimeSafety(false);
+ return @boolToInt(@call(.{ .modifier = .always_inline }, __eqsf2, .{ a, b }) == 0);
+}
+
+pub fn __aeabi_fcmplt(a: f32, b: f32) callconv(.AAPCS) i32 {
+ @setRuntimeSafety(false);
+ return @boolToInt(@call(.{ .modifier = .always_inline }, __ltsf2, .{ a, b }) < 0);
+}
+
+pub fn __aeabi_fcmple(a: f32, b: f32) callconv(.AAPCS) i32 {
+ @setRuntimeSafety(false);
+ return @boolToInt(@call(.{ .modifier = .always_inline }, __lesf2, .{ a, b }) <= 0);
+}
+
+pub fn __aeabi_fcmpge(a: f32, b: f32) callconv(.AAPCS) i32 {
+ @setRuntimeSafety(false);
+ return @boolToInt(@call(.{ .modifier = .always_inline }, __gesf2, .{ a, b }) >= 0);
+}
+
+pub fn __aeabi_fcmpgt(a: f32, b: f32) callconv(.AAPCS) i32 {
+ @setRuntimeSafety(false);
+ return @boolToInt(@call(.{ .modifier = .always_inline }, __gtsf2, .{ a, b }) > 0);
+}
+
pub fn __aeabi_fcmpun(a: f32, b: f32) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
return @call(.{ .modifier = .always_inline }, __unordsf2, .{ a, b });
}
+pub fn __aeabi_dcmpeq(a: f64, b: f64) callconv(.AAPCS) i32 {
+ @setRuntimeSafety(false);
+ return @boolToInt(@call(.{ .modifier = .always_inline }, __eqdf2, .{ a, b }) == 0);
+}
+
+pub fn __aeabi_dcmplt(a: f64, b: f64) callconv(.AAPCS) i32 {
+ @setRuntimeSafety(false);
+ return @boolToInt(@call(.{ .modifier = .always_inline }, __ltdf2, .{ a, b }) < 0);
+}
+
+pub fn __aeabi_dcmple(a: f64, b: f64) callconv(.AAPCS) i32 {
+ @setRuntimeSafety(false);
+ return @boolToInt(@call(.{ .modifier = .always_inline }, __ledf2, .{ a, b }) <= 0);
+}
+
+pub fn __aeabi_dcmpge(a: f64, b: f64) callconv(.AAPCS) i32 {
+ @setRuntimeSafety(false);
+ return @boolToInt(@call(.{ .modifier = .always_inline }, __gedf2, .{ a, b }) >= 0);
+}
+
+pub fn __aeabi_dcmpgt(a: f64, b: f64) callconv(.AAPCS) i32 {
+ @setRuntimeSafety(false);
+ return @boolToInt(@call(.{ .modifier = .always_inline }, __gtdf2, .{ a, b }) > 0);
+}
+
pub fn __aeabi_dcmpun(a: f64, b: f64) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
return @call(.{ .modifier = .always_inline }, __unorddf2, .{ a, b });
From 861724bcf045327204a32b0e97517c0004122434 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sun, 19 Jan 2020 09:31:45 +0100
Subject: [PATCH 34/37] Fix some tests broken by the renamed files
---
lib/std/special/compiler_rt/comparedf2_test.zig | 2 +-
lib/std/special/compiler_rt/comparesf2_test.zig | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/std/special/compiler_rt/comparedf2_test.zig b/lib/std/special/compiler_rt/comparedf2_test.zig
index b0e5757ec0..16a2a258ce 100644
--- a/lib/std/special/compiler_rt/comparedf2_test.zig
+++ b/lib/std/special/compiler_rt/comparedf2_test.zig
@@ -6,7 +6,7 @@ const std = @import("std");
const builtin = @import("builtin");
const is_test = builtin.is_test;
-const comparedf2 = @import("comparedf2.zig");
+const comparedf2 = @import("compareXf2.zig");
const TestVector = struct {
a: f64,
diff --git a/lib/std/special/compiler_rt/comparesf2_test.zig b/lib/std/special/compiler_rt/comparesf2_test.zig
index d736988bfb..e3966c021b 100644
--- a/lib/std/special/compiler_rt/comparesf2_test.zig
+++ b/lib/std/special/compiler_rt/comparesf2_test.zig
@@ -6,7 +6,7 @@ const std = @import("std");
const builtin = @import("builtin");
const is_test = builtin.is_test;
-const comparesf2 = @import("comparesf2.zig");
+const comparesf2 = @import("compareXf2.zig");
const TestVector = struct {
a: f32,
From 7a1cde7206263c8bb3265c225ed4213d1b7bdb58 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Sun, 19 Jan 2020 10:06:48 +0100
Subject: [PATCH 35/37] Fix wrong error code being returned in enum analisys
Fixes the assertion failure seen in #4233
---
src/analyze.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 0bbec66a9b..638b0b03b0 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -2605,7 +2605,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
buf_ptr(&wanted_tag_int_type->name)));
add_error_note(g, msg, decl_node->data.container_decl.init_arg_expr,
buf_sprintf("any integral type of size 8, 16, 32, 64 or 128 bit is valid"));
- return ErrorNone;
+ return ErrorSemanticAnalyzeFail;
}
}
tag_int_type = wanted_tag_int_type;
From 0000de4fee601047f662dc33fe890eb8831d9787 Mon Sep 17 00:00:00 2001
From: Nathan Michaels
Date: Mon, 20 Jan 2020 12:23:43 -0500
Subject: [PATCH 36/37] Handle {s} format for C strings. (#4219)
* Handle {s} format for C strings.
* Fix "cstr" test to actually use c strings.
---
lib/std/fmt.zig | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig
index 548ef8ccce..5a650c3b10 100644
--- a/lib/std/fmt.zig
+++ b/lib/std/fmt.zig
@@ -431,7 +431,7 @@ pub fn formatType(
},
else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
},
- .Many => {
+ .Many, .C => {
if (ptr_info.child == u8) {
if (fmt.len > 0 and fmt[0] == 's') {
const len = mem.len(u8, value);
@@ -449,9 +449,6 @@ pub fn formatType(
}
return format(context, Errors, output, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });
},
- .C => {
- return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
- },
},
.Array => |info| {
const Slice = @Type(builtin.TypeInfo{
@@ -1285,8 +1282,16 @@ test "pointer" {
}
test "cstr" {
- try testFmt("cstr: Test C\n", "cstr: {s}\n", .{"Test C"});
- try testFmt("cstr: Test C \n", "cstr: {s:10}\n", .{"Test C"});
+ try testFmt(
+ "cstr: Test C\n",
+ "cstr: {s}\n",
+ .{@ptrCast([*c]const u8, "Test C")},
+ );
+ try testFmt(
+ "cstr: Test C \n",
+ "cstr: {s:10}\n",
+ .{@ptrCast([*c]const u8, "Test C")},
+ );
}
test "filesize" {
From c522699f28c1df806865c527a7a68a875e606527 Mon Sep 17 00:00:00 2001
From: LemonBoy
Date: Mon, 20 Jan 2020 16:27:18 +0100
Subject: [PATCH 37/37] Fix ICE in build addAssemblyFile
---
lib/std/build.zig | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/lib/std/build.zig b/lib/std/build.zig
index ad4be9e4ca..53f8f19df5 100644
--- a/lib/std/build.zig
+++ b/lib/std/build.zig
@@ -1687,7 +1687,9 @@ pub const LibExeObjStep = struct {
}
pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void {
- self.link_objects.append(LinkObject{ .AssemblyFile = self.builder.dupe(path) }) catch unreachable;
+ self.link_objects.append(LinkObject{
+ .AssemblyFile = .{ .path = self.builder.dupe(path) },
+ }) catch unreachable;
}
pub fn addAssemblyFileFromWriteFileStep(self: *LibExeObjStep, wfs: *WriteFileStep, basename: []const u8) void {