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" {...@@ -2221,8 +2221,9 @@ test "packed enum" {
2221 {#header_close#}2221 {#header_close#}
2222 {#header_open|union#}2222 {#header_open|union#}
2223 {#code_begin|test|union#}2223 {#code_begin|test|union#}
2224const assert = @import("std").debug.assert;2224const std = @import("std");
2225const mem = @import("std").mem;2225const assert = std.debug.assert;
2226const mem = std.mem;
22262227
2227// A union has only 1 active field at a time.2228// A union has only 1 active field at a time.
2228const Payload = union {2229const Payload = union {
...@@ -2231,16 +2232,19 @@ const Payload = union {...@@ -2231,16 +2232,19 @@ const Payload = union {
2231 Bool: bool,2232 Bool: bool,
2232};2233};
2233test "simple union" {2234test "simple union" {
2234 var payload = Payload {.Int = 1234};2235 var payload = Payload{ .Int = 1234 };
2235 // payload.Float = 12.34; // ERROR! field not active2236 // payload.Float = 12.34; // ERROR! field not active
2236 assert(payload.Int == 1234);2237 assert(payload.Int == 1234);
2237 // You can activate another field by assigning the entire union.2238 // You can activate another field by assigning the entire union.
2238 payload = Payload {.Float = 12.34};2239 payload = Payload{ .Float = 12.34 };
2239 assert(payload.Float == 12.34);2240 assert(payload.Float == 12.34);
2240}2241}
22412242
2242// Unions can be given an enum tag type:2243// Unions can be given an enum tag type:
2243const ComplexTypeTag = enum { Ok, NotOk }; 2244const ComplexTypeTag = enum {
2245 Ok,
2246 NotOk,
2247};
2244const ComplexType = union(ComplexTypeTag) {2248const ComplexType = union(ComplexTypeTag) {
2245 Ok: u8,2249 Ok: u8,
2246 NotOk: void,2250 NotOk: void,
...@@ -2248,11 +2252,11 @@ const ComplexType = union(ComplexTypeTag) {...@@ -2248,11 +2252,11 @@ const ComplexType = union(ComplexTypeTag) {
22482252
2249// Declare a specific instance of the union variant.2253// Declare a specific instance of the union variant.
2250test "declare union value" {2254test "declare union value" {
2251 const c = ComplexType { .Ok = 0 };2255 const c = ComplexType{ .Ok = 0 };
2252 assert(ComplexTypeTag(c) == ComplexTypeTag.Ok);2256 assert(ComplexTypeTag(c) == ComplexTypeTag.Ok);
2253}2257}
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.
2256test "@TagType" {2260test "@TagType" {
2257 assert(@TagType(ComplexType) == ComplexTypeTag);2261 assert(@TagType(ComplexType) == ComplexTypeTag);
2258}2262}
...@@ -2266,7 +2270,7 @@ const Foo = union(enum) {...@@ -2266,7 +2270,7 @@ const Foo = union(enum) {
2266 None,2270 None,
2267};2271};
2268test "union variant switch" {2272test "union variant switch" {
2269 const p = Foo { .Number = 54 };2273 const p = Foo{ .Number = 54 };
2270 const what_is_it = switch (p) {2274 const what_is_it = switch (p) {
2271 // Capture by reference2275 // Capture by reference
2272 Foo.String => |*x| blk: {2276 Foo.String => |*x| blk: {
...@@ -2301,14 +2305,13 @@ const Variant = union(enum) {...@@ -2301,14 +2305,13 @@ const Variant = union(enum) {
2301};2305};
23022306
2303test "union method" {2307test "union method" {
2304 var v1 = Variant { .Int = 1 };2308 var v1 = Variant{ .Int = 1 };
2305 var v2 = Variant { .Bool = false };2309 var v2 = Variant{ .Bool = false };
23062310
2307 assert(v1.truthy());2311 assert(v1.truthy());
2308 assert(!v2.truthy());2312 assert(!v2.truthy());
2309}2313}
23102314
2311
2312const Small = union {2315const Small = union {
2313 A: i32,2316 A: i32,
2314 B: bool,2317 B: bool,
...@@ -5660,12 +5663,13 @@ test "main" {...@@ -5660,12 +5663,13 @@ test "main" {
5660 {#header_close#}5663 {#header_close#}
56615664
5662 {#header_open|@enumToInt#}5665 {#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>
5664 <p>5667 <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.
5666 </p>5670 </p>
5667 <p>5671 <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#}
5669 known at {#link|comptime#}.5673 known at {#link|comptime#}.
5670 </p>5674 </p>
5671 {#see_also|@intToEnum#}5675 {#see_also|@intToEnum#}
src/ir.cpp+58-54
...@@ -10305,49 +10305,75 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s...@@ -10305,49 +10305,75 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
10305 return result;10305 return result;
10306}10306}
1030710307
10308static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr,10308static ZigType *ir_resolve_union_tag_type(IrAnalyze *ira, IrInstruction *source_instr, ZigType *union_type) {
10309 IrInstruction *target, ZigType *wanted_type)10309 assert(union_type->id == ZigTypeIdUnion);
10310{10310
10311 Error err;10311 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 AstNode *decl_node = union_type->data.unionation.decl_node;
10315 if ((err = ensure_complete_type(ira->codegen, actual_type)))10316 if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
10316 return ira->codegen->invalid_instruction;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) {10327static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target) {
10319 ir_add_error(ira, source_instr,10328 Error err;
10320 buf_sprintf("enum to integer cast to '%s' instead of its tag type, '%s'",10329
10321 buf_ptr(&wanted_type->name),10330 IrInstruction *enum_target;
10322 buf_ptr(&actual_type->data.enumeration.tag_int_type->name)));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)));
10323 return ira->codegen->invalid_instruction;10345 return ira->codegen->invalid_instruction;
10324 }10346 }
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)) {10351 ZigType *tag_type = enum_type->data.enumeration.tag_int_type;
10329 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);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);
10330 if (!val)10356 if (!val)
10331 return ira->codegen->invalid_instruction;10357 return ira->codegen->invalid_instruction;
10332 IrInstruction *result = ir_const(ira, source_instr, wanted_type);10358 IrInstruction *result = ir_const(ira, source_instr, tag_type);
10333 init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag);10359 init_const_bigint(&result->value, tag_type, &val->data.x_enum_tag);
10334 return result;10360 return result;
10335 }10361 }
1033610362
10337 // If there is only one possible tag, then we know at comptime what it is.10363 // If there is only one possible tag, then we know at comptime what it is.
10338 if (actual_type->data.enumeration.layout == ContainerLayoutAuto &&10364 if (enum_type->data.enumeration.layout == ContainerLayoutAuto &&
10339 actual_type->data.enumeration.src_field_count == 1)10365 enum_type->data.enumeration.src_field_count == 1)
10340 {10366 {
10341 assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int);10367 assert(tag_type == ira->codegen->builtin_types.entry_num_lit_int);
10342 IrInstruction *result = ir_const(ira, source_instr, wanted_type);10368 IrInstruction *result = ir_const(ira, source_instr, tag_type);
10343 init_const_bigint(&result->value, wanted_type,10369 init_const_bigint(&result->value, tag_type,
10344 &actual_type->data.enumeration.fields[0].value);10370 &enum_type->data.enumeration.fields[0].value);
10345 return result;10371 return result;
10346 }10372 }
1034710373
10348 IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,10374 IrInstruction *result = ir_build_widen_or_shorten(&ira->new_irb, source_instr->scope,
10349 source_instr->source_node, target);10375 source_instr->source_node, enum_target);
10350 result->value.type = wanted_type;10376 result->value.type = tag_type;
10351 return result;10377 return result;
10352}10378}
1035310379
...@@ -14358,12 +14384,12 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source...@@ -14358,12 +14384,12 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
14358 if (dst_size == 0)14384 if (dst_size == 0)
14359 return ErrorNone;14385 return ErrorNone;
14360 opt_ir_add_error_node(ira, codegen, source_node,14386 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",
14362 dst_size));14388 dst_size));
14363 return ErrorSemanticAnalyzeFail;14389 return ErrorSemanticAnalyzeFail;
14364 case ConstPtrSpecialRef: {14390 case ConstPtrSpecialRef: {
14365 opt_ir_add_error_node(ira, codegen, source_node,14391 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",
14367 dst_size, buf_ptr(&pointee->type->name), src_size));14393 dst_size, buf_ptr(&pointee->type->name), src_size));
14368 return ErrorSemanticAnalyzeFail;14394 return ErrorSemanticAnalyzeFail;
14369 }14395 }
...@@ -14377,7 +14403,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source...@@ -14377,7 +14403,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
14377 src_size = elem_size * (array_val->type->data.array.len - elem_index);14403 src_size = elem_size * (array_val->type->data.array.len - elem_index);
14378 if (dst_size > src_size) {14404 if (dst_size > src_size) {
14379 opt_ir_add_error_node(ira, codegen, source_node,14405 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",
14381 dst_size, buf_ptr(&array_val->type->name), elem_index, src_size));14407 dst_size, buf_ptr(&array_val->type->name), elem_index, src_size));
14382 return ErrorSemanticAnalyzeFail;14408 return ErrorSemanticAnalyzeFail;
14383 }14409 }
...@@ -21364,20 +21390,10 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct...@@ -21364,20 +21390,10 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct
2136421390
21365 return ir_const_type(ira, &instruction->base, enum_type->data.enumeration.tag_int_type);21391 return ir_const_type(ira, &instruction->base, enum_type->data.enumeration.tag_int_type);
21366 } else if (enum_type->id == ZigTypeIdUnion) {21392 } else if (enum_type->id == ZigTypeIdUnion) {
21367 if ((err = ensure_complete_type(ira->codegen, enum_type)))21393 ZigType *tag_type = ir_resolve_union_tag_type(ira, instruction->target, enum_type);
21368 return ira->codegen->invalid_instruction;21394 if (type_is_invalid(tag_type))
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"));
21379 return ira->codegen->invalid_instruction;21395 return ira->codegen->invalid_instruction;
21380 }21396 return ir_const_type(ira, &instruction->base, tag_type);
21381 } else {21397 } else {
21382 ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'",21398 ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'",
21383 buf_ptr(&enum_type->name)));21399 buf_ptr(&enum_type->name)));
...@@ -21958,23 +21974,11 @@ static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstr...@@ -21958,23 +21974,11 @@ static IrInstruction *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstr
2195821974
2195921975
21960static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) {21976static IrInstruction *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) {
21961 Error err;
21962 IrInstruction *target = instruction->target->child;21977 IrInstruction *target = instruction->target->child;
21963 if (type_is_invalid(target->value.type))21978 if (type_is_invalid(target->value.type))
21964 return ira->codegen->invalid_instruction;21979 return ira->codegen->invalid_instruction;
2196521980
21966 if (target->value.type->id != ZigTypeIdEnum) {21981 return ir_analyze_enum_to_int(ira, &instruction->base, target);
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);
21978}21982}
2197921983
21980static IrInstruction *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) {21984static IrInstruction *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) {
src/target.cpp+2-1
...@@ -9,6 +9,7 @@...@@ -9,6 +9,7 @@
9#include "error.hpp"9#include "error.hpp"
10#include "target.hpp"10#include "target.hpp"
11#include "util.hpp"11#include "util.hpp"
12#include "os.hpp"
1213
13#include <stdio.h>14#include <stdio.h>
1415
...@@ -848,7 +849,7 @@ const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t versio...@@ -848,7 +849,7 @@ const char *target_lib_file_ext(ZigTarget *target, bool is_static, size_t versio
848 if (is_static) {849 if (is_static) {
849 return ".a";850 return ".a";
850 } else {851 } else {
851 return buf_ptr(buf_sprintf(".so.%zu", version_major));852 return buf_ptr(buf_sprintf(".so.%" ZIG_PRI_usize, version_major));
852 }853 }
853 }854 }
854}855}
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...@@ -350,3 +350,18 @@ test "union with only 1 field casted to its enum type which has enum value speci
350 expect(@enumToInt(t) == 33);350 expect(@enumToInt(t) == 33);
351 comptime expect(@enumToInt(t) == 33);351 comptime expect(@enumToInt(t) == 33);
352}352}
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 {...@@ -572,9 +572,7 @@ pub const CompileErrorContext = struct {
572 const source_file = ".tmp_source.zig";572 const source_file = ".tmp_source.zig";
573573
574 fn init(input: []const u8) ErrLineIter {574 fn init(input: []const u8) ErrLineIter {
575 return ErrLineIter {575 return ErrLineIter{ .lines = mem.separate(input, "\n") };
576 .lines = mem.separate(input, "\n"),
577 };
578 }576 }
579577
580 fn next(self: *ErrLineIter) ?[]const u8 {578 fn next(self: *ErrLineIter) ?[]const u8 {
...@@ -718,11 +716,10 @@ pub const CompileErrorContext = struct {...@@ -718,11 +716,10 @@ pub const CompileErrorContext = struct {
718 for (self.case.expected_errors.toSliceConst()) |expected| {716 for (self.case.expected_errors.toSliceConst()) |expected| {
719 if (mem.indexOf(u8, stderr, expected) == null) {717 if (mem.indexOf(u8, stderr, expected) == null) {
720 warn(718 warn(
721 \\=========== Expected compile error: ============719 \\\n=========== Expected compile error: ============
722 \\{}720 \\{}
723 \\721 \\
724 , expected722 , expected);
725 );
726 ok = false;723 ok = false;
727 break;724 break;
728 }725 }
...@@ -734,8 +731,7 @@ pub const CompileErrorContext = struct {...@@ -734,8 +731,7 @@ pub const CompileErrorContext = struct {
734 \\================= Full output: =================731 \\================= Full output: =================
735 \\{}732 \\{}
736 \\733 \\
737 , stderr734 , stderr);
738 );
739 return error.TestFailed;735 return error.TestFailed;
740 }736 }
741737