From 418b0967fc703dbad484b58bc09390e101219581 Mon Sep 17 00:00:00 2001
From: Josh Wolfe
Date: Wed, 29 Nov 2017 17:52:58 -0700
Subject: [PATCH 01/32] fix os.Dir compile errors
---
std/os/index.zig | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/std/os/index.zig b/std/os/index.zig
index e6a5fc4d15..361750aedc 100644
--- a/std/os/index.zig
+++ b/std/os/index.zig
@@ -939,6 +939,7 @@ start_over:
}
pub const Dir = struct {
+ // See man getdents
fd: i32,
allocator: &Allocator,
buf: []u8,
@@ -981,7 +982,7 @@ pub const Dir = struct {
pub fn close(self: &Dir) {
self.allocator.free(self.buf);
- close(self.fd);
+ os.close(self.fd);
}
/// Memory such as file names referenced in this returned entry becomes invalid
@@ -1013,7 +1014,7 @@ pub const Dir = struct {
break;
}
}
- const linux_entry = @ptrCast(&LinuxEntry, &self.buf[self.index]);
+ const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]);
const next_index = self.index + linux_entry.d_reclen;
self.index = next_index;
From 88a7f203f9de9a78f908dc63082173e10f9bf30e Mon Sep 17 00:00:00 2001
From: Josh Wolfe
Date: Wed, 29 Nov 2017 19:31:09 -0700
Subject: [PATCH 02/32] add Buffer.appendFormat()
---
std/buffer.zig | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/std/buffer.zig b/std/buffer.zig
index a1aa8faf9d..96abaeb762 100644
--- a/std/buffer.zig
+++ b/std/buffer.zig
@@ -4,6 +4,8 @@ const Allocator = mem.Allocator;
const assert = debug.assert;
const ArrayList = @import("array_list.zig").ArrayList;
+const fmt = @import("fmt/index.zig");
+
/// A buffer that allocates memory and maintains a null byte at the end.
pub const Buffer = struct {
list: ArrayList(u8),
@@ -96,6 +98,10 @@ pub const Buffer = struct {
mem.copy(u8, self.list.toSlice()[old_len..], m);
}
+ pub fn appendFormat(self: &Buffer, comptime format: []const u8, args: ...) -> %void {
+ return fmt.format(self, append, format, args);
+ }
+
pub fn appendByte(self: &Buffer, byte: u8) -> %void {
return self.appendByteNTimes(byte, 1);
}
From ccea8dcbf61cc4483bc73ba45751e545a8f3541e Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 29 Nov 2017 20:32:59 -0500
Subject: [PATCH 03/32] better error code for File.getEndPos failure
---
std/io.zig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/std/io.zig b/std/io.zig
index d570927488..6c6c171997 100644
--- a/std/io.zig
+++ b/std/io.zig
@@ -259,7 +259,7 @@ pub const File = struct {
if (err > 0) {
return switch (err) {
system.EBADF => error.BadFd,
- system.ENOMEM => error.OutOfMemory,
+ system.ENOMEM => error.SystemResources,
else => os.unexpectedErrorPosix(err),
}
}
From 716b0b8655610a3a64818c51a91254c6e4715e49 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 29 Nov 2017 21:33:58 -0500
Subject: [PATCH 04/32] fix capturing value of switch with all unreachable
prongs
closes #635
---
src/analyze.cpp | 2 +-
src/ir.cpp | 4 ++--
test/cases/switch.zig | 11 +++++++++++
3 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 1c223c63f7..a12934f2b2 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -4664,7 +4664,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
buf_appendf(buf, "%s", buf_ptr(&const_val->data.x_type->name));
return;
case TypeTableEntryIdUnreachable:
- buf_appendf(buf, "@unreachable()");
+ buf_appendf(buf, "unreachable");
return;
case TypeTableEntryIdBool:
{
diff --git a/src/ir.cpp b/src/ir.cpp
index 7c15b48bee..f1dc1e1b4d 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -11154,8 +11154,8 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
}
if (new_incoming_blocks.length == 0) {
- ir_build_const_from(ira, &phi_instruction->base);
- return ira->codegen->builtin_types.entry_void;
+ ir_build_unreachable_from(&ira->new_irb, &phi_instruction->base);
+ return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
}
if (new_incoming_blocks.length == 1) {
diff --git a/test/cases/switch.zig b/test/cases/switch.zig
index 154e251a04..9ec50c7e25 100644
--- a/test/cases/switch.zig
+++ b/test/cases/switch.zig
@@ -224,3 +224,14 @@ fn switchWithUnreachable(x: i32) -> i32 {
}
return 10;
}
+
+fn return_a_number() -> %i32 {
+ return 1;
+}
+
+test "capture value of switch with all unreachable prongs" {
+ const x = return_a_number() %% |err| switch (err) {
+ else => unreachable,
+ };
+ assert(x == 1);
+}
From 7729f6cf4edd7c8eda935b1c7c8b4276d73b6e69 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 29 Nov 2017 21:50:38 -0500
Subject: [PATCH 05/32] translate-c: support static incomplete array inside
function
---
src/translate_c.cpp | 16 ++++++++++++++--
test/translate_c.zig | 10 ++++++++++
2 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/src/translate_c.cpp b/src/translate_c.cpp
index f5c1ef5810..f89444a5ee 100644
--- a/src/translate_c.cpp
+++ b/src/translate_c.cpp
@@ -976,11 +976,23 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
const AttributedType *attributed_ty = static_cast(ty);
return trans_qual_type(c, attributed_ty->getEquivalentType(), source_loc);
}
+ case Type::IncompleteArray:
+ {
+ const IncompleteArrayType *incomplete_array_ty = static_cast(ty);
+ QualType child_qt = incomplete_array_ty->getElementType();
+ AstNode *child_type_node = trans_qual_type(c, child_qt, source_loc);
+ if (child_type_node == nullptr) {
+ emit_warning(c, source_loc, "unresolved array element type");
+ return nullptr;
+ }
+ AstNode *pointer_node = trans_create_node_addr_of(c, child_qt.isConstQualified(),
+ child_qt.isVolatileQualified(), child_type_node);
+ return pointer_node;
+ }
case Type::BlockPointer:
case Type::LValueReference:
case Type::RValueReference:
case Type::MemberPointer:
- case Type::IncompleteArray:
case Type::VariableArray:
case Type::DependentSizedArray:
case Type::DependentSizedExtVector:
@@ -4301,7 +4313,7 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch
}
}
- return 0;
+ return ErrorUnexpected;
}
c->ctx = &ast_unit->getASTContext();
diff --git a/test/translate_c.zig b/test/translate_c.zig
index 90b99b5faf..d4974109da 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -1178,4 +1178,14 @@ pub fn addCases(cases: &tests.TranslateCContext) {
,
\\pub var v0: ?&const u8 = c"0.0.0";
);
+
+ cases.add("static incomplete array inside function",
+ \\void foo(void) {
+ \\ static const char v2[] = "2.2.2";
+ \\}
+ ,
+ \\pub fn foo() {
+ \\ const v2: &const u8 = c"2.2.2";
+ \\}
+ );
}
From 210d0017c40ee24215ce705fcee342fe34b9dccb Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Wed, 29 Nov 2017 23:09:35 -0500
Subject: [PATCH 06/32] fix build broken by previous commit
now we report a compile error for unusual failures from translate-c
---
src/error.cpp | 1 +
src/error.hpp | 1 +
src/ir.cpp | 5 ++++-
src/translate_c.cpp | 2 +-
4 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/src/error.cpp b/src/error.cpp
index a6953d4ab3..8303a80a1d 100644
--- a/src/error.cpp
+++ b/src/error.cpp
@@ -26,6 +26,7 @@ const char *err_str(int err) {
case ErrorExactDivRemainder: return "exact division had a remainder";
case ErrorNegativeDenominator: return "negative denominator";
case ErrorShiftedOutOneBits: return "exact shift shifted out one bits";
+ case ErrorCCompileErrors: return "C compile errors";
}
return "(invalid error)";
}
diff --git a/src/error.hpp b/src/error.hpp
index d7d9c45baf..e3b87fc6b8 100644
--- a/src/error.hpp
+++ b/src/error.hpp
@@ -26,6 +26,7 @@ enum Error {
ErrorExactDivRemainder,
ErrorNegativeDenominator,
ErrorShiftedOutOneBits,
+ ErrorCCompileErrors,
};
const char *err_str(int err);
diff --git a/src/ir.cpp b/src/ir.cpp
index f1dc1e1b4d..e3f223a595 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -13870,7 +13870,10 @@ static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruc
int err;
if ((err = parse_h_buf(child_import, &errors, &cimport_scope->buf, ira->codegen, node))) {
- zig_panic("unable to parse C file: %s\n", err_str(err));
+ if (err != ErrorCCompileErrors) {
+ ir_add_error_node(ira, node, buf_sprintf("C import failed: %s", err_str(err)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
}
if (errors.length > 0) {
diff --git a/src/translate_c.cpp b/src/translate_c.cpp
index f89444a5ee..3dafa757d9 100644
--- a/src/translate_c.cpp
+++ b/src/translate_c.cpp
@@ -4313,7 +4313,7 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch
}
}
- return ErrorUnexpected;
+ return ErrorCCompileErrors;
}
c->ctx = &ast_unit->getASTContext();
From 5786df933d37d52d57fef9c28acb9c2c23128d31 Mon Sep 17 00:00:00 2001
From: Josh Wolfe
Date: Thu, 30 Nov 2017 11:20:39 -0700
Subject: [PATCH 07/32] add mem.readIntLE and readIntBE
---
std/mem.zig | 42 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)
diff --git a/std/mem.zig b/std/mem.zig
index 3cfdb25b35..9d78b1513b 100644
--- a/std/mem.zig
+++ b/std/mem.zig
@@ -180,6 +180,7 @@ test "mem.indexOf" {
/// Reads an integer from memory with size equal to bytes.len.
/// T specifies the return type, which must be large enough to store
/// the result.
+/// See also ::readIntBE or ::readIntLE.
pub fn readInt(bytes: []const u8, comptime T: type, big_endian: bool) -> T {
if (T.bit_count == 8) {
return bytes[0];
@@ -198,6 +199,34 @@ pub fn readInt(bytes: []const u8, comptime T: type, big_endian: bool) -> T {
return result;
}
+/// Reads a big-endian int of type T from bytes.
+/// bytes.len must be exactly @sizeOf(T).
+pub fn readIntBE(comptime T: type, bytes: []const u8) -> T {
+ if (T.is_signed) {
+ return @bitCast(T, readIntBE(@IntType(false, T.bit_count), bytes));
+ }
+ assert(bytes.len == @sizeOf(T));
+ var result: T = 0;
+ {comptime var i = 0; inline while (i < @sizeOf(T)) : (i += 1) {
+ result = (result << 8) | T(bytes[i]);
+ }}
+ return result;
+}
+
+/// Reads a little-endian int of type T from bytes.
+/// bytes.len must be exactly @sizeOf(T).
+pub fn readIntLE(comptime T: type, bytes: []const u8) -> T {
+ if (T.is_signed) {
+ return @bitCast(T, readIntLE(@IntType(false, T.bit_count), bytes));
+ }
+ assert(bytes.len == @sizeOf(T));
+ var result: T = 0;
+ {comptime var i = 0; inline while (i < @sizeOf(T)) : (i += 1) {
+ result |= T(bytes[i]) << i * 8;
+ }}
+ return result;
+}
+
/// Writes an integer to memory with size equal to bytes.len. Pads with zeroes
/// to fill the entire buffer provided.
/// value must be an integer.
@@ -348,8 +377,12 @@ test "testReadInt" {
fn testReadIntImpl() {
{
const bytes = []u8{ 0x12, 0x34, 0x56, 0x78 };
- assert(readInt(bytes, u32, true) == 0x12345678);
+ assert(readInt(bytes, u32, true) == 0x12345678);
+ assert(readIntBE(u32, bytes) == 0x12345678);
+ assert(readIntBE(i32, bytes) == 0x12345678);
assert(readInt(bytes, u32, false) == 0x78563412);
+ assert(readIntLE(u32, bytes) == 0x78563412);
+ assert(readIntLE(i32, bytes) == 0x78563412);
}
{
const buf = []u8{0x00, 0x00, 0x12, 0x34};
@@ -361,6 +394,13 @@ fn testReadIntImpl() {
const answer = readInt(buf, u64, false);
assert(answer == 0x00003412);
}
+ {
+ const bytes = []u8{0xff, 0xfe};
+ assert(readIntBE(u16, bytes) == 0xfffe);
+ assert(readIntBE(i16, bytes) == -0x0002);
+ assert(readIntLE(u16, bytes) == 0xfeff);
+ assert(readIntLE(i16, bytes) == -0x0101);
+ }
}
test "testWriteInt" {
From b62e2fd8703129fcf0dc80675800f005e84ee724 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 30 Nov 2017 21:46:02 -0500
Subject: [PATCH 08/32] ability to specify tag type of enums
see #305
---
doc/langref.html.in | 8 +++++-
src/all_types.hpp | 8 ++++++
src/analyze.cpp | 21 ++++++++++++++-
src/ast_render.cpp | 8 +++++-
src/codegen.cpp | 4 ++-
src/ir.cpp | 57 +++++++++++++++++++++++++++++++++++++++++
src/ir_print.cpp | 9 +++++++
src/parser.cpp | 7 ++++-
src/translate_c.cpp | 12 ++++++++-
test/cases/enum.zig | 24 +++++++++++++++++
test/compile_errors.zig | 28 ++++++++++++++++++++
11 files changed, 180 insertions(+), 6 deletions(-)
diff --git a/doc/langref.html.in b/doc/langref.html.in
index e8f76e230b..32c099f547 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -137,6 +137,7 @@
@divTrunc
@embedFile
@enumTagName
+ @EnumTagType
@errorName
@fence
@fieldParentPtr
@@ -4256,6 +4257,11 @@ test.zig:6:2: error: found compile log statement
Converts an enum tag name to a slice of bytes.
+ @EnumTagType
+ @EnumTagType(T: type) -> type
+
+ Returns the integer type that is used to store the enumeration value.
+
@errorName
@errorName(err: error) -> []u8
@@ -5837,7 +5843,7 @@ GroupedExpression = "(" Expression ")"
KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable"
-ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" many(ContainerMember) "}"
+ContainerDecl = option("extern" | "packed") ("struct" | "union" | ("enum" option(GroupedExpression))) "{" many(ContainerMember) "}"
Zen
- Communicate intent precisely.
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 2fccf08e88..40d246c43c 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -1286,6 +1286,7 @@ enum BuiltinFnId {
BuiltinFnIdIntToPtr,
BuiltinFnIdPtrToInt,
BuiltinFnIdEnumTagName,
+ BuiltinFnIdEnumTagType,
BuiltinFnIdFieldParentPtr,
BuiltinFnIdOffsetOf,
BuiltinFnIdInlineCall,
@@ -1911,6 +1912,7 @@ enum IrInstructionId {
IrInstructionIdDeclRef,
IrInstructionIdPanic,
IrInstructionIdEnumTagName,
+ IrInstructionIdEnumTagType,
IrInstructionIdFieldParentPtr,
IrInstructionIdOffsetOf,
IrInstructionIdTypeId,
@@ -2695,6 +2697,12 @@ struct IrInstructionEnumTagName {
IrInstruction *target;
};
+struct IrInstructionEnumTagType {
+ IrInstruction base;
+
+ IrInstruction *target;
+};
+
struct IrInstructionFieldParentPtr {
IrInstruction base;
diff --git a/src/analyze.cpp b/src/analyze.cpp
index a12934f2b2..33d6ccdc39 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -1267,7 +1267,7 @@ TypeTableEntry *create_enum_tag_type(CodeGen *g, TypeTableEntry *enum_type, Type
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnumTag);
buf_resize(&entry->name, 0);
- buf_appendf(&entry->name, "@enumTagType(%s)", buf_ptr(&enum_type->name));
+ buf_appendf(&entry->name, "@EnumTagType(%s)", buf_ptr(&enum_type->name));
entry->is_copyable = true;
entry->data.enum_tag.enum_type = enum_type;
@@ -1391,6 +1391,25 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
}
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
+ if (decl_node->data.container_decl.init_arg_expr != nullptr) {
+ TypeTableEntry *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr);
+ if (type_is_invalid(wanted_tag_int_type)) {
+ enum_type->data.enumeration.is_invalid = true;
+ } else if (wanted_tag_int_type->id != TypeTableEntryIdInt) {
+ enum_type->data.enumeration.is_invalid = true;
+ add_node_error(g, decl_node->data.container_decl.init_arg_expr,
+ buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));
+ } else if (wanted_tag_int_type->data.integral.bit_count < tag_int_type->data.integral.bit_count) {
+ enum_type->data.enumeration.is_invalid = true;
+ add_node_error(g, decl_node->data.container_decl.init_arg_expr,
+ buf_sprintf("'%s' too small to hold all bits; must be at least '%s'",
+ buf_ptr(&wanted_tag_int_type->name), buf_ptr(&tag_int_type->name)));
+ } else {
+ tag_int_type = wanted_tag_int_type;
+ }
+ }
+
+
TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
enum_type->data.enumeration.tag_type = tag_type_entry;
diff --git a/src/ast_render.cpp b/src/ast_render.cpp
index 5ffec92030..ce7bcd9e36 100644
--- a/src/ast_render.cpp
+++ b/src/ast_render.cpp
@@ -660,7 +660,13 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
{
const char *layout_str = layout_string(node->data.container_decl.layout);
const char *container_str = container_string(node->data.container_decl.kind);
- fprintf(ar->f, "%s%s {\n", layout_str, container_str);
+ fprintf(ar->f, "%s%s", layout_str, container_str);
+ if (node->data.container_decl.init_arg_expr != nullptr) {
+ fprintf(ar->f, "(");
+ render_node_grouped(ar, node->data.container_decl.init_arg_expr);
+ fprintf(ar->f, ")");
+ }
+ fprintf(ar->f, " {\n");
ar->indent += ar->indent_size;
for (size_t field_i = 0; field_i < node->data.container_decl.fields.length; field_i += 1) {
AstNode *field_node = node->data.container_decl.fields.at(field_i);
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 24d24a91e5..da94dd4bcd 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -3537,6 +3537,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdOpaqueType:
case IrInstructionIdSetAlignStack:
case IrInstructionIdArgType:
+ case IrInstructionIdEnumTagType:
zig_unreachable();
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -5049,7 +5050,8 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdBitCast, "bitCast", 2);
create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2);
create_builtin_fn(g, BuiltinFnIdPtrToInt, "ptrToInt", 1);
- create_builtin_fn(g, BuiltinFnIdEnumTagName, "enumTagName", 1);
+ create_builtin_fn(g, BuiltinFnIdEnumTagName, "enumTagName", 1); // TODO rename to memberName
+ create_builtin_fn(g, BuiltinFnIdEnumTagType, "EnumTagType", 1);
create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3);
create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2);
create_builtin_fn(g, BuiltinFnIdDivExact, "divExact", 2);
diff --git a/src/ir.cpp b/src/ir.cpp
index e3f223a595..c8617e3a8a 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -551,6 +551,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTagName *) {
return IrInstructionIdEnumTagName;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTagType *) {
+ return IrInstructionIdEnumTagType;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldParentPtr *) {
return IrInstructionIdFieldParentPtr;
}
@@ -2270,6 +2274,17 @@ static IrInstruction *ir_build_enum_tag_name(IrBuilder *irb, Scope *scope, AstNo
return &instruction->base;
}
+static IrInstruction *ir_build_enum_tag_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *target)
+{
+ IrInstructionEnumTagType *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->target = target;
+
+ ir_ref_instruction(target, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_field_parent_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *type_value, IrInstruction *field_name, IrInstruction *field_ptr, TypeStructField *field)
{
@@ -3066,6 +3081,13 @@ static IrInstruction *ir_instruction_enumtagname_get_dep(IrInstructionEnumTagNam
}
}
+static IrInstruction *ir_instruction_enumtagtype_get_dep(IrInstructionEnumTagType *instruction, size_t index) {
+ switch (index) {
+ case 0: return instruction->target;
+ default: return nullptr;
+ }
+}
+
static IrInstruction *ir_instruction_fieldparentptr_get_dep(IrInstructionFieldParentPtr *instruction, size_t index) {
switch (index) {
case 0: return instruction->type_value;
@@ -3326,6 +3348,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_panic_get_dep((IrInstructionPanic *) instruction, index);
case IrInstructionIdEnumTagName:
return ir_instruction_enumtagname_get_dep((IrInstructionEnumTagName *) instruction, index);
+ case IrInstructionIdEnumTagType:
+ return ir_instruction_enumtagtype_get_dep((IrInstructionEnumTagType *) instruction, index);
case IrInstructionIdFieldParentPtr:
return ir_instruction_fieldparentptr_get_dep((IrInstructionFieldParentPtr *) instruction, index);
case IrInstructionIdOffsetOf:
@@ -4681,6 +4705,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
IrInstruction *actual_tag = ir_build_enum_tag(irb, scope, node, arg0_value);
return ir_build_enum_tag_name(irb, scope, node, actual_tag);
}
+ case BuiltinFnIdEnumTagType:
+ {
+ 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;
+
+ return ir_build_enum_tag_type(irb, scope, node, arg0_value);
+ }
case BuiltinFnIdFieldParentPtr:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
@@ -15831,6 +15864,27 @@ static TypeTableEntry *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruc
return ira->codegen->builtin_types.entry_type;
}
+static TypeTableEntry *ir_analyze_instruction_enum_tag_type(IrAnalyze *ira, IrInstructionEnumTagType *instruction) {
+ IrInstruction *target_inst = instruction->target->other;
+ TypeTableEntry *enum_type = ir_resolve_type(ira, target_inst);
+ if (type_is_invalid(enum_type))
+ return ira->codegen->builtin_types.entry_invalid;
+ if (enum_type->id != TypeTableEntryIdEnum) {
+ ir_add_error(ira, target_inst, buf_sprintf("expected enum, found '%s'", buf_ptr(&enum_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ ensure_complete_type(ira->codegen, enum_type);
+ if (type_is_invalid(enum_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ TypeTableEntry *non_int_tag_type = enum_type->data.enumeration.tag_type;
+ assert(non_int_tag_type->id == TypeTableEntryIdEnumTag);
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ out_val->data.x_type = non_int_tag_type->data.enum_tag.int_type;
+ return ira->codegen->builtin_types.entry_type;
+}
+
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -16029,6 +16083,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_set_align_stack(ira, (IrInstructionSetAlignStack *)instruction);
case IrInstructionIdArgType:
return ir_analyze_instruction_arg_type(ira, (IrInstructionArgType *)instruction);
+ case IrInstructionIdEnumTagType:
+ return ir_analyze_instruction_enum_tag_type(ira, (IrInstructionEnumTagType *)instruction);
}
zig_unreachable();
}
@@ -16214,6 +16270,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdAlignCast:
case IrInstructionIdOpaqueType:
case IrInstructionIdArgType:
+ case IrInstructionIdEnumTagType:
return false;
case IrInstructionIdAsm:
{
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 55ad3ceb6c..0e06d1b563 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -994,6 +994,12 @@ static void ir_print_arg_type(IrPrint *irp, IrInstructionArgType *instruction) {
fprintf(irp->f, ")");
}
+static void ir_print_enum_tag_type(IrPrint *irp, IrInstructionEnumTagType *instruction) {
+ fprintf(irp->f, "@EnumTagType(");
+ ir_print_other_instruction(irp, instruction->target);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
@@ -1312,6 +1318,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdArgType:
ir_print_arg_type(irp, (IrInstructionArgType *)instruction);
break;
+ case IrInstructionIdEnumTagType:
+ ir_print_enum_tag_type(irp, (IrInstructionEnumTagType *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}
diff --git a/src/parser.cpp b/src/parser.cpp
index ba1fd99e57..7f25e3ef21 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -2377,7 +2377,7 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod vi
}
/*
-ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" many(ContainerMember) "}"
+ContainerDecl = option("extern" | "packed") ("struct" | "union" | ("enum" option(GroupedExpression))) "{" many(ContainerMember) "}"
ContainerMember = (ContainerField | FnDef | GlobalVarDecl)
ContainerField = Symbol option(":" Expression) ","
*/
@@ -2415,6 +2415,10 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
node->data.container_decl.layout = layout;
node->data.container_decl.kind = kind;
+ if (kind == ContainerKindEnum || kind == ContainerKindStruct) {
+ node->data.container_decl.init_arg_expr = ast_parse_grouped_expr(pc, token_index, false);
+ }
+
ast_eat_token(pc, token_index, TokenIdLBrace);
for (;;) {
@@ -2804,6 +2808,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeContainerDecl:
visit_node_list(&node->data.container_decl.fields, visit, context);
visit_node_list(&node->data.container_decl.decls, visit, context);
+ visit_field(&node->data.container_decl.init_arg_expr, visit, context);
break;
case NodeTypeStructField:
visit_field(&node->data.struct_field.type, visit, context);
diff --git a/src/translate_c.cpp b/src/translate_c.cpp
index 3dafa757d9..2bba498720 100644
--- a/src/translate_c.cpp
+++ b/src/translate_c.cpp
@@ -651,6 +651,14 @@ static bool c_is_unsigned_integer(Context *c, QualType qt) {
}
}
+static bool c_is_builtin_type(Context *c, QualType qt, BuiltinType::Kind kind) {
+ const Type *c_type = qual_type_canon(qt);
+ if (c_type->getTypeClass() != Type::Builtin)
+ return false;
+ const BuiltinType *builtin_ty = static_cast(c_type);
+ return builtin_ty->getKind() == kind;
+}
+
static bool c_is_float(Context *c, QualType qt) {
const Type *c_type = qt.getTypePtr();
if (c_type->getTypeClass() != Type::Builtin)
@@ -3426,7 +3434,9 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl);
enum_node->data.container_decl.kind = ContainerKindEnum;
enum_node->data.container_decl.layout = ContainerLayoutExtern;
- enum_node->data.container_decl.init_arg_expr = tag_int_type;
+ if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt)) {
+ enum_node->data.container_decl.init_arg_expr = tag_int_type;
+ }
enum_node->data.container_decl.fields.resize(field_count);
uint32_t i = 0;
diff --git a/test/cases/enum.zig b/test/cases/enum.zig
index f2d8ded0d6..a56ed398b8 100644
--- a/test/cases/enum.zig
+++ b/test/cases/enum.zig
@@ -190,3 +190,27 @@ test "enum sizes" {
assert(@sizeOf(ValueCount257) == 2);
}
}
+
+const Small2 = enum (u2) {
+ One,
+ Two,
+};
+const Small = enum (u2) {
+ One,
+ Two,
+ Three,
+ Four,
+};
+
+test "set enum tag type" {
+ {
+ var x = Small.One;
+ x = Small.Two;
+ comptime assert(@EnumTagType(Small) == u2);
+ }
+ {
+ var x = Small2.One;
+ x = Small2.Two;
+ comptime assert(@EnumTagType(Small2) == u2);
+ }
+}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 3ef4a63e5f..9b5ec6a6d6 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -2362,4 +2362,32 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
".tmp_source.zig:4:25: error: aoeu",
".tmp_source.zig:1:36: note: called from here",
".tmp_source.zig:12:20: note: referenced here");
+
+ cases.add("specify enum tag type that is too small",
+ \\const Small = enum (u2) {
+ \\ One,
+ \\ Two,
+ \\ Three,
+ \\ Four,
+ \\ Five,
+ \\};
+ \\
+ \\export fn entry() {
+ \\ var x = Small.One;
+ \\}
+ ,
+ ".tmp_source.zig:1:20: error: 'u2' too small to hold all bits; must be at least 'u3'");
+
+ cases.add("specify non-integer enum tag type",
+ \\const Small = enum (f32) {
+ \\ One,
+ \\ Two,
+ \\ Three,
+ \\};
+ \\
+ \\export fn entry() {
+ \\ var x = Small.One;
+ \\}
+ ,
+ ".tmp_source.zig:1:20: error: expected integer, found 'f32'");
}
From 264c86853b714482d006baa38482a6f7d55e8d94 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 1 Dec 2017 00:34:29 -0500
Subject: [PATCH 09/32] packed structs can have enums with explicit tag types
See #305
---
src/analyze.cpp | 4 ++-
src/codegen.cpp | 9 +++++-
test/cases/enum.zig | 70 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 81 insertions(+), 2 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 33d6ccdc39..235aeea682 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -1536,7 +1536,6 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
case TypeTableEntryIdNullLit:
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdPureError:
- case TypeTableEntryIdEnum:
case TypeTableEntryIdEnumTag:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
@@ -1560,6 +1559,9 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
TypeTableEntry *child_type = type_entry->data.maybe.child_type;
return child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn;
}
+ case TypeTableEntryIdEnum:
+ return type_entry->data.enumeration.gen_field_count == 0 &&
+ type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr;
}
zig_unreachable();
}
diff --git a/src/codegen.cpp b/src/codegen.cpp
index da94dd4bcd..a5f8b85e22 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -3762,7 +3762,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
case TypeTableEntryIdNullLit:
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdPureError:
- case TypeTableEntryIdEnum:
case TypeTableEntryIdEnumTag:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
@@ -3773,6 +3772,13 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
zig_unreachable();
case TypeTableEntryIdBool:
return LLVMConstInt(big_int_type_ref, const_val->data.x_bool ? 1 : 0, false);
+ case TypeTableEntryIdEnum:
+ {
+ assert(type_entry->data.enumeration.gen_field_count == 0);
+ assert(type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr);
+ LLVMValueRef int_val = gen_const_val(g, const_val);
+ return LLVMConstZExt(int_val, big_int_type_ref);
+ }
case TypeTableEntryIdInt:
{
LLVMValueRef int_val = gen_const_val(g, const_val);
@@ -3814,6 +3820,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
}
return val;
}
+
}
zig_unreachable();
}
diff --git a/test/cases/enum.zig b/test/cases/enum.zig
index a56ed398b8..1b2ff10a9b 100644
--- a/test/cases/enum.zig
+++ b/test/cases/enum.zig
@@ -214,3 +214,73 @@ test "set enum tag type" {
comptime assert(@EnumTagType(Small2) == u2);
}
}
+
+
+const A = enum (u3) {
+ One,
+ Two,
+ Three,
+ Four,
+ One2,
+ Two2,
+ Three2,
+ Four2,
+};
+
+const B = enum (u3) {
+ One3,
+ Two3,
+ Three3,
+ Four3,
+ One23,
+ Two23,
+ Three23,
+ Four23,
+};
+
+const C = enum (u2) {
+ One4,
+ Two4,
+ Three4,
+ Four4,
+};
+
+const BitFieldOfEnums = packed struct {
+ a: A,
+ b: B,
+ c: C,
+};
+
+const bit_field_1 = BitFieldOfEnums {
+ .a = A.Two,
+ .b = B.Three3,
+ .c = C.Four4,
+};
+
+test "bit field access with enum fields" {
+ var data = bit_field_1;
+ assert(getA(&data) == A.Two);
+ assert(getB(&data) == B.Three3);
+ assert(getC(&data) == C.Four4);
+ comptime assert(@sizeOf(BitFieldOfEnums) == 1);
+
+ data.b = B.Four3;
+ assert(data.b == B.Four3);
+
+ data.a = A.Three;
+ assert(data.a == A.Three);
+ assert(data.b == B.Four3);
+}
+
+fn getA(data: &const BitFieldOfEnums) -> A {
+ return data.a;
+}
+
+fn getB(data: &const BitFieldOfEnums) -> B {
+ return data.b;
+}
+
+fn getC(data: &const BitFieldOfEnums) -> C {
+ return data.c;
+}
+
From b4120423a5f0785e950739ab8c1324691971d680 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 1 Dec 2017 00:37:15 -0500
Subject: [PATCH 10/32] translate-c: only emit enum tag type if not c_int or
c_uint
---
src/translate_c.cpp | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/translate_c.cpp b/src/translate_c.cpp
index 2bba498720..5082c37a61 100644
--- a/src/translate_c.cpp
+++ b/src/translate_c.cpp
@@ -3434,7 +3434,12 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl);
enum_node->data.container_decl.kind = ContainerKindEnum;
enum_node->data.container_decl.layout = ContainerLayoutExtern;
- if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt)) {
+ // 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 (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) &&
+ !c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int))
+ {
enum_node->data.container_decl.init_arg_expr = tag_int_type;
}
From 77b530b50aedd1cf9943e1d4fdd97a364fe9a921 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 1 Dec 2017 11:59:14 -0500
Subject: [PATCH 11/32] updated embedded LLD to 5.0.1rc2
---
deps/lld-prebuilt/lld/Config/Version.inc | 4 +-
deps/lld/COFF/Driver.cpp | 6 +-
deps/lld/ELF/LinkerScript.cpp | 2 +-
deps/lld/ELF/SyntheticSections.cpp | 12 +++-
deps/lld/ELF/SyntheticSections.h | 3 +-
deps/lld/lib/ReaderWriter/MachO/ArchHandler.h | 4 --
.../ReaderWriter/MachO/ArchHandler_arm.cpp | 4 --
.../ReaderWriter/MachO/ArchHandler_arm64.cpp | 4 --
.../ReaderWriter/MachO/ArchHandler_x86.cpp | 4 --
.../ReaderWriter/MachO/ArchHandler_x86_64.cpp | 6 +-
.../MachO/MachONormalizedFileFromAtoms.cpp | 57 -----------------
.../test/ELF/eh-frame-padding-no-rosegment.s | 64 +++++++++++++++++++
deps/lld/test/mach-o/lazy-bind-x86_64.yaml | 4 +-
13 files changed, 85 insertions(+), 89 deletions(-)
create mode 100644 deps/lld/test/ELF/eh-frame-padding-no-rosegment.s
diff --git a/deps/lld-prebuilt/lld/Config/Version.inc b/deps/lld-prebuilt/lld/Config/Version.inc
index 2fb8a16222..a3f6f44588 100644
--- a/deps/lld-prebuilt/lld/Config/Version.inc
+++ b/deps/lld-prebuilt/lld/Config/Version.inc
@@ -1,5 +1,5 @@
-#define LLD_VERSION 5.0.0
-#define LLD_VERSION_STRING "5.0.0"
+#define LLD_VERSION 5.0.1
+#define LLD_VERSION_STRING "5.0.1"
#define LLD_VERSION_MAJOR 5
#define LLD_VERSION_MINOR 0
#define LLD_REVISION_STRING ""
diff --git a/deps/lld/COFF/Driver.cpp b/deps/lld/COFF/Driver.cpp
index 0dabca6e37..854c3e6909 100644
--- a/deps/lld/COFF/Driver.cpp
+++ b/deps/lld/COFF/Driver.cpp
@@ -61,7 +61,6 @@ bool link(ArrayRef Args, raw_ostream &Diag) {
(ErrorOS == &llvm::errs() && Process::StandardErrHasColors());
Driver = make();
Driver->link(Args);
- freeArena();
return !ErrorCount;
}
@@ -1031,7 +1030,7 @@ void LinkerDriver::link(ArrayRef ArgsArr) {
if (!Args.hasArgNoClaim(OPT_INPUT)) {
fixupExports();
createImportLibrary(/*AsLib=*/true);
- return;
+ exit(0);
}
// Handle /delayload
@@ -1173,6 +1172,9 @@ void LinkerDriver::link(ArrayRef ArgsArr) {
// Write the result.
writeResult(&Symtab);
+
+ // Call exit to avoid calling destructors.
+ exit(0);
}
} // namespace coff
diff --git a/deps/lld/ELF/LinkerScript.cpp b/deps/lld/ELF/LinkerScript.cpp
index 614f5e2c8b..8bdbd8db20 100644
--- a/deps/lld/ELF/LinkerScript.cpp
+++ b/deps/lld/ELF/LinkerScript.cpp
@@ -751,7 +751,7 @@ void LinkerScript::adjustSectionsAfterSorting() {
if (auto *Cmd = dyn_cast(Base)) {
Cmd->MemRegion = findMemoryRegion(Cmd);
// Handle align (e.g. ".foo : ALIGN(16) { ... }").
- if (Cmd->AlignExpr && Cmd->Sec)
+ if (Cmd->AlignExpr)
Cmd->Sec->updateAlignment(Cmd->AlignExpr().getValue());
}
}
diff --git a/deps/lld/ELF/SyntheticSections.cpp b/deps/lld/ELF/SyntheticSections.cpp
index 4bbec4ab34..a67b039ddf 100644
--- a/deps/lld/ELF/SyntheticSections.cpp
+++ b/deps/lld/ELF/SyntheticSections.cpp
@@ -427,10 +427,11 @@ CieRecord *EhFrameSection::addCie(EhSectionPiece &Piece,
&Sec->template getFile()->getRelocTargetSym(Rels[FirstRelI]);
// Search for an existing CIE by CIE contents/relocation target pair.
- CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
+ CieRecord *&Cie = CieMap[{Piece.data(), Personality}];
// If not found, create a new one.
- if (Cie->Piece == nullptr) {
+ if (!Cie) {
+ Cie = make();
Cie->Piece = &Piece;
Cies.push_back(Cie);
}
@@ -522,9 +523,14 @@ template
static void writeCieFde(uint8_t *Buf, ArrayRef D) {
memcpy(Buf, D.data(), D.size());
+ size_t Aligned = alignTo(D.size(), sizeof(typename ELFT::uint));
+
+ // Zero-clear trailing padding if it exists.
+ memset(Buf + D.size(), 0, Aligned - D.size());
+
// Fix the size field. -4 since size does not include the size field itself.
const endianness E = ELFT::TargetEndianness;
- write32(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4);
+ write32(Buf, Aligned - 4);
}
template void EhFrameSection::finalizeContents() {
diff --git a/deps/lld/ELF/SyntheticSections.h b/deps/lld/ELF/SyntheticSections.h
index ddd8ca99a6..ccf021ec95 100644
--- a/deps/lld/ELF/SyntheticSections.h
+++ b/deps/lld/ELF/SyntheticSections.h
@@ -103,7 +103,8 @@ private:
std::vector Cies;
// CIE records are uniquified by their contents and personality functions.
- llvm::DenseMap, SymbolBody *>, CieRecord> CieMap;
+ llvm::DenseMap, SymbolBody *>, CieRecord *>
+ CieMap;
};
class GotSection : public SyntheticSection {
diff --git a/deps/lld/lib/ReaderWriter/MachO/ArchHandler.h b/deps/lld/lib/ReaderWriter/MachO/ArchHandler.h
index 6028006ca9..70a63bd100 100644
--- a/deps/lld/lib/ReaderWriter/MachO/ArchHandler.h
+++ b/deps/lld/lib/ReaderWriter/MachO/ArchHandler.h
@@ -112,10 +112,6 @@ public:
/// info in final executables.
virtual bool isLazyPointer(const Reference &);
- /// Reference from an __stub_helper entry to the required offset of the
- /// lazy bind commands.
- virtual Reference::KindValue lazyImmediateLocationKind() = 0;
-
/// Returns true if the specified relocation is paired to the next relocation.
virtual bool isPairedReloc(const normalized::Relocation &) = 0;
diff --git a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
index 2f663c660f..7d1544854c 100644
--- a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
+++ b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
@@ -67,10 +67,6 @@ public:
return invalid;
}
- Reference::KindValue lazyImmediateLocationKind() override {
- return lazyImmediateLocation;
- }
-
Reference::KindValue pointerKind() override {
return invalid;
}
diff --git a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
index b9c815c5a3..10360b5c6d 100644
--- a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
+++ b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
@@ -127,10 +127,6 @@ public:
return pointer64;
}
- Reference::KindValue lazyImmediateLocationKind() override {
- return lazyImmediateLocation;
- }
-
uint32_t dwarfCompactUnwindType() override {
return 0x03000000;
}
diff --git a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
index a2c6809272..2272bff65c 100644
--- a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
+++ b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
@@ -70,10 +70,6 @@ public:
return delta32;
}
- Reference::KindValue lazyImmediateLocationKind() override {
- return lazyImmediateLocation;
- }
-
Reference::KindValue unwindRefToEhFrameKind() override {
return invalid;
}
diff --git a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
index efe23abb91..d687ca5de5 100644
--- a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
+++ b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
@@ -116,10 +116,6 @@ public:
return unwindFDEToFunction;
}
- Reference::KindValue lazyImmediateLocationKind() override {
- return lazyImmediateLocation;
- }
-
Reference::KindValue unwindRefToEhFrameKind() override {
return unwindInfoToEhFrame;
}
@@ -621,7 +617,7 @@ void ArchHandler_x86_64::applyFixupFinal(
// Fall into llvm_unreachable().
break;
}
- return;
+ llvm_unreachable("invalid x86_64 Reference Kind");
}
void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
diff --git a/deps/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/deps/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
index f2e5ed7816..e58e3d2e7a 100644
--- a/deps/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
+++ b/deps/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
@@ -172,8 +172,6 @@ private:
SymbolScope &symbolScope);
void appendSection(SectionInfo *si, NormalizedFile &file);
uint32_t sectionIndexForAtom(const Atom *atom);
- void fixLazyReferenceImm(const DefinedAtom *atom, uint32_t offset,
- NormalizedFile &file);
typedef llvm::DenseMap AtomToIndex;
struct AtomAndIndex { const Atom *atom; uint32_t index; SymbolScope scope; };
@@ -1425,8 +1423,6 @@ void Util::addRebaseAndBindingInfo(const lld::File &atomFile,
uint8_t segmentIndex;
uint64_t segmentStartAddr;
- uint32_t offsetInBindInfo = 0;
-
for (SectionInfo *sect : _sectionInfos) {
segIndexForSection(sect, segmentIndex, segmentStartAddr);
for (const AtomInfo &info : sect->atomsAndOffsets) {
@@ -1471,59 +1467,6 @@ void Util::addRebaseAndBindingInfo(const lld::File &atomFile,
bind.symbolName = targ->name();
bind.addend = ref->addend();
nFile.lazyBindingInfo.push_back(bind);
-
- // Now that we know the segmentOffset and the ordinal attribute,
- // we can fix the helper's code
-
- fixLazyReferenceImm(atom, offsetInBindInfo, nFile);
-
- // 5 bytes for opcodes + variable sizes (target name + \0 and offset
- // encode's size)
- offsetInBindInfo +=
- 6 + targ->name().size() + llvm::getULEB128Size(bind.segOffset);
- if (bind.ordinal > BIND_IMMEDIATE_MASK)
- offsetInBindInfo += llvm::getULEB128Size(bind.ordinal);
- }
- }
- }
- }
-}
-
-void Util::fixLazyReferenceImm(const DefinedAtom *atom, uint32_t offset,
- NormalizedFile &file) {
- for (const auto &ref : *atom) {
- const DefinedAtom *da = dyn_cast(ref->target());
- if (da == nullptr)
- return;
-
- const Reference *helperRef = nullptr;
- for (const Reference *hr : *da) {
- if (hr->kindValue() == _archHandler.lazyImmediateLocationKind()) {
- helperRef = hr;
- break;
- }
- }
- if (helperRef == nullptr)
- continue;
-
- // TODO: maybe get the fixed atom content from _archHandler ?
- for (SectionInfo *sectInfo : _sectionInfos) {
- for (const AtomInfo &atomInfo : sectInfo->atomsAndOffsets) {
- if (atomInfo.atom == helperRef->target()) {
- auto sectionContent =
- file.sections[sectInfo->normalizedSectionIndex].content;
- uint8_t *rawb =
- file.ownedAllocations.Allocate(sectionContent.size());
- llvm::MutableArrayRef newContent{rawb,
- sectionContent.size()};
- std::copy(sectionContent.begin(), sectionContent.end(),
- newContent.begin());
- llvm::support::ulittle32_t *loc =
- reinterpret_cast(
- &newContent[atomInfo.offsetInSection +
- helperRef->offsetInAtom()]);
- *loc = offset;
- file.sections[sectInfo->normalizedSectionIndex].content = newContent;
}
}
}
diff --git a/deps/lld/test/ELF/eh-frame-padding-no-rosegment.s b/deps/lld/test/ELF/eh-frame-padding-no-rosegment.s
new file mode 100644
index 0000000000..951fed0a56
--- /dev/null
+++ b/deps/lld/test/ELF/eh-frame-padding-no-rosegment.s
@@ -0,0 +1,64 @@
+// REQUIRES: x86
+
+.cfi_startproc
+.cfi_personality 0x1b, bar
+.cfi_endproc
+
+.global bar
+.hidden bar
+bar:
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+// Check the size of the CIE (0x18 + 4) and FDE (0x10 + 4)
+// RUN: llvm-readobj -s -section-data %t.o | FileCheck --check-prefix=OBJ %s
+
+// OBJ: Name: .eh_frame
+// OBJ-NEXT: Type:
+// OBJ-NEXT: Flags [
+// OBJ-NEXT: SHF_ALLOC
+// OBJ-NEXT: ]
+// OBJ-NEXT: Address:
+// OBJ-NEXT: Offset:
+// OBJ-NEXT: Size:
+// OBJ-NEXT: Link:
+// OBJ-NEXT: Info:
+// OBJ-NEXT: AddressAlignment:
+// OBJ-NEXT: EntrySize:
+// OBJ-NEXT: SectionData (
+// OBJ-NEXT: 0000: 18000000 00000000 017A5052 00017810
+// OBJ-NEXT: 0010: 061B0000 00001B0C 07089001 10000000
+// OBJ-NEXT: 0020: 20000000 00000000 00000000 00000000
+// OBJ-NEXT: )
+
+// RUN: ld.lld %t.o -no-rosegment -o %t -shared
+
+// Check that .eh_frame is in the same segment as .text
+// RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=PHDR %s
+
+// PHDR: Segment Sections
+// PHDR: .text
+// PHDR-SAME: .eh_frame
+
+// Check that the CIE and FDE are padded with 0x00 and not 0xCC when the
+// .eh_frame section is placed in the executable segment
+// RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+// CHECK: Name: .eh_frame
+// CHECK-NEXT: Type:
+// CHECK-NEXT: Flags
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Link:
+// CHECK-NEXT: Info:
+// CHECK-NEXT: AddressAlignment:
+// CHECK-NEXT: EntrySize:
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000: 1C000000 00000000 017A5052 00017810
+// CHECK-NEXT: 0010: 061BBEFF FFFF1B0C 07089001 00000000
+// CHECK-NEXT: 0020: 14000000 24000000 A8FFFFFF 00000000
+// CHECK-NEXT: 0030: 00000000 00000000
+// CHECK-NEXT: )
diff --git a/deps/lld/test/mach-o/lazy-bind-x86_64.yaml b/deps/lld/test/mach-o/lazy-bind-x86_64.yaml
index 1322719e5f..5c588c5719 100644
--- a/deps/lld/test/mach-o/lazy-bind-x86_64.yaml
+++ b/deps/lld/test/mach-o/lazy-bind-x86_64.yaml
@@ -80,8 +80,8 @@ undefined-symbols:
# CHECK-HELPERS:Disassembly of section __TEXT,__stub_helper:
# CHECK-HELPERS: 68 00 00 00 00 pushq $0
-# CHECK-HELPERS: 68 0b 00 00 00 pushq $11
-# CHECK-HELPERS: 68 16 00 00 00 pushq $22
+# CHECK-HELPERS: 68 10 00 00 00 pushq $16
+# CHECK-HELPERS: 68 20 00 00 00 pushq $32
# Make sure the stub helper is correctly aligned
# CHECK-DYLIBS: sectname __stub_helper
From 9ea23272fac7f4580d29f7ee557108883f127a5d Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 1 Dec 2017 12:06:33 -0500
Subject: [PATCH 12/32] LLD patch: COFF: better behavior when using as a
library
This applies de776439b61fb71c1256ad86238799c758c66048
from the LLVM git monorepo to the embedded LLD.
---
deps/lld/COFF/Config.h | 1 +
deps/lld/COFF/Driver.cpp | 16 ++++++++++------
deps/lld/COFF/Error.cpp | 5 +++--
deps/lld/COFF/Error.h | 2 ++
deps/lld/include/lld/Driver/Driver.h | 2 +-
deps/lld/tools/lld/lld.cpp | 2 +-
6 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/deps/lld/COFF/Config.h b/deps/lld/COFF/Config.h
index 7f8259d016..ffbd0715cf 100644
--- a/deps/lld/COFF/Config.h
+++ b/deps/lld/COFF/Config.h
@@ -157,6 +157,7 @@ struct Configuration {
uint32_t MinorImageVersion = 0;
uint32_t MajorOSVersion = 6;
uint32_t MinorOSVersion = 0;
+ bool CanExitEarly = false;
bool DynamicBase = true;
bool NxCompat = true;
bool AllowIsolation = true;
diff --git a/deps/lld/COFF/Driver.cpp b/deps/lld/COFF/Driver.cpp
index 854c3e6909..868ff0aa1e 100644
--- a/deps/lld/COFF/Driver.cpp
+++ b/deps/lld/COFF/Driver.cpp
@@ -52,15 +52,22 @@ BumpPtrAllocator BAlloc;
StringSaver Saver{BAlloc};
std::vector SpecificAllocBase::Instances;
-bool link(ArrayRef Args, raw_ostream &Diag) {
+bool link(ArrayRef Args, bool CanExitEarly, raw_ostream &Diag) {
ErrorCount = 0;
ErrorOS = &Diag;
Config = make();
Config->Argv = {Args.begin(), Args.end()};
Config->ColorDiagnostics =
(ErrorOS == &llvm::errs() && Process::StandardErrHasColors());
+ Config->CanExitEarly = CanExitEarly;
Driver = make();
Driver->link(Args);
+
+ // Call exit() if we can to avoid calling destructors.
+ if (CanExitEarly)
+ exitLld(ErrorCount ? 1 : 0);
+
+ freeArena();
return !ErrorCount;
}
@@ -1030,7 +1037,7 @@ void LinkerDriver::link(ArrayRef ArgsArr) {
if (!Args.hasArgNoClaim(OPT_INPUT)) {
fixupExports();
createImportLibrary(/*AsLib=*/true);
- exit(0);
+ return;
}
// Handle /delayload
@@ -1122,7 +1129,7 @@ void LinkerDriver::link(ArrayRef ArgsArr) {
// This is useful because MSVC link.exe can generate complete PDBs.
if (Args.hasArg(OPT_msvclto)) {
invokeMSVC(Args);
- exit(0);
+ return;
}
// Do LTO by compiling bitcode input files to a set of native COFF files then
@@ -1172,9 +1179,6 @@ void LinkerDriver::link(ArrayRef ArgsArr) {
// Write the result.
writeResult(&Symtab);
-
- // Call exit to avoid calling destructors.
- exit(0);
}
} // namespace coff
diff --git a/deps/lld/COFF/Error.cpp b/deps/lld/COFF/Error.cpp
index 34abc280f6..550d9b9696 100644
--- a/deps/lld/COFF/Error.cpp
+++ b/deps/lld/COFF/Error.cpp
@@ -32,7 +32,7 @@ namespace coff {
uint64_t ErrorCount;
raw_ostream *ErrorOS;
-static LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) {
+LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) {
// Dealloc/destroy ManagedStatic variables before calling
// _exit(). In a non-LTO build, this is a nop. In an LTO
// build allows us to get the output of -time-passes.
@@ -78,7 +78,8 @@ void error(const Twine &Msg) {
print("error: ", raw_ostream::RED);
*ErrorOS << "too many errors emitted, stopping now"
<< " (use /ERRORLIMIT:0 to see all errors)\n";
- exitLld(1);
+ if (Config->CanExitEarly)
+ exitLld(1);
}
++ErrorCount;
diff --git a/deps/lld/COFF/Error.h b/deps/lld/COFF/Error.h
index e1e4c1e521..1c1e2beab5 100644
--- a/deps/lld/COFF/Error.h
+++ b/deps/lld/COFF/Error.h
@@ -27,6 +27,8 @@ LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix);
LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error &Err, const Twine &Prefix);
+LLVM_ATTRIBUTE_NORETURN void exitLld(int Val);
+
template T check(ErrorOr V, const Twine &Prefix) {
if (auto EC = V.getError())
fatal(EC, Prefix);
diff --git a/deps/lld/include/lld/Driver/Driver.h b/deps/lld/include/lld/Driver/Driver.h
index 4ba0994e88..02c3c059d3 100644
--- a/deps/lld/include/lld/Driver/Driver.h
+++ b/deps/lld/include/lld/Driver/Driver.h
@@ -15,7 +15,7 @@
namespace lld {
namespace coff {
-bool link(llvm::ArrayRef Args,
+bool link(llvm::ArrayRef Args, bool CanExitEarly,
llvm::raw_ostream &Diag = llvm::errs());
}
diff --git a/deps/lld/tools/lld/lld.cpp b/deps/lld/tools/lld/lld.cpp
index 09f8079010..aa81aa9712 100644
--- a/deps/lld/tools/lld/lld.cpp
+++ b/deps/lld/tools/lld/lld.cpp
@@ -103,7 +103,7 @@ int main(int Argc, const char **Argv) {
case Gnu:
return !elf::link(Args, true);
case WinLink:
- return !coff::link(Args);
+ return !coff::link(Args, true);
case Darwin:
return !mach_o::link(Args);
default:
From fa45407e78c7a20281bf063f659d74f86c127ea1 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 1 Dec 2017 12:08:16 -0500
Subject: [PATCH 13/32] LLD patch: Fix for LLD on linker scripts with empty
sections
This reapplies 569cf286ff79a10126b9f20f39fa8c64df9b8b25
to the embedded LLD.
---
deps/lld/ELF/LinkerScript.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/deps/lld/ELF/LinkerScript.cpp b/deps/lld/ELF/LinkerScript.cpp
index 8bdbd8db20..614f5e2c8b 100644
--- a/deps/lld/ELF/LinkerScript.cpp
+++ b/deps/lld/ELF/LinkerScript.cpp
@@ -751,7 +751,7 @@ void LinkerScript::adjustSectionsAfterSorting() {
if (auto *Cmd = dyn_cast(Base)) {
Cmd->MemRegion = findMemoryRegion(Cmd);
// Handle align (e.g. ".foo : ALIGN(16) { ... }").
- if (Cmd->AlignExpr)
+ if (Cmd->AlignExpr && Cmd->Sec)
Cmd->Sec->updateAlignment(Cmd->AlignExpr().getValue());
}
}
From ddca67a2b94f68985789fc8254fd1326e26269f6 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 1 Dec 2017 12:09:55 -0500
Subject: [PATCH 14/32] LLD patch: workaround for buggy MACH-O code
This reapplies 1a1414fc42c7beb25b6de4134d99884ea6544b57
to the embedded LLD.
---
deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
index d687ca5de5..07958da4b9 100644
--- a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
+++ b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
@@ -617,7 +617,6 @@ void ArchHandler_x86_64::applyFixupFinal(
// Fall into llvm_unreachable().
break;
}
- llvm_unreachable("invalid x86_64 Reference Kind");
}
void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
From a206ef34bbbc46017e471063a4a1832c1ddafb0a Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 1 Dec 2017 12:11:55 -0500
Subject: [PATCH 15/32] LLD patch: Fix the ASM code generated for
__stub_helpers section
This applies 93ca847862af07632197dcf2d8a68b9b27a26d7a
from the llvm-project git monorepo to the embedded LLD.
---
deps/lld/lib/ReaderWriter/MachO/ArchHandler.h | 4 ++
.../ReaderWriter/MachO/ArchHandler_arm.cpp | 4 ++
.../ReaderWriter/MachO/ArchHandler_arm64.cpp | 4 ++
.../ReaderWriter/MachO/ArchHandler_x86.cpp | 4 ++
.../ReaderWriter/MachO/ArchHandler_x86_64.cpp | 4 ++
.../MachO/MachONormalizedFileFromAtoms.cpp | 57 +++++++++++++++++++
deps/lld/test/mach-o/lazy-bind-x86_64.yaml | 4 +-
7 files changed, 79 insertions(+), 2 deletions(-)
diff --git a/deps/lld/lib/ReaderWriter/MachO/ArchHandler.h b/deps/lld/lib/ReaderWriter/MachO/ArchHandler.h
index 70a63bd100..6028006ca9 100644
--- a/deps/lld/lib/ReaderWriter/MachO/ArchHandler.h
+++ b/deps/lld/lib/ReaderWriter/MachO/ArchHandler.h
@@ -112,6 +112,10 @@ public:
/// info in final executables.
virtual bool isLazyPointer(const Reference &);
+ /// Reference from an __stub_helper entry to the required offset of the
+ /// lazy bind commands.
+ virtual Reference::KindValue lazyImmediateLocationKind() = 0;
+
/// Returns true if the specified relocation is paired to the next relocation.
virtual bool isPairedReloc(const normalized::Relocation &) = 0;
diff --git a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
index 7d1544854c..2f663c660f 100644
--- a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
+++ b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
@@ -67,6 +67,10 @@ public:
return invalid;
}
+ Reference::KindValue lazyImmediateLocationKind() override {
+ return lazyImmediateLocation;
+ }
+
Reference::KindValue pointerKind() override {
return invalid;
}
diff --git a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
index 10360b5c6d..b9c815c5a3 100644
--- a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
+++ b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_arm64.cpp
@@ -127,6 +127,10 @@ public:
return pointer64;
}
+ Reference::KindValue lazyImmediateLocationKind() override {
+ return lazyImmediateLocation;
+ }
+
uint32_t dwarfCompactUnwindType() override {
return 0x03000000;
}
diff --git a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
index 2272bff65c..a2c6809272 100644
--- a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
+++ b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
@@ -70,6 +70,10 @@ public:
return delta32;
}
+ Reference::KindValue lazyImmediateLocationKind() override {
+ return lazyImmediateLocation;
+ }
+
Reference::KindValue unwindRefToEhFrameKind() override {
return invalid;
}
diff --git a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
index 07958da4b9..b207c85523 100644
--- a/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
+++ b/deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
@@ -116,6 +116,10 @@ public:
return unwindFDEToFunction;
}
+ Reference::KindValue lazyImmediateLocationKind() override {
+ return lazyImmediateLocation;
+ }
+
Reference::KindValue unwindRefToEhFrameKind() override {
return unwindInfoToEhFrame;
}
diff --git a/deps/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/deps/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
index e58e3d2e7a..f2e5ed7816 100644
--- a/deps/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
+++ b/deps/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
@@ -172,6 +172,8 @@ private:
SymbolScope &symbolScope);
void appendSection(SectionInfo *si, NormalizedFile &file);
uint32_t sectionIndexForAtom(const Atom *atom);
+ void fixLazyReferenceImm(const DefinedAtom *atom, uint32_t offset,
+ NormalizedFile &file);
typedef llvm::DenseMap AtomToIndex;
struct AtomAndIndex { const Atom *atom; uint32_t index; SymbolScope scope; };
@@ -1423,6 +1425,8 @@ void Util::addRebaseAndBindingInfo(const lld::File &atomFile,
uint8_t segmentIndex;
uint64_t segmentStartAddr;
+ uint32_t offsetInBindInfo = 0;
+
for (SectionInfo *sect : _sectionInfos) {
segIndexForSection(sect, segmentIndex, segmentStartAddr);
for (const AtomInfo &info : sect->atomsAndOffsets) {
@@ -1467,6 +1471,59 @@ void Util::addRebaseAndBindingInfo(const lld::File &atomFile,
bind.symbolName = targ->name();
bind.addend = ref->addend();
nFile.lazyBindingInfo.push_back(bind);
+
+ // Now that we know the segmentOffset and the ordinal attribute,
+ // we can fix the helper's code
+
+ fixLazyReferenceImm(atom, offsetInBindInfo, nFile);
+
+ // 5 bytes for opcodes + variable sizes (target name + \0 and offset
+ // encode's size)
+ offsetInBindInfo +=
+ 6 + targ->name().size() + llvm::getULEB128Size(bind.segOffset);
+ if (bind.ordinal > BIND_IMMEDIATE_MASK)
+ offsetInBindInfo += llvm::getULEB128Size(bind.ordinal);
+ }
+ }
+ }
+ }
+}
+
+void Util::fixLazyReferenceImm(const DefinedAtom *atom, uint32_t offset,
+ NormalizedFile &file) {
+ for (const auto &ref : *atom) {
+ const DefinedAtom *da = dyn_cast(ref->target());
+ if (da == nullptr)
+ return;
+
+ const Reference *helperRef = nullptr;
+ for (const Reference *hr : *da) {
+ if (hr->kindValue() == _archHandler.lazyImmediateLocationKind()) {
+ helperRef = hr;
+ break;
+ }
+ }
+ if (helperRef == nullptr)
+ continue;
+
+ // TODO: maybe get the fixed atom content from _archHandler ?
+ for (SectionInfo *sectInfo : _sectionInfos) {
+ for (const AtomInfo &atomInfo : sectInfo->atomsAndOffsets) {
+ if (atomInfo.atom == helperRef->target()) {
+ auto sectionContent =
+ file.sections[sectInfo->normalizedSectionIndex].content;
+ uint8_t *rawb =
+ file.ownedAllocations.Allocate(sectionContent.size());
+ llvm::MutableArrayRef newContent{rawb,
+ sectionContent.size()};
+ std::copy(sectionContent.begin(), sectionContent.end(),
+ newContent.begin());
+ llvm::support::ulittle32_t *loc =
+ reinterpret_cast(
+ &newContent[atomInfo.offsetInSection +
+ helperRef->offsetInAtom()]);
+ *loc = offset;
+ file.sections[sectInfo->normalizedSectionIndex].content = newContent;
}
}
}
diff --git a/deps/lld/test/mach-o/lazy-bind-x86_64.yaml b/deps/lld/test/mach-o/lazy-bind-x86_64.yaml
index 5c588c5719..1322719e5f 100644
--- a/deps/lld/test/mach-o/lazy-bind-x86_64.yaml
+++ b/deps/lld/test/mach-o/lazy-bind-x86_64.yaml
@@ -80,8 +80,8 @@ undefined-symbols:
# CHECK-HELPERS:Disassembly of section __TEXT,__stub_helper:
# CHECK-HELPERS: 68 00 00 00 00 pushq $0
-# CHECK-HELPERS: 68 10 00 00 00 pushq $16
-# CHECK-HELPERS: 68 20 00 00 00 pushq $32
+# CHECK-HELPERS: 68 0b 00 00 00 pushq $11
+# CHECK-HELPERS: 68 16 00 00 00 pushq $22
# Make sure the stub helper is correctly aligned
# CHECK-DYLIBS: sectname __stub_helper
From bdd5241615bf41b69d3e12f3b6796bd796fb90f2 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 1 Dec 2017 12:15:19 -0500
Subject: [PATCH 16/32] update c_headers to llvm 5.0.1rc2
---
c_headers/avx512fintrin.h | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/c_headers/avx512fintrin.h b/c_headers/avx512fintrin.h
index 4ce6945311..4b66acc02f 100644
--- a/c_headers/avx512fintrin.h
+++ b/c_headers/avx512fintrin.h
@@ -267,21 +267,16 @@ _mm512_maskz_set1_epi32(__mmask16 __M, int __A)
__M);
}
+#ifdef __x86_64__
static __inline __m512i __DEFAULT_FN_ATTRS
_mm512_maskz_set1_epi64(__mmask8 __M, long long __A)
{
-#ifdef __x86_64__
return (__m512i) __builtin_ia32_pbroadcastq512_gpr_mask (__A,
(__v8di)
_mm512_setzero_si512 (),
__M);
-#else
- return (__m512i) __builtin_ia32_pbroadcastq512_mem_mask (__A,
- (__v8di)
- _mm512_setzero_si512 (),
- __M);
-#endif
}
+#endif
static __inline __m512 __DEFAULT_FN_ATTRS
_mm512_setzero_ps(void)
From cf96b6f87b5feaa699f0d15b1525d53a374b6227 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Fri, 1 Dec 2017 13:44:28 -0500
Subject: [PATCH 17/32] update to LLVM 5.0.1rc2
---
CMakeLists.txt | 11 ++++++++---
src/zig_llvm.cpp | 2 +-
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 72c480cd40..d8e2d9ff7a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -47,15 +47,20 @@ option(ZIG_TEST_COVERAGE "Build Zig with test coverage instrumentation" OFF)
option(ZIG_FORCE_EXTERNAL_LLD "If your system has the LLD patches use it instead of the embedded LLD" OFF)
find_package(llvm)
-include_directories(${LLVM_INCLUDE_DIRS})
-
find_package(clang)
-include_directories(${CLANG_INCLUDE_DIRS})
if(ZIG_FORCE_EXTERNAL_LLD)
find_package(lld)
+ include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${LLD_INCLUDE_DIRS})
+ include_directories(${CLANG_INCLUDE_DIRS})
else()
+ # This goes first so that we find embedded LLD instead
+ # of system LLD.
+ include_directories("${CMAKE_SOURCE_DIR}/deps/lld/include")
+
+ include_directories(${LLVM_INCLUDE_DIRS})
+ include_directories(${CLANG_INCLUDE_DIRS})
set(EMBEDDED_LLD_LIB_SOURCES
"${CMAKE_SOURCE_DIR}/deps/lld/lib/Driver/DarwinLdDriver.cpp"
"${CMAKE_SOURCE_DIR}/deps/lld/lib/Config/Version.cpp"
diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp
index 658de77b31..fa352147cc 100644
--- a/src/zig_llvm.cpp
+++ b/src/zig_llvm.cpp
@@ -789,7 +789,7 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_
zig_unreachable();
case ZigLLVM_COFF:
- return lld::coff::link(array_ref_args);
+ return lld::coff::link(array_ref_args, false, diag);
case ZigLLVM_ELF:
return lld::elf::link(array_ref_args, false, diag);
From 67b8b00c446634a6db5818bcb84f4207aad3948a Mon Sep 17 00:00:00 2001
From: Josh Wolfe
Date: Fri, 1 Dec 2017 16:11:39 -0700
Subject: [PATCH 18/32] implement insertion sort. something's broken
---
std/sort.zig | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
diff --git a/std/sort.zig b/std/sort.zig
index 1d7ca507ee..a1932c40e6 100644
--- a/std/sort.zig
+++ b/std/sort.zig
@@ -4,6 +4,19 @@ const math = @import("math/index.zig");
pub const Cmp = math.Cmp;
+/// Stable sort using O(1) space. Currently implemented as insertion sort.
+pub fn sort_stable(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b: &const T)->Cmp) {
+ {var i: usize = 1; while (i < array.len) : (i += 1) {
+ const x = array[i];
+ var j: usize = i;
+ while (j > 0 and cmp(array[j - 1], x) == Cmp.Greater) : (j -= 1) {
+ array[j] = array[j - 1];
+ }
+ array[j] = x;
+ }}
+}
+
+/// Unstable sort using O(n) stack space. Currentl implemented as quicksort.
pub fn sort(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b: &const T)->Cmp) {
if (array.len > 0) {
quicksort(T, array, 0, array.len - 1, cmp);
@@ -58,6 +71,62 @@ fn reverse(was: Cmp) -> Cmp {
// ---------------------------------------
// tests
+test "stable sort" {
+ testStableSort();
+ comptime testStableSort();
+}
+fn testStableSort() {
+ var expected = []IdAndValue {
+ IdAndValue{.id = 0, .value = 0},
+ IdAndValue{.id = 1, .value = 0},
+ IdAndValue{.id = 2, .value = 0},
+ IdAndValue{.id = 0, .value = 1},
+ IdAndValue{.id = 1, .value = 1},
+ IdAndValue{.id = 2, .value = 1},
+ IdAndValue{.id = 0, .value = 2},
+ IdAndValue{.id = 1, .value = 2},
+ IdAndValue{.id = 2, .value = 2},
+ };
+ var cases = [][9]IdAndValue {
+ []IdAndValue {
+ IdAndValue{.id = 0, .value = 0},
+ IdAndValue{.id = 0, .value = 1},
+ IdAndValue{.id = 0, .value = 2},
+ IdAndValue{.id = 1, .value = 0},
+ IdAndValue{.id = 1, .value = 1},
+ IdAndValue{.id = 1, .value = 2},
+ IdAndValue{.id = 2, .value = 0},
+ IdAndValue{.id = 2, .value = 1},
+ IdAndValue{.id = 2, .value = 2},
+ },
+ []IdAndValue {
+ IdAndValue{.id = 0, .value = 2},
+ IdAndValue{.id = 0, .value = 1},
+ IdAndValue{.id = 0, .value = 0},
+ IdAndValue{.id = 1, .value = 2},
+ IdAndValue{.id = 1, .value = 1},
+ IdAndValue{.id = 1, .value = 0},
+ IdAndValue{.id = 2, .value = 2},
+ IdAndValue{.id = 2, .value = 1},
+ IdAndValue{.id = 2, .value = 0},
+ },
+ };
+ for (cases) |*case| {
+ sort_stable(IdAndValue, (*case)[0..], cmpByValue);
+ for (*case) |item, i| {
+ assert(item.id == expected[i].id);
+ assert(item.value == expected[i].value);
+ }
+ }
+}
+const IdAndValue = struct {
+ id: i32,
+ value: i32,
+};
+fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> Cmp {
+ return i32asc(a.value, b.value);
+}
+
test "testSort" {
const u8cases = [][]const []const u8 {
[][]const u8{"", ""},
From 54a0db0daf8fd5ef307f275275e10f32ebd7d27a Mon Sep 17 00:00:00 2001
From: Josh Wolfe
Date: Fri, 1 Dec 2017 19:54:01 -0700
Subject: [PATCH 19/32] todo: fix #639
---
std/sort.zig | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/std/sort.zig b/std/sort.zig
index a1932c40e6..57fb0ab4c0 100644
--- a/std/sort.zig
+++ b/std/sort.zig
@@ -73,7 +73,8 @@ fn reverse(was: Cmp) -> Cmp {
test "stable sort" {
testStableSort();
- comptime testStableSort();
+ // TODO: uncomment this after https://github.com/zig-lang/zig/issues/639
+ //comptime testStableSort();
}
fn testStableSort() {
var expected = []IdAndValue {
From 98237f7c0ba62099e85a8caf8fc09039845b224e Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 2 Dec 2017 17:12:37 -0500
Subject: [PATCH 20/32] casting between integer and enum only works via tag
type
See #305
---
src/analyze.cpp | 4 +++
src/ir.cpp | 24 +++++++++++++++--
test/cases/enum.zig | 14 +++++++---
test/compile_errors.zig | 57 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 94 insertions(+), 5 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 235aeea682..7d51e83677 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -1399,6 +1399,10 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
enum_type->data.enumeration.is_invalid = true;
add_node_error(g, decl_node->data.container_decl.init_arg_expr,
buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));
+ } else if (wanted_tag_int_type->data.integral.is_signed) {
+ enum_type->data.enumeration.is_invalid = true;
+ add_node_error(g, decl_node->data.container_decl.init_arg_expr,
+ buf_sprintf("expected unsigned integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));
} else if (wanted_tag_int_type->data.integral.bit_count < tag_int_type->data.integral.bit_count) {
enum_type->data.enumeration.is_invalid = true;
add_node_error(g, decl_node->data.container_decl.init_arg_expr,
diff --git a/src/ir.cpp b/src/ir.cpp
index c8617e3a8a..c6003fbf32 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -8911,7 +8911,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
wanted_type->id == TypeTableEntryIdEnum &&
wanted_type->data.enumeration.gen_field_count == 0)
{
- return ir_analyze_int_to_enum(ira, source_instr, value, wanted_type);
+ ensure_complete_type(ira->codegen, wanted_type);
+ if (type_is_invalid(wanted_type))
+ return ira->codegen->invalid_instruction;
+ if (actual_type == wanted_type->data.enumeration.tag_type->data.enum_tag.int_type) {
+ return ir_analyze_int_to_enum(ira, source_instr, value, wanted_type);
+ }
+ ir_add_error(ira, source_instr,
+ buf_sprintf("integer to enum cast from '%s' instead of its tag type, '%s'",
+ buf_ptr(&actual_type->name),
+ buf_ptr(&wanted_type->data.enumeration.tag_type->data.enum_tag.int_type->name)));
+ return ira->codegen->invalid_instruction;
}
// explicit cast from enum type with no payload to integer
@@ -8919,7 +8929,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
actual_type->id == TypeTableEntryIdEnum &&
actual_type->data.enumeration.gen_field_count == 0)
{
- return ir_analyze_enum_to_int(ira, source_instr, value, wanted_type);
+ ensure_complete_type(ira->codegen, actual_type);
+ if (type_is_invalid(actual_type))
+ return ira->codegen->invalid_instruction;
+ if (wanted_type == actual_type->data.enumeration.tag_type->data.enum_tag.int_type) {
+ return ir_analyze_enum_to_int(ira, source_instr, value, wanted_type);
+ }
+ ir_add_error(ira, source_instr,
+ buf_sprintf("enum to integer cast to '%s' instead of its tag type, '%s'",
+ buf_ptr(&wanted_type->name),
+ buf_ptr(&actual_type->data.enumeration.tag_type->data.enum_tag.int_type->name)));
+ return ira->codegen->invalid_instruction;
}
// explicit cast from undefined to anything
diff --git a/test/cases/enum.zig b/test/cases/enum.zig
index 1b2ff10a9b..6df858a48f 100644
--- a/test/cases/enum.zig
+++ b/test/cases/enum.zig
@@ -89,8 +89,8 @@ test "enum to int" {
shouldEqual(Number.Four, 4);
}
-fn shouldEqual(n: Number, expected: usize) {
- assert(usize(n) == expected);
+fn shouldEqual(n: Number, expected: u3) {
+ assert(u3(n) == expected);
}
@@ -98,7 +98,7 @@ test "int to enum" {
testIntToEnumEval(3);
}
fn testIntToEnumEval(x: i32) {
- assert(IntToEnumNumber(x) == IntToEnumNumber.Three);
+ assert(IntToEnumNumber(u3(x)) == IntToEnumNumber.Three);
}
const IntToEnumNumber = enum {
Zero,
@@ -284,3 +284,11 @@ fn getC(data: &const BitFieldOfEnums) -> C {
return data.c;
}
+test "casting enum to its tag type" {
+ testCastEnumToTagType(Small2.Two);
+ comptime testCastEnumToTagType(Small2.Two);
+}
+
+fn testCastEnumToTagType(value: Small2) {
+ assert(u2(value) == 1);
+}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 9b5ec6a6d6..367dec08b3 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -2390,4 +2390,61 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\}
,
".tmp_source.zig:1:20: error: expected integer, found 'f32'");
+
+ cases.add("implicitly casting enum to tag type",
+ \\const Small = enum(u2) {
+ \\ One,
+ \\ Two,
+ \\ Three,
+ \\ Four,
+ \\};
+ \\
+ \\export fn entry() {
+ \\ var x: u2 = Small.Two;
+ \\}
+ ,
+ ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'");
+
+ cases.add("explicitly casting enum to non tag type",
+ \\const Small = enum(u2) {
+ \\ One,
+ \\ Two,
+ \\ Three,
+ \\ Four,
+ \\};
+ \\
+ \\export fn entry() {
+ \\ var x = u3(Small.Two);
+ \\}
+ ,
+ ".tmp_source.zig:9:15: error: enum to integer cast to 'u3' instead of its tag type, 'u2'");
+
+ cases.add("explicitly casting non tag type to enum",
+ \\const Small = enum(u2) {
+ \\ One,
+ \\ Two,
+ \\ Three,
+ \\ Four,
+ \\};
+ \\
+ \\export fn entry() {
+ \\ var y = u3(3);
+ \\ var x = Small(y);
+ \\}
+ ,
+ ".tmp_source.zig:10:18: error: integer to enum cast from 'u3' instead of its tag type, 'u2'");
+
+ cases.add("non unsigned integer enum tag type",
+ \\const Small = enum(i2) {
+ \\ One,
+ \\ Two,
+ \\ Three,
+ \\ Four,
+ \\};
+ \\
+ \\export fn entry() {
+ \\ var y = Small.Two;
+ \\}
+ ,
+ ".tmp_source.zig:1:19: error: expected unsigned integer, found 'i2'");
}
From 137c8f5e8a6023db24f90555e968b592a4b843e4 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sat, 2 Dec 2017 22:31:42 -0500
Subject: [PATCH 21/32] ability to set tag values of enums
also remove support for enums with 0 values
closes #305
---
doc/langref.html.in | 2 +-
src/all_types.hpp | 10 +-
src/analyze.cpp | 234 +++++++++++++++++++++++++++++++---------
src/analyze.hpp | 9 +-
src/ast_render.cpp | 4 +
src/bigint.cpp | 32 ++++++
src/bigint.hpp | 5 +
src/codegen.cpp | 31 +++---
src/ir.cpp | 109 +++++++++++--------
src/parser.cpp | 50 ++++-----
std/sort.zig | 2 +-
test/cases/enum.zig | 56 +++++++++-
test/compile_errors.zig | 55 ++++++++--
13 files changed, 452 insertions(+), 147 deletions(-)
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 32c099f547..20b8ae1eee 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -5709,7 +5709,7 @@ VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" Typ
ContainerMember = (ContainerField | FnDef | GlobalVarDecl)
-ContainerField = Symbol option(":" Expression) ","
+ContainerField = Symbol option(":" PrefixOpExpression option("=" PrefixOpExpression ","
UseDecl = "use" Expression ";"
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 40d246c43c..8d4ffc5b84 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -98,7 +98,7 @@ struct ConstParent {
};
struct ConstEnumValue {
- uint64_t tag;
+ BigInt tag;
ConstExprValue *payload;
};
@@ -108,7 +108,7 @@ struct ConstStructValue {
};
struct ConstUnionValue {
- uint64_t tag;
+ BigInt tag;
ConstExprValue *payload;
ConstParent parent;
};
@@ -346,14 +346,14 @@ struct TldCompTime {
struct TypeEnumField {
Buf *name;
TypeTableEntry *type_entry;
- uint32_t value;
+ BigInt value;
uint32_t gen_index;
};
struct TypeUnionField {
Buf *name;
TypeTableEntry *type_entry;
- uint32_t value;
+ BigInt value;
uint32_t gen_index;
};
@@ -780,6 +780,7 @@ struct AstNodeStructField {
VisibMod visib_mod;
Buf *name;
AstNode *type;
+ AstNode *value;
};
struct AstNodeStringLiteral {
@@ -1014,6 +1015,7 @@ struct TypeTableEntryEnum {
TypeEnumField *fields;
bool is_invalid; // true if any fields are invalid
TypeTableEntry *tag_type;
+ TypeTableEntry *tag_int_type;
LLVMTypeRef union_type_ref;
ScopeDecls *decls_scope;
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 7d51e83677..b7d12443a0 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -1390,30 +1390,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
return;
}
- TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
- if (decl_node->data.container_decl.init_arg_expr != nullptr) {
- TypeTableEntry *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr);
- if (type_is_invalid(wanted_tag_int_type)) {
- enum_type->data.enumeration.is_invalid = true;
- } else if (wanted_tag_int_type->id != TypeTableEntryIdInt) {
- enum_type->data.enumeration.is_invalid = true;
- add_node_error(g, decl_node->data.container_decl.init_arg_expr,
- buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));
- } else if (wanted_tag_int_type->data.integral.is_signed) {
- enum_type->data.enumeration.is_invalid = true;
- add_node_error(g, decl_node->data.container_decl.init_arg_expr,
- buf_sprintf("expected unsigned integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));
- } else if (wanted_tag_int_type->data.integral.bit_count < tag_int_type->data.integral.bit_count) {
- enum_type->data.enumeration.is_invalid = true;
- add_node_error(g, decl_node->data.container_decl.init_arg_expr,
- buf_sprintf("'%s' too small to hold all bits; must be at least '%s'",
- buf_ptr(&wanted_tag_int_type->name), buf_ptr(&tag_int_type->name)));
- } else {
- tag_int_type = wanted_tag_int_type;
- }
- }
-
-
+ TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type;
TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
enum_type->data.enumeration.tag_type = tag_type_entry;
@@ -1683,7 +1660,6 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
TypeTableEntry *field_type = type_struct_field->type_entry;
ensure_complete_type(g, field_type);
-
if (type_is_invalid(field_type)) {
struct_type->data.structure.is_invalid = true;
break;
@@ -2121,6 +2097,18 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *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) {
+ add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields"));
+
+ enum_type->data.enumeration.src_field_count = field_count;
+ enum_type->data.enumeration.fields = nullptr;
+ enum_type->data.enumeration.is_invalid = true;
+ enum_type->data.enumeration.zero_bits_loop_flag = false;
+ enum_type->data.enumeration.gen_field_count = 0;
+ enum_type->data.enumeration.zero_bits_known = true;
+ return;
+ }
+
enum_type->data.enumeration.src_field_count = field_count;
enum_type->data.enumeration.fields = allocate(field_count);
@@ -2128,14 +2116,69 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
Scope *scope = &enum_type->data.enumeration.decls_scope->base;
+ HashMap occupied_tag_values = {};
+ occupied_tag_values.init(field_count);
+
+ TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
+
+ if (decl_node->data.container_decl.init_arg_expr != nullptr) {
+ TypeTableEntry *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr);
+ if (type_is_invalid(wanted_tag_int_type)) {
+ enum_type->data.enumeration.is_invalid = true;
+ } else if (wanted_tag_int_type->id != TypeTableEntryIdInt) {
+ enum_type->data.enumeration.is_invalid = true;
+ add_node_error(g, decl_node->data.container_decl.init_arg_expr,
+ buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));
+ } else if (wanted_tag_int_type->data.integral.is_signed) {
+ enum_type->data.enumeration.is_invalid = true;
+ add_node_error(g, decl_node->data.container_decl.init_arg_expr,
+ buf_sprintf("expected unsigned integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));
+ } else if (wanted_tag_int_type->data.integral.bit_count < tag_int_type->data.integral.bit_count) {
+ enum_type->data.enumeration.is_invalid = true;
+ add_node_error(g, decl_node->data.container_decl.init_arg_expr,
+ buf_sprintf("'%s' too small to hold all bits; must be at least '%s'",
+ buf_ptr(&wanted_tag_int_type->name), buf_ptr(&tag_int_type->name)));
+ } else {
+ tag_int_type = wanted_tag_int_type;
+ }
+ }
+ enum_type->data.enumeration.tag_int_type = tag_int_type;
+
uint32_t gen_field_index = 0;
- for (uint32_t i = 0; i < field_count; i += 1) {
- AstNode *field_node = decl_node->data.container_decl.fields.at(i);
- TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
+ for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
+ AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
+ TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i];
type_enum_field->name = field_node->data.struct_field.name;
TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
type_enum_field->type_entry = field_type;
- type_enum_field->value = i;
+
+ AstNode *tag_value = field_node->data.struct_field.value;
+
+ // In this first pass we resolve explicit tag values.
+ // In a second pass we will fill in the unspecified ones.
+ if (tag_value != nullptr) {
+ IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
+ if (result_inst->value.type->id == TypeTableEntryIdInvalid) {
+ enum_type->data.enumeration.is_invalid = true;
+ continue;
+ }
+ assert(result_inst->value.special != ConstValSpecialRuntime);
+ assert(result_inst->value.type->id == TypeTableEntryIdInt);
+ auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
+ if (entry == nullptr) {
+ bigint_init_bigint(&type_enum_field->value, &result_inst->value.data.x_bigint);
+ } else {
+ Buf *val_buf = buf_alloc();
+ bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10);
+
+ ErrorMsg *msg = add_node_error(g, tag_value,
+ buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf)));
+ add_error_note(g, msg, entry->value,
+ buf_sprintf("other occurrence here"));
+ enum_type->data.enumeration.is_invalid = true;
+ continue;
+ }
+ }
type_ensure_zero_bits_known(g, field_type);
if (type_is_invalid(field_type)) {
@@ -2155,6 +2198,34 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
}
}
+ // Now iterate again and populate the unspecified tag values
+ uint32_t next_maybe_unoccupied_index = 0;
+
+ for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
+ AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
+ TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i];
+ AstNode *tag_value = field_node->data.struct_field.value;
+
+ if (tag_value == nullptr) {
+ if (occupied_tag_values.size() == 0) {
+ bigint_init_unsigned(&type_enum_field->value, next_maybe_unoccupied_index);
+ next_maybe_unoccupied_index += 1;
+ } else {
+ BigInt proposed_value;
+ for (;;) {
+ bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index);
+ next_maybe_unoccupied_index += 1;
+ auto entry = occupied_tag_values.put_unique(proposed_value, field_node);
+ if (entry != nullptr) {
+ continue;
+ }
+ break;
+ }
+ bigint_init_bigint(&type_enum_field->value, &proposed_value);
+ }
+ }
+ }
+
enum_type->data.enumeration.zero_bits_loop_flag = false;
enum_type->data.enumeration.gen_field_count = gen_field_index;
enum_type->zero_bits = (gen_field_index == 0 && field_count < 2);
@@ -2162,7 +2233,6 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
// also compute abi_alignment
if (!enum_type->zero_bits) {
- TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
uint32_t align_of_tag_in_bytes = LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
enum_type->data.enumeration.abi_alignment = max(align_of_tag_in_bytes, biggest_align_bytes);
}
@@ -2214,6 +2284,11 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
type_struct_field->src_index = i;
type_struct_field->gen_index = SIZE_MAX;
+ if (field_node->data.struct_field.value != nullptr) {
+ add_node_error(g, field_node->data.struct_field.value,
+ buf_sprintf("enums, not structs, support field assignment"));
+ }
+
type_ensure_zero_bits_known(g, field_type);
if (type_is_invalid(field_type)) {
struct_type->data.structure.is_invalid = true;
@@ -2277,7 +2352,14 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
type_union_field->name = field_node->data.struct_field.name;
TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
type_union_field->type_entry = field_type;
- type_union_field->value = i;
+
+ // TODO look for enum arg to union
+ bigint_init_unsigned(&type_union_field->value, i);
+
+ if (field_node->data.struct_field.value != nullptr) {
+ add_node_error(g, field_node->data.struct_field.value,
+ buf_sprintf("enums, not unions, support field assignment"));
+ }
type_ensure_zero_bits_known(g, field_type);
if (type_is_invalid(field_type)) {
@@ -3190,6 +3272,29 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {
return nullptr;
}
+static TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) {
+ assert(type_entry->id == TypeTableEntryIdUnion);
+ assert(type_entry->data.unionation.complete);
+ for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {
+ TypeUnionField *field = &type_entry->data.unionation.fields[i];
+ if (bigint_cmp(&field->value, tag) == CmpEQ) {
+ return field;
+ }
+ }
+ return nullptr;
+}
+
+TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag) {
+ for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
+ TypeEnumField *field = &enum_type->data.enumeration.fields[i];
+ if (bigint_cmp(&field->value, tag) == CmpEQ) {
+ return field;
+ }
+ }
+ return nullptr;
+}
+
+
static bool is_container(TypeTableEntry *type_entry) {
switch (type_entry->id) {
case TypeTableEntryIdInvalid:
@@ -4178,6 +4283,18 @@ ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *str) {
return const_val;
}
+void init_const_bigint(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *bigint) {
+ const_val->special = ConstValSpecialStatic;
+ const_val->type = type;
+ bigint_init_bigint(&const_val->data.x_bigint, bigint);
+}
+
+ConstExprValue *create_const_bigint(TypeTableEntry *type, const BigInt *bigint) {
+ ConstExprValue *const_val = create_const_vals(1);
+ init_const_bigint(const_val, type, bigint);
+ return const_val;
+}
+
void init_const_unsigned_negative(ConstExprValue *const_val, TypeTableEntry *type, uint64_t x, bool negative) {
const_val->special = ConstValSpecialStatic;
const_val->type = type;
@@ -4241,13 +4358,13 @@ ConstExprValue *create_const_float(TypeTableEntry *type, double value) {
return const_val;
}
-void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, uint64_t tag) {
+void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *tag) {
const_val->special = ConstValSpecialStatic;
const_val->type = type;
- const_val->data.x_enum.tag = tag;
+ bigint_init_bigint(&const_val->data.x_enum.tag, tag);
}
-ConstExprValue *create_const_enum_tag(TypeTableEntry *type, uint64_t tag) {
+ConstExprValue *create_const_enum_tag(TypeTableEntry *type, const BigInt *tag) {
ConstExprValue *const_val = create_const_vals(1);
init_const_enum_tag(const_val, type, tag);
return const_val;
@@ -4450,20 +4567,35 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
switch (a->type->id) {
case TypeTableEntryIdOpaque:
zig_unreachable();
- case TypeTableEntryIdEnum:
- {
- ConstEnumValue *enum1 = &a->data.x_enum;
- ConstEnumValue *enum2 = &b->data.x_enum;
- if (enum1->tag == enum2->tag) {
- TypeEnumField *enum_field = &a->type->data.enumeration.fields[enum1->tag];
- if (type_has_bits(enum_field->type_entry)) {
- zig_panic("TODO const expr analyze enum special value for equality");
- } else {
- return true;
- }
+ case TypeTableEntryIdEnum: {
+ ConstEnumValue *enum1 = &a->data.x_enum;
+ ConstEnumValue *enum2 = &b->data.x_enum;
+ if (bigint_cmp(&enum1->tag, &enum2->tag) == CmpEQ) {
+ TypeEnumField *field = find_enum_field_by_tag(a->type, &enum1->tag);
+ assert(field != nullptr);
+ if (type_has_bits(field->type_entry)) {
+ zig_panic("TODO const expr analyze enum field value for equality");
+ } else {
+ return true;
}
- return false;
}
+ return false;
+ }
+ case TypeTableEntryIdUnion: {
+ ConstUnionValue *union1 = &a->data.x_union;
+ ConstUnionValue *union2 = &b->data.x_union;
+
+ if (bigint_cmp(&union1->tag, &union2->tag) == CmpEQ) {
+ TypeUnionField *field = find_union_field_by_tag(a->type, &union1->tag);
+ assert(field != nullptr);
+ if (type_has_bits(field->type_entry)) {
+ zig_panic("TODO const expr analyze union field value for equality");
+ } else {
+ return true;
+ }
+ }
+ return false;
+ }
case TypeTableEntryIdMetaType:
return a->data.x_type == b->data.x_type;
case TypeTableEntryIdVoid:
@@ -4544,8 +4676,6 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
return false;
}
return true;
- case TypeTableEntryIdUnion:
- zig_panic("TODO");
case TypeTableEntryIdUndefLit:
zig_panic("TODO");
case TypeTableEntryIdNullLit:
@@ -4855,11 +4985,10 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
}
TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
- assert(size_in_bits > 0);
-
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->is_copyable = true;
- entry->type_ref = LLVMIntType(size_in_bits);
+ entry->type_ref = (size_in_bits == 0) ? LLVMVoidType() : LLVMIntType(size_in_bits);
+ entry->zero_bits = (size_in_bits == 0);
const char u_or_i = is_signed ? 'i' : 'u';
buf_resize(&entry->name, 0);
@@ -4880,7 +5009,8 @@ TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits)
}
}
- uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
+ uint64_t debug_size_in_bits = (size_in_bits == 0) ?
+ 0 : (8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref));
entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), debug_size_in_bits, dwarf_tag);
entry->data.integral.is_signed = is_signed;
entry->data.integral.bit_count = size_in_bits;
diff --git a/src/analyze.hpp b/src/analyze.hpp
index b2464af9a0..50eb2a800f 100644
--- a/src/analyze.hpp
+++ b/src/analyze.hpp
@@ -64,6 +64,8 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name);
ScopeDecls *get_container_scope(TypeTableEntry *type_entry);
TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name);
TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name);
+TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag);
+
bool is_container_ref(TypeTableEntry *type_entry);
void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
void scan_import(CodeGen *g, ImportTableEntry *import);
@@ -109,6 +111,9 @@ ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str);
void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *c_str);
ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *c_str);
+void init_const_bigint(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *bigint);
+ConstExprValue *create_const_bigint(TypeTableEntry *type, const BigInt *bigint);
+
void init_const_unsigned_negative(ConstExprValue *const_val, TypeTableEntry *type, uint64_t x, bool negative);
ConstExprValue *create_const_unsigned_negative(TypeTableEntry *type, uint64_t x, bool negative);
@@ -121,8 +126,8 @@ ConstExprValue *create_const_usize(CodeGen *g, uint64_t x);
void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double value);
ConstExprValue *create_const_float(TypeTableEntry *type, double value);
-void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, uint64_t tag);
-ConstExprValue *create_const_enum_tag(TypeTableEntry *type, uint64_t tag);
+void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *tag);
+ConstExprValue *create_const_enum_tag(TypeTableEntry *type, const BigInt *tag);
void init_const_bool(CodeGen *g, ConstExprValue *const_val, bool value);
ConstExprValue *create_const_bool(CodeGen *g, bool value);
diff --git a/src/ast_render.cpp b/src/ast_render.cpp
index ce7bcd9e36..cdc18c7252 100644
--- a/src/ast_render.cpp
+++ b/src/ast_render.cpp
@@ -677,6 +677,10 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
fprintf(ar->f, ": ");
render_node_grouped(ar, field_node->data.struct_field.type);
}
+ if (field_node->data.struct_field.value != nullptr) {
+ fprintf(ar->f, "= ");
+ render_node_grouped(ar, field_node->data.struct_field.value);
+ }
fprintf(ar->f, ",\n");
}
diff --git a/src/bigint.cpp b/src/bigint.cpp
index d12c8d0759..f01436d232 100644
--- a/src/bigint.cpp
+++ b/src/bigint.cpp
@@ -1224,3 +1224,35 @@ Cmp bigint_cmp_zero(const BigInt *op) {
}
return op->is_negative ? CmpLT : CmpGT;
}
+
+uint32_t bigint_hash(BigInt x) {
+ if (x.digit_count == 0) {
+ return 0;
+ } else {
+ return bigint_ptr(&x)[0];
+ }
+}
+
+bool bigint_eql(BigInt a, BigInt b) {
+ return bigint_cmp(&a, &b) == CmpEQ;
+}
+
+void bigint_incr(BigInt *x) {
+ if (x->digit_count == 0) {
+ bigint_init_unsigned(x, 1);
+ return;
+ }
+
+ if (x->digit_count == 1 && x->data.digit != UINT64_MAX) {
+ x->data.digit += 1;
+ return;
+ }
+
+ BigInt copy;
+ bigint_init_bigint(©, x);
+
+ BigInt one;
+ bigint_init_unsigned(&one, 1);
+
+ bigint_add(x, ©, &one);
+}
diff --git a/src/bigint.hpp b/src/bigint.hpp
index a1facb5c78..9f044c8722 100644
--- a/src/bigint.hpp
+++ b/src/bigint.hpp
@@ -88,6 +88,11 @@ size_t bigint_bits_needed(const BigInt *op);
// convenience functions
Cmp bigint_cmp_zero(const BigInt *op);
+void bigint_incr(BigInt *value);
+
bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result);
+uint32_t bigint_hash(BigInt x);
+bool bigint_eql(BigInt a, BigInt b);
+
#endif
diff --git a/src/codegen.cpp b/src/codegen.cpp
index a5f8b85e22..0ac8ffb7e1 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -1362,8 +1362,12 @@ static LLVMValueRef bigint_to_llvm_const(LLVMTypeRef type_ref, BigInt *bigint) {
if (bigint->digit_count == 0) {
return LLVMConstNull(type_ref);
}
- LLVMValueRef unsigned_val = LLVMConstIntOfArbitraryPrecision(type_ref,
- bigint->digit_count, bigint_ptr(bigint));
+ LLVMValueRef unsigned_val;
+ if (bigint->digit_count == 1) {
+ unsigned_val = LLVMConstInt(type_ref, bigint_ptr(bigint)[0], false);
+ } else {
+ unsigned_val = LLVMConstIntOfArbitraryPrecision(type_ref, bigint->digit_count, bigint_ptr(bigint));
+ }
if (bigint->is_negative) {
return LLVMConstNeg(unsigned_val);
} else {
@@ -2420,9 +2424,10 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab
if (ir_want_debug_safety(g, &instruction->base)) {
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_tag_index, "");
LLVMValueRef tag_value = gen_load_untyped(g, tag_field_ptr, 0, false, "");
- LLVMValueRef expected_tag_value = LLVMConstInt(union_type->data.unionation.tag_type->type_ref,
- field->value, false);
+
+ LLVMValueRef expected_tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
+ &field->value);
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckOk");
LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckFail");
LLVMValueRef ok_val = LLVMBuildICmp(g->builder, LLVMIntEQ, tag_value, expected_tag_value, "");
@@ -3364,9 +3369,9 @@ static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrI
static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, IrInstructionInitEnum *instruction) {
TypeTableEntry *enum_type = instruction->enum_type;
- uint32_t value = instruction->field->value;
LLVMTypeRef tag_type_ref = enum_type->data.enumeration.tag_type->type_ref;
- LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, value, false);
+
+ LLVMValueRef tag_value = bigint_to_llvm_const(tag_type_ref, &instruction->field->value);
if (enum_type->data.enumeration.gen_field_count == 0)
return tag_value;
@@ -3429,8 +3434,9 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I
if (union_type->data.unionation.gen_tag_index != SIZE_MAX) {
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
union_type->data.unionation.gen_tag_index, "");
- LLVMValueRef tag_value = LLVMConstInt(union_type->data.unionation.tag_type->type_ref,
- type_union_field->value, false);
+
+ LLVMValueRef tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
+ &type_union_field->value);
gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
@@ -4039,7 +4045,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
return union_value_ref;
}
- LLVMValueRef tag_value = LLVMConstInt(type_entry->data.unionation.tag_type->type_ref, const_val->data.x_union.tag, false);
+ LLVMValueRef tag_value = bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref,
+ &const_val->data.x_union.tag);
LLVMValueRef fields[2];
fields[type_entry->data.unionation.gen_union_index] = union_value_ref;
@@ -4055,13 +4062,13 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
case TypeTableEntryIdEnum:
{
LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
- LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, const_val->data.x_enum.tag, false);
+ LLVMValueRef tag_value = bigint_to_llvm_const(tag_type_ref, &const_val->data.x_enum.tag);
if (type_entry->data.enumeration.gen_field_count == 0) {
return tag_value;
} else {
LLVMTypeRef union_type_ref = type_entry->data.enumeration.union_type_ref;
- TypeEnumField *enum_field = &type_entry->data.enumeration.fields[const_val->data.x_enum.tag];
- assert(enum_field->value == const_val->data.x_enum.tag);
+ TypeEnumField *enum_field = find_enum_field_by_tag(type_entry, &const_val->data.x_enum.tag);
+ assert(bigint_cmp(&enum_field->value, &const_val->data.x_enum.tag) == CmpEQ);
LLVMValueRef union_value;
bool make_unnamed_struct;
diff --git a/src/ir.cpp b/src/ir.cpp
index c6003fbf32..e51f52adae 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -8387,7 +8387,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
return ira->codegen->invalid_instruction;
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
source_instr->source_node, wanted_type);
- init_const_unsigned_negative(&result->value, wanted_type, val->data.x_enum.tag, false);
+ init_const_bigint(&result->value, wanted_type, &val->data.x_enum.tag);
return result;
}
@@ -8469,7 +8469,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
source_instr->source_node, wanted_type);
- result->value.data.x_enum.tag = bigint_as_unsigned(&val->data.x_bigint);
+ bigint_init_bigint(&result->value.data.x_enum.tag, &val->data.x_bigint);
return result;
}
@@ -9148,7 +9148,7 @@ static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, Atomic
if (!const_val)
return false;
- *out = (AtomicOrder)const_val->data.x_enum.tag;
+ *out = (AtomicOrder)bigint_as_unsigned(&const_val->data.x_enum.tag);
return true;
}
@@ -9168,7 +9168,27 @@ static bool ir_resolve_global_linkage(IrAnalyze *ira, IrInstruction *value, Glob
if (!const_val)
return false;
- *out = (GlobalLinkageId)const_val->data.x_enum.tag;
+ *out = (GlobalLinkageId)bigint_as_unsigned(&const_val->data.x_enum.tag);
+ return true;
+}
+
+static bool ir_resolve_float_mode(IrAnalyze *ira, IrInstruction *value, FloatMode *out) {
+ if (type_is_invalid(value->value.type))
+ return false;
+
+ ConstExprValue *float_mode_val = get_builtin_value(ira->codegen, "FloatMode");
+ assert(float_mode_val->type->id == TypeTableEntryIdMetaType);
+ TypeTableEntry *float_mode_type = float_mode_val->data.x_type;
+
+ IrInstruction *casted_value = ir_implicit_cast(ira, value, float_mode_type);
+ if (type_is_invalid(casted_value->value.type))
+ return false;
+
+ ConstExprValue *const_val = ir_resolve_const(ira, casted_value, UndefBad);
+ if (!const_val)
+ return false;
+
+ *out = (FloatMode)bigint_as_unsigned(&const_val->data.x_enum.tag);
return true;
}
@@ -11825,13 +11845,13 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
bool ptr_is_const = true;
bool ptr_is_volatile = false;
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
- create_const_enum_tag(child_type, field->value), child_type,
+ create_const_enum_tag(child_type, &field->value), child_type,
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
} else {
bool ptr_is_const = true;
bool ptr_is_volatile = false;
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
- create_const_unsigned_negative(child_type->data.enumeration.tag_type, field->value, false),
+ create_const_bigint(child_type->data.enumeration.tag_type, &field->value),
child_type->data.enumeration.tag_type,
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
}
@@ -12420,21 +12440,11 @@ static TypeTableEntry *ir_analyze_instruction_set_float_mode(IrAnalyze *ira,
return ira->codegen->builtin_types.entry_invalid;
}
- ConstExprValue *float_mode_val = get_builtin_value(ira->codegen, "FloatMode");
- assert(float_mode_val->type->id == TypeTableEntryIdMetaType);
- TypeTableEntry *float_mode_enum_type = float_mode_val->data.x_type;
-
IrInstruction *float_mode_value = instruction->mode_value->other;
- if (type_is_invalid(float_mode_value->value.type))
- return ira->codegen->builtin_types.entry_invalid;
- IrInstruction *casted_value = ir_implicit_cast(ira, float_mode_value, float_mode_enum_type);
- if (type_is_invalid(casted_value->value.type))
- return ira->codegen->builtin_types.entry_invalid;
- ConstExprValue *mode_val = ir_resolve_const(ira, casted_value, UndefBad);
- if (!mode_val)
- return ira->codegen->builtin_types.entry_invalid;
- bool want_fast_math = (mode_val->data.x_enum.tag == FloatModeOptimized);
+ FloatMode float_mode_scalar;
+ if (!ir_resolve_float_mode(ira, float_mode_value, &float_mode_scalar))
+ return ira->codegen->builtin_types.entry_invalid;
AstNode *source_node = instruction->base.source_node;
if (*fast_math_set_node_ptr) {
@@ -12444,7 +12454,7 @@ static TypeTableEntry *ir_analyze_instruction_set_float_mode(IrAnalyze *ira,
return ira->codegen->builtin_types.entry_invalid;
}
*fast_math_set_node_ptr = source_node;
- *fast_math_off_ptr = !want_fast_math;
+ *fast_math_off_ptr = (float_mode_scalar == FloatModeStrict);
ir_build_const_from(ira, &instruction->base);
return ira->codegen->builtin_types.entry_void;
@@ -12835,7 +12845,7 @@ static IrInstruction *ir_analyze_enum_tag(IrAnalyze *ira, IrInstruction *source_
source_instr->scope, source_instr->source_node);
const_instruction->base.value.type = tag_type;
const_instruction->base.value.special = ConstValSpecialStatic;
- bigint_init_unsigned(&const_instruction->base.value.data.x_bigint, val->data.x_enum.tag);
+ bigint_init_bigint(&const_instruction->base.value.data.x_bigint, &val->data.x_enum.tag);
return &const_instruction->base;
}
@@ -13005,7 +13015,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
assert(tag_type != nullptr);
if (pointee_val) {
ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);
- bigint_init_unsigned(&out_val->data.x_bigint, pointee_val->data.x_enum.tag);
+ bigint_init_bigint(&out_val->data.x_bigint, &pointee_val->data.x_enum.tag);
return tag_type;
}
@@ -13056,9 +13066,9 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr
TypeEnumField *field;
if (prong_value->value.type->id == TypeTableEntryIdEnumTag) {
- field = &target_type->data.enumeration.fields[bigint_as_unsigned(&prong_val->data.x_bigint)];
+ field = find_enum_field_by_tag(target_type, &prong_val->data.x_bigint);
} else if (prong_value->value.type->id == TypeTableEntryIdEnum) {
- field = &target_type->data.enumeration.fields[prong_val->data.x_enum.tag];
+ field = find_enum_field_by_tag(target_type, &prong_val->data.x_enum.tag);
} else {
zig_unreachable();
}
@@ -13503,8 +13513,8 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
TypeTableEntry *enum_type = container_type_value->value.type->data.enum_tag.enum_type;
- uint64_t tag_uint = bigint_as_unsigned(&tag_value->data.x_bigint);
- TypeEnumField *field = &enum_type->data.enumeration.fields[tag_uint];
+ TypeEnumField *field = find_enum_field_by_tag(enum_type, &tag_value->data.x_bigint);
+ assert(field != nullptr);
TypeTableEntry *this_field_type = field->type_entry;
IrInstruction *init_value = instruction->items[0]->other;
@@ -13520,7 +13530,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
if (!init_val)
return ira->codegen->builtin_types.entry_invalid;
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
- out_val->data.x_enum.tag = tag_uint;
+ bigint_init_bigint(&out_val->data.x_enum.tag, &tag_value->data.x_bigint);
out_val->data.x_enum.payload = init_val;
return enum_type;
}
@@ -13859,7 +13869,7 @@ static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira,
TypeTableEntry *result_type = var_value->data.x_type;
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
- out_val->data.x_enum.tag = type_id_index(type_entry->id);
+ bigint_init_unsigned(&out_val->data.x_enum.tag, type_id_index(type_entry->id));
return result_type;
}
@@ -15117,7 +15127,9 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
if (switch_type->id == TypeTableEntryIdEnumTag) {
TypeTableEntry *enum_type = switch_type->data.enum_tag.enum_type;
- AstNode **field_prev_uses = allocate(enum_type->data.enumeration.src_field_count);
+ HashMap field_prev_uses = {};
+ field_prev_uses.init(enum_type->data.enumeration.src_field_count);
+
for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) {
IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i];
@@ -15129,41 +15141,52 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
if (type_is_invalid(end_value->value.type))
return ira->codegen->builtin_types.entry_invalid;
- size_t start_index;
- size_t end_index;
+ BigInt start_index;
+ BigInt end_index;
if (start_value->value.type->id == TypeTableEntryIdEnumTag) {
- start_index = bigint_as_unsigned(&start_value->value.data.x_bigint);
+ bigint_init_bigint(&start_index, &start_value->value.data.x_bigint);
} else if (start_value->value.type->id == TypeTableEntryIdEnum) {
- start_index = start_value->value.data.x_enum.tag;
+ bigint_init_bigint(&start_index, &start_value->value.data.x_enum.tag);
} else {
zig_unreachable();
}
if (end_value->value.type->id == TypeTableEntryIdEnumTag) {
- end_index = bigint_as_unsigned(&end_value->value.data.x_bigint);
+ bigint_init_bigint(&end_index, &end_value->value.data.x_bigint);
} else if (end_value->value.type->id == TypeTableEntryIdEnum) {
- end_index = end_value->value.data.x_enum.tag;
+ bigint_init_bigint(&end_index, &end_value->value.data.x_enum.tag);
} else {
zig_unreachable();
}
- for (size_t field_index = start_index; field_index <= end_index; field_index += 1) {
- AstNode *prev_node = field_prev_uses[field_index];
- if (prev_node != nullptr) {
- TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_index];
+ BigInt field_index;
+ bigint_init_bigint(&field_index, &start_index);
+ for (;;) {
+ Cmp cmp = bigint_cmp(&field_index, &end_index);
+ if (cmp == CmpGT) {
+ break;
+ }
+ auto entry = field_prev_uses.put_unique(field_index, start_value->source_node);
+ if (entry) {
+ AstNode *prev_node = entry->value;
+ TypeEnumField *enum_field = find_enum_field_by_tag(enum_type, &field_index);
+ assert(enum_field != nullptr);
ErrorMsg *msg = ir_add_error(ira, start_value,
buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&enum_type->name),
- buf_ptr(type_enum_field->name)));
+ buf_ptr(enum_field->name)));
add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value is here"));
}
- field_prev_uses[field_index] = start_value->source_node;
+ bigint_incr(&field_index);
}
}
if (!instruction->have_else_prong) {
for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
- if (field_prev_uses[i] == nullptr) {
+ TypeEnumField *enum_field = &enum_type->data.enumeration.fields[i];
+
+ 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(&enum_type->name),
- buf_ptr(enum_type->data.enumeration.fields[i].name)));
+ buf_ptr(enum_field->name)));
}
}
}
diff --git a/src/parser.cpp b/src/parser.cpp
index 7f25e3ef21..c36434b521 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -2379,7 +2379,7 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod vi
/*
ContainerDecl = option("extern" | "packed") ("struct" | "union" | ("enum" option(GroupedExpression))) "{" many(ContainerMember) "}"
ContainerMember = (ContainerField | FnDef | GlobalVarDecl)
-ContainerField = Symbol option(":" Expression) ","
+ContainerField = Symbol option(":" PrefixOpExpression option("=" PrefixOpExpression ","
*/
static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory) {
Token *first_token = &pc->tokens->at(*token_index);
@@ -2414,10 +2414,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
AstNode *node = ast_create_node(pc, NodeTypeContainerDecl, first_token);
node->data.container_decl.layout = layout;
node->data.container_decl.kind = kind;
-
- if (kind == ContainerKindEnum || kind == ContainerKindStruct) {
- node->data.container_decl.init_arg_expr = ast_parse_grouped_expr(pc, token_index, false);
- }
+ node->data.container_decl.init_arg_expr = ast_parse_grouped_expr(pc, token_index, false);
ast_eat_token(pc, token_index, TokenIdLBrace);
@@ -2456,31 +2453,35 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
AstNode *field_node = ast_create_node(pc, NodeTypeStructField, token);
*token_index += 1;
+ node->data.container_decl.fields.append(field_node);
field_node->data.struct_field.visib_mod = visib_mod;
field_node->data.struct_field.name = token_buf(token);
- Token *token = &pc->tokens->at(*token_index);
- if (token->id == TokenIdComma || token->id == TokenIdRBrace) {
- field_node->data.struct_field.type = ast_create_void_type_node(pc, token);
+ Token *colon_token = &pc->tokens->at(*token_index);
+ if (colon_token->id == TokenIdColon) {
*token_index += 1;
- node->data.container_decl.fields.append(field_node);
-
- if (token->id == TokenIdRBrace) {
- break;
- }
+ field_node->data.struct_field.type = ast_parse_prefix_op_expr(pc, token_index, true);
} else {
- ast_eat_token(pc, token_index, TokenIdColon);
- field_node->data.struct_field.type = ast_parse_expression(pc, token_index, true);
- node->data.container_decl.fields.append(field_node);
-
- Token *token = &pc->tokens->at(*token_index);
- if (token->id == TokenIdRBrace) {
- *token_index += 1;
- break;
- } else {
- ast_eat_token(pc, token_index, TokenIdComma);
- }
+ field_node->data.struct_field.type = ast_create_void_type_node(pc, colon_token);
}
+ Token *eq_token = &pc->tokens->at(*token_index);
+ if (eq_token->id == TokenIdEq) {
+ *token_index += 1;
+ field_node->data.struct_field.value = ast_parse_prefix_op_expr(pc, token_index, true);
+ }
+
+ Token *next_token = &pc->tokens->at(*token_index);
+ if (next_token->id == TokenIdComma) {
+ *token_index += 1;
+ continue;
+ }
+
+ if (next_token->id == TokenIdRBrace) {
+ *token_index += 1;
+ break;
+ }
+
+ ast_invalid_token_error(pc, next_token);
} else {
ast_invalid_token_error(pc, token);
}
@@ -2812,6 +2813,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
break;
case NodeTypeStructField:
visit_field(&node->data.struct_field.type, visit, context);
+ visit_field(&node->data.struct_field.value, visit, context);
break;
case NodeTypeContainerInitExpr:
visit_field(&node->data.container_init_expr.type, visit, context);
diff --git a/std/sort.zig b/std/sort.zig
index 57fb0ab4c0..d02d685e07 100644
--- a/std/sort.zig
+++ b/std/sort.zig
@@ -16,7 +16,7 @@ pub fn sort_stable(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b
}}
}
-/// Unstable sort using O(n) stack space. Currentl implemented as quicksort.
+/// Unstable sort using O(n) stack space. Currently implemented as quicksort.
pub fn sort(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b: &const T)->Cmp) {
if (array.len > 0) {
quicksort(T, array, 0, array.len - 1, cmp);
diff --git a/test/cases/enum.zig b/test/cases/enum.zig
index 6df858a48f..eda3cf6376 100644
--- a/test/cases/enum.zig
+++ b/test/cases/enum.zig
@@ -137,7 +137,6 @@ const AlignTestEnum = enum {
B: u64,
};
-const ValueCount0 = enum {};
const ValueCount1 = enum { I0 };
const ValueCount2 = enum { I0, I1 };
const ValueCount256 = enum {
@@ -183,7 +182,6 @@ const ValueCount257 = enum {
test "enum sizes" {
comptime {
- assert(@sizeOf(ValueCount0) == 0);
assert(@sizeOf(ValueCount1) == 0);
assert(@sizeOf(ValueCount2) == 1);
assert(@sizeOf(ValueCount256) == 1);
@@ -292,3 +290,57 @@ test "casting enum to its tag type" {
fn testCastEnumToTagType(value: Small2) {
assert(u2(value) == 1);
}
+
+const MultipleChoice = enum(u32) {
+ A = 20,
+ B = 40,
+ C = 60,
+ D = 1000,
+};
+
+test "enum with specified tag values" {
+ testEnumWithSpecifiedTagValues(MultipleChoice.C);
+ comptime testEnumWithSpecifiedTagValues(MultipleChoice.C);
+}
+
+fn testEnumWithSpecifiedTagValues(x: MultipleChoice) {
+ assert(u32(x) == 60);
+ assert(1234 == switch (x) {
+ MultipleChoice.A => 1,
+ MultipleChoice.B => 2,
+ MultipleChoice.C => u32(1234),
+ MultipleChoice.D => 4,
+ });
+}
+
+const MultipleChoice2 = enum(u32) {
+ Unspecified1,
+ A = 20,
+ Unspecified2,
+ B = 40,
+ Unspecified3,
+ C = 60,
+ Unspecified4,
+ D = 1000,
+ Unspecified5,
+};
+
+test "enum with specified and unspecified tag values" {
+ testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
+ comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
+}
+
+fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) {
+ assert(u32(x) == 1000);
+ assert(1234 == switch (x) {
+ MultipleChoice2.A => 1,
+ MultipleChoice2.B => 2,
+ MultipleChoice2.C => 3,
+ MultipleChoice2.D => u32(1234),
+ MultipleChoice2.Unspecified1 => 5,
+ MultipleChoice2.Unspecified2 => 6,
+ MultipleChoice2.Unspecified3 => 7,
+ MultipleChoice2.Unspecified4 => 8,
+ MultipleChoice2.Unspecified5 => 9,
+ });
+}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 367dec08b3..e1de167ac5 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -2307,11 +2307,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
cases.add("@memberType enum out of bounds",
\\comptime {
- \\ _ = @memberType(Foo, 0);
+ \\ _ = @memberType(Foo, 1);
\\}
- \\const Foo = enum {};
+ \\const Foo = enum {A,};
,
- ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
+ ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members");
cases.add("@memberName on unsupported type",
\\comptime {
@@ -2330,11 +2330,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
cases.add("@memberName enum out of bounds",
\\comptime {
- \\ _ = @memberName(Foo, 0);
+ \\ _ = @memberName(Foo, 1);
\\}
- \\const Foo = enum {};
+ \\const Foo = enum {A,};
,
- ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
+ ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members");
cases.add("calling var args extern function, passing array instead of pointer",
\\export fn entry() {
@@ -2447,4 +2447,47 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\}
,
".tmp_source.zig:1:19: error: expected unsigned integer, found 'i2'");
+
+ cases.add("struct fields with value assignments",
+ \\const MultipleChoice = struct {
+ \\ A: i32 = 20,
+ \\};
+ \\export fn entry() {
+ \\ var x: MultipleChoice = undefined;
+ \\}
+ ,
+ ".tmp_source.zig:2:14: error: enums, not structs, support field assignment");
+
+ cases.add("union fields with value assignments",
+ \\const MultipleChoice = union {
+ \\ A: i32 = 20,
+ \\};
+ \\export fn entry() {
+ \\ var x: MultipleChoice = undefined;
+ \\}
+ ,
+ ".tmp_source.zig:2:14: error: enums, not unions, support field assignment");
+
+ cases.add("enum with 0 fields",
+ \\const Foo = enum {};
+ \\export fn entry() -> usize {
+ \\ return @sizeOf(Foo);
+ \\}
+ ,
+ ".tmp_source.zig:1:13: error: enums must have 1 or more fields");
+
+ cases.add("enum value already taken",
+ \\const MultipleChoice = enum(u32) {
+ \\ A = 20,
+ \\ B = 40,
+ \\ C = 60,
+ \\ D = 1000,
+ \\ E = 60,
+ \\};
+ \\export fn entry() {
+ \\ var x = MultipleChoice.C;
+ \\}
+ ,
+ ".tmp_source.zig:6:9: error: enum tag value 60 already taken",
+ ".tmp_source.zig:4:9: note: other occurrence here");
}
From 0ad1239522c70418990dc7b9da4e128da7cdd1d5 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 3 Dec 2017 20:43:56 -0500
Subject: [PATCH 22/32] rework enums and unions and their relationship to each
other
* @enumTagName renamed to @tagName and it works on enums and
union-enums
* Remove the EnumTag type. Now there is only enum and union,
and the tag type of a union is always an enum.
* unions support specifying the tag enum type, and they support
inferring an enum tag type.
* Enums no longer support field types but they do support
setting the tag values. Likewise union-enums when inferring
an enum tag type support setting the tag values.
* It is now an error for enums and unions to have 0 fields.
* switch statements support union-enums
closes #618
---
doc/langref.html.in | 21 +-
src/all_types.hpp | 59 +--
src/analyze.cpp | 607 +++++++++++-----------
src/analyze.hpp | 6 +-
src/ast_render.cpp | 7 +
src/codegen.cpp | 245 +++------
src/ir.cpp | 488 ++++++++---------
src/ir_print.cpp | 31 +-
src/parser.cpp | 29 +-
std/build.zig | 42 +-
std/debug.zig | 28 +-
std/os/child_process.zig | 10 +-
std/os/path.zig | 2 +-
test/cases/bugs/394.zig | 4 +-
test/cases/enum.zig | 24 +-
test/cases/enum_with_members.zig | 6 +-
test/cases/misc.zig | 16 +-
test/cases/reflection.zig | 4 +-
test/cases/switch.zig | 16 +-
test/cases/switch_prong_err_enum.zig | 4 +-
test/cases/switch_prong_implicit_cast.zig | 8 +-
test/cases/union.zig | 35 +-
test/compile_errors.zig | 54 +-
test/tests.zig | 10 +-
24 files changed, 803 insertions(+), 953 deletions(-)
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 20b8ae1eee..76bf0ce237 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -136,7 +136,7 @@
- @divFloor
- @divTrunc
- @embedFile
- - @enumTagName
+ - @tagName
- @EnumTagType
- @errorName
- @fence
@@ -2165,7 +2165,7 @@ test "enum variant switch" {
};
}
-// The @enumTagName and @memberCount builtin functions can be used to
+// The @memberName and @memberCount builtin functions can be used to
// the string representation and number of members respectively.
const BuiltinType = enum {
A: f32,
@@ -2174,8 +2174,8 @@ const BuiltinType = enum {
};
test "enum builtins" {
- assert(mem.eql(u8, @enumTagName(BuiltinType.A { 0 }), "A"));
- assert(mem.eql(u8, @enumTagName(BuiltinType.C), "C"));
+ assert(mem.eql(u8, @memberName(BuiltinType.A { 0 }), "A"));
+ assert(mem.eql(u8, @memberName(BuiltinType.C), "C"));
assert(@memberCount(BuiltinType) == 3);
}
$ zig test enum.zig
@@ -2189,8 +2189,9 @@ Test 4/4 enum builtins...OK
See also:
union
TODO union documentation
@@ -4252,10 +4253,10 @@ test.zig:6:2: error: found compile log statement
- @enumTagName
- @enumTagName(value: var) -> []const u8
+ @tagName
+ @tagName(value: var) -> []const u8
- Converts an enum tag name to a slice of bytes.
+ Converts an enum value or union value to a slice of bytes representing the name.
@EnumTagType
@EnumTagType(T: type) -> type
@@ -5843,7 +5844,9 @@ GroupedExpression = "(" Expression ")"
KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable"
-ContainerDecl = option("extern" | "packed") ("struct" | "union" | ("enum" option(GroupedExpression))) "{" many(ContainerMember) "}"
+ContainerDecl = option("extern" | "packed")
+ ("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression)))
+ "{" many(ContainerMember) "}"
Zen
- Communicate intent precisely.
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 8d4ffc5b84..6061f63da6 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -97,11 +97,6 @@ struct ConstParent {
} data;
};
-struct ConstEnumValue {
- BigInt tag;
- ConstExprValue *payload;
-};
-
struct ConstStructValue {
ConstExprValue *fields;
ConstParent parent;
@@ -249,7 +244,7 @@ struct ConstExprValue {
ConstExprValue *x_maybe;
ConstErrValue x_err_union;
ErrorTableEntry *x_pure_err;
- ConstEnumValue x_enum;
+ BigInt x_enum_tag;
ConstStructValue x_struct;
ConstUnionValue x_union;
ConstArrayValue x_array;
@@ -345,15 +340,14 @@ struct TldCompTime {
struct TypeEnumField {
Buf *name;
- TypeTableEntry *type_entry;
BigInt value;
- uint32_t gen_index;
+ uint32_t decl_index;
};
struct TypeUnionField {
Buf *name;
+ TypeEnumField *enum_field;
TypeTableEntry *type_entry;
- BigInt value;
uint32_t gen_index;
};
@@ -773,7 +767,8 @@ struct AstNodeContainerDecl {
ZigList fields;
ZigList decls;
ContainerLayout layout;
- AstNode *init_arg_expr; // enum(T) or struct(endianness)
+ AstNode *init_arg_expr; // enum(T), struct(endianness), or union(T), or union(enum(T))
+ bool auto_enum; // union(enum)
};
struct AstNodeStructField {
@@ -1010,13 +1005,9 @@ struct TypeTableEntryEnum {
AstNode *decl_node;
ContainerLayout layout;
uint32_t src_field_count;
- // number of fields in the union. 0 if enum with no payload
- uint32_t gen_field_count;
TypeEnumField *fields;
bool is_invalid; // true if any fields are invalid
- TypeTableEntry *tag_type;
TypeTableEntry *tag_int_type;
- LLVMTypeRef union_type_ref;
ScopeDecls *decls_scope;
@@ -1028,18 +1019,7 @@ struct TypeTableEntryEnum {
bool zero_bits_loop_flag;
bool zero_bits_known;
- uint32_t abi_alignment; // also figured out with zero_bits pass
- size_t gen_union_index;
- size_t gen_tag_index;
-
- uint32_t union_size_bytes;
- TypeTableEntry *most_aligned_union_member;
-};
-
-struct TypeTableEntryEnumTag {
- TypeTableEntry *enum_type;
- TypeTableEntry *int_type;
bool generate_name_table;
LLVMValueRef name_table;
};
@@ -1054,7 +1034,7 @@ struct TypeTableEntryUnion {
uint32_t gen_field_count;
TypeUnionField *fields;
bool is_invalid; // true if any fields are invalid
- TypeTableEntry *tag_type;
+ TypeTableEntry *tag_type; // always an enum or null
LLVMTypeRef union_type_ref;
ScopeDecls *decls_scope;
@@ -1119,7 +1099,6 @@ enum TypeTableEntryId {
TypeTableEntryIdErrorUnion,
TypeTableEntryIdPureError,
TypeTableEntryIdEnum,
- TypeTableEntryIdEnumTag,
TypeTableEntryIdUnion,
TypeTableEntryIdFn,
TypeTableEntryIdNamespace,
@@ -1148,7 +1127,6 @@ struct TypeTableEntry {
TypeTableEntryMaybe maybe;
TypeTableEntryError error;
TypeTableEntryEnum enumeration;
- TypeTableEntryEnumTag enum_tag;
TypeTableEntryUnion unionation;
TypeTableEntryFn fn;
TypeTableEntryBoundFn bound_fn;
@@ -1287,7 +1265,7 @@ enum BuiltinFnId {
BuiltinFnIdBitCast,
BuiltinFnIdIntToPtr,
BuiltinFnIdPtrToInt,
- BuiltinFnIdEnumTagName,
+ BuiltinFnIdTagName,
BuiltinFnIdEnumTagType,
BuiltinFnIdFieldParentPtr,
BuiltinFnIdOffsetOf,
@@ -1832,7 +1810,6 @@ enum IrInstructionId {
IrInstructionIdStorePtr,
IrInstructionIdFieldPtr,
IrInstructionIdStructFieldPtr,
- IrInstructionIdEnumFieldPtr,
IrInstructionIdUnionFieldPtr,
IrInstructionIdElemPtr,
IrInstructionIdVarPtr,
@@ -1857,7 +1834,7 @@ enum IrInstructionId {
IrInstructionIdTestNonNull,
IrInstructionIdUnwrapMaybe,
IrInstructionIdMaybeWrap,
- IrInstructionIdEnumTag,
+ IrInstructionIdUnionTag,
IrInstructionIdClz,
IrInstructionIdCtz,
IrInstructionIdImport,
@@ -1896,7 +1873,6 @@ enum IrInstructionId {
IrInstructionIdErrWrapPayload,
IrInstructionIdFnProto,
IrInstructionIdTestComptime,
- IrInstructionIdInitEnum,
IrInstructionIdPtrCast,
IrInstructionIdBitCast,
IrInstructionIdWidenOrShorten,
@@ -2092,14 +2068,6 @@ struct IrInstructionStructFieldPtr {
bool is_const;
};
-struct IrInstructionEnumFieldPtr {
- IrInstruction base;
-
- IrInstruction *enum_ptr;
- TypeEnumField *field;
- bool is_const;
-};
-
struct IrInstructionUnionFieldPtr {
IrInstruction base;
@@ -2303,7 +2271,7 @@ struct IrInstructionClz {
IrInstruction *value;
};
-struct IrInstructionEnumTag {
+struct IrInstructionUnionTag {
IrInstruction base;
IrInstruction *value;
@@ -2573,15 +2541,6 @@ struct IrInstructionTestComptime {
IrInstruction *value;
};
-struct IrInstructionInitEnum {
- IrInstruction base;
-
- TypeTableEntry *enum_type;
- TypeEnumField *field;
- IrInstruction *init_value;
- LLVMValueRef tmp_ptr;
-};
-
struct IrInstructionPtrCast {
IrInstruction base;
diff --git a/src/analyze.cpp b/src/analyze.cpp
index b7d12443a0..9d2d4f1a8f 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -223,7 +223,6 @@ bool type_is_complete(TypeTableEntry *type_entry) {
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
- case TypeTableEntryIdEnumTag:
case TypeTableEntryIdArgTuple:
return true;
}
@@ -260,7 +259,6 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) {
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
- case TypeTableEntryIdEnumTag:
case TypeTableEntryIdArgTuple:
case TypeTableEntryIdOpaque:
return true;
@@ -1175,7 +1173,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
- case TypeTableEntryIdEnumTag:
ensure_complete_type(g, type_entry);
if (fn_type_id.cc == CallingConventionUnspecified && !type_is_copyable(g, type_entry)) {
add_node_error(g, param_node->data.param_decl.type,
@@ -1239,7 +1236,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
- case TypeTableEntryIdEnumTag:
break;
}
@@ -1263,22 +1259,6 @@ bool type_is_invalid(TypeTableEntry *type_entry) {
}
-TypeTableEntry *create_enum_tag_type(CodeGen *g, TypeTableEntry *enum_type, TypeTableEntry *int_type) {
- TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnumTag);
-
- buf_resize(&entry->name, 0);
- buf_appendf(&entry->name, "@EnumTagType(%s)", buf_ptr(&enum_type->name));
-
- entry->is_copyable = true;
- entry->data.enum_tag.enum_type = enum_type;
- entry->data.enum_tag.int_type = int_type;
- entry->type_ref = int_type->type_ref;
- entry->di_type = int_type->di_type;
- entry->zero_bits = int_type->zero_bits;
-
- return entry;
-}
-
static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
assert(enum_type->id == TypeTableEntryIdEnum);
@@ -1308,14 +1288,6 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
assert(enum_type->data.enumeration.fields);
ZigLLVMDIEnumerator **di_enumerators = allocate(field_count);
- uint32_t gen_field_count = enum_type->data.enumeration.gen_field_count;
- ZigLLVMDIType **union_inner_di_types = allocate(gen_field_count);
-
- TypeTableEntry *most_aligned_union_member = nullptr;
- uint64_t size_of_most_aligned_member_in_bits = 0;
- uint64_t biggest_align_in_bits = 0;
- uint64_t biggest_size_in_bits = 0;
-
Scope *scope = &enum_type->data.enumeration.decls_scope->base;
ImportTableEntry *import = get_scope_import(scope);
@@ -1323,49 +1295,17 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
enum_type->data.enumeration.embedded_in_current = true;
for (uint32_t i = 0; i < field_count; i += 1) {
- AstNode *field_node = decl_node->data.container_decl.fields.at(i);
- TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
- TypeTableEntry *field_type = type_enum_field->type_entry;
+ TypeEnumField *enum_field = &enum_type->data.enumeration.fields[i];
- di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i);
-
- ensure_complete_type(g, field_type);
- if (type_is_invalid(field_type)) {
- enum_type->data.enumeration.is_invalid = true;
- continue;
- }
-
- if (!type_has_bits(field_type))
- continue;
-
- uint64_t store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
- uint64_t abi_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref);
-
- assert(store_size_in_bits > 0);
- assert(abi_align_in_bits > 0);
-
- union_inner_di_types[type_enum_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
- ZigLLVMTypeToScope(enum_type->di_type), buf_ptr(type_enum_field->name),
- import->di_file, (unsigned)(field_node->line + 1),
- store_size_in_bits,
- abi_align_in_bits,
- 0,
- 0, field_type->di_type);
-
- biggest_size_in_bits = max(biggest_size_in_bits, store_size_in_bits);
-
- if (!most_aligned_union_member || abi_align_in_bits > biggest_align_in_bits) {
- most_aligned_union_member = field_type;
- biggest_align_in_bits = abi_align_in_bits;
- size_of_most_aligned_member_in_bits = store_size_in_bits;
- }
+ // TODO send patch to LLVM to support APInt in createEnumerator instead of int64_t
+ // http://lists.llvm.org/pipermail/llvm-dev/2017-December/119456.html
+ di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(enum_field->name),
+ bigint_as_signed(&enum_field->value));
}
// unset temporary flag
enum_type->data.enumeration.embedded_in_current = false;
enum_type->data.enumeration.complete = true;
- enum_type->data.enumeration.union_size_bytes = biggest_size_in_bits / 8;
- enum_type->data.enumeration.most_aligned_union_member = most_aligned_union_member;
if (enum_type->data.enumeration.is_invalid)
return;
@@ -1391,117 +1331,20 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
}
TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type;
- TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
- enum_type->data.enumeration.tag_type = tag_type_entry;
- uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
+ // create debug type for tag
+ uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_int_type->type_ref);
+ uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
+ ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
+ ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
+ import->di_file, (unsigned)(decl_node->line + 1),
+ tag_debug_size_in_bits,
+ tag_debug_align_in_bits,
+ di_enumerators, field_count,
+ tag_int_type->di_type, "");
- if (most_aligned_union_member) {
- // create llvm type for union
- uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
- LLVMTypeRef union_type_ref;
- if (padding_in_bits > 0) {
- TypeTableEntry *u8_type = get_int_type(g, false, 8);
- TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
- LLVMTypeRef union_element_types[] = {
- most_aligned_union_member->type_ref,
- padding_array->type_ref,
- };
- union_type_ref = LLVMStructType(union_element_types, 2, false);
- } else {
- union_type_ref = most_aligned_union_member->type_ref;
- }
- enum_type->data.enumeration.union_type_ref = union_type_ref;
-
- assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);
- assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);
-
- if (align_of_tag_in_bits >= biggest_align_in_bits) {
- enum_type->data.enumeration.gen_tag_index = 0;
- enum_type->data.enumeration.gen_union_index = 1;
- } else {
- enum_type->data.enumeration.gen_union_index = 0;
- enum_type->data.enumeration.gen_tag_index = 1;
- }
-
- // create llvm type for root struct
- LLVMTypeRef root_struct_element_types[2];
- root_struct_element_types[enum_type->data.enumeration.gen_tag_index] = tag_type_entry->type_ref;
- root_struct_element_types[enum_type->data.enumeration.gen_union_index] = union_type_ref;
- LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false);
-
- // create debug type for tag
- uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
- uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
- ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
- ZigLLVMTypeToScope(enum_type->di_type), "AnonEnum",
- import->di_file, (unsigned)(decl_node->line + 1),
- tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
- tag_type_entry->di_type, "");
-
- // create debug type for union
- ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
- ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion",
- import->di_file, (unsigned)(decl_node->line + 1),
- biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
- gen_field_count, 0, "");
-
- // create debug types for members of root struct
- uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
- enum_type->data.enumeration.gen_tag_index);
- ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
- ZigLLVMTypeToScope(enum_type->di_type), "tag_field",
- import->di_file, (unsigned)(decl_node->line + 1),
- tag_debug_size_in_bits,
- tag_debug_align_in_bits,
- tag_offset_in_bits,
- 0, tag_di_type);
-
- uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
- enum_type->data.enumeration.gen_union_index);
- ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
- ZigLLVMTypeToScope(enum_type->di_type), "union_field",
- import->di_file, (unsigned)(decl_node->line + 1),
- biggest_size_in_bits,
- biggest_align_in_bits,
- union_offset_in_bits,
- 0, union_di_type);
-
- // create debug type for root struct
- ZigLLVMDIType *di_root_members[2];
- di_root_members[enum_type->data.enumeration.gen_tag_index] = tag_member_di_type;
- di_root_members[enum_type->data.enumeration.gen_union_index] = union_member_di_type;
-
- uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, enum_type->type_ref);
- uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref);
- ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
- ZigLLVMFileToScope(import->di_file),
- buf_ptr(&enum_type->name),
- import->di_file, (unsigned)(decl_node->line + 1),
- debug_size_in_bits,
- debug_align_in_bits,
- 0, nullptr, di_root_members, 2, 0, nullptr, "");
-
- ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type);
- enum_type->di_type = replacement_di_type;
- } else {
- // create llvm type for root struct
- enum_type->type_ref = tag_type_entry->type_ref;
-
- // create debug type for tag
- uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
- uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
- ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
- ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
- import->di_file, (unsigned)(decl_node->line + 1),
- tag_debug_size_in_bits,
- tag_debug_align_in_bits,
- di_enumerators, field_count,
- tag_type_entry->di_type, "");
-
- ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type);
- enum_type->di_type = tag_di_type;
- }
+ ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type);
+ enum_type->di_type = tag_di_type;
}
static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
@@ -1517,7 +1360,6 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
case TypeTableEntryIdNullLit:
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdPureError:
- case TypeTableEntryIdEnumTag:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
@@ -1541,8 +1383,7 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
return child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn;
}
case TypeTableEntryIdEnum:
- return type_entry->data.enumeration.gen_field_count == 0 &&
- type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr;
+ return type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr;
}
zig_unreachable();
}
@@ -1850,6 +1691,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
if (union_type->data.unionation.embedded_in_current) {
if (!union_type->data.unionation.reported_infinite_err) {
union_type->data.unionation.reported_infinite_err = true;
+ union_type->data.unionation.is_invalid = true;
add_node_error(g, decl_node, buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name)));
}
return;
@@ -1871,8 +1713,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
uint64_t biggest_align_in_bits = 0;
uint64_t biggest_size_in_bits = 0;
- bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
- ZigLLVMDIEnumerator **di_enumerators = allocate(field_count);
+ ZigLLVMDIEnumerator **di_enumerators;
Scope *scope = &union_type->data.unionation.decls_scope->base;
ImportTableEntry *import = get_scope_import(scope);
@@ -1880,10 +1721,77 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
// set temporary flag
union_type->data.unionation.embedded_in_current = true;
+ HashMap occupied_tag_values = {};
+
+ AstNode *enum_type_node = decl_node->data.container_decl.init_arg_expr;
+ bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
+ bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr);
+ TypeTableEntry *tag_type;
+ bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety);
+ bool *covered_enum_fields;
+ if (create_enum_type) {
+ occupied_tag_values.init(field_count);
+
+ di_enumerators = allocate(field_count);
+
+ TypeTableEntry *tag_int_type;
+ if (enum_type_node != nullptr) {
+ tag_int_type = analyze_type_expr(g, scope, enum_type_node);
+ if (type_is_invalid(tag_int_type)) {
+ union_type->data.unionation.is_invalid = true;
+ return;
+ }
+ if (tag_int_type->id != TypeTableEntryIdInt) {
+ add_node_error(g, enum_type_node,
+ buf_sprintf("expected integer tag type, found '%s'", buf_ptr(&tag_int_type->name)));
+ union_type->data.unionation.is_invalid = true;
+ return;
+ }
+ } else {
+ tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
+ }
+
+ tag_type = new_type_table_entry(TypeTableEntryIdEnum);
+ buf_resize(&tag_type->name, 0);
+ buf_appendf(&tag_type->name, "@EnumTagType(%s)", buf_ptr(&union_type->name));
+ tag_type->is_copyable = true;
+ tag_type->type_ref = tag_int_type->type_ref;
+ tag_type->zero_bits = tag_int_type->zero_bits;
+
+ tag_type->data.enumeration.tag_int_type = tag_int_type;
+ tag_type->data.enumeration.zero_bits_known = true;
+ tag_type->data.enumeration.decl_node = decl_node;
+ tag_type->data.enumeration.layout = ContainerLayoutAuto;
+ tag_type->data.enumeration.src_field_count = field_count;
+ tag_type->data.enumeration.fields = allocate(field_count);
+ tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope;
+ tag_type->data.enumeration.complete = true;
+ } else if (enum_type_node != nullptr) {
+ TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node);
+ if (type_is_invalid(enum_type)) {
+ union_type->data.unionation.is_invalid = true;
+ union_type->data.unionation.embedded_in_current = false;
+ return;
+ }
+ if (enum_type->id != TypeTableEntryIdEnum) {
+ union_type->data.unionation.is_invalid = true;
+ union_type->data.unionation.embedded_in_current = false;
+ add_node_error(g, enum_type_node,
+ buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
+ return;
+ }
+ tag_type = enum_type;
+ covered_enum_fields = allocate(enum_type->data.enumeration.src_field_count);
+ } else {
+ tag_type = nullptr;
+ }
+ union_type->data.unionation.tag_type = tag_type;
+
for (uint32_t i = 0; i < field_count; i += 1) {
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
- TypeUnionField *type_union_field = &union_type->data.unionation.fields[i];
- TypeTableEntry *field_type = type_union_field->type_entry;
+ TypeUnionField *union_field = &union_type->data.unionation.fields[i];
+ Buf *field_name = field_node->data.struct_field.name;
+ TypeTableEntry *field_type = union_field->type_entry;
ensure_complete_type(g, field_type);
if (type_is_invalid(field_type)) {
@@ -1891,19 +1799,68 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
continue;
}
+ if (create_enum_type) {
+ di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field_name), i);
+ union_field->enum_field = &tag_type->data.enumeration.fields[i];
+ union_field->enum_field->name = field_name;
+ union_field->enum_field->decl_index = i;
+
+ AstNode *tag_value = field_node->data.struct_field.value;
+ // In this first pass we resolve explicit tag values.
+ // In a second pass we will fill in the unspecified ones.
+ if (tag_value != nullptr) {
+ TypeTableEntry *tag_int_type = tag_type->data.enumeration.tag_int_type;
+ IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
+ if (result_inst->value.type->id == TypeTableEntryIdInvalid) {
+ union_type->data.unionation.is_invalid = true;
+ continue;
+ }
+ assert(result_inst->value.special != ConstValSpecialRuntime);
+ assert(result_inst->value.type->id == TypeTableEntryIdInt);
+ auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
+ if (entry == nullptr) {
+ bigint_init_bigint(&union_field->enum_field->value, &result_inst->value.data.x_bigint);
+ } else {
+ Buf *val_buf = buf_alloc();
+ bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10);
+
+ ErrorMsg *msg = add_node_error(g, tag_value,
+ buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf)));
+ add_error_note(g, msg, entry->value,
+ buf_sprintf("other occurrence here"));
+ union_type->data.unionation.is_invalid = true;
+ continue;
+ }
+ }
+ } else if (enum_type_node != nullptr) {
+ union_field->enum_field = find_enum_type_field(tag_type, field_name);
+ if (union_field->enum_field == nullptr) {
+ ErrorMsg *msg = add_node_error(g, field_node,
+ buf_sprintf("enum field not found: '%s'", buf_ptr(field_name)));
+ add_error_note(g, msg, tag_type->data.enumeration.decl_node,
+ buf_sprintf("enum declared here"));
+ union_type->data.unionation.is_invalid = true;
+ continue;
+ }
+ covered_enum_fields[union_field->enum_field->decl_index] = true;
+ } else {
+ union_field->enum_field = allocate(1);
+ union_field->enum_field->name = field_name;
+ union_field->enum_field->decl_index = i;
+ bigint_init_unsigned(&union_field->enum_field->value, i);
+ }
+
if (!type_has_bits(field_type))
continue;
- di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(type_union_field->name), i);
-
uint64_t store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
uint64_t abi_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref);
assert(store_size_in_bits > 0);
assert(abi_align_in_bits > 0);
- union_inner_di_types[type_union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
- ZigLLVMTypeToScope(union_type->di_type), buf_ptr(type_union_field->name),
+ union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
+ ZigLLVMTypeToScope(union_type->di_type), buf_ptr(union_field->enum_field->name),
import->di_file, (unsigned)(field_node->line + 1),
store_size_in_bits,
abi_align_in_bits,
@@ -1919,6 +1876,49 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
}
}
+ if (create_enum_type) {
+ // Now iterate again and populate the unspecified tag values
+ uint32_t next_maybe_unoccupied_index = 0;
+
+ for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
+ AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
+ TypeUnionField *union_field = &union_type->data.unionation.fields[field_i];
+ AstNode *tag_value = field_node->data.struct_field.value;
+
+ if (tag_value == nullptr) {
+ if (occupied_tag_values.size() == 0) {
+ bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index);
+ next_maybe_unoccupied_index += 1;
+ } else {
+ BigInt proposed_value;
+ for (;;) {
+ bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index);
+ next_maybe_unoccupied_index += 1;
+ auto entry = occupied_tag_values.put_unique(proposed_value, field_node);
+ if (entry != nullptr) {
+ continue;
+ }
+ break;
+ }
+ bigint_init_bigint(&union_field->enum_field->value, &proposed_value);
+ }
+ }
+ }
+ } 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]) {
+ 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,
+ buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name)));
+ add_error_note(g, msg, field_node,
+ buf_sprintf("declared here"));
+ union_type->data.unionation.is_invalid = true;
+ }
+ }
+ }
+
// unset temporary flag
union_type->data.unionation.embedded_in_current = false;
union_type->data.unionation.complete = true;
@@ -1950,11 +1950,9 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
assert(most_aligned_union_member != nullptr);
- bool want_safety = auto_layout && (field_count >= 2);
uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
-
- if (!want_safety) {
+ if (tag_type == nullptr) {
if (padding_in_bits > 0) {
TypeTableEntry *u8_type = get_int_type(g, false, 8);
TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
@@ -1994,6 +1992,8 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
padding_array->type_ref,
};
union_type_ref = LLVMStructType(union_element_types, 2, false);
+ } else if (most_aligned_union_member == nullptr) {
+ zig_panic("TODO zero bit payload");
} else {
union_type_ref = most_aligned_union_member->type_ref;
}
@@ -2003,9 +2003,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);
// create llvm type for root struct
- TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
- TypeTableEntry *tag_type_entry = tag_int_type;
- union_type->data.unionation.tag_type = tag_type_entry;
+ TypeTableEntry *tag_int_type = tag_type->data.enumeration.tag_int_type;
uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
if (align_of_tag_in_bits >= biggest_align_in_bits) {
@@ -2017,21 +2015,24 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
}
LLVMTypeRef root_struct_element_types[2];
- root_struct_element_types[union_type->data.unionation.gen_tag_index] = tag_type_entry->type_ref;
+ root_struct_element_types[union_type->data.unionation.gen_tag_index] = tag_type->type_ref;
root_struct_element_types[union_type->data.unionation.gen_union_index] = union_type_ref;
LLVMStructSetBody(union_type->type_ref, root_struct_element_types, 2, false);
// create debug type for root struct
- // create debug type for tag
- uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
- uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
- ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
- ZigLLVMTypeToScope(union_type->di_type), "AnonEnum",
- import->di_file, (unsigned)(decl_node->line + 1),
- tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
- tag_type_entry->di_type, "");
+ uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
+ uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
+ if (create_enum_type) {
+ // create debug type for tag
+ ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
+ ZigLLVMTypeToScope(union_type->di_type), "AnonEnum",
+ import->di_file, (unsigned)(decl_node->line + 1),
+ tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
+ tag_type->di_type, "");
+ tag_type->di_type = tag_di_type;
+ }
// create debug type for union
ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
@@ -2046,19 +2047,19 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
union_type->data.unionation.gen_tag_index);
ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
- ZigLLVMTypeToScope(union_type->di_type), "union_field",
+ ZigLLVMTypeToScope(union_type->di_type), "payload",
import->di_file, (unsigned)(decl_node->line + 1),
biggest_size_in_bits,
biggest_align_in_bits,
union_offset_in_bits,
0, union_di_type);
ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
- ZigLLVMTypeToScope(union_type->di_type), "tag_field",
+ ZigLLVMTypeToScope(union_type->di_type), "tag",
import->di_file, (unsigned)(decl_node->line + 1),
tag_debug_size_in_bits,
tag_debug_align_in_bits,
tag_offset_in_bits,
- 0, tag_di_type);
+ 0, tag_type->di_type);
ZigLLVMDIType *di_root_members[2];
di_root_members[union_type->data.unionation.gen_tag_index] = tag_member_di_type;
@@ -2104,7 +2105,6 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
enum_type->data.enumeration.fields = nullptr;
enum_type->data.enumeration.is_invalid = true;
enum_type->data.enumeration.zero_bits_loop_flag = false;
- enum_type->data.enumeration.gen_field_count = 0;
enum_type->data.enumeration.zero_bits_known = true;
return;
}
@@ -2112,8 +2112,6 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
enum_type->data.enumeration.src_field_count = field_count;
enum_type->data.enumeration.fields = allocate(field_count);
- uint32_t biggest_align_bytes = 0;
-
Scope *scope = &enum_type->data.enumeration.decls_scope->base;
HashMap occupied_tag_values = {};
@@ -2143,14 +2141,20 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
}
}
enum_type->data.enumeration.tag_int_type = tag_int_type;
+ enum_type->type_ref = tag_int_type->type_ref;
- uint32_t gen_field_index = 0;
for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i];
type_enum_field->name = field_node->data.struct_field.name;
- TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
- type_enum_field->type_entry = field_type;
+ type_enum_field->decl_index = field_i;
+
+ if (field_node->data.struct_field.type != nullptr) {
+ ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.type,
+ buf_sprintf("structs and unions, not enums, support field types"));
+ add_error_note(g, msg, decl_node,
+ buf_sprintf("consider 'union(enum)' here"));
+ }
AstNode *tag_value = field_node->data.struct_field.value;
@@ -2179,23 +2183,6 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
continue;
}
}
-
- type_ensure_zero_bits_known(g, field_type);
- if (type_is_invalid(field_type)) {
- enum_type->data.enumeration.is_invalid = true;
- continue;
- }
-
- if (!type_has_bits(field_type))
- continue;
-
- type_enum_field->gen_index = gen_field_index;
- gen_field_index += 1;
-
- uint32_t field_align_bytes = get_abi_alignment(g, field_type);
- if (field_align_bytes > biggest_align_bytes) {
- biggest_align_bytes = field_align_bytes;
- }
}
// Now iterate again and populate the unspecified tag values
@@ -2227,15 +2214,8 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
}
enum_type->data.enumeration.zero_bits_loop_flag = false;
- enum_type->data.enumeration.gen_field_count = gen_field_index;
- enum_type->zero_bits = (gen_field_index == 0 && field_count < 2);
+ enum_type->zero_bits = (field_count < 2);
enum_type->data.enumeration.zero_bits_known = true;
-
- // also compute abi_alignment
- if (!enum_type->zero_bits) {
- uint32_t align_of_tag_in_bytes = LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
- enum_type->data.enumeration.abi_alignment = max(align_of_tag_in_bytes, biggest_align_bytes);
- }
}
static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
@@ -2279,6 +2259,13 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
type_struct_field->name = field_node->data.struct_field.name;
+
+ if (field_node->data.struct_field.type == nullptr) {
+ add_node_error(g, field_node, buf_sprintf("struct field missing type"));
+ struct_type->data.structure.is_invalid = true;
+ continue;
+ }
+
TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
type_struct_field->type_entry = field_type;
type_struct_field->src_index = i;
@@ -2338,6 +2325,16 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
assert(!union_type->data.unionation.fields);
uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length;
+ if (field_count == 0) {
+ add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields"));
+
+ union_type->data.unionation.src_field_count = field_count;
+ union_type->data.unionation.fields = nullptr;
+ union_type->data.unionation.is_invalid = true;
+ union_type->data.unionation.zero_bits_loop_flag = false;
+ union_type->data.unionation.zero_bits_known = true;
+ return;
+ }
union_type->data.unionation.src_field_count = field_count;
union_type->data.unionation.fields = allocate(field_count);
@@ -2348,17 +2345,23 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
uint32_t gen_field_index = 0;
for (uint32_t i = 0; i < field_count; i += 1) {
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
- TypeUnionField *type_union_field = &union_type->data.unionation.fields[i];
- type_union_field->name = field_node->data.struct_field.name;
+ TypeUnionField *union_field = &union_type->data.unionation.fields[i];
+ union_field->name = field_node->data.struct_field.name;
+
+ if (field_node->data.struct_field.type == nullptr) {
+ add_node_error(g, field_node, buf_sprintf("union field missing type"));
+ union_type->data.unionation.is_invalid = true;
+ continue;
+ }
+
TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
- type_union_field->type_entry = field_type;
+ union_field->type_entry = field_type;
- // TODO look for enum arg to union
- bigint_init_unsigned(&type_union_field->value, i);
-
- if (field_node->data.struct_field.value != nullptr) {
- add_node_error(g, field_node->data.struct_field.value,
- buf_sprintf("enums, not unions, support field assignment"));
+ if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
+ ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
+ buf_sprintf("non-enum union field assignment"));
+ add_error_note(g, msg, decl_node,
+ buf_sprintf("consider 'union(enum)' here"));
}
type_ensure_zero_bits_known(g, field_type);
@@ -2370,7 +2373,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
if (!type_has_bits(field_type))
continue;
- type_union_field->gen_index = gen_field_index;
+ union_field->gen_index = gen_field_index;
gen_field_index += 1;
uint32_t field_align_bytes = get_abi_alignment(g, field_type);
@@ -2379,11 +2382,32 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
}
}
- bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
+ bool src_have_tag = decl_node->data.container_decl.auto_enum ||
+ decl_node->data.container_decl.init_arg_expr != nullptr;
+
+ if (src_have_tag && union_type->data.unionation.layout != ContainerLayoutAuto) {
+ const char *qual_str;
+ switch (union_type->data.unionation.layout) {
+ case ContainerLayoutAuto:
+ zig_unreachable();
+ case ContainerLayoutPacked:
+ qual_str = "packed";
+ break;
+ case ContainerLayoutExtern:
+ qual_str = "extern";
+ break;
+ }
+ AstNode *source_node = (decl_node->data.container_decl.init_arg_expr != nullptr) ?
+ decl_node->data.container_decl.init_arg_expr : decl_node;
+ add_node_error(g, source_node,
+ buf_sprintf("%s union does not support enum tag type", qual_str));
+ union_type->data.unionation.is_invalid = true;
+ return;
+ }
union_type->data.unionation.zero_bits_loop_flag = false;
union_type->data.unionation.gen_field_count = gen_field_index;
- union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !auto_layout));
+ union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !src_have_tag));
union_type->data.unionation.zero_bits_known = true;
// also compute abi_alignment
@@ -2848,7 +2872,6 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
case TypeTableEntryIdBoundFn:
- case TypeTableEntryIdEnumTag:
return type_entry;
}
zig_unreachable();
@@ -3265,19 +3288,20 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {
assert(type_entry->data.unionation.complete);
for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {
TypeUnionField *field = &type_entry->data.unionation.fields[i];
- if (buf_eql_buf(field->name, name)) {
+ if (buf_eql_buf(field->enum_field->name, name)) {
return field;
}
}
return nullptr;
}
-static TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) {
+TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) {
assert(type_entry->id == TypeTableEntryIdUnion);
assert(type_entry->data.unionation.complete);
+ assert(type_entry->data.unionation.gen_tag_index != SIZE_MAX);
for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {
TypeUnionField *field = &type_entry->data.unionation.fields[i];
- if (bigint_cmp(&field->value, tag) == CmpEQ) {
+ if (bigint_cmp(&field->enum_field->value, tag) == CmpEQ) {
return field;
}
}
@@ -3323,7 +3347,6 @@ static bool is_container(TypeTableEntry *type_entry) {
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
- case TypeTableEntryIdEnumTag:
case TypeTableEntryIdArgTuple:
case TypeTableEntryIdOpaque:
return false;
@@ -3374,7 +3397,6 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdInvalid:
case TypeTableEntryIdVar:
- case TypeTableEntryIdEnumTag:
case TypeTableEntryIdArgTuple:
case TypeTableEntryIdOpaque:
zig_unreachable();
@@ -3828,7 +3850,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
case TypeTableEntryIdPointer:
case TypeTableEntryIdPureError:
case TypeTableEntryIdFn:
- case TypeTableEntryIdEnumTag:
+ case TypeTableEntryIdEnum:
return false;
case TypeTableEntryIdArray:
case TypeTableEntryIdStruct:
@@ -3836,9 +3858,6 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
return type_has_bits(type_entry);
case TypeTableEntryIdErrorUnion:
return type_has_bits(type_entry->data.error.child_type);
- case TypeTableEntryIdEnum:
- assert(type_entry->data.enumeration.complete);
- return type_entry->data.enumeration.gen_field_count != 0;
case TypeTableEntryIdMaybe:
return type_has_bits(type_entry->data.maybe.child_type) &&
type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer &&
@@ -3980,7 +3999,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
return (uint32_t)4149439618;
case TypeTableEntryIdInt:
case TypeTableEntryIdNumLitInt:
- case TypeTableEntryIdEnumTag:
{
uint32_t result = 1331471175;
for (size_t i = 0; i < const_val->data.x_bigint.digit_count; i += 1) {
@@ -3989,6 +4007,15 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
}
return result;
}
+ case TypeTableEntryIdEnum:
+ {
+ uint32_t result = 31643936;
+ for (size_t i = 0; i < const_val->data.x_enum_tag.digit_count; i += 1) {
+ uint64_t digit = bigint_ptr(&const_val->data.x_enum_tag)[i];
+ result ^= ((uint32_t)(digit >> 32)) ^ (uint32_t)(result);
+ }
+ return result;
+ }
case TypeTableEntryIdFloat:
switch (const_val->type->data.floating.bit_count) {
case 32:
@@ -4089,9 +4116,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
case TypeTableEntryIdPureError:
// TODO better hashing algorithm
return 2630160122;
- case TypeTableEntryIdEnum:
- // TODO better hashing algorithm
- return 31643936;
case TypeTableEntryIdFn:
return 4133894920 ^ hash_ptr(const_val->data.x_fn.fn_entry);
case TypeTableEntryIdNamespace:
@@ -4224,7 +4248,6 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
case TypeTableEntryIdInt:
case TypeTableEntryIdFloat:
case TypeTableEntryIdPointer:
- case TypeTableEntryIdEnumTag:
case TypeTableEntryIdVoid:
case TypeTableEntryIdUnreachable:
return false;
@@ -4295,6 +4318,7 @@ ConstExprValue *create_const_bigint(TypeTableEntry *type, const BigInt *bigint)
return const_val;
}
+
void init_const_unsigned_negative(ConstExprValue *const_val, TypeTableEntry *type, uint64_t x, bool negative) {
const_val->special = ConstValSpecialStatic;
const_val->type = type;
@@ -4358,18 +4382,19 @@ ConstExprValue *create_const_float(TypeTableEntry *type, double value) {
return const_val;
}
-void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *tag) {
+void init_const_enum(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *tag) {
const_val->special = ConstValSpecialStatic;
const_val->type = type;
- bigint_init_bigint(&const_val->data.x_enum.tag, tag);
+ bigint_init_bigint(&const_val->data.x_enum_tag, tag);
}
-ConstExprValue *create_const_enum_tag(TypeTableEntry *type, const BigInt *tag) {
+ConstExprValue *create_const_enum(TypeTableEntry *type, const BigInt *tag) {
ConstExprValue *const_val = create_const_vals(1);
- init_const_enum_tag(const_val, type, tag);
+ init_const_enum(const_val, type, tag);
return const_val;
}
+
void init_const_bool(CodeGen *g, ConstExprValue *const_val, bool value) {
const_val->special = ConstValSpecialStatic;
const_val->type = g->builtin_types.entry_bool;
@@ -4567,20 +4592,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
switch (a->type->id) {
case TypeTableEntryIdOpaque:
zig_unreachable();
- case TypeTableEntryIdEnum: {
- ConstEnumValue *enum1 = &a->data.x_enum;
- ConstEnumValue *enum2 = &b->data.x_enum;
- if (bigint_cmp(&enum1->tag, &enum2->tag) == CmpEQ) {
- TypeEnumField *field = find_enum_field_by_tag(a->type, &enum1->tag);
- assert(field != nullptr);
- if (type_has_bits(field->type_entry)) {
- zig_panic("TODO const expr analyze enum field value for equality");
- } else {
- return true;
- }
- }
- return false;
- }
+ case TypeTableEntryIdEnum:
+ return bigint_cmp(&a->data.x_enum_tag, &b->data.x_enum_tag) == CmpEQ;
case TypeTableEntryIdUnion: {
ConstUnionValue *union1 = &a->data.x_union;
ConstUnionValue *union2 = &b->data.x_union;
@@ -4622,7 +4635,6 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
return bigfloat_cmp(&a->data.x_bigfloat, &b->data.x_bigfloat) == CmpEQ;
case TypeTableEntryIdInt:
case TypeTableEntryIdNumLitInt:
- case TypeTableEntryIdEnumTag:
return bigint_cmp(&a->data.x_bigint, &b->data.x_bigint) == CmpEQ;
case TypeTableEntryIdPointer:
if (a->data.x_ptr.special != b->data.x_ptr.special)
@@ -4949,7 +4961,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
}
case TypeTableEntryIdEnum:
{
- buf_appendf(buf, "(enum %s constant)", buf_ptr(&type_entry->name));
+ TypeEnumField *field = find_enum_field_by_tag(type_entry, &const_val->data.x_enum_tag);
+ buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(field->name));
return;
}
case TypeTableEntryIdErrorUnion:
@@ -4967,14 +4980,6 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
buf_appendf(buf, "(pure error constant)");
return;
}
- case TypeTableEntryIdEnumTag:
- {
- TypeTableEntry *enum_type = type_entry->data.enum_tag.enum_type;
- size_t field_index = bigint_as_unsigned(&const_val->data.x_bigint);
- TypeEnumField *field = &enum_type->data.enumeration.fields[field_index];
- buf_appendf(buf, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name));
- return;
- }
case TypeTableEntryIdArgTuple:
{
buf_appendf(buf, "(args value)");
@@ -5036,7 +5041,6 @@ uint32_t type_id_hash(TypeId x) {
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdPureError:
case TypeTableEntryIdEnum:
- case TypeTableEntryIdEnumTag:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
case TypeTableEntryIdNamespace:
@@ -5081,7 +5085,6 @@ bool type_id_eql(TypeId a, TypeId b) {
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdPureError:
case TypeTableEntryIdEnum:
- case TypeTableEntryIdEnumTag:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
case TypeTableEntryIdNamespace:
@@ -5196,7 +5199,6 @@ static const TypeTableEntryId all_type_ids[] = {
TypeTableEntryIdErrorUnion,
TypeTableEntryIdPureError,
TypeTableEntryIdEnum,
- TypeTableEntryIdEnumTag,
TypeTableEntryIdUnion,
TypeTableEntryIdFn,
TypeTableEntryIdNamespace,
@@ -5254,22 +5256,20 @@ size_t type_id_index(TypeTableEntryId id) {
return 15;
case TypeTableEntryIdEnum:
return 16;
- case TypeTableEntryIdEnumTag:
- return 17;
case TypeTableEntryIdUnion:
- return 18;
+ return 17;
case TypeTableEntryIdFn:
- return 19;
+ return 18;
case TypeTableEntryIdNamespace:
- return 20;
+ return 19;
case TypeTableEntryIdBlock:
- return 21;
+ return 20;
case TypeTableEntryIdBoundFn:
- return 22;
+ return 21;
case TypeTableEntryIdArgTuple:
- return 23;
+ return 22;
case TypeTableEntryIdOpaque:
- return 24;
+ return 23;
}
zig_unreachable();
}
@@ -5313,8 +5313,6 @@ const char *type_id_name(TypeTableEntryId id) {
return "Error";
case TypeTableEntryIdEnum:
return "Enum";
- case TypeTableEntryIdEnumTag:
- return "EnumTag";
case TypeTableEntryIdUnion:
return "Union";
case TypeTableEntryIdFn:
@@ -5381,9 +5379,6 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) {
if (type_entry->id == TypeTableEntryIdStruct) {
assert(type_entry->data.structure.abi_alignment != 0);
return type_entry->data.structure.abi_alignment;
- } else if (type_entry->id == TypeTableEntryIdEnum) {
- assert(type_entry->data.enumeration.abi_alignment != 0);
- return type_entry->data.enumeration.abi_alignment;
} else if (type_entry->id == TypeTableEntryIdUnion) {
assert(type_entry->data.unionation.abi_alignment != 0);
return type_entry->data.unionation.abi_alignment;
diff --git a/src/analyze.hpp b/src/analyze.hpp
index 50eb2a800f..e6100c692c 100644
--- a/src/analyze.hpp
+++ b/src/analyze.hpp
@@ -65,6 +65,7 @@ ScopeDecls *get_container_scope(TypeTableEntry *type_entry);
TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name);
TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name);
TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag);
+TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag);
bool is_container_ref(TypeTableEntry *type_entry);
void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
@@ -126,8 +127,8 @@ ConstExprValue *create_const_usize(CodeGen *g, uint64_t x);
void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double value);
ConstExprValue *create_const_float(TypeTableEntry *type, double value);
-void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *tag);
-ConstExprValue *create_const_enum_tag(TypeTableEntry *type, const BigInt *tag);
+void init_const_enum(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *tag);
+ConstExprValue *create_const_enum(TypeTableEntry *type, const BigInt *tag);
void init_const_bool(CodeGen *g, ConstExprValue *const_val, bool value);
ConstExprValue *create_const_bool(CodeGen *g, bool value);
@@ -163,7 +164,6 @@ ConstExprValue *create_const_vals(size_t count);
TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits);
ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value);
-TypeTableEntry *create_enum_tag_type(CodeGen *g, TypeTableEntry *enum_type, TypeTableEntry *int_type);
void expand_undef_array(CodeGen *g, ConstExprValue *const_val);
void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value);
diff --git a/src/ast_render.cpp b/src/ast_render.cpp
index cdc18c7252..4f4dc1decd 100644
--- a/src/ast_render.cpp
+++ b/src/ast_render.cpp
@@ -661,11 +661,18 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
const char *layout_str = layout_string(node->data.container_decl.layout);
const char *container_str = container_string(node->data.container_decl.kind);
fprintf(ar->f, "%s%s", layout_str, container_str);
+ if (node->data.container_decl.auto_enum) {
+ fprintf(ar->f, "(enum");
+ }
if (node->data.container_decl.init_arg_expr != nullptr) {
fprintf(ar->f, "(");
render_node_grouped(ar, node->data.container_decl.init_arg_expr);
fprintf(ar->f, ")");
}
+ if (node->data.container_decl.auto_enum) {
+ fprintf(ar->f, ")");
+ }
+
fprintf(ar->f, " {\n");
ar->indent += ar->indent_size;
for (size_t field_i = 0; field_i < node->data.container_decl.fields.length; field_i += 1) {
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 0ac8ffb7e1..dbf4f8522b 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -1631,12 +1631,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, type_entry->data.integral.is_signed);
return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
} else if (type_entry->id == TypeTableEntryIdEnum) {
- if (type_entry->data.enumeration.gen_field_count == 0) {
- LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
- return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
- } else {
- zig_unreachable();
- }
+ LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
+ return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
} else if (type_entry->id == TypeTableEntryIdPureError ||
type_entry->id == TypeTableEntryIdPointer ||
type_entry->id == TypeTableEntryIdBool)
@@ -1920,9 +1916,7 @@ static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executa
// enum_tag to the underlying int type
TypeTableEntry *int_type;
if (actual_type->id == TypeTableEntryIdEnum) {
- TypeTableEntry *tag_type = actual_type->data.enumeration.tag_type;
- assert(tag_type->id == TypeTableEntryIdEnumTag);
- int_type = tag_type->data.enum_tag.int_type;
+ int_type = actual_type->data.enumeration.tag_int_type;
} else {
int_type = actual_type;
}
@@ -1946,19 +1940,11 @@ static LLVMValueRef ir_render_ptr_to_int(CodeGen *g, IrExecutable *executable, I
static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable, IrInstructionIntToEnum *instruction) {
TypeTableEntry *wanted_type = instruction->base.value.type;
assert(wanted_type->id == TypeTableEntryIdEnum);
- TypeTableEntry *tag_type = wanted_type->data.enumeration.tag_type;
- TypeTableEntry *wanted_int_type;
- if (tag_type->id == TypeTableEntryIdEnumTag) {
- wanted_int_type = tag_type->data.enum_tag.int_type;
- } else if (tag_type->id == TypeTableEntryIdInt) {
- wanted_int_type = tag_type;
- } else {
- zig_unreachable();
- }
+ TypeTableEntry *tag_int_type = wanted_type->data.enumeration.tag_int_type;
LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base),
- instruction->target->value.type, wanted_int_type, target_val);
+ instruction->target->value.type, tag_int_type, target_val);
}
static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) {
@@ -2378,27 +2364,6 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa
return LLVMBuildStructGEP(g->builder, struct_ptr, (unsigned)field->gen_index, "");
}
-static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executable,
- IrInstructionEnumFieldPtr *instruction)
-{
- TypeTableEntry *enum_ptr_type = instruction->enum_ptr->value.type;
- assert(enum_ptr_type->id == TypeTableEntryIdPointer);
- TypeTableEntry *enum_type = enum_ptr_type->data.pointer.child_type;
- assert(enum_type->id == TypeTableEntryIdEnum);
-
- TypeEnumField *field = instruction->field;
-
- if (!type_has_bits(field->type_entry))
- return nullptr;
-
- LLVMValueRef enum_ptr = ir_llvm_value(g, instruction->enum_ptr);
- LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0);
- LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, enum_ptr, enum_type->data.enumeration.gen_union_index, "");
- LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
-
- return bitcasted_union_field_ptr;
-}
-
static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executable,
IrInstructionUnionFieldPtr *instruction)
{
@@ -2427,7 +2392,7 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab
LLVMValueRef expected_tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
- &field->value);
+ &field->enum_field->value);
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckOk");
LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckFail");
LLVMValueRef ok_val = LLVMBuildICmp(g->builder, LLVMIntEQ, tag_value, expected_tag_value, "");
@@ -2754,19 +2719,19 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI
static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable,
IrInstructionEnumTagName *instruction)
{
- TypeTableEntry *enum_tag_type = instruction->target->value.type;
- assert(enum_tag_type->data.enum_tag.generate_name_table);
+ TypeTableEntry *enum_type = instruction->target->value.type;
+ assert(enum_type->id == TypeTableEntryIdEnum);
+ assert(enum_type->data.enumeration.generate_name_table);
+ TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type;
LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target);
if (ir_want_debug_safety(g, &instruction->base)) {
- TypeTableEntry *enum_type = enum_tag_type->data.enum_tag.enum_type;
size_t field_count = enum_type->data.enumeration.src_field_count;
- // if the field_count can't fit in the bits of the enum_tag_type, then it can't possibly
+ // if the field_count can't fit in the bits of the enum_type, then it can't possibly
// be the wrong value
BigInt field_bi;
bigint_init_unsigned(&field_bi, field_count);
- TypeTableEntry *tag_int_type = enum_tag_type->data.enum_tag.int_type;
if (bigint_fits_in_bits(&field_bi, tag_int_type->data.integral.bit_count, false)) {
LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(enum_tag_value), field_count, false);
add_bounds_check(g, enum_tag_value, LLVMIntEQ, nullptr, LLVMIntULT, end_val);
@@ -2775,10 +2740,10 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable
LLVMValueRef indices[] = {
LLVMConstNull(g->builtin_types.entry_usize->type_ref),
- gen_widen_or_shorten(g, false, enum_tag_type->data.enum_tag.int_type,
+ gen_widen_or_shorten(g, false, tag_int_type,
g->builtin_types.entry_usize, enum_tag_value),
};
- return LLVMBuildInBoundsGEP(g->builder, enum_tag_type->data.enum_tag.name_table, indices, 2, "");
+ return LLVMBuildInBoundsGEP(g->builder, enum_type->data.enumeration.name_table, indices, 2, "");
}
static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executable,
@@ -3352,48 +3317,24 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
return instruction->tmp_ptr;
}
-static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrInstructionEnumTag *instruction) {
- TypeTableEntry *enum_type = instruction->value->value.type;
- TypeTableEntry *tag_type = enum_type->data.enumeration.tag_type;
+static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, IrInstructionUnionTag *instruction) {
+ TypeTableEntry *union_type = instruction->value->value.type;
+ assert(union_type->data.unionation.gen_tag_index != SIZE_MAX);
+
+ TypeTableEntry *tag_type = union_type->data.unionation.tag_type;
if (!type_has_bits(tag_type))
return nullptr;
- LLVMValueRef enum_val = ir_llvm_value(g, instruction->value);
- if (enum_type->data.enumeration.gen_field_count == 0)
- return enum_val;
+ LLVMValueRef union_val = ir_llvm_value(g, instruction->value);
+ if (union_type->data.unionation.gen_field_count == 0)
+ return union_val;
- LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, enum_val, enum_type->data.enumeration.gen_tag_index, "");
+ LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_val,
+ union_type->data.unionation.gen_tag_index, "");
TypeTableEntry *ptr_type = get_pointer_to_type(g, tag_type, false);
return get_handle_value(g, tag_field_ptr, tag_type, ptr_type);
}
-static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, IrInstructionInitEnum *instruction) {
- TypeTableEntry *enum_type = instruction->enum_type;
- LLVMTypeRef tag_type_ref = enum_type->data.enumeration.tag_type->type_ref;
-
- LLVMValueRef tag_value = bigint_to_llvm_const(tag_type_ref, &instruction->field->value);
-
- if (enum_type->data.enumeration.gen_field_count == 0)
- return tag_value;
-
- LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr;
-
- LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_type->data.enumeration.gen_tag_index, "");
- gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
-
- TypeTableEntry *union_val_type = instruction->field->type_entry;
- if (type_has_bits(union_val_type)) {
- LLVMValueRef new_union_val = ir_llvm_value(g, instruction->init_value);
- LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_type->data.enumeration.gen_union_index, "");
- LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr,
- LLVMPointerType(union_val_type->type_ref, 0), "");
-
- gen_assign_raw(g, bitcasted_union_field_ptr, get_pointer_to_type(g, union_val_type, false), new_union_val);
- }
-
- return tmp_struct_ptr;
-}
-
static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, IrInstructionStructInit *instruction) {
for (size_t i = 0; i < instruction->field_count; i += 1) {
IrInstructionStructInitField *field = &instruction->fields[i];
@@ -3436,7 +3377,7 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I
union_type->data.unionation.gen_tag_index, "");
LLVMValueRef tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
- &type_union_field->value);
+ &type_union_field->enum_field->value);
gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
@@ -3573,8 +3514,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_call(g, executable, (IrInstructionCall *)instruction);
case IrInstructionIdStructFieldPtr:
return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);
- case IrInstructionIdEnumFieldPtr:
- return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction);
case IrInstructionIdUnionFieldPtr:
return ir_render_union_field_ptr(g, executable, (IrInstructionUnionFieldPtr *)instruction);
case IrInstructionIdAsm:
@@ -3629,10 +3568,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction);
case IrInstructionIdErrWrapPayload:
return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction);
- case IrInstructionIdEnumTag:
- return ir_render_enum_tag(g, executable, (IrInstructionEnumTag *)instruction);
- case IrInstructionIdInitEnum:
- return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction);
+ case IrInstructionIdUnionTag:
+ return ir_render_union_tag(g, executable, (IrInstructionUnionTag *)instruction);
case IrInstructionIdStructInit:
return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);
case IrInstructionIdUnionInit:
@@ -3768,7 +3705,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
case TypeTableEntryIdNullLit:
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdPureError:
- case TypeTableEntryIdEnumTag:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
@@ -3780,7 +3716,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
return LLVMConstInt(big_int_type_ref, const_val->data.x_bool ? 1 : 0, false);
case TypeTableEntryIdEnum:
{
- assert(type_entry->data.enumeration.gen_field_count == 0);
assert(type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr);
LLVMValueRef int_val = gen_const_val(g, const_val);
return LLVMConstZExt(int_val, big_int_type_ref);
@@ -3852,7 +3787,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
switch (type_entry->id) {
case TypeTableEntryIdInt:
- case TypeTableEntryIdEnumTag:
return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint);
case TypeTableEntryIdPureError:
assert(const_val->data.x_pure_err);
@@ -4015,34 +3949,48 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
ConstExprValue *payload_value = const_val->data.x_union.payload;
assert(payload_value != nullptr);
- if (!type_has_bits(payload_value->type)) {
- return LLVMGetUndef(union_type_ref);
- }
-
- uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref);
- uint64_t pad_bytes = type_entry->data.unionation.union_size_bytes - field_type_bytes;
- LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value);
- bool make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) ||
- payload_value->type != type_entry->data.unionation.most_aligned_union_member;
-
- LLVMValueRef union_value_ref;
- {
- if (pad_bytes == 0) {
- union_value_ref = correctly_typed_value;
+ if (type_entry->data.unionation.gen_field_count == 0) {
+ if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) {
+ return nullptr;
} else {
- LLVMValueRef fields[2];
- fields[0] = correctly_typed_value;
- fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes));
- if (make_unnamed_struct || type_entry->data.unionation.gen_tag_index != SIZE_MAX) {
- union_value_ref = LLVMConstStruct(fields, 2, false);
- } else {
- union_value_ref = LLVMConstNamedStruct(union_type_ref, fields, 2);
- }
+ return bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref,
+ &const_val->data.x_union.tag);
}
}
- if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) {
- return union_value_ref;
+ LLVMValueRef union_value_ref;
+ bool make_unnamed_struct;
+ if (!type_has_bits(payload_value->type)) {
+ if (type_entry->data.unionation.gen_tag_index == SIZE_MAX)
+ return LLVMGetUndef(type_entry->type_ref);
+
+ union_value_ref = LLVMGetUndef(type_entry->data.unionation.most_aligned_union_member->type_ref);
+ make_unnamed_struct = false;
+ } else {
+ uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref);
+ uint64_t pad_bytes = type_entry->data.unionation.union_size_bytes - field_type_bytes;
+ LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value);
+ make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) ||
+ payload_value->type != type_entry->data.unionation.most_aligned_union_member;
+
+ {
+ if (pad_bytes == 0) {
+ union_value_ref = correctly_typed_value;
+ } else {
+ LLVMValueRef fields[2];
+ fields[0] = correctly_typed_value;
+ fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes));
+ if (make_unnamed_struct || type_entry->data.unionation.gen_tag_index != SIZE_MAX) {
+ union_value_ref = LLVMConstStruct(fields, 2, false);
+ } else {
+ union_value_ref = LLVMConstNamedStruct(union_type_ref, fields, 2);
+ }
+ }
+ }
+
+ if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) {
+ return union_value_ref;
+ }
}
LLVMValueRef tag_value = bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref,
@@ -4059,55 +4007,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
}
}
+
case TypeTableEntryIdEnum:
- {
- LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
- LLVMValueRef tag_value = bigint_to_llvm_const(tag_type_ref, &const_val->data.x_enum.tag);
- if (type_entry->data.enumeration.gen_field_count == 0) {
- return tag_value;
- } else {
- LLVMTypeRef union_type_ref = type_entry->data.enumeration.union_type_ref;
- TypeEnumField *enum_field = find_enum_field_by_tag(type_entry, &const_val->data.x_enum.tag);
- assert(bigint_cmp(&enum_field->value, &const_val->data.x_enum.tag) == CmpEQ);
- LLVMValueRef union_value;
-
- bool make_unnamed_struct;
-
- if (type_has_bits(enum_field->type_entry)) {
- uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref,
- enum_field->type_entry->type_ref);
- uint64_t pad_bytes = type_entry->data.enumeration.union_size_bytes - field_type_bytes;
-
- ConstExprValue *payload_value = const_val->data.x_enum.payload;
- LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value);
-
- make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) ||
- payload_value->type != type_entry->data.enumeration.most_aligned_union_member;
-
- if (pad_bytes == 0) {
- union_value = correctly_typed_value;
- } else {
- LLVMValueRef fields[] = {
- correctly_typed_value,
- LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes)),
- };
- union_value = LLVMConstStruct(fields, 2, false);
- }
- } else {
- make_unnamed_struct = false;
- union_value = LLVMGetUndef(union_type_ref);
- }
- LLVMValueRef fields[2];
- fields[type_entry->data.enumeration.gen_tag_index] = tag_value;
- fields[type_entry->data.enumeration.gen_union_index] = union_value;
-
- if (make_unnamed_struct) {
- return LLVMConstStruct(fields, 2, false);
- } else {
- return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
- }
- }
- }
+ return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_enum_tag);
case TypeTableEntryIdFn:
return fn_llvm_value(g, const_val->data.x_fn.fn_entry);
case TypeTableEntryIdPointer:
@@ -4318,9 +4220,8 @@ static void generate_enum_name_tables(CodeGen *g) {
for (size_t enum_i = 0; enum_i < g->name_table_enums.length; enum_i += 1) {
- TypeTableEntry *enum_tag_type = g->name_table_enums.at(enum_i);
- assert(enum_tag_type->id == TypeTableEntryIdEnumTag);
- TypeTableEntry *enum_type = enum_tag_type->data.enum_tag.enum_type;
+ TypeTableEntry *enum_type = g->name_table_enums.at(enum_i);
+ assert(enum_type->id == TypeTableEntryIdEnum);
size_t field_count = enum_type->data.enumeration.src_field_count;
LLVMValueRef *values = allocate(field_count);
@@ -4351,7 +4252,7 @@ static void generate_enum_name_tables(CodeGen *g) {
LLVMSetGlobalConstant(name_table, true);
LLVMSetUnnamedAddr(name_table, true);
LLVMSetAlignment(name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(name_table_init)));
- enum_tag_type->data.enum_tag.name_table = name_table;
+ enum_type->data.enumeration.name_table = name_table;
}
}
@@ -4555,9 +4456,6 @@ static void do_code_gen(CodeGen *g) {
} else if (instruction->id == IrInstructionIdErrWrapCode) {
IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction;
slot = &err_wrap_code_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdInitEnum) {
- IrInstructionInitEnum *init_enum_instruction = (IrInstructionInitEnum *)instruction;
- slot = &init_enum_instruction->tmp_ptr;
} else {
zig_unreachable();
}
@@ -5054,7 +4952,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdTruncate, "truncate", 2);
create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);
create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
- create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2);
+ create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);
create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 2);
create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2);
@@ -5064,7 +4962,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdBitCast, "bitCast", 2);
create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2);
create_builtin_fn(g, BuiltinFnIdPtrToInt, "ptrToInt", 1);
- create_builtin_fn(g, BuiltinFnIdEnumTagName, "enumTagName", 1); // TODO rename to memberName
+ create_builtin_fn(g, BuiltinFnIdTagName, "tagName", 1);
create_builtin_fn(g, BuiltinFnIdEnumTagType, "EnumTagType", 1);
create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3);
create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2);
@@ -5681,7 +5579,6 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
- case TypeTableEntryIdEnumTag:
zig_panic("TODO implement get_c_type for more types");
case TypeTableEntryIdInvalid:
case TypeTableEntryIdMetaType:
diff --git a/src/ir.cpp b/src/ir.cpp
index e51f52adae..5da59fedb7 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -223,10 +223,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructFieldPtr *
return IrInstructionIdStructFieldPtr;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumFieldPtr *) {
- return IrInstructionIdEnumFieldPtr;
-}
-
static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionFieldPtr *) {
return IrInstructionIdUnionFieldPtr;
}
@@ -319,8 +315,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCtz *) {
return IrInstructionIdCtz;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTag *) {
- return IrInstructionIdEnumTag;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionTag *) {
+ return IrInstructionIdUnionTag;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionImport *) {
@@ -479,10 +475,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestComptime *)
return IrInstructionIdTestComptime;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionInitEnum *) {
- return IrInstructionIdInitEnum;
-}
-
static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCast *) {
return IrInstructionIdPtrCast;
}
@@ -913,27 +905,6 @@ static IrInstruction *ir_build_struct_field_ptr_from(IrBuilder *irb, IrInstructi
return new_instruction;
}
-static IrInstruction *ir_build_enum_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *enum_ptr, TypeEnumField *field)
-{
- IrInstructionEnumFieldPtr *instruction = ir_build_instruction(irb, scope, source_node);
- instruction->enum_ptr = enum_ptr;
- instruction->field = field;
-
- ir_ref_instruction(enum_ptr, irb->current_basic_block);
-
- return &instruction->base;
-}
-
-static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction *old_instruction,
- IrInstruction *enum_ptr, TypeEnumField *type_enum_field)
-{
- IrInstruction *new_instruction = ir_build_enum_field_ptr(irb, old_instruction->scope,
- old_instruction->source_node, enum_ptr, type_enum_field);
- ir_link_new_instruction(new_instruction, old_instruction);
- return new_instruction;
-}
-
static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *union_ptr, TypeUnionField *field)
{
@@ -1528,8 +1499,8 @@ static IrInstruction *ir_build_switch_var(IrBuilder *irb, Scope *scope, AstNode
return &instruction->base;
}
-static IrInstruction *ir_build_enum_tag(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
- IrInstructionEnumTag *instruction = ir_build_instruction(irb, scope, source_node);
+static IrInstruction *ir_build_union_tag(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
+ IrInstructionUnionTag *instruction = ir_build_instruction(irb, scope, source_node);
instruction->value = value;
ir_ref_instruction(value, irb->current_basic_block);
@@ -1537,13 +1508,6 @@ static IrInstruction *ir_build_enum_tag(IrBuilder *irb, Scope *scope, AstNode *s
return &instruction->base;
}
-static IrInstruction *ir_build_enum_tag_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *value) {
- IrInstruction *new_instruction = ir_build_enum_tag(irb, old_instruction->scope,
- old_instruction->source_node, value);
- ir_link_new_instruction(new_instruction, old_instruction);
- return new_instruction;
-}
-
static IrInstruction *ir_build_import(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *name) {
IrInstructionImport *instruction = ir_build_instruction(irb, scope, source_node);
instruction->name = name;
@@ -2033,28 +1997,6 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo
return &instruction->base;
}
-static IrInstruction *ir_build_init_enum(IrBuilder *irb, Scope *scope, AstNode *source_node,
- TypeTableEntry *enum_type, TypeEnumField *field, IrInstruction *init_value)
-{
- IrInstructionInitEnum *instruction = ir_build_instruction(irb, scope, source_node);
- instruction->enum_type = enum_type;
- instruction->field = field;
- instruction->init_value = init_value;
-
- ir_ref_instruction(init_value, irb->current_basic_block);
-
- return &instruction->base;
-}
-
-static IrInstruction *ir_build_init_enum_from(IrBuilder *irb, IrInstruction *old_instruction,
- TypeTableEntry *enum_type, TypeEnumField *field, IrInstruction *init_value)
-{
- IrInstruction *new_instruction = ir_build_init_enum(irb, old_instruction->scope, old_instruction->source_node,
- enum_type, field, init_value);
- ir_link_new_instruction(new_instruction, old_instruction);
- return new_instruction;
-}
-
static IrInstruction *ir_build_ptr_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *dest_type, IrInstruction *ptr)
{
@@ -2481,13 +2423,6 @@ static IrInstruction *ir_instruction_structfieldptr_get_dep(IrInstructionStructF
}
}
-static IrInstruction *ir_instruction_enumfieldptr_get_dep(IrInstructionEnumFieldPtr *instruction, size_t index) {
- switch (index) {
- case 0: return instruction->enum_ptr;
- default: return nullptr;
- }
-}
-
static IrInstruction *ir_instruction_unionfieldptr_get_dep(IrInstructionUnionFieldPtr *instruction, size_t index) {
switch (index) {
case 0: return instruction->union_ptr;
@@ -2657,7 +2592,7 @@ static IrInstruction *ir_instruction_maybewrap_get_dep(IrInstructionMaybeWrap *i
}
}
-static IrInstruction *ir_instruction_enumtag_get_dep(IrInstructionEnumTag *instruction, size_t index) {
+static IrInstruction *ir_instruction_uniontag_get_dep(IrInstructionUnionTag *instruction, size_t index) {
switch (index) {
case 0: return instruction->value;
default: return nullptr;
@@ -2943,13 +2878,6 @@ static IrInstruction *ir_instruction_testcomptime_get_dep(IrInstructionTestCompt
}
}
-static IrInstruction *ir_instruction_initenum_get_dep(IrInstructionInitEnum *instruction, size_t index) {
- switch (index) {
- case 0: return instruction->init_value;
- default: return nullptr;
- }
-}
-
static IrInstruction *ir_instruction_ptrcast_get_dep(IrInstructionPtrCast *instruction,
size_t index)
{
@@ -3184,8 +3112,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_fieldptr_get_dep((IrInstructionFieldPtr *) instruction, index);
case IrInstructionIdStructFieldPtr:
return ir_instruction_structfieldptr_get_dep((IrInstructionStructFieldPtr *) instruction, index);
- case IrInstructionIdEnumFieldPtr:
- return ir_instruction_enumfieldptr_get_dep((IrInstructionEnumFieldPtr *) instruction, index);
case IrInstructionIdUnionFieldPtr:
return ir_instruction_unionfieldptr_get_dep((IrInstructionUnionFieldPtr *) instruction, index);
case IrInstructionIdElemPtr:
@@ -3234,8 +3160,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_unwrapmaybe_get_dep((IrInstructionUnwrapMaybe *) instruction, index);
case IrInstructionIdMaybeWrap:
return ir_instruction_maybewrap_get_dep((IrInstructionMaybeWrap *) instruction, index);
- case IrInstructionIdEnumTag:
- return ir_instruction_enumtag_get_dep((IrInstructionEnumTag *) instruction, index);
+ case IrInstructionIdUnionTag:
+ return ir_instruction_uniontag_get_dep((IrInstructionUnionTag *) instruction, index);
case IrInstructionIdClz:
return ir_instruction_clz_get_dep((IrInstructionClz *) instruction, index);
case IrInstructionIdCtz:
@@ -3312,8 +3238,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_fnproto_get_dep((IrInstructionFnProto *) instruction, index);
case IrInstructionIdTestComptime:
return ir_instruction_testcomptime_get_dep((IrInstructionTestComptime *) instruction, index);
- case IrInstructionIdInitEnum:
- return ir_instruction_initenum_get_dep((IrInstructionInitEnum *) instruction, index);
case IrInstructionIdPtrCast:
return ir_instruction_ptrcast_get_dep((IrInstructionPtrCast *) instruction, index);
case IrInstructionIdBitCast:
@@ -4695,14 +4619,14 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_build_ptr_to_int(irb, scope, node, arg0_value);
}
- case BuiltinFnIdEnumTagName:
+ case BuiltinFnIdTagName:
{
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 *actual_tag = ir_build_enum_tag(irb, scope, node, arg0_value);
+ IrInstruction *actual_tag = ir_build_union_tag(irb, scope, node, arg0_value);
return ir_build_enum_tag_name(irb, scope, node, actual_tag);
}
case BuiltinFnIdEnumTagType:
@@ -8381,13 +8305,28 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
{
assert(wanted_type->id == TypeTableEntryIdInt);
+ TypeTableEntry *actual_type = target->value.type;
+ ensure_complete_type(ira->codegen, actual_type);
+ if (type_is_invalid(actual_type))
+ return ira->codegen->invalid_instruction;
+
+ if (wanted_type != actual_type->data.enumeration.tag_int_type) {
+ ir_add_error(ira, source_instr,
+ buf_sprintf("enum to integer cast to '%s' instead of its tag type, '%s'",
+ buf_ptr(&wanted_type->name),
+ buf_ptr(&actual_type->data.enumeration.tag_int_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ assert(actual_type->id == TypeTableEntryIdEnum);
+
if (instr_is_comptime(target)) {
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
if (!val)
return ira->codegen->invalid_instruction;
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
source_instr->source_node, wanted_type);
- init_const_bigint(&result->value, wanted_type, &val->data.x_enum.tag);
+ init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag);
return result;
}
@@ -8397,6 +8336,31 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
return result;
}
+static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *target, TypeTableEntry *wanted_type)
+{
+ assert(target->value.type->id == TypeTableEntryIdUnion);
+ assert(wanted_type->id == TypeTableEntryIdEnum);
+ assert(wanted_type == target->value.type->data.unionation.tag_type);
+
+ if (instr_is_comptime(target)) {
+ ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
+ if (!val)
+ return ira->codegen->invalid_instruction;
+ IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, wanted_type);
+ result->value.special = ConstValSpecialStatic;
+ result->value.type = wanted_type;
+ bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_union.tag);
+ return result;
+ }
+
+ IrInstruction *result = ir_build_union_tag(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, target);
+ result->value.type = wanted_type;
+ return result;
+}
+
static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *target, TypeTableEntry *wanted_type)
{
@@ -8452,6 +8416,22 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
{
assert(wanted_type->id == TypeTableEntryIdEnum);
+ TypeTableEntry *actual_type = target->value.type;
+
+ ensure_complete_type(ira->codegen, wanted_type);
+ if (type_is_invalid(wanted_type))
+ return ira->codegen->invalid_instruction;
+
+ if (actual_type != wanted_type->data.enumeration.tag_int_type) {
+ ir_add_error(ira, source_instr,
+ buf_sprintf("integer to enum cast from '%s' instead of its tag type, '%s'",
+ buf_ptr(&actual_type->name),
+ buf_ptr(&wanted_type->data.enumeration.tag_int_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ assert(actual_type->id == TypeTableEntryIdInt);
+
if (instr_is_comptime(target)) {
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
if (!val)
@@ -8469,7 +8449,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
source_instr->source_node, wanted_type);
- bigint_init_bigint(&result->value.data.x_enum.tag, &val->data.x_bigint);
+ bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_bigint);
return result;
}
@@ -8907,39 +8887,24 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
}
// explicit cast from integer to enum type with no payload
- if (actual_type->id == TypeTableEntryIdInt &&
- wanted_type->id == TypeTableEntryIdEnum &&
- wanted_type->data.enumeration.gen_field_count == 0)
- {
- ensure_complete_type(ira->codegen, wanted_type);
- if (type_is_invalid(wanted_type))
- return ira->codegen->invalid_instruction;
- if (actual_type == wanted_type->data.enumeration.tag_type->data.enum_tag.int_type) {
- return ir_analyze_int_to_enum(ira, source_instr, value, wanted_type);
- }
- ir_add_error(ira, source_instr,
- buf_sprintf("integer to enum cast from '%s' instead of its tag type, '%s'",
- buf_ptr(&actual_type->name),
- buf_ptr(&wanted_type->data.enumeration.tag_type->data.enum_tag.int_type->name)));
- return ira->codegen->invalid_instruction;
+ if (actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdEnum) {
+ return ir_analyze_int_to_enum(ira, source_instr, value, wanted_type);
}
// explicit cast from enum type with no payload to integer
- if (wanted_type->id == TypeTableEntryIdInt &&
- actual_type->id == TypeTableEntryIdEnum &&
- actual_type->data.enumeration.gen_field_count == 0)
- {
- ensure_complete_type(ira->codegen, actual_type);
+ if (wanted_type->id == TypeTableEntryIdInt && actual_type->id == TypeTableEntryIdEnum) {
+ return ir_analyze_enum_to_int(ira, source_instr, value, wanted_type);
+ }
+
+ // explicit cast from union to the enum type of the union
+ if (actual_type->id == TypeTableEntryIdUnion && wanted_type->id == TypeTableEntryIdEnum) {
+ type_ensure_zero_bits_known(ira->codegen, actual_type);
if (type_is_invalid(actual_type))
return ira->codegen->invalid_instruction;
- if (wanted_type == actual_type->data.enumeration.tag_type->data.enum_tag.int_type) {
- return ir_analyze_enum_to_int(ira, source_instr, value, wanted_type);
+
+ if (actual_type->data.unionation.tag_type == wanted_type) {
+ return ir_analyze_union_to_tag(ira, source_instr, value, wanted_type);
}
- ir_add_error(ira, source_instr,
- buf_sprintf("enum to integer cast to '%s' instead of its tag type, '%s'",
- buf_ptr(&wanted_type->name),
- buf_ptr(&actual_type->data.enumeration.tag_type->data.enum_tag.int_type->name)));
- return ira->codegen->invalid_instruction;
}
// explicit cast from undefined to anything
@@ -9148,7 +9113,7 @@ static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, Atomic
if (!const_val)
return false;
- *out = (AtomicOrder)bigint_as_unsigned(&const_val->data.x_enum.tag);
+ *out = (AtomicOrder)bigint_as_unsigned(&const_val->data.x_enum_tag);
return true;
}
@@ -9168,7 +9133,7 @@ static bool ir_resolve_global_linkage(IrAnalyze *ira, IrInstruction *value, Glob
if (!const_val)
return false;
- *out = (GlobalLinkageId)bigint_as_unsigned(&const_val->data.x_enum.tag);
+ *out = (GlobalLinkageId)bigint_as_unsigned(&const_val->data.x_enum_tag);
return true;
}
@@ -9188,7 +9153,7 @@ static bool ir_resolve_float_mode(IrAnalyze *ira, IrInstruction *value, FloatMod
if (!const_val)
return false;
- *out = (FloatMode)bigint_as_unsigned(&const_val->data.x_enum.tag);
+ *out = (FloatMode)bigint_as_unsigned(&const_val->data.x_enum_tag);
return true;
}
@@ -9400,7 +9365,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
break;
case TypeTableEntryIdEnum:
- if (!is_equality_cmp || resolved_type->data.enumeration.gen_field_count != 0) {
+ if (!is_equality_cmp) {
ir_add_error_node(ira, source_node,
buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
return ira->codegen->builtin_types.entry_invalid;
@@ -9419,9 +9384,6 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
return ira->codegen->builtin_types.entry_invalid;
- case TypeTableEntryIdEnumTag:
- zig_panic("TODO implement comparison for enum tag type");
-
case TypeTableEntryIdVar:
zig_unreachable();
}
@@ -10170,7 +10132,6 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) {
case TypeTableEntryIdVoid:
case TypeTableEntryIdPureError:
case TypeTableEntryIdFn:
- case TypeTableEntryIdEnumTag:
return VarClassRequiredAny;
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
@@ -10913,7 +10874,6 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
case TypeTableEntryIdBoundFn:
- case TypeTableEntryIdEnumTag:
{
ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);
TypeTableEntry *result_type = get_error_type(ira->codegen, meta_type);
@@ -11001,7 +10961,6 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
- case TypeTableEntryIdEnumTag:
case TypeTableEntryIdArgTuple:
{
ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);
@@ -11662,15 +11621,8 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
field_ptr_instruction, container_ptr, container_type);
}
} else if (bare_type->id == TypeTableEntryIdEnum) {
- TypeEnumField *field = find_enum_type_field(bare_type, field_name);
- if (field) {
- ir_build_enum_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
- return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
- get_abi_alignment(ira->codegen, field->type_entry), 0, 0);
- } else {
- return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
- field_ptr_instruction, container_ptr, container_type);
- }
+ return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
+ field_ptr_instruction, container_ptr, container_type);
} else if (bare_type->id == TypeTableEntryIdUnion) {
TypeUnionField *field = find_union_type_field(bare_type, field_name);
if (field) {
@@ -11841,20 +11793,27 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
TypeEnumField *field = find_enum_type_field(child_type, field_name);
if (field) {
- if (field->type_entry->id == TypeTableEntryIdVoid) {
- bool ptr_is_const = true;
- bool ptr_is_volatile = false;
- return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
- create_const_enum_tag(child_type, &field->value), child_type,
- ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
- } else {
- bool ptr_is_const = true;
- bool ptr_is_volatile = false;
- return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
- create_const_bigint(child_type->data.enumeration.tag_type, &field->value),
- child_type->data.enumeration.tag_type,
+ bool ptr_is_const = true;
+ bool ptr_is_volatile = false;
+ return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+ create_const_enum(child_type, &field->value), child_type,
+ ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
+ }
+ } else if (child_type->id == TypeTableEntryIdUnion &&
+ (child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr ||
+ child_type->data.unionation.decl_node->data.container_decl.auto_enum))
+ {
+ ensure_complete_type(ira->codegen, child_type);
+ if (type_is_invalid(child_type))
+ return ira->codegen->builtin_types.entry_invalid;
+ TypeUnionField *field = find_union_type_field(child_type, field_name);
+ if (field) {
+ TypeTableEntry *enum_type = child_type->data.unionation.tag_type;
+ bool ptr_is_const = true;
+ bool ptr_is_volatile = false;
+ return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
+ create_const_enum(enum_type, &field->enum_field->value), enum_type,
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
- }
}
}
ScopeDecls *container_scope = get_container_scope(child_type);
@@ -12163,7 +12122,6 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
- case TypeTableEntryIdEnumTag:
case TypeTableEntryIdArgTuple:
case TypeTableEntryIdOpaque:
{
@@ -12511,7 +12469,6 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
case TypeTableEntryIdFn:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBoundFn:
- case TypeTableEntryIdEnumTag:
{
type_ensure_zero_bits_known(ira->codegen, child_type);
TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
@@ -12620,7 +12577,6 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
case TypeTableEntryIdFn:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBoundFn:
- case TypeTableEntryIdEnumTag:
{
TypeTableEntry *result_type = get_array_type(ira->codegen, child_type, size);
ConstExprValue *out_val = ir_build_const_from(ira, &array_type_instruction->base);
@@ -12671,7 +12627,6 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
case TypeTableEntryIdPureError:
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
- case TypeTableEntryIdEnumTag:
case TypeTableEntryIdFn:
{
uint64_t size_in_bytes = type_size(ira->codegen, type_entry);
@@ -12824,17 +12779,22 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC
}
}
-static IrInstruction *ir_analyze_enum_tag(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value) {
+static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value) {
if (type_is_invalid(value->value.type))
return ira->codegen->invalid_instruction;
- if (value->value.type->id != TypeTableEntryIdEnum) {
+ if (value->value.type->id == TypeTableEntryIdEnum) {
+ return value;
+ }
+
+ if (value->value.type->id != TypeTableEntryIdUnion) {
ir_add_error(ira, source_instr,
- buf_sprintf("expected enum type, found '%s'", buf_ptr(&value->value.type->name)));
+ buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value.type->name)));
return ira->codegen->invalid_instruction;
}
- TypeTableEntry *tag_type = value->value.type->data.enumeration.tag_type;
+ TypeTableEntry *tag_type = value->value.type->data.unionation.tag_type;
+ assert(tag_type->id == TypeTableEntryIdEnum);
if (instr_is_comptime(value)) {
ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
@@ -12845,11 +12805,11 @@ static IrInstruction *ir_analyze_enum_tag(IrAnalyze *ira, IrInstruction *source_
source_instr->scope, source_instr->source_node);
const_instruction->base.value.type = tag_type;
const_instruction->base.value.special = ConstValSpecialStatic;
- bigint_init_bigint(&const_instruction->base.value.data.x_bigint, &val->data.x_enum.tag);
+ bigint_init_bigint(&const_instruction->base.value.data.x_enum_tag, &val->data.x_union.tag);
return &const_instruction->base;
}
- IrInstruction *result = ir_build_enum_tag(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
+ IrInstruction *result = ir_build_union_tag(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
result->value.type = tag_type;
return result;
}
@@ -12880,7 +12840,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
return ir_unreach_error(ira);
if (case_value->value.type->id == TypeTableEntryIdEnum) {
- case_value = ir_analyze_enum_tag(ira, &switch_br_instruction->base, case_value);
+ 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);
}
@@ -12927,7 +12887,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
continue;
if (new_value->value.type->id == TypeTableEntryIdEnum) {
- new_value = ir_analyze_enum_tag(ira, &switch_br_instruction->base, new_value);
+ new_value = ir_analyze_union_tag(ira, &switch_br_instruction->base, new_value);
if (type_is_invalid(new_value->value.type))
continue;
}
@@ -13009,34 +12969,54 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
ir_build_load_ptr_from(&ira->new_irb, &switch_target_instruction->base, target_value_ptr);
return target_type;
- case TypeTableEntryIdEnum:
- {
- TypeTableEntry *tag_type = target_type->data.enumeration.tag_type;
- assert(tag_type != nullptr);
- if (pointee_val) {
- ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);
- bigint_init_bigint(&out_val->data.x_bigint, &pointee_val->data.x_enum.tag);
- return tag_type;
- }
-
- IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
- switch_target_instruction->base.source_node, target_value_ptr);
- enum_value->value.type = target_type;
- ir_build_enum_tag_from(&ira->new_irb, &switch_target_instruction->base, enum_value);
+ case TypeTableEntryIdUnion: {
+ if (target_type->data.unionation.gen_tag_index == SIZE_MAX) {
+ ErrorMsg *msg = ir_add_error(ira, target_value_ptr,
+ buf_sprintf("switch on union which has no attached enum"));
+ add_error_note(ira->codegen, msg, target_type->data.unionation.decl_node,
+ buf_sprintf("union declared here"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ TypeTableEntry *tag_type = target_type->data.unionation.tag_type;
+ assert(tag_type != nullptr);
+ if (pointee_val) {
+ ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);
+ bigint_init_bigint(&out_val->data.x_enum_tag, &pointee_val->data.x_union.tag);
return tag_type;
}
+
+ IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
+ switch_target_instruction->base.source_node, target_value_ptr);
+ union_value->value.type = target_type;
+
+ IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope,
+ switch_target_instruction->base.source_node, union_value);
+ union_tag_inst->value.type = tag_type;
+ ir_link_new_instruction(union_tag_inst, &switch_target_instruction->base);
+ return tag_type;
+ }
+ case TypeTableEntryIdEnum: {
+ if (pointee_val) {
+ ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);
+ bigint_init_bigint(&out_val->data.x_enum_tag, &pointee_val->data.x_enum_tag);
+ return target_type;
+ }
+
+ IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
+ switch_target_instruction->base.source_node, target_value_ptr);
+ enum_value->value.type = target_type;
+ ir_link_new_instruction(enum_value, &switch_target_instruction->base);
+ return target_type;
+ }
case TypeTableEntryIdErrorUnion:
- // see https://github.com/andrewrk/zig/issues/83
+ // see https://github.com/andrewrk/zig/issues/632
zig_panic("TODO switch on error union");
- case TypeTableEntryIdEnumTag:
- zig_panic("TODO switch on enum tag type");
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdArray:
case TypeTableEntryIdStruct:
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdNullLit:
case TypeTableEntryIdMaybe:
- case TypeTableEntryIdUnion:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
case TypeTableEntryIdArgTuple:
@@ -13059,19 +13039,13 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr
assert(target_value_ptr->value.type->id == TypeTableEntryIdPointer);
TypeTableEntry *target_type = target_value_ptr->value.type->data.pointer.child_type;
- if (target_type->id == TypeTableEntryIdEnum) {
+ if (target_type->id == TypeTableEntryIdUnion) {
ConstExprValue *prong_val = ir_resolve_const(ira, prong_value, UndefBad);
if (!prong_val)
return ira->codegen->builtin_types.entry_invalid;
- TypeEnumField *field;
- if (prong_value->value.type->id == TypeTableEntryIdEnumTag) {
- field = find_enum_field_by_tag(target_type, &prong_val->data.x_bigint);
- } else if (prong_value->value.type->id == TypeTableEntryIdEnum) {
- field = find_enum_field_by_tag(target_type, &prong_val->data.x_enum.tag);
- } else {
- zig_unreachable();
- }
+ assert(prong_value->value.type->id == TypeTableEntryIdEnum);
+ TypeUnionField *field = find_union_field_by_tag(target_type, &prong_val->data.x_enum_tag);
if (instr_is_comptime(target_value_ptr)) {
ConstExprValue *target_val_ptr = ir_resolve_const(ira, target_value_ptr, UndefBad);
@@ -13082,11 +13056,11 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
out_val->data.x_ptr.special = ConstPtrSpecialRef;
out_val->data.x_ptr.mut = target_val_ptr->data.x_ptr.mut;
- out_val->data.x_ptr.data.ref.pointee = pointee_val->data.x_enum.payload;
+ out_val->data.x_ptr.data.ref.pointee = pointee_val->data.x_union.payload;
return get_pointer_to_type(ira->codegen, field->type_entry, target_val_ptr->type->data.pointer.is_const);
}
- ir_build_enum_field_ptr_from(&ira->new_irb, &instruction->base, target_value_ptr, field);
+ ir_build_union_field_ptr_from(&ira->new_irb, &instruction->base, target_value_ptr, field);
return get_pointer_to_type(ira->codegen, field->type_entry,
target_value_ptr->value.type->data.pointer.is_const);
} else {
@@ -13096,10 +13070,10 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr
}
}
-static TypeTableEntry *ir_analyze_instruction_enum_tag(IrAnalyze *ira, IrInstructionEnumTag *enum_tag_instruction) {
- IrInstruction *value = enum_tag_instruction->value->other;
- IrInstruction *new_instruction = ir_analyze_enum_tag(ira, &enum_tag_instruction->base, value);
- ir_link_new_instruction(new_instruction, &enum_tag_instruction->base);
+static TypeTableEntry *ir_analyze_instruction_union_tag(IrAnalyze *ira, IrInstructionUnionTag *instruction) {
+ IrInstruction *value = instruction->value->other;
+ IrInstruction *new_instruction = ir_analyze_union_tag(ira, &instruction->base, value);
+ ir_link_new_instruction(new_instruction, &instruction->base);
return new_instruction->value.type;
}
@@ -13255,7 +13229,7 @@ static TypeTableEntry *ir_analyze_container_init_fields_union(IrAnalyze *ira, Ir
ConstExprValue *out_val = ir_build_const_from(ira, instruction);
out_val->data.x_union.payload = field_val;
- out_val->data.x_union.tag = type_field->value;
+ out_val->data.x_union.tag = type_field->enum_field->value;
ConstParent *parent = get_const_val_parent(ira->codegen, field_val);
if (parent != nullptr) {
@@ -13502,46 +13476,9 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
buf_ptr(&container_type->name)));
return ira->codegen->builtin_types.entry_invalid;
}
- } else if (container_type_value->value.type->id == TypeTableEntryIdEnumTag) {
- if (elem_count != 1) {
- ir_add_error(ira, &instruction->base, buf_sprintf("enum initialization requires exactly one element"));
- return ira->codegen->builtin_types.entry_invalid;
- }
- ConstExprValue *tag_value = ir_resolve_const(ira, container_type_value, UndefBad);
- if (!tag_value)
- return ira->codegen->builtin_types.entry_invalid;
-
- TypeTableEntry *enum_type = container_type_value->value.type->data.enum_tag.enum_type;
-
- TypeEnumField *field = find_enum_field_by_tag(enum_type, &tag_value->data.x_bigint);
- assert(field != nullptr);
- TypeTableEntry *this_field_type = field->type_entry;
-
- IrInstruction *init_value = instruction->items[0]->other;
- if (type_is_invalid(init_value->value.type))
- return ira->codegen->builtin_types.entry_invalid;
-
- IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, this_field_type);
- if (casted_init_value == ira->codegen->invalid_instruction)
- return ira->codegen->builtin_types.entry_invalid;
-
- if (instr_is_comptime(casted_init_value)) {
- ConstExprValue *init_val = ir_resolve_const(ira, casted_init_value, UndefOk);
- if (!init_val)
- return ira->codegen->builtin_types.entry_invalid;
- ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
- bigint_init_bigint(&out_val->data.x_enum.tag, &tag_value->data.x_bigint);
- out_val->data.x_enum.payload = init_val;
- return enum_type;
- }
-
- IrInstruction *new_instruction = ir_build_init_enum_from(&ira->new_irb, &instruction->base,
- enum_type, field, casted_init_value);
- ir_add_alloca(ira, new_instruction, enum_type);
- return enum_type;
} else {
ir_add_error(ira, container_type_value,
- buf_sprintf("expected type, found '%s'", buf_ptr(&container_type_value->value.type->name)));
+ buf_sprintf("expected type, found '%s' value", buf_ptr(&container_type_value->value.type->name)));
return ira->codegen->builtin_types.entry_invalid;
}
}
@@ -13584,8 +13521,8 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
eval_min_max_value(ira->codegen, target_type, out_val, is_max);
return target_type;
}
- case TypeTableEntryIdEnumTag:
- zig_panic("TODO min/max value for enum tag type");
+ case TypeTableEntryIdEnum:
+ zig_panic("TODO min/max value for enum type");
case TypeTableEntryIdVar:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdUnreachable:
@@ -13599,7 +13536,6 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdPureError:
- case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
case TypeTableEntryIdNamespace:
@@ -13707,20 +13643,18 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn
if (type_is_invalid(target->value.type))
return ira->codegen->builtin_types.entry_invalid;
- assert(target->value.type->id == TypeTableEntryIdEnumTag);
+ assert(target->value.type->id == TypeTableEntryIdEnum);
if (instr_is_comptime(target)) {
- TypeTableEntry *enum_type = target->value.type->data.enum_tag.enum_type;
- uint64_t tag_value = bigint_as_unsigned(&target->value.data.x_bigint);
- TypeEnumField *field = &enum_type->data.enumeration.fields[tag_value];
+ TypeEnumField *field = find_enum_field_by_tag(target->value.type, &target->value.data.x_bigint);
ConstExprValue *array_val = create_const_str_lit(ira->codegen, field->name);
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
init_const_slice(ira->codegen, out_val, array_val, 0, buf_len(field->name), true);
return out_val->type;
}
- if (!target->value.type->data.enum_tag.generate_name_table) {
- target->value.type->data.enum_tag.generate_name_table = true;
+ if (!target->value.type->data.enumeration.generate_name_table) {
+ target->value.type->data.enumeration.generate_name_table = true;
ira->codegen->name_table_enums.append(target->value.type);
}
@@ -13869,7 +13803,7 @@ static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira,
TypeTableEntry *result_type = var_value->data.x_type;
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
- bigint_init_unsigned(&out_val->data.x_enum.tag, type_id_index(type_entry->id));
+ bigint_init_unsigned(&out_val->data.x_enum_tag, type_id_index(type_entry->id));
return result_type;
}
@@ -14698,14 +14632,14 @@ static TypeTableEntry *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInst
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
out_val->data.x_type = field->type_entry;
return ira->codegen->builtin_types.entry_type;
- } else if (container_type->id == TypeTableEntryIdEnum) {
- if (member_index >= container_type->data.enumeration.src_field_count) {
+ } else if (container_type->id == TypeTableEntryIdUnion) {
+ if (member_index >= container_type->data.unionation.src_field_count) {
ir_add_error(ira, index_value,
buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
- member_index, buf_ptr(&container_type->name), container_type->data.enumeration.src_field_count));
+ member_index, buf_ptr(&container_type->name), container_type->data.unionation.src_field_count));
return ira->codegen->builtin_types.entry_invalid;
}
- TypeEnumField *field = &container_type->data.enumeration.fields[member_index];
+ TypeUnionField *field = &container_type->data.unionation.fields[member_index];
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
out_val->data.x_type = field->type_entry;
@@ -14749,6 +14683,18 @@ static TypeTableEntry *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInst
}
TypeEnumField *field = &container_type->data.enumeration.fields[member_index];
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ init_const_str_lit(ira->codegen, out_val, field->name);
+ return out_val->type;
+ } else if (container_type->id == TypeTableEntryIdUnion) {
+ if (member_index >= container_type->data.unionation.src_field_count) {
+ ir_add_error(ira, index_value,
+ buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
+ member_index, buf_ptr(&container_type->name), container_type->data.unionation.src_field_count));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ TypeUnionField *field = &container_type->data.unionation.fields[member_index];
+
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
init_const_str_lit(ira->codegen, out_val, field->name);
return out_val->type;
@@ -14819,7 +14765,6 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdPureError:
case TypeTableEntryIdEnum:
- case TypeTableEntryIdEnumTag:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
{
@@ -15125,10 +15070,9 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
if (type_is_invalid(switch_type))
return ira->codegen->builtin_types.entry_invalid;
- if (switch_type->id == TypeTableEntryIdEnumTag) {
- TypeTableEntry *enum_type = switch_type->data.enum_tag.enum_type;
+ if (switch_type->id == TypeTableEntryIdEnum) {
HashMap field_prev_uses = {};
- field_prev_uses.init(enum_type->data.enumeration.src_field_count);
+ field_prev_uses.init(switch_type->data.enumeration.src_field_count);
for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) {
IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i];
@@ -15141,22 +15085,13 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
if (type_is_invalid(end_value->value.type))
return ira->codegen->builtin_types.entry_invalid;
+ assert(start_value->value.type->id == TypeTableEntryIdEnum);
BigInt start_index;
+ bigint_init_bigint(&start_index, &start_value->value.data.x_enum_tag);
+
+ assert(end_value->value.type->id == TypeTableEntryIdEnum);
BigInt end_index;
- if (start_value->value.type->id == TypeTableEntryIdEnumTag) {
- bigint_init_bigint(&start_index, &start_value->value.data.x_bigint);
- } else if (start_value->value.type->id == TypeTableEntryIdEnum) {
- bigint_init_bigint(&start_index, &start_value->value.data.x_enum.tag);
- } else {
- zig_unreachable();
- }
- if (end_value->value.type->id == TypeTableEntryIdEnumTag) {
- bigint_init_bigint(&end_index, &end_value->value.data.x_bigint);
- } else if (end_value->value.type->id == TypeTableEntryIdEnum) {
- bigint_init_bigint(&end_index, &end_value->value.data.x_enum.tag);
- } else {
- zig_unreachable();
- }
+ bigint_init_bigint(&end_index, &end_value->value.data.x_enum_tag);
BigInt field_index;
bigint_init_bigint(&field_index, &start_index);
@@ -15168,10 +15103,10 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
auto entry = field_prev_uses.put_unique(field_index, start_value->source_node);
if (entry) {
AstNode *prev_node = entry->value;
- TypeEnumField *enum_field = find_enum_field_by_tag(enum_type, &field_index);
+ TypeEnumField *enum_field = find_enum_field_by_tag(switch_type, &field_index);
assert(enum_field != nullptr);
ErrorMsg *msg = ir_add_error(ira, start_value,
- buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&enum_type->name),
+ buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&switch_type->name),
buf_ptr(enum_field->name)));
add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value is here"));
}
@@ -15179,13 +15114,13 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
}
}
if (!instruction->have_else_prong) {
- for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
- TypeEnumField *enum_field = &enum_type->data.enumeration.fields[i];
+ for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) {
+ TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i];
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(&enum_type->name),
+ buf_sprintf("enumeration value '%s.%s' not handled in switch", buf_ptr(&switch_type->name),
buf_ptr(enum_field->name)));
}
}
@@ -15481,8 +15416,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
zig_panic("TODO buf_write_value_bytes pure error type");
case TypeTableEntryIdEnum:
zig_panic("TODO buf_write_value_bytes enum type");
- case TypeTableEntryIdEnumTag:
- zig_panic("TODO buf_write_value_bytes enum tag type");
case TypeTableEntryIdFn:
zig_panic("TODO buf_write_value_bytes fn type");
case TypeTableEntryIdUnion:
@@ -15541,8 +15474,6 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
zig_panic("TODO buf_read_value_bytes pure error type");
case TypeTableEntryIdEnum:
zig_panic("TODO buf_read_value_bytes enum type");
- case TypeTableEntryIdEnumTag:
- zig_panic("TODO buf_read_value_bytes enum tag type");
case TypeTableEntryIdFn:
zig_panic("TODO buf_read_value_bytes fn type");
case TypeTableEntryIdUnion:
@@ -15920,11 +15851,8 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_type(IrAnalyze *ira, IrIn
if (type_is_invalid(enum_type))
return ira->codegen->builtin_types.entry_invalid;
- TypeTableEntry *non_int_tag_type = enum_type->data.enumeration.tag_type;
- assert(non_int_tag_type->id == TypeTableEntryIdEnumTag);
-
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
- out_val->data.x_type = non_int_tag_type->data.enum_tag.int_type;
+ out_val->data.x_type = enum_type->data.enumeration.tag_int_type;
return ira->codegen->builtin_types.entry_type;
}
@@ -15938,9 +15866,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
case IrInstructionIdStructInit:
case IrInstructionIdUnionInit:
case IrInstructionIdStructFieldPtr:
- case IrInstructionIdEnumFieldPtr:
case IrInstructionIdUnionFieldPtr:
- case IrInstructionIdInitEnum:
case IrInstructionIdMaybeWrap:
case IrInstructionIdErrWrapCode:
case IrInstructionIdErrWrapPayload:
@@ -16012,8 +15938,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_switch_target(ira, (IrInstructionSwitchTarget *)instruction);
case IrInstructionIdSwitchVar:
return ir_analyze_instruction_switch_var(ira, (IrInstructionSwitchVar *)instruction);
- case IrInstructionIdEnumTag:
- return ir_analyze_instruction_enum_tag(ira, (IrInstructionEnumTag *)instruction);
+ case IrInstructionIdUnionTag:
+ return ir_analyze_instruction_union_tag(ira, (IrInstructionUnionTag *)instruction);
case IrInstructionIdImport:
return ir_analyze_instruction_import(ira, (IrInstructionImport *)instruction);
case IrInstructionIdArrayLen:
@@ -16260,7 +16186,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdPtrTypeChild:
case IrInstructionIdArrayLen:
case IrInstructionIdStructFieldPtr:
- case IrInstructionIdEnumFieldPtr:
case IrInstructionIdUnionFieldPtr:
case IrInstructionIdArrayType:
case IrInstructionIdSliceType:
@@ -16271,7 +16196,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdCtz:
case IrInstructionIdSwitchVar:
case IrInstructionIdSwitchTarget:
- case IrInstructionIdEnumTag:
+ case IrInstructionIdUnionTag:
case IrInstructionIdRef:
case IrInstructionIdMinValue:
case IrInstructionIdMaxValue:
@@ -16293,7 +16218,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdErrWrapPayload:
case IrInstructionIdFnProto:
case IrInstructionIdTestComptime:
- case IrInstructionIdInitEnum:
case IrInstructionIdPtrCast:
case IrInstructionIdBitCast:
case IrInstructionIdWidenOrShorten:
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 0e06d1b563..99617056de 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -291,7 +291,7 @@ static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruct
}
static void ir_print_union_init(IrPrint *irp, IrInstructionUnionInit *instruction) {
- Buf *field_name = instruction->field->name;
+ Buf *field_name = instruction->field->enum_field->name;
fprintf(irp->f, "%s {", buf_ptr(&instruction->union_type->name));
fprintf(irp->f, ".%s = ", buf_ptr(field_name));
@@ -361,17 +361,10 @@ static void ir_print_struct_field_ptr(IrPrint *irp, IrInstructionStructFieldPtr
fprintf(irp->f, ")");
}
-static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *instruction) {
- fprintf(irp->f, "@EnumFieldPtr(&");
- ir_print_other_instruction(irp, instruction->enum_ptr);
- fprintf(irp->f, ".%s", buf_ptr(instruction->field->name));
- fprintf(irp->f, ")");
-}
-
static void ir_print_union_field_ptr(IrPrint *irp, IrInstructionUnionFieldPtr *instruction) {
fprintf(irp->f, "@UnionFieldPtr(&");
ir_print_other_instruction(irp, instruction->union_ptr);
- fprintf(irp->f, ".%s", buf_ptr(instruction->field->name));
+ fprintf(irp->f, ".%s", buf_ptr(instruction->field->enum_field->name));
fprintf(irp->f, ")");
}
@@ -509,8 +502,8 @@ static void ir_print_switch_target(IrPrint *irp, IrInstructionSwitchTarget *inst
ir_print_other_instruction(irp, instruction->target_value_ptr);
}
-static void ir_print_enum_tag(IrPrint *irp, IrInstructionEnumTag *instruction) {
- fprintf(irp->f, "enumtag ");
+static void ir_print_union_tag(IrPrint *irp, IrInstructionUnionTag *instruction) {
+ fprintf(irp->f, "uniontag ");
ir_print_other_instruction(irp, instruction->value);
}
@@ -799,12 +792,6 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst
fprintf(irp->f, ")");
}
-static void ir_print_init_enum(IrPrint *irp, IrInstructionInitEnum *instruction) {
- fprintf(irp->f, "%s.%s {", buf_ptr(&instruction->enum_type->name), buf_ptr(instruction->field->name));
- ir_print_other_instruction(irp, instruction->init_value);
- fprintf(irp->f, "}");
-}
-
static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) {
fprintf(irp->f, "@ptrCast(");
if (instruction->dest_type) {
@@ -1078,9 +1065,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdStructFieldPtr:
ir_print_struct_field_ptr(irp, (IrInstructionStructFieldPtr *)instruction);
break;
- case IrInstructionIdEnumFieldPtr:
- ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction);
- break;
case IrInstructionIdUnionFieldPtr:
ir_print_union_field_ptr(irp, (IrInstructionUnionFieldPtr *)instruction);
break;
@@ -1123,8 +1107,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdSwitchTarget:
ir_print_switch_target(irp, (IrInstructionSwitchTarget *)instruction);
break;
- case IrInstructionIdEnumTag:
- ir_print_enum_tag(irp, (IrInstructionEnumTag *)instruction);
+ case IrInstructionIdUnionTag:
+ ir_print_union_tag(irp, (IrInstructionUnionTag *)instruction);
break;
case IrInstructionIdImport:
ir_print_import(irp, (IrInstructionImport *)instruction);
@@ -1237,9 +1221,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdTestComptime:
ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction);
break;
- case IrInstructionIdInitEnum:
- ir_print_init_enum(irp, (IrInstructionInitEnum *)instruction);
- break;
case IrInstructionIdPtrCast:
ir_print_ptr_cast(irp, (IrInstructionPtrCast *)instruction);
break;
diff --git a/src/parser.cpp b/src/parser.cpp
index c36434b521..26ca7da31a 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -2377,7 +2377,9 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod vi
}
/*
-ContainerDecl = option("extern" | "packed") ("struct" | "union" | ("enum" option(GroupedExpression))) "{" many(ContainerMember) "}"
+ContainerDecl = option("extern" | "packed")
+ ("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression)))
+ "{" many(ContainerMember) "}"
ContainerMember = (ContainerField | FnDef | GlobalVarDecl)
ContainerField = Symbol option(":" PrefixOpExpression option("=" PrefixOpExpression ","
*/
@@ -2414,7 +2416,28 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
AstNode *node = ast_create_node(pc, NodeTypeContainerDecl, first_token);
node->data.container_decl.layout = layout;
node->data.container_decl.kind = kind;
- node->data.container_decl.init_arg_expr = ast_parse_grouped_expr(pc, token_index, false);
+
+ if (kind == ContainerKindUnion) {
+ Token *lparen_token = &pc->tokens->at(*token_index);
+ if (lparen_token->id == TokenIdLParen) {
+ Token *enum_token = &pc->tokens->at(*token_index + 1);
+ if (enum_token->id == TokenIdKeywordEnum) {
+ Token *paren_token = &pc->tokens->at(*token_index + 2);
+ if (paren_token->id == TokenIdLParen) {
+ node->data.container_decl.auto_enum = true;
+ *token_index += 2;
+ node->data.container_decl.init_arg_expr = ast_parse_grouped_expr(pc, token_index, true);
+ ast_eat_token(pc, token_index, TokenIdRParen);
+ } else if (paren_token->id == TokenIdRParen) {
+ node->data.container_decl.auto_enum = true;
+ *token_index += 3;
+ }
+ }
+ }
+ }
+ if (!node->data.container_decl.auto_enum) {
+ node->data.container_decl.init_arg_expr = ast_parse_grouped_expr(pc, token_index, false);
+ }
ast_eat_token(pc, token_index, TokenIdLBrace);
@@ -2461,8 +2484,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
if (colon_token->id == TokenIdColon) {
*token_index += 1;
field_node->data.struct_field.type = ast_parse_prefix_op_expr(pc, token_index, true);
- } else {
- field_node->data.struct_field.type = ast_create_void_type_node(pc, colon_token);
}
Token *eq_token = &pc->tokens->at(*token_index);
if (eq_token->id == TokenIdEq) {
diff --git a/std/build.zig b/std/build.zig
index 009295c6ad..9bdc4b3076 100644
--- a/std/build.zig
+++ b/std/build.zig
@@ -69,8 +69,8 @@ pub const Builder = struct {
used: bool,
};
- const UserValue = enum {
- Flag,
+ const UserValue = union(enum) {
+ Flag: void,
Scalar: []const u8,
List: ArrayList([]const u8),
};
@@ -450,7 +450,7 @@ pub const Builder = struct {
pub fn addUserInputOption(self: &Builder, name: []const u8, value: []const u8) -> bool {
if (%%self.user_input_options.put(name, UserInputOption {
.name = name,
- .value = UserValue.Scalar { value },
+ .value = UserValue { .Scalar = value },
.used = false,
})) |*prev_value| {
// option already exists
@@ -462,7 +462,7 @@ pub const Builder = struct {
%%list.append(value);
_ = %%self.user_input_options.put(name, UserInputOption {
.name = name,
- .value = UserValue.List { list },
+ .value = UserValue { .List = list },
.used = false,
});
},
@@ -471,7 +471,7 @@ pub const Builder = struct {
%%list.append(value);
_ = %%self.user_input_options.put(name, UserInputOption {
.name = name,
- .value = UserValue.List { *list },
+ .value = UserValue { .List = *list },
.used = false,
});
},
@@ -487,7 +487,7 @@ pub const Builder = struct {
pub fn addUserInputFlag(self: &Builder, name: []const u8) -> bool {
if (%%self.user_input_options.put(name, UserInputOption {
.name = name,
- .value = UserValue.Flag,
+ .value = UserValue {.Flag = {} },
.used = false,
})) |*prev_value| {
switch (prev_value.value) {
@@ -685,8 +685,8 @@ const CrossTarget = struct {
environ: builtin.Environ,
};
-const Target = enum {
- Native,
+const Target = union(enum) {
+ Native: void,
Cross: CrossTarget,
pub fn oFileExt(self: &const Target) -> []const u8 {
@@ -844,7 +844,7 @@ pub const LibExeObjStep = struct {
.kind = kind,
.root_src = root_src,
.name = name,
- .target = Target.Native,
+ .target = Target { .Native = {} },
.linker_script = null,
.link_libs = BufSet.init(builder.allocator),
.frameworks = BufSet.init(builder.allocator),
@@ -879,7 +879,7 @@ pub const LibExeObjStep = struct {
.kind = kind,
.version = *version,
.static = static,
- .target = Target.Native,
+ .target = Target { .Native = {} },
.cflags = ArrayList([]const u8).init(builder.allocator),
.source_files = ArrayList([]const u8).init(builder.allocator),
.object_files = ArrayList([]const u8).init(builder.allocator),
@@ -948,8 +948,8 @@ pub const LibExeObjStep = struct {
pub fn setTarget(self: &LibExeObjStep, target_arch: builtin.Arch, target_os: builtin.Os,
target_environ: builtin.Environ)
{
- self.target = Target.Cross {
- CrossTarget {
+ self.target = Target {
+ .Cross = CrossTarget {
.arch = target_arch,
.os = target_os,
.environ = target_environ,
@@ -1186,13 +1186,13 @@ pub const LibExeObjStep = struct {
Target.Native => {},
Target.Cross => |cross_target| {
%%zig_args.append("--target-arch");
- %%zig_args.append(@enumTagName(cross_target.arch));
+ %%zig_args.append(@tagName(cross_target.arch));
%%zig_args.append("--target-os");
- %%zig_args.append(@enumTagName(cross_target.os));
+ %%zig_args.append(@tagName(cross_target.os));
%%zig_args.append("--target-environ");
- %%zig_args.append(@enumTagName(cross_target.environ));
+ %%zig_args.append(@tagName(cross_target.environ));
},
}
@@ -1553,7 +1553,7 @@ pub const TestStep = struct {
.name_prefix = "",
.filter = null,
.link_libs = BufSet.init(builder.allocator),
- .target = Target.Native,
+ .target = Target { .Native = {} },
.exec_cmd_args = null,
}
}
@@ -1581,8 +1581,8 @@ pub const TestStep = struct {
pub fn setTarget(self: &TestStep, target_arch: builtin.Arch, target_os: builtin.Os,
target_environ: builtin.Environ)
{
- self.target = Target.Cross {
- CrossTarget {
+ self.target = Target {
+ .Cross = CrossTarget {
.arch = target_arch,
.os = target_os,
.environ = target_environ,
@@ -1620,13 +1620,13 @@ pub const TestStep = struct {
Target.Native => {},
Target.Cross => |cross_target| {
%%zig_args.append("--target-arch");
- %%zig_args.append(@enumTagName(cross_target.arch));
+ %%zig_args.append(@tagName(cross_target.arch));
%%zig_args.append("--target-os");
- %%zig_args.append(@enumTagName(cross_target.os));
+ %%zig_args.append(@tagName(cross_target.os));
%%zig_args.append("--target-environ");
- %%zig_args.append(@enumTagName(cross_target.environ));
+ %%zig_args.append(@tagName(cross_target.environ));
},
}
diff --git a/std/debug.zig b/std/debug.zig
index 50322024c3..5bfa436614 100644
--- a/std/debug.zig
+++ b/std/debug.zig
@@ -280,7 +280,7 @@ const AbbrevAttr = struct {
form_id: u64,
};
-const FormValue = enum {
+const FormValue = union(enum) {
Address: u64,
Block: []u8,
Const: Constant,
@@ -475,7 +475,7 @@ fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usiz
fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
const buf = %return readAllocBytes(allocator, in_stream, size);
- return FormValue.Block { buf };
+ return FormValue { .Block = buf };
}
fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
@@ -484,7 +484,7 @@ fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size:
}
fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue {
- FormValue.Const { Constant {
+ FormValue { .Const = Constant {
.signed = signed,
.payload = %return readAllocBytes(allocator, in_stream, size),
}}
@@ -510,7 +510,7 @@ fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 {
fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
const buf = %return readAllocBytes(allocator, in_stream, size);
- return FormValue.Ref { buf };
+ return FormValue { .Ref = buf };
}
fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptime T: type) -> %FormValue {
@@ -520,7 +520,7 @@ fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptim
fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool) -> %FormValue {
return switch (form_id) {
- DW.FORM_addr => FormValue.Address { %return parseFormValueTargetAddrSize(in_stream) },
+ DW.FORM_addr => FormValue { .Address = %return parseFormValueTargetAddrSize(in_stream) },
DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
@@ -540,13 +540,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
DW.FORM_exprloc => {
const size = %return readULeb128(in_stream);
const buf = %return readAllocBytes(allocator, in_stream, size);
- return FormValue.ExprLoc { buf };
- },
- DW.FORM_flag => FormValue.Flag { (%return in_stream.readByte()) != 0 },
- DW.FORM_flag_present => FormValue.Flag { true },
- DW.FORM_sec_offset => FormValue.SecOffset {
- %return parseFormValueDwarfOffsetSize(in_stream, is_64)
+ return FormValue { .ExprLoc = buf };
},
+ DW.FORM_flag => FormValue { .Flag = (%return in_stream.readByte()) != 0 },
+ DW.FORM_flag_present => FormValue { .Flag = true },
+ DW.FORM_sec_offset => FormValue { .SecOffset = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
@@ -557,11 +555,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
parseFormValueRefLen(allocator, in_stream, ref_len)
},
- DW.FORM_ref_addr => FormValue.RefAddr { %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
- DW.FORM_ref_sig8 => FormValue.RefSig8 { %return in_stream.readIntLe(u64) },
+ DW.FORM_ref_addr => FormValue { .RefAddr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
+ DW.FORM_ref_sig8 => FormValue { .RefSig8 = %return in_stream.readIntLe(u64) },
- DW.FORM_string => FormValue.String { %return readStringRaw(allocator, in_stream) },
- DW.FORM_strp => FormValue.StrPtr { %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
+ DW.FORM_string => FormValue { .String = %return readStringRaw(allocator, in_stream) },
+ DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
DW.FORM_indirect => {
const child_form_id = %return readULeb128(in_stream);
parseFormValue(allocator, in_stream, child_form_id, is_64)
diff --git a/std/os/child_process.zig b/std/os/child_process.zig
index 005d9772e4..3a4c9410c5 100644
--- a/std/os/child_process.zig
+++ b/std/os/child_process.zig
@@ -58,7 +58,7 @@ pub const ChildProcess = struct {
err_pipe: if (is_windows) void else [2]i32,
llnode: if (is_windows) void else LinkedList(&ChildProcess).Node,
- pub const Term = enum {
+ pub const Term = union(enum) {
Exited: i32,
Signal: i32,
Stopped: i32,
@@ -281,13 +281,13 @@ pub const ChildProcess = struct {
fn statusToTerm(status: i32) -> Term {
return if (posix.WIFEXITED(status)) {
- Term.Exited { posix.WEXITSTATUS(status) }
+ Term { .Exited = posix.WEXITSTATUS(status) }
} else if (posix.WIFSIGNALED(status)) {
- Term.Signal { posix.WTERMSIG(status) }
+ Term { .Signal = posix.WTERMSIG(status) }
} else if (posix.WIFSTOPPED(status)) {
- Term.Stopped { posix.WSTOPSIG(status) }
+ Term { .Stopped = posix.WSTOPSIG(status) }
} else {
- Term.Unknown { status }
+ Term { .Unknown = status }
};
}
diff --git a/std/os/path.zig b/std/os/path.zig
index a372b5b077..3fd7b5e2db 100644
--- a/std/os/path.zig
+++ b/std/os/path.zig
@@ -1016,7 +1016,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 {
return os.readLink(allocator, proc_path);
},
- else => @compileError("TODO implement os.path.real for " ++ @enumTagName(builtin.os)),
+ else => @compileError("TODO implement os.path.real for " ++ @tagName(builtin.os)),
}
}
diff --git a/test/cases/bugs/394.zig b/test/cases/bugs/394.zig
index aaa7de6f88..071619d59c 100644
--- a/test/cases/bugs/394.zig
+++ b/test/cases/bugs/394.zig
@@ -1,9 +1,9 @@
-const E = enum { A: [9]u8, B: u64, };
+const E = union(enum) { A: [9]u8, B: u64, };
const S = struct { x: u8, y: E, };
const assert = @import("std").debug.assert;
test "bug 394 fixed" {
- const x = S { .x = 3, .y = E.B {1} };
+ const x = S { .x = 3, .y = E {.B = 1 } };
assert(x.x == 3);
}
diff --git a/test/cases/enum.zig b/test/cases/enum.zig
index eda3cf6376..f3240045df 100644
--- a/test/cases/enum.zig
+++ b/test/cases/enum.zig
@@ -2,8 +2,8 @@ const assert = @import("std").debug.assert;
const mem = @import("std").mem;
test "enum type" {
- const foo1 = Foo.One {13};
- const foo2 = Foo.Two { Point { .x = 1234, .y = 5678, }};
+ const foo1 = Foo{ .One = 13};
+ const foo2 = Foo{. Two = Point { .x = 1234, .y = 5678, }};
const bar = Bar.B;
assert(bar == Bar.B);
@@ -24,12 +24,12 @@ const Point = struct {
x: u64,
y: u64,
};
-const Foo = enum {
+const Foo = union(enum) {
One: i32,
Two: Point,
Three: void,
};
-const FooNoVoid = enum {
+const FooNoVoid = union(enum) {
One: i32,
Two: Point,
};
@@ -41,13 +41,13 @@ const Bar = enum {
};
fn returnAnInt(x: i32) -> Foo {
- Foo.One { x }
+ Foo { .One = x }
}
test "constant enum with payload" {
- var empty = AnEnumWithPayload.Empty;
- var full = AnEnumWithPayload.Full {13};
+ var empty = AnEnumWithPayload {.Empty = {}};
+ var full = AnEnumWithPayload {.Full = 13};
shouldBeEmpty(empty);
shouldBeNotEmpty(full);
}
@@ -66,8 +66,8 @@ fn shouldBeNotEmpty(x: &const AnEnumWithPayload) {
}
}
-const AnEnumWithPayload = enum {
- Empty,
+const AnEnumWithPayload = union(enum) {
+ Empty: void,
Full: i32,
};
@@ -109,13 +109,13 @@ const IntToEnumNumber = enum {
};
-test "@enumTagName" {
+test "@tagName" {
assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
}
fn testEnumTagNameBare(n: BareNumber) -> []const u8 {
- return @enumTagName(n);
+ return @tagName(n);
}
const BareNumber = enum {
@@ -132,7 +132,7 @@ test "enum alignment" {
}
}
-const AlignTestEnum = enum {
+const AlignTestEnum = union(enum) {
A: [9]u8,
B: u64,
};
diff --git a/test/cases/enum_with_members.zig b/test/cases/enum_with_members.zig
index 67ed0410bc..ae48a266d0 100644
--- a/test/cases/enum_with_members.zig
+++ b/test/cases/enum_with_members.zig
@@ -2,7 +2,7 @@ const assert = @import("std").debug.assert;
const mem = @import("std").mem;
const fmt = @import("std").fmt;
-const ET = enum {
+const ET = union(enum) {
SINT: i32,
UINT: u32,
@@ -15,8 +15,8 @@ const ET = enum {
};
test "enum with members" {
- const a = ET.SINT { -42 };
- const b = ET.UINT { 42 };
+ const a = ET { .SINT = -42 };
+ const b = ET { .UINT = 42 };
var buf: [20]u8 = undefined;
assert(%%a.print(buf[0..]) == 3);
diff --git a/test/cases/misc.zig b/test/cases/misc.zig
index 76e1b829ee..9f4f064f6b 100644
--- a/test/cases/misc.zig
+++ b/test/cases/misc.zig
@@ -324,8 +324,8 @@ test "constant enum initialization with differing sizes" {
test3_1(test3_foo);
test3_2(test3_bar);
}
-const Test3Foo = enum {
- One,
+const Test3Foo = union(enum) {
+ One: void,
Two: f32,
Three: Test3Point,
};
@@ -333,8 +333,8 @@ const Test3Point = struct {
x: i32,
y: i32,
};
-const test3_foo = Test3Foo.Three{Test3Point {.x = 3, .y = 4}};
-const test3_bar = Test3Foo.Two{13};
+const test3_foo = Test3Foo { .Three = Test3Point {.x = 3, .y = 4}};
+const test3_bar = Test3Foo { .Two = 13};
fn test3_1(f: &const Test3Foo) {
switch (*f) {
Test3Foo.Three => |pt| {
@@ -449,7 +449,8 @@ fn testArray2DConstDoublePtr(ptr: &const f32) {
const Tid = builtin.TypeId;
const AStruct = struct { x: i32, };
const AnEnum = enum { One, Two, };
-const AnEnumWithPayload = enum { One: i32, Two, };
+const AUnionEnum = union(enum) { One: i32, Two: void, };
+const AUnion = union { One: void, Two: void };
test "@typeId" {
comptime {
@@ -474,8 +475,9 @@ test "@typeId" {
assert(@typeId(%i32) == Tid.ErrorUnion);
assert(@typeId(error) == Tid.Error);
assert(@typeId(AnEnum) == Tid.Enum);
- assert(@typeId(@typeOf(AnEnumWithPayload.One)) == Tid.EnumTag);
- // TODO union
+ assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
+ assert(@typeId(AUnionEnum) == Tid.Union);
+ assert(@typeId(AUnion) == Tid.Union);
assert(@typeId(fn()) == Tid.Fn);
assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
assert(@typeId(@typeOf({this})) == Tid.Block);
diff --git a/test/cases/reflection.zig b/test/cases/reflection.zig
index 4227f79a04..cbd98d212f 100644
--- a/test/cases/reflection.zig
+++ b/test/cases/reflection.zig
@@ -62,8 +62,8 @@ const Foo = struct {
three: void,
};
-const Bar = enum {
- One,
+const Bar = union(enum) {
+ One: void,
Two: i32,
Three: bool,
Four: f64,
diff --git a/test/cases/switch.zig b/test/cases/switch.zig
index 9ec50c7e25..11c2178427 100644
--- a/test/cases/switch.zig
+++ b/test/cases/switch.zig
@@ -83,14 +83,14 @@ const SwitchStatmentFoo = enum {
test "switch prong with variable" {
- switchProngWithVarFn(SwitchProngWithVarEnum.One {13});
- switchProngWithVarFn(SwitchProngWithVarEnum.Two {13.0});
- switchProngWithVarFn(SwitchProngWithVarEnum.Meh);
+ switchProngWithVarFn(SwitchProngWithVarEnum { .One = 13});
+ switchProngWithVarFn(SwitchProngWithVarEnum { .Two = 13.0});
+ switchProngWithVarFn(SwitchProngWithVarEnum { .Meh = {}});
}
-const SwitchProngWithVarEnum = enum {
+const SwitchProngWithVarEnum = union(enum) {
One: i32,
Two: f32,
- Meh,
+ Meh: void,
};
fn switchProngWithVarFn(a: &const SwitchProngWithVarEnum) {
switch(*a) {
@@ -112,7 +112,7 @@ test "switch on enum using pointer capture" {
}
fn testSwitchEnumPtrCapture() {
- var value = SwitchProngWithVarEnum.One { 1234 };
+ var value = SwitchProngWithVarEnum { .One = 1234 };
switch (value) {
SwitchProngWithVarEnum.One => |*x| *x += 1,
else => unreachable,
@@ -136,13 +136,13 @@ fn returnsFive() -> i32 {
}
-const Number = enum {
+const Number = union(enum) {
One: u64,
Two: u8,
Three: f32,
};
-const number = Number.Three { 1.23 };
+const number = Number { .Three = 1.23 };
fn returnsFalse() -> bool {
switch (number) {
diff --git a/test/cases/switch_prong_err_enum.zig b/test/cases/switch_prong_err_enum.zig
index d565de8c71..21f6b04037 100644
--- a/test/cases/switch_prong_err_enum.zig
+++ b/test/cases/switch_prong_err_enum.zig
@@ -9,14 +9,14 @@ fn readOnce() -> %u64 {
error InvalidDebugInfo;
-const FormValue = enum {
+const FormValue = union(enum) {
Address: u64,
Other: bool,
};
fn doThing(form_id: u64) -> %FormValue {
return switch (form_id) {
- 17 => FormValue.Address { %return readOnce() },
+ 17 => FormValue { .Address = %return readOnce() },
else => error.InvalidDebugInfo,
}
}
diff --git a/test/cases/switch_prong_implicit_cast.zig b/test/cases/switch_prong_implicit_cast.zig
index 131c5e1c80..e7fe53b841 100644
--- a/test/cases/switch_prong_implicit_cast.zig
+++ b/test/cases/switch_prong_implicit_cast.zig
@@ -1,7 +1,7 @@
const assert = @import("std").debug.assert;
-const FormValue = enum {
- One,
+const FormValue = union(enum) {
+ One: void,
Two: bool,
};
@@ -9,8 +9,8 @@ error Whatever;
fn foo(id: u64) -> %FormValue {
switch (id) {
- 2 => FormValue.Two { true },
- 1 => FormValue.One,
+ 2 => FormValue { .Two = true },
+ 1 => FormValue { .One = {} },
else => return error.Whatever,
}
}
diff --git a/test/cases/union.zig b/test/cases/union.zig
index 4044721582..ec050a20d5 100644
--- a/test/cases/union.zig
+++ b/test/cases/union.zig
@@ -1,6 +1,6 @@
const assert = @import("std").debug.assert;
-const Value = enum {
+const Value = union(enum) {
Int: u64,
Array: [9]u8,
};
@@ -10,8 +10,8 @@ const Agg = struct {
val2: Value,
};
-const v1 = Value.Int { 1234 };
-const v2 = Value.Array { []u8{3} ** 9 };
+const v1 = Value { .Int = 1234 };
+const v2 = Value { .Array = []u8{3} ** 9 };
const err = (%Agg)(Agg {
.val1 = v1,
@@ -75,3 +75,32 @@ test "basic extern unions" {
assert(foo.float == 12.34);
}
+
+const Letter = enum {
+ A,
+ B,
+ C,
+};
+const Payload = union(Letter) {
+ A: i32,
+ B: f64,
+ C: bool,
+};
+
+test "union with specified enum tag" {
+ doTest();
+ comptime doTest();
+}
+
+fn doTest() {
+ assert(bar(Payload {.A = 1234}) == -10);
+}
+
+fn bar(value: &const Payload) -> i32 {
+ assert(Letter(*value) == Letter.A);
+ return switch (*value) {
+ Payload.A => |x| return x - 1244,
+ Payload.B => |x| if (x == 12.34) i32(20) else 21,
+ Payload.C => |x| if (x) i32(30) else 31,
+ };
+}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index e1de167ac5..ac06b5aa2a 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -930,8 +930,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\fn bad_eql_1(a: []u8, b: []u8) -> bool {
\\ a == b
\\}
- \\const EnumWithData = enum {
- \\ One,
+ \\const EnumWithData = union(enum) {
+ \\ One: void,
\\ Two: i32,
\\};
\\fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) -> bool {
@@ -1145,19 +1145,19 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\const JasonHM = u8;
\\const JasonList = &JsonNode;
\\
- \\const JsonOA = enum {
+ \\const JsonOA = union(enum) {
\\ JSONArray: JsonList,
\\ JSONObject: JasonHM,
\\};
\\
- \\const JsonType = enum {
+ \\const JsonType = union(enum) {
\\ JSONNull: void,
\\ JSONInteger: isize,
\\ JSONDouble: f64,
\\ JSONBool: bool,
\\ JSONString: []u8,
- \\ JSONArray,
- \\ JSONObject,
+ \\ JSONArray: void,
+ \\ JSONObject: void,
\\};
\\
\\pub const JsonNode = struct {
@@ -2138,7 +2138,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\
\\const MdText = ArrayList(u8);
\\
- \\const MdNode = enum {
+ \\const MdNode = union(enum) {
\\ Header: struct {
\\ text: MdText,
\\ weight: HeaderValue,
@@ -2297,6 +2297,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
,
".tmp_source.zig:2:21: error: type 'i32' does not support @memberType");
+ cases.add("@memberType on enum",
+ \\comptime {
+ \\ _ = @memberType(Foo, 0);
+ \\}
+ \\const Foo = enum {A,};
+ ,
+ ".tmp_source.zig:2:21: error: type 'Foo' does not support @memberType");
+
cases.add("@memberType struct out of bounds",
\\comptime {
\\ _ = @memberType(Foo, 0);
@@ -2305,11 +2313,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
,
".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
- cases.add("@memberType enum out of bounds",
+ cases.add("@memberType union out of bounds",
\\comptime {
\\ _ = @memberType(Foo, 1);
\\}
- \\const Foo = enum {A,};
+ \\const Foo = union {A: void,};
,
".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members");
@@ -2336,6 +2344,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
,
".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members");
+ cases.add("@memberName union out of bounds",
+ \\comptime {
+ \\ _ = @memberName(Foo, 1);
+ \\}
+ \\const Foo = union {A:i32,};
+ ,
+ ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members");
+
cases.add("calling var args extern function, passing array instead of pointer",
\\export fn entry() {
\\ foo("hello");
@@ -2466,7 +2482,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\ var x: MultipleChoice = undefined;
\\}
,
- ".tmp_source.zig:2:14: error: enums, not unions, support field assignment");
+ ".tmp_source.zig:2:14: error: non-enum union field assignment",
+ ".tmp_source.zig:1:24: note: consider 'union(enum)' here");
cases.add("enum with 0 fields",
\\const Foo = enum {};
@@ -2490,4 +2507,21 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
,
".tmp_source.zig:6:9: error: enum tag value 60 already taken",
".tmp_source.zig:4:9: note: other occurrence here");
+
+ cases.add("union with specified enum omits field",
+ \\const Letter = enum {
+ \\ A,
+ \\ B,
+ \\ C,
+ \\};
+ \\const Payload = union(Letter) {
+ \\ A: i32,
+ \\ B: f64,
+ \\};
+ \\export fn entry() -> usize {
+ \\ return @sizeOf(Payload);
+ \\}
+ ,
+ ".tmp_source.zig:6:17: error: enum field missing: 'C'",
+ ".tmp_source.zig:4:5: note: declared here");
}
diff --git a/test/tests.zig b/test/tests.zig
index 73d9646552..e74afa1755 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -150,8 +150,8 @@ pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []cons
continue;
}
const these_tests = b.addTest(root_src);
- these_tests.setNamePrefix(b.fmt("{}-{}-{}-{}-{} ", name, @enumTagName(test_target.os),
- @enumTagName(test_target.arch), @enumTagName(mode), if (link_libc) "c" else "bare"));
+ these_tests.setNamePrefix(b.fmt("{}-{}-{}-{}-{} ", name, @tagName(test_target.os),
+ @tagName(test_target.arch), @tagName(mode), if (link_libc) "c" else "bare"));
these_tests.setFilter(test_filter);
these_tests.setBuildMode(mode);
if (!is_native) {
@@ -428,7 +428,7 @@ pub const CompareOutputContext = struct {
Special.None => {
for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "{} {} ({})",
- "compare-output", case.name, @enumTagName(mode));
+ "compare-output", case.name, @tagName(mode));
if (self.test_filter) |filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null)
continue;
@@ -682,7 +682,7 @@ pub const CompileErrorContext = struct {
for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "compile-error {} ({})",
- case.name, @enumTagName(mode));
+ case.name, @tagName(mode));
if (self.test_filter) |filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null)
continue;
@@ -750,7 +750,7 @@ pub const BuildExamplesContext = struct {
for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "build {} ({})",
- root_src, @enumTagName(mode));
+ root_src, @tagName(mode));
if (self.test_filter) |filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null)
continue;
From 5a8367e8924e809b1390796eb656633ea5e34a86 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Sun, 3 Dec 2017 22:36:01 -0500
Subject: [PATCH 23/32] rename @EnumTagType to @TagType. add tests for
union-enums
See #618
---
src/all_types.hpp | 10 ++---
src/codegen.cpp | 10 ++---
src/ir.cpp | 91 +++++++++++++++++++++++++++-----------------
src/ir_print.cpp | 16 ++++----
test/cases/enum.zig | 4 +-
test/cases/union.zig | 33 ++++++++++++++++
6 files changed, 109 insertions(+), 55 deletions(-)
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 6061f63da6..086ad7db49 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -1266,7 +1266,7 @@ enum BuiltinFnId {
BuiltinFnIdIntToPtr,
BuiltinFnIdPtrToInt,
BuiltinFnIdTagName,
- BuiltinFnIdEnumTagType,
+ BuiltinFnIdTagType,
BuiltinFnIdFieldParentPtr,
BuiltinFnIdOffsetOf,
BuiltinFnIdInlineCall,
@@ -1889,8 +1889,8 @@ enum IrInstructionId {
IrInstructionIdSetGlobalLinkage,
IrInstructionIdDeclRef,
IrInstructionIdPanic,
- IrInstructionIdEnumTagName,
- IrInstructionIdEnumTagType,
+ IrInstructionIdTagName,
+ IrInstructionIdTagType,
IrInstructionIdFieldParentPtr,
IrInstructionIdOffsetOf,
IrInstructionIdTypeId,
@@ -2652,13 +2652,13 @@ struct IrInstructionPanic {
IrInstruction *msg;
};
-struct IrInstructionEnumTagName {
+struct IrInstructionTagName {
IrInstruction base;
IrInstruction *target;
};
-struct IrInstructionEnumTagType {
+struct IrInstructionTagType {
IrInstruction base;
IrInstruction *target;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index dbf4f8522b..bd84310ff1 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -2717,7 +2717,7 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI
}
static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable,
- IrInstructionEnumTagName *instruction)
+ IrInstructionTagName *instruction)
{
TypeTableEntry *enum_type = instruction->target->value.type;
assert(enum_type->id == TypeTableEntryIdEnum);
@@ -3484,7 +3484,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdOpaqueType:
case IrInstructionIdSetAlignStack:
case IrInstructionIdArgType:
- case IrInstructionIdEnumTagType:
+ case IrInstructionIdTagType:
zig_unreachable();
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -3594,8 +3594,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction);
case IrInstructionIdPanic:
return ir_render_panic(g, executable, (IrInstructionPanic *)instruction);
- case IrInstructionIdEnumTagName:
- return ir_render_enum_tag_name(g, executable, (IrInstructionEnumTagName *)instruction);
+ case IrInstructionIdTagName:
+ return ir_render_enum_tag_name(g, executable, (IrInstructionTagName *)instruction);
case IrInstructionIdFieldParentPtr:
return ir_render_field_parent_ptr(g, executable, (IrInstructionFieldParentPtr *)instruction);
case IrInstructionIdAlignCast:
@@ -4963,7 +4963,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2);
create_builtin_fn(g, BuiltinFnIdPtrToInt, "ptrToInt", 1);
create_builtin_fn(g, BuiltinFnIdTagName, "tagName", 1);
- create_builtin_fn(g, BuiltinFnIdEnumTagType, "EnumTagType", 1);
+ create_builtin_fn(g, BuiltinFnIdTagType, "TagType", 1);
create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3);
create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2);
create_builtin_fn(g, BuiltinFnIdDivExact, "divExact", 2);
diff --git a/src/ir.cpp b/src/ir.cpp
index 5da59fedb7..e70340b300 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -539,12 +539,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPanic *) {
return IrInstructionIdPanic;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTagName *) {
- return IrInstructionIdEnumTagName;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionTagName *) {
+ return IrInstructionIdTagName;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTagType *) {
- return IrInstructionIdEnumTagType;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionTagType *) {
+ return IrInstructionIdTagType;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldParentPtr *) {
@@ -2205,10 +2205,10 @@ static IrInstruction *ir_build_panic(IrBuilder *irb, Scope *scope, AstNode *sour
return &instruction->base;
}
-static IrInstruction *ir_build_enum_tag_name(IrBuilder *irb, Scope *scope, AstNode *source_node,
+static IrInstruction *ir_build_tag_name(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *target)
{
- IrInstructionEnumTagName *instruction = ir_build_instruction(irb, scope, source_node);
+ IrInstructionTagName *instruction = ir_build_instruction(irb, scope, source_node);
instruction->target = target;
ir_ref_instruction(target, irb->current_basic_block);
@@ -2216,10 +2216,10 @@ static IrInstruction *ir_build_enum_tag_name(IrBuilder *irb, Scope *scope, AstNo
return &instruction->base;
}
-static IrInstruction *ir_build_enum_tag_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
+static IrInstruction *ir_build_tag_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *target)
{
- IrInstructionEnumTagType *instruction = ir_build_instruction(irb, scope, source_node);
+ IrInstructionTagType *instruction = ir_build_instruction(irb, scope, source_node);
instruction->target = target;
ir_ref_instruction(target, irb->current_basic_block);
@@ -3002,14 +3002,14 @@ static IrInstruction *ir_instruction_panic_get_dep(IrInstructionPanic *instructi
}
}
-static IrInstruction *ir_instruction_enumtagname_get_dep(IrInstructionEnumTagName *instruction, size_t index) {
+static IrInstruction *ir_instruction_enumtagname_get_dep(IrInstructionTagName *instruction, size_t index) {
switch (index) {
case 0: return instruction->target;
default: return nullptr;
}
}
-static IrInstruction *ir_instruction_enumtagtype_get_dep(IrInstructionEnumTagType *instruction, size_t index) {
+static IrInstruction *ir_instruction_enumtagtype_get_dep(IrInstructionTagType *instruction, size_t index) {
switch (index) {
case 0: return instruction->target;
default: return nullptr;
@@ -3270,10 +3270,10 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
return ir_instruction_declref_get_dep((IrInstructionDeclRef *) instruction, index);
case IrInstructionIdPanic:
return ir_instruction_panic_get_dep((IrInstructionPanic *) instruction, index);
- case IrInstructionIdEnumTagName:
- return ir_instruction_enumtagname_get_dep((IrInstructionEnumTagName *) instruction, index);
- case IrInstructionIdEnumTagType:
- return ir_instruction_enumtagtype_get_dep((IrInstructionEnumTagType *) instruction, index);
+ case IrInstructionIdTagName:
+ return ir_instruction_enumtagname_get_dep((IrInstructionTagName *) instruction, index);
+ case IrInstructionIdTagType:
+ return ir_instruction_enumtagtype_get_dep((IrInstructionTagType *) instruction, index);
case IrInstructionIdFieldParentPtr:
return ir_instruction_fieldparentptr_get_dep((IrInstructionFieldParentPtr *) instruction, index);
case IrInstructionIdOffsetOf:
@@ -4627,16 +4627,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return arg0_value;
IrInstruction *actual_tag = ir_build_union_tag(irb, scope, node, arg0_value);
- return ir_build_enum_tag_name(irb, scope, node, actual_tag);
+ return ir_build_tag_name(irb, scope, node, actual_tag);
}
- case BuiltinFnIdEnumTagType:
+ case BuiltinFnIdTagType:
{
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;
- return ir_build_enum_tag_type(irb, scope, node, arg0_value);
+ return ir_build_tag_type(irb, scope, node, arg0_value);
}
case BuiltinFnIdFieldParentPtr:
{
@@ -13638,7 +13638,7 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc
return str_type;
}
-static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstructionEnumTagName *instruction) {
+static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstructionTagName *instruction) {
IrInstruction *target = instruction->target->other;
if (type_is_invalid(target->value.type))
return ira->codegen->builtin_types.entry_invalid;
@@ -13658,7 +13658,7 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn
ira->codegen->name_table_enums.append(target->value.type);
}
- IrInstruction *result = ir_build_enum_tag_name(&ira->new_irb, instruction->base.scope,
+ IrInstruction *result = ir_build_tag_name(&ira->new_irb, instruction->base.scope,
instruction->base.source_node, target);
ir_link_new_instruction(result, &instruction->base);
TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
@@ -15838,22 +15838,43 @@ static TypeTableEntry *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruc
return ira->codegen->builtin_types.entry_type;
}
-static TypeTableEntry *ir_analyze_instruction_enum_tag_type(IrAnalyze *ira, IrInstructionEnumTagType *instruction) {
+static TypeTableEntry *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstructionTagType *instruction) {
IrInstruction *target_inst = instruction->target->other;
TypeTableEntry *enum_type = ir_resolve_type(ira, target_inst);
if (type_is_invalid(enum_type))
return ira->codegen->builtin_types.entry_invalid;
- if (enum_type->id != TypeTableEntryIdEnum) {
- ir_add_error(ira, target_inst, buf_sprintf("expected enum, found '%s'", buf_ptr(&enum_type->name)));
+
+ if (enum_type->id == TypeTableEntryIdEnum) {
+ ensure_complete_type(ira->codegen, enum_type);
+ if (type_is_invalid(enum_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ out_val->data.x_type = enum_type->data.enumeration.tag_int_type;
+ return ira->codegen->builtin_types.entry_type;
+ } else if (enum_type->id == TypeTableEntryIdUnion) {
+ ensure_complete_type(ira->codegen, enum_type);
+ if (type_is_invalid(enum_type))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ AstNode *decl_node = enum_type->data.unionation.decl_node;
+ if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
+ assert(enum_type->data.unionation.tag_type != nullptr);
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
+ out_val->data.x_type = enum_type->data.unionation.tag_type;
+ return ira->codegen->builtin_types.entry_type;
+ } else {
+ ErrorMsg *msg = ir_add_error(ira, target_inst, buf_sprintf("union '%s' has no tag",
+ buf_ptr(&enum_type->name)));
+ add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ } else {
+ ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'",
+ buf_ptr(&enum_type->name)));
return ira->codegen->builtin_types.entry_invalid;
}
- ensure_complete_type(ira->codegen, enum_type);
- if (type_is_invalid(enum_type))
- return ira->codegen->builtin_types.entry_invalid;
-
- ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
- out_val->data.x_type = enum_type->data.enumeration.tag_int_type;
- return ira->codegen->builtin_types.entry_type;
}
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
@@ -16032,8 +16053,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_int_to_ptr(ira, (IrInstructionIntToPtr *)instruction);
case IrInstructionIdPtrToInt:
return ir_analyze_instruction_ptr_to_int(ira, (IrInstructionPtrToInt *)instruction);
- case IrInstructionIdEnumTagName:
- return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionEnumTagName *)instruction);
+ case IrInstructionIdTagName:
+ return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionTagName *)instruction);
case IrInstructionIdFieldParentPtr:
return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction);
case IrInstructionIdOffsetOf:
@@ -16052,8 +16073,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_set_align_stack(ira, (IrInstructionSetAlignStack *)instruction);
case IrInstructionIdArgType:
return ir_analyze_instruction_arg_type(ira, (IrInstructionArgType *)instruction);
- case IrInstructionIdEnumTagType:
- return ir_analyze_instruction_enum_tag_type(ira, (IrInstructionEnumTagType *)instruction);
+ case IrInstructionIdTagType:
+ return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction);
}
zig_unreachable();
}
@@ -16230,14 +16251,14 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdDeclRef:
case IrInstructionIdErrName:
case IrInstructionIdTypeName:
- case IrInstructionIdEnumTagName:
+ case IrInstructionIdTagName:
case IrInstructionIdFieldParentPtr:
case IrInstructionIdOffsetOf:
case IrInstructionIdTypeId:
case IrInstructionIdAlignCast:
case IrInstructionIdOpaqueType:
case IrInstructionIdArgType:
- case IrInstructionIdEnumTagType:
+ case IrInstructionIdTagType:
return false;
case IrInstructionIdAsm:
{
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 99617056de..223a012456 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -872,8 +872,8 @@ static void ir_print_type_name(IrPrint *irp, IrInstructionTypeName *instruction)
ir_print_other_instruction(irp, instruction->type_value);
}
-static void ir_print_enum_tag_name(IrPrint *irp, IrInstructionEnumTagName *instruction) {
- fprintf(irp->f, "enumtagname ");
+static void ir_print_tag_name(IrPrint *irp, IrInstructionTagName *instruction) {
+ fprintf(irp->f, "tagname ");
ir_print_other_instruction(irp, instruction->target);
}
@@ -981,8 +981,8 @@ static void ir_print_arg_type(IrPrint *irp, IrInstructionArgType *instruction) {
fprintf(irp->f, ")");
}
-static void ir_print_enum_tag_type(IrPrint *irp, IrInstructionEnumTagType *instruction) {
- fprintf(irp->f, "@EnumTagType(");
+static void ir_print_enum_tag_type(IrPrint *irp, IrInstructionTagType *instruction) {
+ fprintf(irp->f, "@TagType(");
ir_print_other_instruction(irp, instruction->target);
fprintf(irp->f, ")");
}
@@ -1254,8 +1254,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdTypeName:
ir_print_type_name(irp, (IrInstructionTypeName *)instruction);
break;
- case IrInstructionIdEnumTagName:
- ir_print_enum_tag_name(irp, (IrInstructionEnumTagName *)instruction);
+ case IrInstructionIdTagName:
+ ir_print_tag_name(irp, (IrInstructionTagName *)instruction);
break;
case IrInstructionIdCanImplicitCast:
ir_print_can_implicit_cast(irp, (IrInstructionCanImplicitCast *)instruction);
@@ -1299,8 +1299,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdArgType:
ir_print_arg_type(irp, (IrInstructionArgType *)instruction);
break;
- case IrInstructionIdEnumTagType:
- ir_print_enum_tag_type(irp, (IrInstructionEnumTagType *)instruction);
+ case IrInstructionIdTagType:
+ ir_print_enum_tag_type(irp, (IrInstructionTagType *)instruction);
break;
}
fprintf(irp->f, "\n");
diff --git a/test/cases/enum.zig b/test/cases/enum.zig
index f3240045df..ec900511eb 100644
--- a/test/cases/enum.zig
+++ b/test/cases/enum.zig
@@ -204,12 +204,12 @@ test "set enum tag type" {
{
var x = Small.One;
x = Small.Two;
- comptime assert(@EnumTagType(Small) == u2);
+ comptime assert(@TagType(Small) == u2);
}
{
var x = Small2.One;
x = Small2.Two;
- comptime assert(@EnumTagType(Small2) == u2);
+ comptime assert(@TagType(Small2) == u2);
}
}
diff --git a/test/cases/union.zig b/test/cases/union.zig
index ec050a20d5..c4767fd649 100644
--- a/test/cases/union.zig
+++ b/test/cases/union.zig
@@ -104,3 +104,36 @@ fn bar(value: &const Payload) -> i32 {
Payload.C => |x| if (x) i32(30) else 31,
};
}
+
+const MultipleChoice2 = union(enum(u32)) {
+ Unspecified1: i32,
+ A: f32 = 20,
+ Unspecified2: void,
+ B: bool = 40,
+ Unspecified3: i32,
+ C: i8 = 60,
+ Unspecified4: void,
+ D: void = 1000,
+ Unspecified5: i32,
+};
+
+test "union(enum(u32)) with specified and unspecified tag values" {
+ comptime assert(@TagType(@TagType(MultipleChoice2)) == u32);
+ testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2 {.C = 123});
+ comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2 { .C = 123} );
+}
+
+fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) {
+ assert(u32(@TagType(MultipleChoice2)(*x)) == 60);
+ assert(1123 == switch (*x) {
+ MultipleChoice2.A => 1,
+ MultipleChoice2.B => 2,
+ MultipleChoice2.C => |v| i32(1000) + v,
+ MultipleChoice2.D => 4,
+ MultipleChoice2.Unspecified1 => 5,
+ MultipleChoice2.Unspecified2 => 6,
+ MultipleChoice2.Unspecified3 => 7,
+ MultipleChoice2.Unspecified4 => 8,
+ MultipleChoice2.Unspecified5 => 9,
+ });
+}
From fce435db269162774106ce7e6ddf70871d5eeb49 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 4 Dec 2017 00:32:12 -0500
Subject: [PATCH 24/32] fix abi alignment of union-enums not counting tag type
add more tests for unions
See #618
---
src/analyze.cpp | 418 ++++++++++++++++++++++------------------
src/ir.cpp | 7 +-
test/cases/union.zig | 13 ++
test/compile_errors.zig | 47 +++++
4 files changed, 291 insertions(+), 194 deletions(-)
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 9d2d4f1a8f..96f0eb44db 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -1713,84 +1713,16 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
uint64_t biggest_align_in_bits = 0;
uint64_t biggest_size_in_bits = 0;
- ZigLLVMDIEnumerator **di_enumerators;
-
Scope *scope = &union_type->data.unionation.decls_scope->base;
ImportTableEntry *import = get_scope_import(scope);
// set temporary flag
union_type->data.unionation.embedded_in_current = true;
- HashMap occupied_tag_values = {};
-
- AstNode *enum_type_node = decl_node->data.container_decl.init_arg_expr;
- bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
- bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr);
- TypeTableEntry *tag_type;
- bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety);
- bool *covered_enum_fields;
- if (create_enum_type) {
- occupied_tag_values.init(field_count);
-
- di_enumerators = allocate(field_count);
-
- TypeTableEntry *tag_int_type;
- if (enum_type_node != nullptr) {
- tag_int_type = analyze_type_expr(g, scope, enum_type_node);
- if (type_is_invalid(tag_int_type)) {
- union_type->data.unionation.is_invalid = true;
- return;
- }
- if (tag_int_type->id != TypeTableEntryIdInt) {
- add_node_error(g, enum_type_node,
- buf_sprintf("expected integer tag type, found '%s'", buf_ptr(&tag_int_type->name)));
- union_type->data.unionation.is_invalid = true;
- return;
- }
- } else {
- tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
- }
-
- tag_type = new_type_table_entry(TypeTableEntryIdEnum);
- buf_resize(&tag_type->name, 0);
- buf_appendf(&tag_type->name, "@EnumTagType(%s)", buf_ptr(&union_type->name));
- tag_type->is_copyable = true;
- tag_type->type_ref = tag_int_type->type_ref;
- tag_type->zero_bits = tag_int_type->zero_bits;
-
- tag_type->data.enumeration.tag_int_type = tag_int_type;
- tag_type->data.enumeration.zero_bits_known = true;
- tag_type->data.enumeration.decl_node = decl_node;
- tag_type->data.enumeration.layout = ContainerLayoutAuto;
- tag_type->data.enumeration.src_field_count = field_count;
- tag_type->data.enumeration.fields = allocate(field_count);
- tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope;
- tag_type->data.enumeration.complete = true;
- } else if (enum_type_node != nullptr) {
- TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node);
- if (type_is_invalid(enum_type)) {
- union_type->data.unionation.is_invalid = true;
- union_type->data.unionation.embedded_in_current = false;
- return;
- }
- if (enum_type->id != TypeTableEntryIdEnum) {
- union_type->data.unionation.is_invalid = true;
- union_type->data.unionation.embedded_in_current = false;
- add_node_error(g, enum_type_node,
- buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
- return;
- }
- tag_type = enum_type;
- covered_enum_fields = allocate(enum_type->data.enumeration.src_field_count);
- } else {
- tag_type = nullptr;
- }
- union_type->data.unionation.tag_type = tag_type;
for (uint32_t i = 0; i < field_count; i += 1) {
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
TypeUnionField *union_field = &union_type->data.unionation.fields[i];
- Buf *field_name = field_node->data.struct_field.name;
TypeTableEntry *field_type = union_field->type_entry;
ensure_complete_type(g, field_type);
@@ -1799,57 +1731,6 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
continue;
}
- if (create_enum_type) {
- di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field_name), i);
- union_field->enum_field = &tag_type->data.enumeration.fields[i];
- union_field->enum_field->name = field_name;
- union_field->enum_field->decl_index = i;
-
- AstNode *tag_value = field_node->data.struct_field.value;
- // In this first pass we resolve explicit tag values.
- // In a second pass we will fill in the unspecified ones.
- if (tag_value != nullptr) {
- TypeTableEntry *tag_int_type = tag_type->data.enumeration.tag_int_type;
- IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
- if (result_inst->value.type->id == TypeTableEntryIdInvalid) {
- union_type->data.unionation.is_invalid = true;
- continue;
- }
- assert(result_inst->value.special != ConstValSpecialRuntime);
- assert(result_inst->value.type->id == TypeTableEntryIdInt);
- auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
- if (entry == nullptr) {
- bigint_init_bigint(&union_field->enum_field->value, &result_inst->value.data.x_bigint);
- } else {
- Buf *val_buf = buf_alloc();
- bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10);
-
- ErrorMsg *msg = add_node_error(g, tag_value,
- buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf)));
- add_error_note(g, msg, entry->value,
- buf_sprintf("other occurrence here"));
- union_type->data.unionation.is_invalid = true;
- continue;
- }
- }
- } else if (enum_type_node != nullptr) {
- union_field->enum_field = find_enum_type_field(tag_type, field_name);
- if (union_field->enum_field == nullptr) {
- ErrorMsg *msg = add_node_error(g, field_node,
- buf_sprintf("enum field not found: '%s'", buf_ptr(field_name)));
- add_error_note(g, msg, tag_type->data.enumeration.decl_node,
- buf_sprintf("enum declared here"));
- union_type->data.unionation.is_invalid = true;
- continue;
- }
- covered_enum_fields[union_field->enum_field->decl_index] = true;
- } else {
- union_field->enum_field = allocate(1);
- union_field->enum_field->name = field_name;
- union_field->enum_field->decl_index = i;
- bigint_init_unsigned(&union_field->enum_field->value, i);
- }
-
if (!type_has_bits(field_type))
continue;
@@ -1876,48 +1757,6 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
}
}
- if (create_enum_type) {
- // Now iterate again and populate the unspecified tag values
- uint32_t next_maybe_unoccupied_index = 0;
-
- for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
- AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
- TypeUnionField *union_field = &union_type->data.unionation.fields[field_i];
- AstNode *tag_value = field_node->data.struct_field.value;
-
- if (tag_value == nullptr) {
- if (occupied_tag_values.size() == 0) {
- bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index);
- next_maybe_unoccupied_index += 1;
- } else {
- BigInt proposed_value;
- for (;;) {
- bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index);
- next_maybe_unoccupied_index += 1;
- auto entry = occupied_tag_values.put_unique(proposed_value, field_node);
- if (entry != nullptr) {
- continue;
- }
- break;
- }
- bigint_init_bigint(&union_field->enum_field->value, &proposed_value);
- }
- }
- }
- } 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]) {
- 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,
- buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name)));
- add_error_note(g, msg, field_node,
- buf_sprintf("declared here"));
- union_type->data.unionation.is_invalid = true;
- }
- }
- }
// unset temporary flag
union_type->data.unionation.embedded_in_current = false;
@@ -1948,11 +1787,12 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
return;
}
- assert(most_aligned_union_member != nullptr);
-
uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
+ TypeTableEntry *tag_type = union_type->data.unionation.tag_type;
if (tag_type == nullptr) {
+ assert(most_aligned_union_member != nullptr);
+
if (padding_in_bits > 0) {
TypeTableEntry *u8_type = get_int_type(g, false, 8);
TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
@@ -1993,7 +1833,13 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
};
union_type_ref = LLVMStructType(union_element_types, 2, false);
} else if (most_aligned_union_member == nullptr) {
- zig_panic("TODO zero bit payload");
+ union_type->data.unionation.gen_tag_index = SIZE_MAX;
+ union_type->data.unionation.gen_union_index = SIZE_MAX;
+ union_type->type_ref = tag_type->type_ref;
+
+ ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, tag_type->di_type);
+ union_type->di_type = tag_type->di_type;
+ return;
} else {
union_type_ref = most_aligned_union_member->type_ref;
}
@@ -2020,20 +1866,6 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
LLVMStructSetBody(union_type->type_ref, root_struct_element_types, 2, false);
- // create debug type for root struct
-
- uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
- uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
- if (create_enum_type) {
- // create debug type for tag
- ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
- ZigLLVMTypeToScope(union_type->di_type), "AnonEnum",
- import->di_file, (unsigned)(decl_node->line + 1),
- tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
- tag_type->di_type, "");
- tag_type->di_type = tag_di_type;
- }
-
// create debug type for union
ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
ZigLLVMTypeToScope(union_type->di_type), "AnonUnion",
@@ -2053,6 +1885,10 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
biggest_align_in_bits,
union_offset_in_bits,
0, union_di_type);
+
+ uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
+ uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
+
ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
ZigLLVMTypeToScope(union_type->di_type), "tag",
import->di_file, (unsigned)(decl_node->line + 1),
@@ -2312,8 +2148,23 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
if (union_type->data.unionation.zero_bits_known)
return;
+ if (type_is_invalid(union_type))
+ return;
+
if (union_type->data.unionation.zero_bits_loop_flag) {
+ // If we get here it's due to recursion. From this we conclude that the struct is
+ // not zero bits, and if abi_alignment == 0 we further conclude that the first field
+ // is a pointer to this very struct, or a function pointer with parameters that
+ // reference such a type.
union_type->data.unionation.zero_bits_known = true;
+ if (union_type->data.unionation.abi_alignment == 0) {
+ if (union_type->data.unionation.layout == ContainerLayoutPacked) {
+ union_type->data.unionation.abi_alignment = 1;
+ } else {
+ union_type->data.unionation.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref,
+ LLVMPointerType(LLVMInt8Type(), 0));
+ }
+ }
return;
}
@@ -2342,19 +2193,99 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
Scope *scope = &union_type->data.unionation.decls_scope->base;
+ HashMap occupied_tag_values = {};
+
+ AstNode *enum_type_node = decl_node->data.container_decl.init_arg_expr;
+ bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
+ bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr);
+ TypeTableEntry *tag_type;
+ bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety);
+ bool *covered_enum_fields;
+ ZigLLVMDIEnumerator **di_enumerators;
+ if (create_enum_type) {
+ occupied_tag_values.init(field_count);
+
+ di_enumerators = allocate(field_count);
+
+ TypeTableEntry *tag_int_type;
+ if (enum_type_node != nullptr) {
+ tag_int_type = analyze_type_expr(g, scope, enum_type_node);
+ if (type_is_invalid(tag_int_type)) {
+ union_type->data.unionation.is_invalid = true;
+ return;
+ }
+ if (tag_int_type->id != TypeTableEntryIdInt) {
+ add_node_error(g, enum_type_node,
+ buf_sprintf("expected integer tag type, found '%s'", buf_ptr(&tag_int_type->name)));
+ union_type->data.unionation.is_invalid = true;
+ return;
+ }
+ } else {
+ tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
+ }
+ union_type->data.unionation.abi_alignment = get_abi_alignment(g, tag_int_type);
+
+ tag_type = new_type_table_entry(TypeTableEntryIdEnum);
+ buf_resize(&tag_type->name, 0);
+ buf_appendf(&tag_type->name, "@EnumTagType(%s)", buf_ptr(&union_type->name));
+ tag_type->is_copyable = true;
+ tag_type->type_ref = tag_int_type->type_ref;
+ tag_type->zero_bits = tag_int_type->zero_bits;
+
+ tag_type->data.enumeration.tag_int_type = tag_int_type;
+ tag_type->data.enumeration.zero_bits_known = true;
+ tag_type->data.enumeration.decl_node = decl_node;
+ tag_type->data.enumeration.layout = ContainerLayoutAuto;
+ tag_type->data.enumeration.src_field_count = field_count;
+ tag_type->data.enumeration.fields = allocate(field_count);
+ tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope;
+ tag_type->data.enumeration.complete = true;
+ } else if (enum_type_node != nullptr) {
+ TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node);
+ if (type_is_invalid(enum_type)) {
+ union_type->data.unionation.is_invalid = true;
+ union_type->data.unionation.embedded_in_current = false;
+ return;
+ }
+ if (enum_type->id != TypeTableEntryIdEnum) {
+ union_type->data.unionation.is_invalid = true;
+ union_type->data.unionation.embedded_in_current = false;
+ add_node_error(g, enum_type_node,
+ buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
+ return;
+ }
+ tag_type = enum_type;
+ covered_enum_fields = allocate(enum_type->data.enumeration.src_field_count);
+ union_type->data.unionation.abi_alignment = get_abi_alignment(g, enum_type);
+ } else {
+ tag_type = nullptr;
+ }
+ union_type->data.unionation.tag_type = tag_type;
+
uint32_t gen_field_index = 0;
for (uint32_t i = 0; i < field_count; i += 1) {
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
+ Buf *field_name = field_node->data.struct_field.name;
TypeUnionField *union_field = &union_type->data.unionation.fields[i];
union_field->name = field_node->data.struct_field.name;
+ TypeTableEntry *field_type;
if (field_node->data.struct_field.type == nullptr) {
- add_node_error(g, field_node, buf_sprintf("union field missing type"));
- union_type->data.unionation.is_invalid = true;
- continue;
+ if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
+ field_type = g->builtin_types.entry_void;
+ } else {
+ add_node_error(g, field_node, buf_sprintf("union field missing type"));
+ union_type->data.unionation.is_invalid = true;
+ continue;
+ }
+ } else {
+ field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
+ type_ensure_zero_bits_known(g, field_type);
+ if (type_is_invalid(field_type)) {
+ union_type->data.unionation.is_invalid = true;
+ continue;
+ }
}
-
- TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
union_field->type_entry = field_type;
if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
@@ -2364,11 +2295,57 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
buf_sprintf("consider 'union(enum)' here"));
}
- type_ensure_zero_bits_known(g, field_type);
- if (type_is_invalid(field_type)) {
- union_type->data.unionation.is_invalid = true;
- continue;
+ if (create_enum_type) {
+ di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field_name), i);
+ union_field->enum_field = &tag_type->data.enumeration.fields[i];
+ union_field->enum_field->name = field_name;
+ union_field->enum_field->decl_index = i;
+
+ AstNode *tag_value = field_node->data.struct_field.value;
+ // In this first pass we resolve explicit tag values.
+ // In a second pass we will fill in the unspecified ones.
+ if (tag_value != nullptr) {
+ TypeTableEntry *tag_int_type = tag_type->data.enumeration.tag_int_type;
+ IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
+ if (result_inst->value.type->id == TypeTableEntryIdInvalid) {
+ union_type->data.unionation.is_invalid = true;
+ continue;
+ }
+ assert(result_inst->value.special != ConstValSpecialRuntime);
+ assert(result_inst->value.type->id == TypeTableEntryIdInt);
+ auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
+ if (entry == nullptr) {
+ bigint_init_bigint(&union_field->enum_field->value, &result_inst->value.data.x_bigint);
+ } else {
+ Buf *val_buf = buf_alloc();
+ bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10);
+
+ ErrorMsg *msg = add_node_error(g, tag_value,
+ buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf)));
+ add_error_note(g, msg, entry->value,
+ buf_sprintf("other occurrence here"));
+ union_type->data.unionation.is_invalid = true;
+ continue;
+ }
+ }
+ } else if (enum_type_node != nullptr) {
+ union_field->enum_field = find_enum_type_field(tag_type, field_name);
+ if (union_field->enum_field == nullptr) {
+ ErrorMsg *msg = add_node_error(g, field_node,
+ buf_sprintf("enum field not found: '%s'", buf_ptr(field_name)));
+ add_error_note(g, msg, tag_type->data.enumeration.decl_node,
+ buf_sprintf("enum declared here"));
+ union_type->data.unionation.is_invalid = true;
+ continue;
+ }
+ covered_enum_fields[union_field->enum_field->decl_index] = true;
+ } else {
+ union_field->enum_field = allocate(1);
+ union_field->enum_field->name = field_name;
+ union_field->enum_field->decl_index = i;
+ bigint_init_unsigned(&union_field->enum_field->value, i);
}
+ assert(union_field->enum_field != nullptr);
if (!type_has_bits(field_type))
continue;
@@ -2379,9 +2356,15 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
uint32_t field_align_bytes = get_abi_alignment(g, field_type);
if (field_align_bytes > biggest_align_bytes) {
biggest_align_bytes = field_align_bytes;
+ if (biggest_align_bytes > union_type->data.unionation.abi_alignment) {
+ union_type->data.unionation.abi_alignment = biggest_align_bytes;
+ }
}
}
+ if (union_type->data.unionation.is_invalid)
+ return;
+
bool src_have_tag = decl_node->data.container_decl.auto_enum ||
decl_node->data.container_decl.init_arg_expr != nullptr;
@@ -2405,15 +2388,66 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
return;
}
+ if (create_enum_type) {
+ // Now iterate again and populate the unspecified tag values
+ uint32_t next_maybe_unoccupied_index = 0;
+
+ for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
+ AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
+ TypeUnionField *union_field = &union_type->data.unionation.fields[field_i];
+ AstNode *tag_value = field_node->data.struct_field.value;
+
+ if (tag_value == nullptr) {
+ if (occupied_tag_values.size() == 0) {
+ bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index);
+ next_maybe_unoccupied_index += 1;
+ } else {
+ BigInt proposed_value;
+ for (;;) {
+ bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index);
+ next_maybe_unoccupied_index += 1;
+ auto entry = occupied_tag_values.put_unique(proposed_value, field_node);
+ if (entry != nullptr) {
+ continue;
+ }
+ break;
+ }
+ bigint_init_bigint(&union_field->enum_field->value, &proposed_value);
+ }
+ }
+ }
+ } 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]) {
+ 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,
+ buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name)));
+ add_error_note(g, msg, field_node,
+ buf_sprintf("declared here"));
+ union_type->data.unionation.is_invalid = true;
+ }
+ }
+ }
+
+ if (create_enum_type) {
+ ImportTableEntry *import = get_scope_import(scope);
+ uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
+ uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
+ // TODO get a more accurate debug scope
+ ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
+ ZigLLVMFileToScope(import->di_file), buf_ptr(&tag_type->name),
+ import->di_file, (unsigned)(decl_node->line + 1),
+ tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
+ tag_type->di_type, "");
+ tag_type->di_type = tag_di_type;
+ }
+
union_type->data.unionation.zero_bits_loop_flag = false;
union_type->data.unionation.gen_field_count = gen_field_index;
union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !src_have_tag));
union_type->data.unionation.zero_bits_known = true;
-
- // also compute abi_alignment
- if (!union_type->zero_bits) {
- union_type->data.unionation.abi_alignment = biggest_align_bytes;
- }
}
static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) {
diff --git a/src/ir.cpp b/src/ir.cpp
index e70340b300..d784974ae8 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -12970,10 +12970,13 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
ir_build_load_ptr_from(&ira->new_irb, &switch_target_instruction->base, target_value_ptr);
return target_type;
case TypeTableEntryIdUnion: {
- if (target_type->data.unionation.gen_tag_index == SIZE_MAX) {
+ AstNode *decl_node = target_type->data.unionation.decl_node;
+ if (!decl_node->data.container_decl.auto_enum &&
+ decl_node->data.container_decl.init_arg_expr == nullptr)
+ {
ErrorMsg *msg = ir_add_error(ira, target_value_ptr,
buf_sprintf("switch on union which has no attached enum"));
- add_error_note(ira->codegen, msg, target_type->data.unionation.decl_node,
+ add_error_note(ira->codegen, msg, decl_node,
buf_sprintf("union declared here"));
return ira->codegen->builtin_types.entry_invalid;
}
diff --git a/test/cases/union.zig b/test/cases/union.zig
index c4767fd649..291384eaeb 100644
--- a/test/cases/union.zig
+++ b/test/cases/union.zig
@@ -105,6 +105,18 @@ fn bar(value: &const Payload) -> i32 {
};
}
+const MultipleChoice = union(enum(u32)) {
+ A = 20,
+ B = 40,
+ C = 60,
+ D = 1000,
+};
+test "simple union(enum(u32))" {
+ var x = MultipleChoice.C;
+ assert(x == MultipleChoice.C);
+ assert(u32(@TagType(MultipleChoice)(x)) == 60);
+}
+
const MultipleChoice2 = union(enum(u32)) {
Unspecified1: i32,
A: f32 = 20,
@@ -137,3 +149,4 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) {
MultipleChoice2.Unspecified5 => 9,
});
}
+
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index ac06b5aa2a..e8a517b1ca 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -2524,4 +2524,51 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
,
".tmp_source.zig:6:17: error: enum field missing: 'C'",
".tmp_source.zig:4:5: note: declared here");
+
+ cases.add("@TagType when union has no attached enum",
+ \\const Foo = union {
+ \\ A: i32,
+ \\};
+ \\export fn entry() {
+ \\ const x = @TagType(Foo);
+ \\}
+ ,
+ ".tmp_source.zig:5:24: error: union 'Foo' has no tag",
+ ".tmp_source.zig:1:13: note: consider 'union(enum)' here");
+
+ cases.add("non-integer tag type to automatic union enum",
+ \\const Foo = union(enum(f32)) {
+ \\ A: i32,
+ \\};
+ \\export fn entry() {
+ \\ const x = @TagType(Foo);
+ \\}
+ ,
+ ".tmp_source.zig:1:23: error: expected integer tag type, found 'f32'");
+
+ cases.add("non-enum tag type passed to union",
+ \\const Foo = union(u32) {
+ \\ A: i32,
+ \\};
+ \\export fn entry() {
+ \\ const x = @TagType(Foo);
+ \\}
+ ,
+ ".tmp_source.zig:1:18: error: expected enum tag type, found 'u32'");
+
+ cases.add("union auto-enum value already taken",
+ \\const MultipleChoice = union(enum(u32)) {
+ \\ A = 20,
+ \\ B = 40,
+ \\ C = 60,
+ \\ D = 1000,
+ \\ E = 60,
+ \\};
+ \\export fn entry() {
+ \\ var x = MultipleChoice { .C = {} };
+ \\}
+ ,
+ ".tmp_source.zig:6:9: error: enum tag value 60 already taken",
+ ".tmp_source.zig:4:9: note: other occurrence here");
+
}
From 05d9f07541c8c5b788687046ad313c6cff211476 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 4 Dec 2017 00:56:27 -0500
Subject: [PATCH 25/32] more tests for unions
See #618
---
src/ir.cpp | 2 +-
test/compile_errors.zig | 115 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 115 insertions(+), 2 deletions(-)
diff --git a/src/ir.cpp b/src/ir.cpp
index d784974ae8..facd7087f0 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -12977,7 +12977,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
ErrorMsg *msg = ir_add_error(ira, target_value_ptr,
buf_sprintf("switch on union which has no attached enum"));
add_error_note(ira->codegen, msg, decl_node,
- buf_sprintf("union declared here"));
+ buf_sprintf("consider 'union(enum)' here"));
return ira->codegen->builtin_types.entry_invalid;
}
TypeTableEntry *tag_type = target_type->data.unionation.tag_type;
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index e8a517b1ca..5d13ed8d48 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -2479,7 +2479,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\ A: i32 = 20,
\\};
\\export fn entry() {
- \\ var x: MultipleChoice = undefined;
+ \\ var x: MultipleChoice = undefined;
\\}
,
".tmp_source.zig:2:14: error: non-enum union field assignment",
@@ -2493,6 +2493,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
,
".tmp_source.zig:1:13: error: enums must have 1 or more fields");
+ cases.add("union with 0 fields",
+ \\const Foo = union {};
+ \\export fn entry() -> usize {
+ \\ return @sizeOf(Foo);
+ \\}
+ ,
+ ".tmp_source.zig:1:13: error: unions must have 1 or more fields");
+
cases.add("enum value already taken",
\\const MultipleChoice = enum(u32) {
\\ A = 20,
@@ -2571,4 +2579,109 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
".tmp_source.zig:6:9: error: enum tag value 60 already taken",
".tmp_source.zig:4:9: note: other occurrence here");
+ cases.add("union enum field does not match enum",
+ \\const Letter = enum {
+ \\ A,
+ \\ B,
+ \\ C,
+ \\};
+ \\const Payload = union(Letter) {
+ \\ A: i32,
+ \\ B: f64,
+ \\ C: bool,
+ \\ D: bool,
+ \\};
+ \\export fn entry() {
+ \\ var a = Payload {.A = 1234};
+ \\}
+ ,
+ ".tmp_source.zig:10:5: error: enum field not found: 'D'",
+ ".tmp_source.zig:1:16: note: enum declared here");
+
+ cases.add("field type supplied in an enum",
+ \\const Letter = enum {
+ \\ A: void,
+ \\ B,
+ \\ C,
+ \\};
+ \\export fn entry() {
+ \\ var b = Letter.B;
+ \\}
+ ,
+ ".tmp_source.zig:2:8: error: structs and unions, not enums, support field types",
+ ".tmp_source.zig:1:16: note: consider 'union(enum)' here");
+
+ cases.add("struct field missing type",
+ \\const Letter = struct {
+ \\ A,
+ \\};
+ \\export fn entry() {
+ \\ var a = Letter { .A = {} };
+ \\}
+ ,
+ ".tmp_source.zig:2:5: error: struct field missing type");
+
+ cases.add("extern union field missing type",
+ \\const Letter = extern union {
+ \\ A,
+ \\};
+ \\export fn entry() {
+ \\ var a = Letter { .A = {} };
+ \\}
+ ,
+ ".tmp_source.zig:2:5: error: union field missing type");
+
+ cases.add("extern union given enum tag type",
+ \\const Letter = enum {
+ \\ A,
+ \\ B,
+ \\ C,
+ \\};
+ \\const Payload = extern union(Letter) {
+ \\ A: i32,
+ \\ B: f64,
+ \\ C: bool,
+ \\};
+ \\export fn entry() {
+ \\ var a = Payload { .A = { 1234 } };
+ \\}
+ ,
+ ".tmp_source.zig:6:29: error: extern union does not support enum tag type");
+
+ cases.add("packed union given enum tag type",
+ \\const Letter = enum {
+ \\ A,
+ \\ B,
+ \\ C,
+ \\};
+ \\const Payload = packed union(Letter) {
+ \\ A: i32,
+ \\ B: f64,
+ \\ C: bool,
+ \\};
+ \\export fn entry() {
+ \\ var a = Payload { .A = { 1234 } };
+ \\}
+ ,
+ ".tmp_source.zig:6:29: error: packed union does not support enum tag type");
+
+ cases.add("switch on union with no attached enum",
+ \\const Payload = union {
+ \\ A: i32,
+ \\ B: f64,
+ \\ C: bool,
+ \\};
+ \\export fn entry() {
+ \\ const a = Payload { .A = { 1234 } };
+ \\ foo(a);
+ \\}
+ \\fn foo(a: &const Payload) {
+ \\ switch (*a) {
+ \\ Payload.A => {},
+ \\ else => unreachable,
+ \\ }
+ \\}
+ ,
+ ".tmp_source.zig:11:13: error: switch on union which has no attached enum",
+ ".tmp_source.zig:1:17: note: consider 'union(enum)' here");
}
From 942b250895581f01adf52b3d5addd99b7a4bc0d3 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 4 Dec 2017 01:42:02 -0500
Subject: [PATCH 26/32] update docs regarding enums and unions
---
doc/langref.html.in | 211 ++++++++++++++++++++++++++++++++++----------
1 file changed, 163 insertions(+), 48 deletions(-)
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 76bf0ce237..e5b896410d 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -2096,30 +2096,38 @@ const Type = enum {
NotOk,
};
-// Enums are sum types, and can hold more complex data of different types.
-const ComplexType = enum {
- Ok: u8,
- NotOk: void,
-};
-
// Declare a specific instance of the enum variant.
-const c = ComplexType.Ok { 0 };
+const c = Type.Ok;
-// The ordinal value of a simple enum with no data members can be
-// retrieved by a simple cast.
-// The value starts from 0, counting up for each member.
-const Value = enum {
+// If you want access to the ordinal value of an enum, you
+// can specify the tag type.
+const Value = enum(u2) {
Zero,
One,
Two,
};
+
+// Now you can cast between u2 and Value.
+// The ordinal value starts from 0, counting up for each member.
test "enum ordinal value" {
- assert(usize(Value.Zero) == 0);
- assert(usize(Value.One) == 1);
- assert(usize(Value.Two) == 2);
+ assert(u2(Value.Zero) == 0);
+ assert(u2(Value.One) == 1);
+ assert(u2(Value.Two) == 2);
}
-// Enums can have methods, the same as structs.
+// You can override the ordinal value for an enum.
+const Value2 = enum(u32) {
+ Hundred = 100,
+ Thousand = 1000,
+ Million = 1000000,
+};
+test "set enum ordinal value" {
+ assert(u32(Value2.Hundred) == 100);
+ assert(u32(Value2.Thousand) == 1000);
+ assert(u32(Value2.Million) == 1000000);
+}
+
+// Enums can have methods, the same as structs and unions.
// Enum methods are not special, they are only namespaced
// functions that you can call with dot syntax.
const Suit = enum {
@@ -2128,26 +2136,120 @@ const Suit = enum {
Diamonds,
Hearts,
- pub fn ordinal(self: &const Suit) -> u8 {
- u8(*self)
+ pub fn isClubs(self: Suit) -> bool {
+ return self == Suit.Clubs;
}
};
test "enum method" {
const p = Suit.Spades;
- assert(p.ordinal() == 1);
+ assert(!p.isClubs());
}
// An enum variant of different types can be switched upon.
-// The associated data can be retrieved using `|...|` syntax.
-//
-// A void type is not required on a tag-only member.
const Foo = enum {
- String: []const u8,
- Number: u64,
+ String,
+ Number,
None,
};
test "enum variant switch" {
- const p = Foo.Number { 54 };
+ const p = Foo.Number;
+ const what_is_it = switch (p) {
+ Foo.String => "this is a string",
+ Foo.Number => "this is a number",
+ Foo.None => "this is a none",
+ };
+ assert(mem.eql(u8, what_is_it, "this is a number"));
+}
+
+// @TagType can be used to access the integer tag type of an enum.
+const Small = enum {
+ One,
+ Two,
+ Three,
+ Four,
+};
+test "@TagType" {
+ assert(@TagType(Small) == u2);
+}
+
+// @memberCount tells how many fields an enum has:
+test "@memberCount" {
+ assert(@memberCount(Small) == 4);
+}
+
+// @memberName tells the name of a field in an enum:
+test "@memberName" {
+ assert(mem.eql(u8, @memberName(Small, 1), "Two"));
+}
+
+// @tagName gives a []const u8 representation of an enum value:
+test "@tagName" {
+ assert(mem.eql(u8, @tagName(Small.Three), "Three"));
+}
+ TODO extern enum
+ TODO packed enum
+ $ zig test enum.zig
+Test 1/8 enum ordinal value...OK
+Test 2/8 set enum ordinal value...OK
+Test 3/8 enum method...OK
+Test 4/8 enum variant switch...OK
+Test 5/8 @TagType...OK
+Test 6/8 @memberCount...OK
+Test 7/8 @memberName...OK
+Test 8/8 @tagName...OK
+ See also:
+
+ union
+ const assert = @import("std").debug.assert;
+const mem = @import("std").mem;
+
+// A union has only 1 active field at a time.
+const Payload = union {
+ Int: i64,
+ Float: f64,
+ Bool: bool,
+};
+test "simple union" {
+ var payload = Payload {.Int = 1234};
+ // payload.Float = 12.34; // ERROR! field not active
+ assert(payload.Int == 1234);
+ // You can activate another field by assigning the entire union.
+ payload = Payload {.Float = 12.34};
+ assert(payload.Float == 12.34);
+}
+
+// Unions can be given an enum tag type:
+const ComplexTypeTag = enum { Ok, NotOk };
+const ComplexType = union(ComplexTypeTag) {
+ Ok: u8,
+ NotOk: void,
+};
+
+// Declare a specific instance of the union variant.
+test "declare union value" {
+ const c = ComplexType { .Ok = 0 };
+ assert(ComplexTypeTag(c) == ComplexTypeTag.Ok);
+}
+
+// @TagType can be used to access the enum tag type of a union.
+test "@TagType" {
+ assert(@TagType(ComplexType) == ComplexTypeTag);
+}
+
+// Unions can be made to infer the enum tag type.
+const Foo = union(enum) {
+ String: []const u8,
+ Number: u64,
+
+ // void can be omitted when inferring enum tag type.
+ None,
+};
+test "union variant switch" {
+ const p = Foo { .Number = 54 };
const what_is_it = switch (p) {
// Capture by reference
Foo.String => |*x| {
@@ -2156,6 +2258,7 @@ test "enum variant switch" {
// Capture by value
Foo.Number => |x| {
+ assert(x == 54);
"this is a number"
},
@@ -2163,38 +2266,50 @@ test "enum variant switch" {
"this is a none"
}
};
+ assert(mem.eql(u8, what_is_it, "this is a number"));
}
-// The @memberName and @memberCount builtin functions can be used to
-// the string representation and number of members respectively.
-const BuiltinType = enum {
- A: f32,
- B: u32,
- C,
+// TODO union methods
+
+
+const Small = union {
+ A: i32,
+ B: bool,
+ C: u8,
};
-test "enum builtins" {
- assert(mem.eql(u8, @memberName(BuiltinType.A { 0 }), "A"));
- assert(mem.eql(u8, @memberName(BuiltinType.C), "C"));
- assert(@memberCount(BuiltinType) == 3);
+// @memberCount tells how many fields a union has:
+test "@memberCount" {
+ assert(@memberCount(Small) == 3);
+}
+
+// @memberName tells the name of a field in an enum:
+test "@memberName" {
+ assert(mem.eql(u8, @memberName(Small, 1), "B"));
+}
+
+// @tagName gives a []const u8 representation of an enum value,
+// but only if the union has an enum tag type.
+const Small2 = union(enum) {
+ A: i32,
+ B: bool,
+ C: u8,
+};
+test "@tagName" {
+ assert(mem.eql(u8, @tagName(Small2.C), "C"));
}
- $ zig test enum.zig
-Test 1/4 enum ordinal value...OK
-Test 2/4 enum method...OK
-Test 3/4 enum variant switch...OK
-Test 4/4 enum builtins...OK
+ $ zig test union.zig
+Test 1/7 simple union...OK
+Test 2/7 declare union value...OK
+Test 3/7 @TagType...OK
+Test 4/7 union variant switch...OK
+Test 5/7 @memberCount...OK
+Test 6/7 @memberName...OK
+Test 7/7 @tagName...OK
- Enums are generated as a struct with a tag field and union field. Zig
+ Unions with an enum tag are generated as a struct with a tag field and union field. Zig
sorts the order of the tag and union field by the largest alignment.
- See also:
-
- union
- TODO union documentation
switch
const assert = @import("std").debug.assert;
const builtin = @import("builtin");
From 084911d9b376fa9bea2567f53854511adc6d07ec Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 4 Dec 2017 02:04:08 -0500
Subject: [PATCH 27/32] add test for @sizeOf on extern and packed unions
---
test/cases/union.zig | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/test/cases/union.zig b/test/cases/union.zig
index 291384eaeb..fb0ca1238d 100644
--- a/test/cases/union.zig
+++ b/test/cases/union.zig
@@ -150,3 +150,19 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) {
});
}
+
+const ExternPtrOrInt = extern union {
+ ptr: &u8,
+ int: u64
+};
+test "extern union size" {
+ comptime assert(@sizeOf(ExternPtrOrInt) == 8);
+}
+
+const PackedPtrOrInt = packed union {
+ ptr: &u8,
+ int: u64
+};
+test "extern union size" {
+ comptime assert(@sizeOf(PackedPtrOrInt) == 8);
+}
From 54138d9e82d545094a85435ef862a6d4894e859e Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 4 Dec 2017 02:05:33 -0500
Subject: [PATCH 28/32] add test for union with 1 void field being 0 bits
---
test/cases/union.zig | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/test/cases/union.zig b/test/cases/union.zig
index fb0ca1238d..13bc084551 100644
--- a/test/cases/union.zig
+++ b/test/cases/union.zig
@@ -166,3 +166,10 @@ const PackedPtrOrInt = packed union {
test "extern union size" {
comptime assert(@sizeOf(PackedPtrOrInt) == 8);
}
+
+const ZeroBits = union {
+ OnlyField: void,
+};
+test "union with only 1 field which is void should be zero bits" {
+ comptime assert(@sizeOf(ZeroBits) == 0);
+}
From dd3437d5ba30c2101719fa38a95914fae5d965dd Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 4 Dec 2017 02:08:26 -0500
Subject: [PATCH 29/32] fix build on windows
---
std/os/child_process.zig | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/std/os/child_process.zig b/std/os/child_process.zig
index 3a4c9410c5..0548592f56 100644
--- a/std/os/child_process.zig
+++ b/std/os/child_process.zig
@@ -213,9 +213,9 @@ pub const ChildProcess = struct {
self.term = (%Term)({
var exit_code: windows.DWORD = undefined;
if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {
- Term.Unknown{0}
+ Term { .Unknown = 0 }
} else {
- Term.Exited {@bitCast(i32, exit_code)}
+ Term { .Exited = @bitCast(i32, exit_code)}
}
});
From 76f3bdfff8224144e7b57748eb8eda2001d0308d Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 4 Dec 2017 02:12:13 -0500
Subject: [PATCH 30/32] add test for casting union to tag type of union
---
test/cases/union.zig | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/test/cases/union.zig b/test/cases/union.zig
index 13bc084551..1db9a1bef1 100644
--- a/test/cases/union.zig
+++ b/test/cases/union.zig
@@ -173,3 +173,20 @@ const ZeroBits = union {
test "union with only 1 field which is void should be zero bits" {
comptime assert(@sizeOf(ZeroBits) == 0);
}
+
+const TheTag = enum {A, B, C};
+const TheUnion = union(TheTag) { A: i32, B: i32, C: i32 };
+test "union field access gives the enum values" {
+ assert(TheUnion.A == TheTag.A);
+ assert(TheUnion.B == TheTag.B);
+ assert(TheUnion.C == TheTag.C);
+}
+
+test "cast union to tag type of union" {
+ testCastUnionToTagType(TheUnion {.B = 1234});
+ comptime testCastUnionToTagType(TheUnion {.B = 1234});
+}
+
+fn testCastUnionToTagType(x: &const TheUnion) {
+ assert(TheTag(*x) == TheTag.B);
+}
From fea016afc0c1102a4847f4e5676260b14d81096e Mon Sep 17 00:00:00 2001
From: MIURA Masahiro
Date: Mon, 4 Dec 2017 19:22:34 +0900
Subject: [PATCH 31/32] Fix the color of compiler messages for light-themed
terminal.
---
src/errmsg.cpp | 8 ++++----
src/os.cpp | 5 +++++
src/os.hpp | 1 +
3 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/src/errmsg.cpp b/src/errmsg.cpp
index 01c3ee8429..edbfd858a8 100644
--- a/src/errmsg.cpp
+++ b/src/errmsg.cpp
@@ -24,20 +24,20 @@ static void print_err_msg_type(ErrorMsg *err, ErrColor color, ErrType err_type)
bool is_tty = os_stderr_tty();
if (color == ErrColorOn || (color == ErrColorAuto && is_tty)) {
if (err_type == ErrTypeError) {
- os_stderr_set_color(TermColorWhite);
+ os_stderr_set_color(TermColorBold);
fprintf(stderr, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ": ", path, line, col);
os_stderr_set_color(TermColorRed);
fprintf(stderr, "error:");
- os_stderr_set_color(TermColorWhite);
+ os_stderr_set_color(TermColorBold);
fprintf(stderr, " %s", text);
os_stderr_set_color(TermColorReset);
fprintf(stderr, "\n");
} else if (err_type == ErrTypeNote) {
- os_stderr_set_color(TermColorWhite);
+ os_stderr_set_color(TermColorBold);
fprintf(stderr, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ": ", path, line, col);
os_stderr_set_color(TermColorCyan);
fprintf(stderr, "note:");
- os_stderr_set_color(TermColorWhite);
+ os_stderr_set_color(TermColorBold);
fprintf(stderr, " %s", text);
os_stderr_set_color(TermColorReset);
fprintf(stderr, "\n");
diff --git a/src/os.cpp b/src/os.cpp
index 6c242bc350..a59fa12657 100644
--- a/src/os.cpp
+++ b/src/os.cpp
@@ -931,6 +931,7 @@ int os_self_exe_path(Buf *out_path) {
#define VT_GREEN "\x1b[32;1m"
#define VT_CYAN "\x1b[36;1m"
#define VT_WHITE "\x1b[37;1m"
+#define VT_BOLD "\x1b[0;1m"
#define VT_RESET "\x1b[0m"
static void set_color_posix(TermColor color) {
@@ -947,6 +948,9 @@ static void set_color_posix(TermColor color) {
case TermColorWhite:
fprintf(stderr, VT_WHITE);
break;
+ case TermColorBold:
+ fprintf(stderr, VT_BOLD);
+ break;
case TermColorReset:
fprintf(stderr, VT_RESET);
break;
@@ -989,6 +993,7 @@ void os_stderr_set_color(TermColor color) {
SetConsoleTextAttribute(stderr_handle, FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY);
break;
case TermColorWhite:
+ case TermColorBold:
SetConsoleTextAttribute(stderr_handle,
FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY);
break;
diff --git a/src/os.hpp b/src/os.hpp
index 611779f7c8..d4d1676df6 100644
--- a/src/os.hpp
+++ b/src/os.hpp
@@ -21,6 +21,7 @@ enum TermColor {
TermColorGreen,
TermColorCyan,
TermColorWhite,
+ TermColorBold,
TermColorReset,
};
From a966275e509670e750ef54a37f7202078aa4cf07 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Mon, 4 Dec 2017 10:35:55 -0500
Subject: [PATCH 32/32] rename builtin.is_big_endian to builtin.endian
See #307
---
example/guess_number/main.zig | 3 +-
src/codegen.cpp | 14 ++++-
std/debug.zig | 18 +++----
std/elf.zig | 79 +++++++++++++++--------------
std/endian.zig | 4 +-
std/io.zig | 12 ++---
std/mem.zig | 69 ++++++++++++++-----------
std/os/child_process.zig | 4 +-
std/rand.zig | 6 +--
std/special/compiler_rt/udivmod.zig | 2 +-
10 files changed, 116 insertions(+), 95 deletions(-)
diff --git a/example/guess_number/main.zig b/example/guess_number/main.zig
index 20a2fefc9f..db7e38ada3 100644
--- a/example/guess_number/main.zig
+++ b/example/guess_number/main.zig
@@ -1,3 +1,4 @@
+const builtin = @import("builtin");
const std = @import("std");
const io = std.io;
const fmt = std.fmt;
@@ -15,7 +16,7 @@ pub fn main() -> %void {
var seed_bytes: [@sizeOf(usize)]u8 = undefined;
%%os.getRandomBytes(seed_bytes[0..]);
- const seed = std.mem.readInt(seed_bytes, usize, true);
+ const seed = std.mem.readInt(seed_bytes, usize, builtin.Endian.Big);
var rand = Rand.init(seed);
const answer = rand.range(u8, 0, 100) + 1;
diff --git a/src/codegen.cpp b/src/codegen.cpp
index bd84310ff1..e10d260e6e 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -5129,7 +5129,19 @@ static void define_builtin_compile_vars(CodeGen *g) {
assert(FloatModeOptimized == 0);
assert(FloatModeStrict == 1);
}
- buf_appendf(contents, "pub const is_big_endian = %s;\n", bool_to_str(g->is_big_endian));
+ {
+ buf_appendf(contents,
+ "pub const Endian = enum {\n"
+ " Big,\n"
+ " Little,\n"
+ "};\n\n");
+ assert(FloatModeOptimized == 0);
+ assert(FloatModeStrict == 1);
+ }
+ {
+ const char *endian_str = g->is_big_endian ? "Endian.Big" : "Endian.Little";
+ buf_appendf(contents, "pub const endian = %s;\n", endian_str);
+ }
buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));
buf_appendf(contents, "pub const os = Os.%s;\n", cur_os);
buf_appendf(contents, "pub const arch = Arch.%s;\n", cur_arch);
diff --git a/std/debug.zig b/std/debug.zig
index 5bfa436614..a2bea9eddd 100644
--- a/std/debug.zig
+++ b/std/debug.zig
@@ -303,7 +303,7 @@ const Constant = struct {
return error.InvalidDebugInfo;
if (self.signed)
return error.InvalidDebugInfo;
- return mem.readInt(self.payload, u64, false);
+ return mem.readInt(self.payload, u64, builtin.Endian.Little);
}
};
@@ -479,7 +479,7 @@ fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, si
}
fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
- const block_len = %return in_stream.readVarInt(false, usize, size);
+ const block_len = %return in_stream.readVarInt(builtin.Endian.Little, usize, size);
return parseFormValueBlockLen(allocator, in_stream, block_len);
}
@@ -669,10 +669,10 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
continue;
}
- const version = %return in_stream.readInt(st.elf.is_big_endian, u16);
+ const version = %return in_stream.readInt(st.elf.endian, u16);
if (version != 2) return error.InvalidDebugInfo;
- const prologue_length = %return in_stream.readInt(st.elf.is_big_endian, u32);
+ const prologue_length = %return in_stream.readInt(st.elf.endian, u32);
const prog_start_offset = (%return in_file.getPos()) + prologue_length;
const minimum_instruction_length = %return in_stream.readByte();
@@ -739,7 +739,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
return error.MissingDebugInfo;
},
DW.LNE_set_address => {
- const addr = %return in_stream.readInt(st.elf.is_big_endian, usize);
+ const addr = %return in_stream.readInt(st.elf.endian, usize);
prog.address = addr;
},
DW.LNE_define_file => {
@@ -801,7 +801,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
prog.address += inc_addr;
},
DW.LNS_fixed_advance_pc => {
- const arg = %return in_stream.readInt(st.elf.is_big_endian, u16);
+ const arg = %return in_stream.readInt(st.elf.endian, u16);
prog.address += arg;
},
DW.LNS_set_prologue_end => {
@@ -839,13 +839,13 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
return;
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
- const version = %return in_stream.readInt(st.elf.is_big_endian, u16);
+ const version = %return in_stream.readInt(st.elf.endian, u16);
if (version < 2 or version > 5) return error.InvalidDebugInfo;
const debug_abbrev_offset = if (is_64) {
- %return in_stream.readInt(st.elf.is_big_endian, u64)
+ %return in_stream.readInt(st.elf.endian, u64)
} else {
- %return in_stream.readInt(st.elf.is_big_endian, u32)
+ %return in_stream.readInt(st.elf.endian, u32)
};
const address_size = %return in_stream.readByte();
diff --git a/std/elf.zig b/std/elf.zig
index f3f7de512f..f7be236d15 100644
--- a/std/elf.zig
+++ b/std/elf.zig
@@ -1,3 +1,4 @@
+const builtin = @import("builtin");
const std = @import("index.zig");
const io = std.io;
const math = std.math;
@@ -67,7 +68,7 @@ pub const Elf = struct {
in_file: &io.File,
auto_close_stream: bool,
is_64: bool,
- is_big_endian: bool,
+ endian: builtin.Endian,
file_type: FileType,
arch: Arch,
entry_addr: u64,
@@ -105,9 +106,9 @@ pub const Elf = struct {
else => return error.InvalidFormat,
};
- elf.is_big_endian = switch (%return in.readByte()) {
- 1 => false,
- 2 => true,
+ elf.endian = switch (%return in.readByte()) {
+ 1 => builtin.Endian.Little,
+ 2 => builtin.Endian.Big,
else => return error.InvalidFormat,
};
@@ -117,7 +118,7 @@ pub const Elf = struct {
// skip over padding
%return elf.in_file.seekForward(9);
- elf.file_type = switch (%return in.readInt(elf.is_big_endian, u16)) {
+ elf.file_type = switch (%return in.readInt(elf.endian, u16)) {
1 => FileType.Relocatable,
2 => FileType.Executable,
3 => FileType.Shared,
@@ -125,7 +126,7 @@ pub const Elf = struct {
else => return error.InvalidFormat,
};
- elf.arch = switch (%return in.readInt(elf.is_big_endian, u16)) {
+ elf.arch = switch (%return in.readInt(elf.endian, u16)) {
0x02 => Arch.Sparc,
0x03 => Arch.x86,
0x08 => Arch.Mips,
@@ -138,34 +139,34 @@ pub const Elf = struct {
else => return error.InvalidFormat,
};
- const elf_version = %return in.readInt(elf.is_big_endian, u32);
+ const elf_version = %return in.readInt(elf.endian, u32);
if (elf_version != 1) return error.InvalidFormat;
if (elf.is_64) {
- elf.entry_addr = %return in.readInt(elf.is_big_endian, u64);
- elf.program_header_offset = %return in.readInt(elf.is_big_endian, u64);
- elf.section_header_offset = %return in.readInt(elf.is_big_endian, u64);
+ elf.entry_addr = %return in.readInt(elf.endian, u64);
+ elf.program_header_offset = %return in.readInt(elf.endian, u64);
+ elf.section_header_offset = %return in.readInt(elf.endian, u64);
} else {
- elf.entry_addr = u64(%return in.readInt(elf.is_big_endian, u32));
- elf.program_header_offset = u64(%return in.readInt(elf.is_big_endian, u32));
- elf.section_header_offset = u64(%return in.readInt(elf.is_big_endian, u32));
+ elf.entry_addr = u64(%return in.readInt(elf.endian, u32));
+ elf.program_header_offset = u64(%return in.readInt(elf.endian, u32));
+ elf.section_header_offset = u64(%return in.readInt(elf.endian, u32));
}
// skip over flags
%return elf.in_file.seekForward(4);
- const header_size = %return in.readInt(elf.is_big_endian, u16);
+ const header_size = %return in.readInt(elf.endian, u16);
if ((elf.is_64 and header_size != 64) or
(!elf.is_64 and header_size != 52))
{
return error.InvalidFormat;
}
- const ph_entry_size = %return in.readInt(elf.is_big_endian, u16);
- const ph_entry_count = %return in.readInt(elf.is_big_endian, u16);
- const sh_entry_size = %return in.readInt(elf.is_big_endian, u16);
- const sh_entry_count = %return in.readInt(elf.is_big_endian, u16);
- elf.string_section_index = u64(%return in.readInt(elf.is_big_endian, u16));
+ const ph_entry_size = %return in.readInt(elf.endian, u16);
+ const ph_entry_count = %return in.readInt(elf.endian, u16);
+ const sh_entry_size = %return in.readInt(elf.endian, u16);
+ const sh_entry_count = %return in.readInt(elf.endian, u16);
+ elf.string_section_index = u64(%return in.readInt(elf.endian, u16));
if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat;
@@ -188,32 +189,32 @@ pub const Elf = struct {
if (sh_entry_size != 64) return error.InvalidFormat;
for (elf.section_headers) |*section| {
- section.name = %return in.readInt(elf.is_big_endian, u32);
- section.sh_type = %return in.readInt(elf.is_big_endian, u32);
- section.flags = %return in.readInt(elf.is_big_endian, u64);
- section.addr = %return in.readInt(elf.is_big_endian, u64);
- section.offset = %return in.readInt(elf.is_big_endian, u64);
- section.size = %return in.readInt(elf.is_big_endian, u64);
- section.link = %return in.readInt(elf.is_big_endian, u32);
- section.info = %return in.readInt(elf.is_big_endian, u32);
- section.addr_align = %return in.readInt(elf.is_big_endian, u64);
- section.ent_size = %return in.readInt(elf.is_big_endian, u64);
+ section.name = %return in.readInt(elf.endian, u32);
+ section.sh_type = %return in.readInt(elf.endian, u32);
+ section.flags = %return in.readInt(elf.endian, u64);
+ section.addr = %return in.readInt(elf.endian, u64);
+ section.offset = %return in.readInt(elf.endian, u64);
+ section.size = %return in.readInt(elf.endian, u64);
+ section.link = %return in.readInt(elf.endian, u32);
+ section.info = %return in.readInt(elf.endian, u32);
+ section.addr_align = %return in.readInt(elf.endian, u64);
+ section.ent_size = %return in.readInt(elf.endian, u64);
}
} else {
if (sh_entry_size != 40) return error.InvalidFormat;
for (elf.section_headers) |*section| {
// TODO (multiple occurences) allow implicit cast from %u32 -> %u64 ?
- section.name = %return in.readInt(elf.is_big_endian, u32);
- section.sh_type = %return in.readInt(elf.is_big_endian, u32);
- section.flags = u64(%return in.readInt(elf.is_big_endian, u32));
- section.addr = u64(%return in.readInt(elf.is_big_endian, u32));
- section.offset = u64(%return in.readInt(elf.is_big_endian, u32));
- section.size = u64(%return in.readInt(elf.is_big_endian, u32));
- section.link = %return in.readInt(elf.is_big_endian, u32);
- section.info = %return in.readInt(elf.is_big_endian, u32);
- section.addr_align = u64(%return in.readInt(elf.is_big_endian, u32));
- section.ent_size = u64(%return in.readInt(elf.is_big_endian, u32));
+ section.name = %return in.readInt(elf.endian, u32);
+ section.sh_type = %return in.readInt(elf.endian, u32);
+ section.flags = u64(%return in.readInt(elf.endian, u32));
+ section.addr = u64(%return in.readInt(elf.endian, u32));
+ section.offset = u64(%return in.readInt(elf.endian, u32));
+ section.size = u64(%return in.readInt(elf.endian, u32));
+ section.link = %return in.readInt(elf.endian, u32);
+ section.info = %return in.readInt(elf.endian, u32);
+ section.addr_align = u64(%return in.readInt(elf.endian, u32));
+ section.ent_size = u64(%return in.readInt(elf.endian, u32));
}
}
diff --git a/std/endian.zig b/std/endian.zig
index 8ae8ae22f8..2dc6b8d34e 100644
--- a/std/endian.zig
+++ b/std/endian.zig
@@ -9,8 +9,8 @@ pub fn swapIfBe(comptime T: type, x: T) -> T {
swapIf(true, T, x)
}
-pub fn swapIf(is_be: bool, comptime T: type, x: T) -> T {
- if (builtin.is_big_endian == is_be) swap(T, x) else x
+pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T {
+ if (builtin.endian == endian) swap(T, x) else x
}
pub fn swap(comptime T: type, x: T) -> T {
diff --git a/std/io.zig b/std/io.zig
index 6c6c171997..c86ebed326 100644
--- a/std/io.zig
+++ b/std/io.zig
@@ -441,26 +441,26 @@ pub const InStream = struct {
}
pub fn readIntLe(self: &InStream, comptime T: type) -> %T {
- return self.readInt(false, T);
+ return self.readInt(builtin.Endian.Little, T);
}
pub fn readIntBe(self: &InStream, comptime T: type) -> %T {
- return self.readInt(true, T);
+ return self.readInt(builtin.Endian.Big, T);
}
- pub fn readInt(self: &InStream, is_be: bool, comptime T: type) -> %T {
+ pub fn readInt(self: &InStream, endian: builtin.Endian, comptime T: type) -> %T {
var bytes: [@sizeOf(T)]u8 = undefined;
%return self.readNoEof(bytes[0..]);
- return mem.readInt(bytes, T, is_be);
+ return mem.readInt(bytes, T, endian);
}
- pub fn readVarInt(self: &InStream, is_be: bool, comptime T: type, size: usize) -> %T {
+ pub fn readVarInt(self: &InStream, endian: builtin.Endian, comptime T: type, size: usize) -> %T {
assert(size <= @sizeOf(T));
assert(size <= 8);
var input_buf: [8]u8 = undefined;
const input_slice = input_buf[0..size];
%return self.readNoEof(input_slice);
- return mem.readInt(input_slice, T, is_be);
+ return mem.readInt(input_slice, T, endian);
}
diff --git a/std/mem.zig b/std/mem.zig
index 9d78b1513b..815e122812 100644
--- a/std/mem.zig
+++ b/std/mem.zig
@@ -1,6 +1,7 @@
const debug = @import("debug.zig");
const assert = debug.assert;
const math = @import("math/index.zig");
+const builtin = @import("builtin");
pub const Cmp = math.Cmp;
@@ -181,20 +182,23 @@ test "mem.indexOf" {
/// T specifies the return type, which must be large enough to store
/// the result.
/// See also ::readIntBE or ::readIntLE.
-pub fn readInt(bytes: []const u8, comptime T: type, big_endian: bool) -> T {
+pub fn readInt(bytes: []const u8, comptime T: type, endian: builtin.Endian) -> T {
if (T.bit_count == 8) {
return bytes[0];
}
var result: T = 0;
- if (big_endian) {
- for (bytes) |b| {
- result = (result << 8) | b;
- }
- } else {
- const ShiftType = math.Log2Int(T);
- for (bytes) |b, index| {
- result = result | (T(b) << ShiftType(index * 8));
- }
+ switch (endian) {
+ builtin.Endian.Big => {
+ for (bytes) |b| {
+ result = (result << 8) | b;
+ }
+ },
+ builtin.Endian.Little => {
+ const ShiftType = math.Log2Int(T);
+ for (bytes) |b, index| {
+ result = result | (T(b) << ShiftType(index * 8));
+ }
+ },
}
return result;
}
@@ -230,22 +234,25 @@ pub fn readIntLE(comptime T: type, bytes: []const u8) -> T {
/// Writes an integer to memory with size equal to bytes.len. Pads with zeroes
/// to fill the entire buffer provided.
/// value must be an integer.
-pub fn writeInt(buf: []u8, value: var, big_endian: bool) {
+pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) {
const uint = @IntType(false, @typeOf(value).bit_count);
var bits = @truncate(uint, value);
- if (big_endian) {
- var index: usize = buf.len;
- while (index != 0) {
- index -= 1;
+ switch (endian) {
+ builtin.Endian.Big => {
+ var index: usize = buf.len;
+ while (index != 0) {
+ index -= 1;
- buf[index] = @truncate(u8, bits);
- bits >>= 8;
- }
- } else {
- for (buf) |*b| {
- *b = @truncate(u8, bits);
- bits >>= 8;
- }
+ buf[index] = @truncate(u8, bits);
+ bits >>= 8;
+ }
+ },
+ builtin.Endian.Little => {
+ for (buf) |*b| {
+ *b = @truncate(u8, bits);
+ bits >>= 8;
+ }
+ },
}
assert(bits == 0);
}
@@ -377,21 +384,21 @@ test "testReadInt" {
fn testReadIntImpl() {
{
const bytes = []u8{ 0x12, 0x34, 0x56, 0x78 };
- assert(readInt(bytes, u32, true) == 0x12345678);
+ assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678);
assert(readIntBE(u32, bytes) == 0x12345678);
assert(readIntBE(i32, bytes) == 0x12345678);
- assert(readInt(bytes, u32, false) == 0x78563412);
+ assert(readInt(bytes, u32, builtin.Endian.Little) == 0x78563412);
assert(readIntLE(u32, bytes) == 0x78563412);
assert(readIntLE(i32, bytes) == 0x78563412);
}
{
const buf = []u8{0x00, 0x00, 0x12, 0x34};
- const answer = readInt(buf, u64, true);
+ const answer = readInt(buf, u64, builtin.Endian.Big);
assert(answer == 0x00001234);
}
{
const buf = []u8{0x12, 0x34, 0x00, 0x00};
- const answer = readInt(buf, u64, false);
+ const answer = readInt(buf, u64, builtin.Endian.Little);
assert(answer == 0x00003412);
}
{
@@ -410,16 +417,16 @@ test "testWriteInt" {
fn testWriteIntImpl() {
var bytes: [4]u8 = undefined;
- writeInt(bytes[0..], u32(0x12345678), true);
+ writeInt(bytes[0..], u32(0x12345678), builtin.Endian.Big);
assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 }));
- writeInt(bytes[0..], u32(0x78563412), false);
+ writeInt(bytes[0..], u32(0x78563412), builtin.Endian.Little);
assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 }));
- writeInt(bytes[0..], u16(0x1234), true);
+ writeInt(bytes[0..], u16(0x1234), builtin.Endian.Big);
assert(eql(u8, bytes, []u8{ 0x00, 0x00, 0x12, 0x34 }));
- writeInt(bytes[0..], u16(0x1234), false);
+ writeInt(bytes[0..], u16(0x1234), builtin.Endian.Little);
assert(eql(u8, bytes, []u8{ 0x34, 0x12, 0x00, 0x00 }));
}
diff --git a/std/os/child_process.zig b/std/os/child_process.zig
index 0548592f56..75a2dcf24d 100644
--- a/std/os/child_process.zig
+++ b/std/os/child_process.zig
@@ -722,14 +722,14 @@ const ErrInt = @IntType(false, @sizeOf(error) * 8);
fn writeIntFd(fd: i32, value: ErrInt) -> %void {
var bytes: [@sizeOf(ErrInt)]u8 = undefined;
- mem.writeInt(bytes[0..], value, true);
+ mem.writeInt(bytes[0..], value, builtin.endian);
os.posixWrite(fd, bytes[0..]) %% return error.SystemResources;
}
fn readIntFd(fd: i32) -> %ErrInt {
var bytes: [@sizeOf(ErrInt)]u8 = undefined;
os.posixRead(fd, bytes[0..]) %% return error.SystemResources;
- return mem.readInt(bytes[0..], ErrInt, true);
+ return mem.readInt(bytes[0..], ErrInt, builtin.endian);
}
extern fn sigchld_handler(_: i32) {
diff --git a/std/rand.zig b/std/rand.zig
index d7798df3da..09e0c8ac78 100644
--- a/std/rand.zig
+++ b/std/rand.zig
@@ -50,12 +50,12 @@ pub const Rand = struct {
pub fn fillBytes(r: &Rand, buf: []u8) {
var bytes_left = buf.len;
while (bytes_left >= @sizeOf(usize)) {
- mem.writeInt(buf[buf.len - bytes_left..], r.rng.get(), false);
+ mem.writeInt(buf[buf.len - bytes_left..], r.rng.get(), builtin.Endian.Little);
bytes_left -= @sizeOf(usize);
}
if (bytes_left > 0) {
var rand_val_array: [@sizeOf(usize)]u8 = undefined;
- mem.writeInt(rand_val_array[0..], r.rng.get(), false);
+ mem.writeInt(rand_val_array[0..], r.rng.get(), builtin.Endian.Little);
while (bytes_left > 0) {
buf[buf.len - bytes_left] = rand_val_array[@sizeOf(usize) - bytes_left];
bytes_left -= 1;
@@ -98,7 +98,7 @@ pub const Rand = struct {
while (true) {
r.fillBytes(rand_val_array[0..]);
- const rand_val = mem.readInt(rand_val_array, T, false);
+ const rand_val = mem.readInt(rand_val_array, T, builtin.Endian.Little);
if (rand_val < upper_bound) {
return start + (rand_val % total_range);
}
diff --git a/std/special/compiler_rt/udivmod.zig b/std/special/compiler_rt/udivmod.zig
index c6a2babbf6..7e09c3d4d7 100644
--- a/std/special/compiler_rt/udivmod.zig
+++ b/std/special/compiler_rt/udivmod.zig
@@ -1,7 +1,7 @@
const builtin = @import("builtin");
const is_test = builtin.is_test;
-const low = if (builtin.is_big_endian) 1 else 0;
+const low = switch (builtin.endian) { builtin.Endian.Big => 1, builtin.Endian.Little => 0 };
const high = 1 - low;
pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: ?&DoubleInt) -> DoubleInt {