authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-18 13:12:03-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-18 13:12:03-05:00
log74a335c4ccd9eb4cfcc5cc6c01b633584c6bb6ba
tree1d44cdfafe00762e388d3114a0b9d44bb3bc0c4d
parentd2fb95af8804229181c4d28506ec37d94b9926e6
parent7a84fe79b9d61bb3d4e21c169cc2b58722b194ce
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'emekoi-fix-1711'


5 files changed, 97 insertions(+), 77 deletions(-)

doc/langref.html.in+18-14
......@@ -2221,8 +2221,9 @@ test "packed enum" {
22212221 {#header_close#}
22222222 {#header_open|union#}
22232223 {#code_begin|test|union#}
2224const assert = @import("std").debug.assert;
2225const mem = @import("std").mem;
2224const std = @import("std");
2225const assert = std.debug.assert;
2226const mem = std.mem;
22262227
22272228// A union has only 1 active field at a time.
22282229const Payload = union {
......@@ -2231,16 +2232,19 @@ const Payload = union {
22312232 Bool: bool,
22322233};
22332234test "simple union" {
2234 var payload = Payload {.Int = 1234};
2235 var payload = Payload{ .Int = 1234 };
22352236 // payload.Float = 12.34; // ERROR! field not active
22362237 assert(payload.Int == 1234);
22372238 // You can activate another field by assigning the entire union.
2238 payload = Payload {.Float = 12.34};
2239 payload = Payload{ .Float = 12.34 };
22392240 assert(payload.Float == 12.34);
22402241}
22412242
22422243// Unions can be given an enum tag type:
2243const ComplexTypeTag = enum { Ok, NotOk };
2244const ComplexTypeTag = enum {
2245 Ok,
2246 NotOk,
2247};
22442248const ComplexType = union(ComplexTypeTag) {
22452249 Ok: u8,
22462250 NotOk: void,
......@@ -2248,11 +2252,11 @@ const ComplexType = union(ComplexTypeTag) {
22482252
22492253// Declare a specific instance of the union variant.
22502254test "declare union value" {
2251 const c = ComplexType { .Ok = 0 };
2255 const c = ComplexType{ .Ok = 0 };
22522256 assert(ComplexTypeTag(c) == ComplexTypeTag.Ok);
22532257}
22542258
2255// @TagType can be used to access the enum tag type of a union.
2259// @TagType can be used to access the enum tag type of a tagged union.
22562260test "@TagType" {
22572261 assert(@TagType(ComplexType) == ComplexTypeTag);
22582262}
......@@ -2266,7 +2270,7 @@ const Foo = union(enum) {
22662270 None,
22672271};
22682272test "union variant switch" {
2269 const p = Foo { .Number = 54 };
2273 const p = Foo{ .Number = 54 };
22702274 const what_is_it = switch (p) {
22712275 // Capture by reference
22722276 Foo.String => |*x| blk: {
......@@ -2301,14 +2305,13 @@ const Variant = union(enum) {
23012305};
23022306
23032307test "union method" {
2304 var v1 = Variant { .Int = 1 };
2305 var v2 = Variant { .Bool = false };
2308 var v1 = Variant{ .Int = 1 };
2309 var v2 = Variant{ .Bool = false };
23062310
23072311 assert(v1.truthy());
23082312 assert(!v2.truthy());
23092313}
23102314
2311
23122315const Small = union {
23132316 A: i32,
23142317 B: bool,
......@@ -5660,12 +5663,13 @@ test "main" {
56605663 {#header_close#}
56615664
56625665 {#header_open|@enumToInt#}
5663 <pre>{#syntax#}@enumToInt(enum_value: var) var{#endsyntax#}</pre>
5666 <pre>{#syntax#}@enumToInt(enum_or_tagged_union: var) var{#endsyntax#}</pre>
56645667 <p>
5665 Converts an enumeration value into its integer tag type.
5668 Converts an enumeration value into its integer tag type. When a tagged union is passed,
5669 the tag value is used as the enumeration value.
56665670 </p>
56675671 <p>
5668 If the enum has only 1 possible value, the resut is a {#syntax#}comptime_int{#endsyntax#}
5672 If there is only one possible enum value, the resut is a {#syntax#}comptime_int{#endsyntax#}
56695673 known at {#link|comptime#}.
56705674 </p>
56715675 {#see_also|@intToEnum#}
src/ir.cpp+58-54
......@@ -10305,49 +10305,75 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
1030510305 return result;
1030610306}
1030710307
10308static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr,
10309 IrInstruction *target, ZigType *wanted_type)
10310{
10308static ZigType *ir_resolve_union_tag_type(IrAnalyze *ira, IrInstruction *source_instr, ZigType *union_type) {
10309 assert(union_type->id == ZigTypeIdUnion);
10310
1031110311 Error err;
10312 assert(wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt);
10312 if ((err = type_resolve(ira->codegen, union_type, ResolveStatusSizeKnown)))
10313 return ira->codegen->builtin_types.entry_invalid;
1031310314
10314 ZigType *actual_type = target->value.type;
10315 if ((err = ensure_complete_type(ira->codegen, actual_type)))
10316 return ira->codegen->invalid_instruction;
10315 AstNode *decl_node = union_type->data.unionation.decl_node;
10316 if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
10317 assert(union_type->data.unionation.tag_type != nullptr);
10318 return union_type->data.unionation.tag_type;
10319 } else {
10320 ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("union '%s' has no tag",
10321 buf_ptr(&union_type->name)));
10322 add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here"));
10323 return ira->codegen->builtin_types.entry_invalid;
10324 }
10325}
1031710326
10318 if (wanted_type != actual_type->data.enumeration.tag_int_type) {
10319 ir_add_error(ira, source_instr,
10320 buf_sprintf("enum to integer cast to '%s' instead of its tag type, '%s'",
10321 buf_ptr(&wanted_type->name),
10322 buf_ptr(&actual_type->data.enumeration.tag_int_type->name)));
10327static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target) {
10328 Error err;
10329
10330 IrInstruction *enum_target;
10331 ZigType *enum_type;
10332 if (target->value.type->id == ZigTypeIdUnion) {
10333 enum_type = ir_resolve_union_tag_type(ira, target, target->value.type);
10334 if (type_is_invalid(enum_type))
10335 return ira->codegen->invalid_instruction;
10336 enum_target = ir_implicit_cast(ira, target, enum_type);
10337 if (type_is_invalid(enum_target->value.type))
10338 return ira->codegen->invalid_instruction;
10339 } else if (target->value.type->id == ZigTypeIdEnum) {
10340 enum_target = target;
10341 enum_type = target->value.type;
10342 } else {
10343 ir_add_error(ira, target,
10344 buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value.type->name)));
1032310345 return ira->codegen->invalid_instruction;
1032410346 }
1032510347
10326 assert(actual_type->id == ZigTypeIdEnum);
10348 if ((err = type_resolve(ira->codegen, enum_type, ResolveStatusSizeKnown)))
10349 return ira->codegen->invalid_instruction;
1032710350
10328 if (instr_is_comptime(target)) {
10329 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
10351 ZigType *tag_type = enum_type->data.enumeration.tag_int_type;
10352 assert(tag_type->id == ZigTypeIdInt || tag_type->id == ZigTypeIdComptimeInt);
10353
10354 if (instr_is_comptime(enum_target)) {
10355 ConstExprValue *val = ir_resolve_const(ira, enum_target, UndefBad);
1033010356 if (!val)
1033110357 return ira->codegen->invalid_instruction;
10332 IrInstruction *result = ir_const(ira, source_instr, wanted_type);
10333 init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag);
10358 IrInstruction *result = ir_const(ira, source_instr, tag_type);
10359 init_const_bigint(&result->value, tag_type, &val->data.x_enum_tag);
1033410360 return result;
1033510361 }
1033610362
1033710363 // If there is only one possible tag, then we know at comptime what it is.
10338 if (actual_type->data.enumeration.layout == ContainerLayoutAuto &&
10339 actual_type->data.enumeration.src_field_count == 1)
10364 if (enum_type->data.enumeration.layout == ContainerLayoutAuto &&
10365 enum_type->data.enumeration.src_field_count == 1)
1034010366 {
10341 assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int);
10342 IrInstruction *result = ir_const(ira, source_instr, wanted_type);
10343 init_const_bigint(&result->value, wanted_type,
10344 &actual_type->data.enumeration.fields[0].value);
10367 assert(tag_type == ira->codegen->builtin_types.entry_num_lit_int);
10368 IrInstruction *result = ir_const(ira, source_instr, tag_type);
10369 init_const_bigint(&result->value, tag_type,
10370 &enum_type->data.enumeration.fields[0].value);
1034510371 return result;
1034610372 }
1034710373
1034810374 IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
10349 source_instr->source_node, target);
10350 result->value.type = wanted_type;
10375 source_instr->source_node, enum_target);
10376 result->value.type = tag_type;
1035110377 return result;
1035210378}
1035310379
......@@ -14358,12 +14384,12 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
1435814384 if (dst_size == 0)
1435914385 return ErrorNone;
1436014386 opt_ir_add_error_node(ira, codegen, source_node,
14361 buf_sprintf("attempt to read %zu bytes from null pointer",
14387 buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from null pointer",
1436214388 dst_size));
1436314389 return ErrorSemanticAnalyzeFail;
1436414390 case ConstPtrSpecialRef: {
1436514391 opt_ir_add_error_node(ira, codegen, source_node,
14366 buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes",
14392 buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from pointer to %s which is %" ZIG_PRI_usize " bytes",
1436714393 dst_size, buf_ptr(&pointee->type->name), src_size));
1436814394 return ErrorSemanticAnalyzeFail;
1436914395 }
......@@ -14377,7 +14403,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
1437714403 src_size = elem_size * (array_val->type->data.array.len - elem_index);
1437814404 if (dst_size > src_size) {
1437914405 opt_ir_add_error_node(ira, codegen, source_node,
14380 buf_sprintf("attempt to read %zu bytes from %s at index %" ZIG_PRI_usize " which is %zu bytes",
14406 buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from %s at index %" ZIG_PRI_usize " which is %" ZIG_PRI_usize " bytes",
1438114407 dst_size, buf_ptr(&array_val->type->name), elem_index, src_size));
1438214408 return ErrorSemanticAnalyzeFail;
1438314409 }
......@@ -21364,20 +21390,10 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct
2136421390
2136521391 return ir_const_type(ira, &instruction->base, enum_type->data.enumeration.tag_int_type);
2136621392 } else if (enum_type->id == ZigTypeIdUnion) {
21367 if ((err = ensure_complete_type(ira->codegen, enum_type)))
21368 return ira->codegen->invalid_instruction;
21369
21370 AstNode *decl_node = enum_type->data.unionation.decl_node;
21371 if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
21372 assert(enum_type->data.unionation.tag_type != nullptr);
21373
21374 return ir_const_type(ira, &instruction->base, enum_type->data.unionation.tag_type);
21375 } else {
21376 ErrorMsg *msg = ir_add_error(ira, target_inst, buf_sprintf("union '%s' has no tag",
21377 buf_ptr(&enum_type->name)));
21378 add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here"));
21393 ZigType *tag_type = ir_resolve_union_tag_type(ira, instruction->target, enum_type);
21394 if (type_is_invalid(tag_type))
2137921395 return ira->codegen->invalid_instruction;
21380 }
21396 return ir_const_type(ira, &instruction->base, tag_type);
2138121397 } else {
2138221398 ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'",
2138321399 buf_ptr(&enum_type->name)));
......@@ -21958,23 +21974,11 @@ static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstr
2195821974
2195921975
2196021976static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) {
21961 Error err;
2196221977 IrInstruction *target = instruction->target->child;
2196321978 if (type_is_invalid(target->value.type))
2196421979 return ira->codegen->invalid_instruction;
2196521980
21966 if (target->value.type->id != ZigTypeIdEnum) {
21967 ir_add_error(ira, instruction->target,
21968 buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value.type->name)));
21969 return ira->codegen->invalid_instruction;
21970 }
21971
21972 if ((err = type_resolve(ira->codegen, target->value.type, ResolveStatusZeroBitsKnown)))
21973 return ira->codegen->invalid_instruction;
21974
21975 ZigType *tag_type = target->value.type->data.enumeration.tag_int_type;
21976
21977 return ir_analyze_enum_to_int(ira, &instruction->base, target, tag_type);
21981 return ir_analyze_enum_to_int(ira, &instruction->base, target);
2197821982}
2197921983
2198021984static IrInstruction *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) {
src/target.cpp+2-1
......@@ -9,6 +9,7 @@
99#include "error.hpp"
1010#include "target.hpp"
1111#include "util.hpp"
12#include "os.hpp"
1213
1314#include <stdio.h>
1415
......@@ -848,7 +849,7 @@ const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t versio
848849 if (is_static) {
849850 return ".a";
850851 } else {
851 return buf_ptr(buf_sprintf(".so.%zu", version_major));
852 return buf_ptr(buf_sprintf(".so.%" ZIG_PRI_usize, version_major));
852853 }
853854 }
854855}
test/stage1/behavior/union.zig+15
......@@ -350,3 +350,18 @@ test "union with only 1 field casted to its enum type which has enum value speci
350350 expect(@enumToInt(t) == 33);
351351 comptime expect(@enumToInt(t) == 33);
352352}
353
354test "@enumToInt works on unions" {
355 const Bar = union(enum) {
356 A: bool,
357 B: u8,
358 C,
359 };
360
361 const a = Bar{ .A = true };
362 var b = Bar{ .B = undefined };
363 var c = Bar.C;
364 expect(@enumToInt(a) == 0);
365 expect(@enumToInt(b) == 1);
366 expect(@enumToInt(c) == 2);
367}
test/tests.zig+4-8
......@@ -572,9 +572,7 @@ pub const CompileErrorContext = struct {
572572 const source_file = ".tmp_source.zig";
573573
574574 fn init(input: []const u8) ErrLineIter {
575 return ErrLineIter {
576 .lines = mem.separate(input, "\n"),
577 };
575 return ErrLineIter{ .lines = mem.separate(input, "\n") };
578576 }
579577
580578 fn next(self: *ErrLineIter) ?[]const u8 {
......@@ -718,11 +716,10 @@ pub const CompileErrorContext = struct {
718716 for (self.case.expected_errors.toSliceConst()) |expected| {
719717 if (mem.indexOf(u8, stderr, expected) == null) {
720718 warn(
721 \\=========== Expected compile error: ============
719 \\\n=========== Expected compile error: ============
722720 \\{}
723721 \\
724 , expected
725 );
722 , expected);
726723 ok = false;
727724 break;
728725 }
......@@ -734,8 +731,7 @@ pub const CompileErrorContext = struct {
734731 \\================= Full output: =================
735732 \\{}
736733 \\
737 , stderr
738 );
734 , stderr);
739735 return error.TestFailed;
740736 }
741737