authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-05 20:49:03-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-05 20:49:03-05:00
log6018dbd3391d1e71eef650aff700eab53074c308
tree4d3bd0c5bb0a55a7ad144270eed99d90855efd45
parent08d531143f0b373cbc54e037fa526fb00d9db398
parent960914a073c367883c9fdf54e900890a6aefc05f

Merge branch 'master' into self-hosted


6 files changed, 171 insertions(+), 20 deletions(-)

src/analyze.cpp+10-5
...@@ -2244,12 +2244,10 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {...@@ -2244,12 +2244,10 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
2244 TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node);2244 TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node);
2245 if (type_is_invalid(enum_type)) {2245 if (type_is_invalid(enum_type)) {
2246 union_type->data.unionation.is_invalid = true;2246 union_type->data.unionation.is_invalid = true;
2247 union_type->data.unionation.embedded_in_current = false;
2248 return;2247 return;
2249 }2248 }
2250 if (enum_type->id != TypeTableEntryIdEnum) {2249 if (enum_type->id != TypeTableEntryIdEnum) {
2251 union_type->data.unionation.is_invalid = true;2250 union_type->data.unionation.is_invalid = true;
2252 union_type->data.unionation.embedded_in_current = false;
2253 add_node_error(g, enum_type_node,2251 add_node_error(g, enum_type_node,
2254 buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));2252 buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
2255 return;2253 return;
...@@ -3319,7 +3317,7 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) {...@@ -3319,7 +3317,7 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) {
33193317
3320TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {3318TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {
3321 assert(type_entry->id == TypeTableEntryIdUnion);3319 assert(type_entry->id == TypeTableEntryIdUnion);
3322 assert(type_entry->data.unionation.complete);3320 assert(type_entry->data.unionation.zero_bits_known);
3323 for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {3321 for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {
3324 TypeUnionField *field = &type_entry->data.unionation.fields[i];3322 TypeUnionField *field = &type_entry->data.unionation.fields[i];
3325 if (buf_eql_buf(field->enum_field->name, name)) {3323 if (buf_eql_buf(field->enum_field->name, name)) {
...@@ -3331,7 +3329,7 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {...@@ -3331,7 +3329,7 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {
33313329
3332TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) {3330TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) {
3333 assert(type_entry->id == TypeTableEntryIdUnion);3331 assert(type_entry->id == TypeTableEntryIdUnion);
3334 assert(type_entry->data.unionation.complete);3332 assert(type_entry->data.unionation.zero_bits_known);
3335 assert(type_entry->data.unionation.gen_tag_index != SIZE_MAX);3333 assert(type_entry->data.unionation.gen_tag_index != SIZE_MAX);
3336 for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {3334 for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {
3337 TypeUnionField *field = &type_entry->data.unionation.fields[i];3335 TypeUnionField *field = &type_entry->data.unionation.fields[i];
...@@ -3888,7 +3886,6 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {...@@ -3888,7 +3886,6 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
3888 return false;3886 return false;
3889 case TypeTableEntryIdArray:3887 case TypeTableEntryIdArray:
3890 case TypeTableEntryIdStruct:3888 case TypeTableEntryIdStruct:
3891 case TypeTableEntryIdUnion:
3892 return type_has_bits(type_entry);3889 return type_has_bits(type_entry);
3893 case TypeTableEntryIdErrorUnion:3890 case TypeTableEntryIdErrorUnion:
3894 return type_has_bits(type_entry->data.error.child_type);3891 return type_has_bits(type_entry->data.error.child_type);
...@@ -3896,6 +3893,14 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {...@@ -3896,6 +3893,14 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
3896 return type_has_bits(type_entry->data.maybe.child_type) &&3893 return type_has_bits(type_entry->data.maybe.child_type) &&
3897 type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer &&3894 type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer &&
3898 type_entry->data.maybe.child_type->id != TypeTableEntryIdFn;3895 type_entry->data.maybe.child_type->id != TypeTableEntryIdFn;
3896 case TypeTableEntryIdUnion:
3897 assert(type_entry->data.unionation.complete);
3898 if (type_entry->data.unionation.gen_field_count == 0)
3899 return false;
3900 if (!type_has_bits(type_entry))
3901 return false;
3902 return true;
3903
3899 }3904 }
3900 zig_unreachable();3905 zig_unreachable();
3901}3906}
src/codegen.cpp+8-8
...@@ -3946,8 +3946,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {...@@ -3946,8 +3946,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
3946 case TypeTableEntryIdUnion:3946 case TypeTableEntryIdUnion:
3947 {3947 {
3948 LLVMTypeRef union_type_ref = type_entry->data.unionation.union_type_ref;3948 LLVMTypeRef union_type_ref = type_entry->data.unionation.union_type_ref;
3949 ConstExprValue *payload_value = const_val->data.x_union.payload;
3950 assert(payload_value != nullptr);
39513949
3952 if (type_entry->data.unionation.gen_field_count == 0) {3950 if (type_entry->data.unionation.gen_field_count == 0) {
3953 if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) {3951 if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) {
...@@ -3960,7 +3958,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {...@@ -3960,7 +3958,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
39603958
3961 LLVMValueRef union_value_ref;3959 LLVMValueRef union_value_ref;
3962 bool make_unnamed_struct;3960 bool make_unnamed_struct;
3963 if (!type_has_bits(payload_value->type)) {3961 ConstExprValue *payload_value = const_val->data.x_union.payload;
3962 if (payload_value == nullptr || !type_has_bits(payload_value->type)) {
3964 if (type_entry->data.unionation.gen_tag_index == SIZE_MAX)3963 if (type_entry->data.unionation.gen_tag_index == SIZE_MAX)
3965 return LLVMGetUndef(type_entry->type_ref);3964 return LLVMGetUndef(type_entry->type_ref);
39663965
...@@ -5298,18 +5297,19 @@ void codegen_translate_c(CodeGen *g, Buf *full_path) {...@@ -5298,18 +5297,19 @@ void codegen_translate_c(CodeGen *g, Buf *full_path) {
52985297
5299 ZigList<ErrorMsg *> errors = {0};5298 ZigList<ErrorMsg *> errors = {0};
5300 int err = parse_h_file(import, &errors, buf_ptr(full_path), g, nullptr);5299 int err = parse_h_file(import, &errors, buf_ptr(full_path), g, nullptr);
5301 if (err) {
5302 fprintf(stderr, "unable to parse C file: %s\n", err_str(err));
5303 exit(1);
5304 }
53055300
5306 if (errors.length > 0) {5301 if (err == ErrorCCompileErrors && errors.length > 0) {
5307 for (size_t i = 0; i < errors.length; i += 1) {5302 for (size_t i = 0; i < errors.length; i += 1) {
5308 ErrorMsg *err_msg = errors.at(i);5303 ErrorMsg *err_msg = errors.at(i);
5309 print_err_msg(err_msg, g->err_color);5304 print_err_msg(err_msg, g->err_color);
5310 }5305 }
5311 exit(1);5306 exit(1);
5312 }5307 }
5308
5309 if (err) {
5310 fprintf(stderr, "unable to parse C file: %s\n", err_str(err));
5311 exit(1);
5312 }
5313}5313}
53145314
5315static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package, const char *basename) {5315static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package, const char *basename) {
src/ir.cpp+98-7
...@@ -7468,6 +7468,17 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,...@@ -7468,6 +7468,17 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
7468 }7468 }
7469 }7469 }
74707470
7471 // implicit enum to union which has the enum as the tag type
7472 if (expected_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum &&
7473 (expected_type->data.unionation.decl_node->data.container_decl.auto_enum ||
7474 expected_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
7475 {
7476 type_ensure_zero_bits_known(ira->codegen, expected_type);
7477 if (expected_type->data.unionation.tag_type == actual_type) {
7478 return ImplicitCastMatchResultYes;
7479 }
7480 }
7481
7471 // implicit undefined literal to anything7482 // implicit undefined literal to anything
7472 if (actual_type->id == TypeTableEntryIdUndefLit) {7483 if (actual_type->id == TypeTableEntryIdUndefLit) {
7473 return ImplicitCastMatchResultYes;7484 return ImplicitCastMatchResultYes;
...@@ -8370,6 +8381,63 @@ static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruc...@@ -8370,6 +8381,63 @@ static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruc
8370 return result;8381 return result;
8371}8382}
83728383
8384static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *source_instr,
8385 IrInstruction *target, TypeTableEntry *wanted_type)
8386{
8387 assert(wanted_type->id == TypeTableEntryIdUnion);
8388 assert(target->value.type->id == TypeTableEntryIdEnum);
8389
8390 if (instr_is_comptime(target)) {
8391 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
8392 if (!val)
8393 return ira->codegen->invalid_instruction;
8394 TypeUnionField *union_field = find_union_field_by_tag(wanted_type, &val->data.x_enum_tag);
8395 assert(union_field != nullptr);
8396 type_ensure_zero_bits_known(ira->codegen, union_field->type_entry);
8397 if (!union_field->type_entry->zero_bits) {
8398 AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at(
8399 union_field->enum_field->decl_index);
8400 ErrorMsg *msg = ir_add_error(ira, source_instr,
8401 buf_sprintf("cast to union '%s' must initialize '%s' field '%s'",
8402 buf_ptr(&wanted_type->name),
8403 buf_ptr(&union_field->type_entry->name),
8404 buf_ptr(union_field->name)));
8405 add_error_note(ira->codegen, msg, field_node,
8406 buf_sprintf("field '%s' declared here", buf_ptr(union_field->name)));
8407 return ira->codegen->invalid_instruction;
8408 }
8409 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
8410 source_instr->source_node, wanted_type);
8411 result->value.special = ConstValSpecialStatic;
8412 result->value.type = wanted_type;
8413 bigint_init_bigint(&result->value.data.x_union.tag, &val->data.x_enum_tag);
8414 return result;
8415 }
8416
8417 // if the union has all fields 0 bits, we can do it
8418 // and in fact it's a noop cast because the union value is just the enum value
8419 if (wanted_type->data.unionation.gen_field_count == 0) {
8420 IrInstruction *result = ir_build_cast(&ira->new_irb, target->scope, target->source_node, wanted_type, target, CastOpNoop);
8421 result->value.type = wanted_type;
8422 return result;
8423 }
8424
8425 ErrorMsg *msg = ir_add_error(ira, source_instr,
8426 buf_sprintf("runtime cast to union '%s' which has non-void fields",
8427 buf_ptr(&wanted_type->name)));
8428 for (uint32_t i = 0; i < wanted_type->data.unionation.src_field_count; i += 1) {
8429 TypeUnionField *union_field = &wanted_type->data.unionation.fields[i];
8430 if (type_has_bits(union_field->type_entry)) {
8431 AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at(i);
8432 add_error_note(ira->codegen, msg, field_node,
8433 buf_sprintf("field '%s' has type '%s'",
8434 buf_ptr(union_field->name),
8435 buf_ptr(&union_field->type_entry->name)));
8436 }
8437 }
8438 return ira->codegen->invalid_instruction;
8439}
8440
8373static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction *source_instr,8441static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction *source_instr,
8374 IrInstruction *target, TypeTableEntry *wanted_type)8442 IrInstruction *target, TypeTableEntry *wanted_type)
8375{8443{
...@@ -8426,14 +8494,16 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour...@@ -8426,14 +8494,16 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
8426 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);8494 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
8427 if (!val)8495 if (!val)
8428 return ira->codegen->invalid_instruction;8496 return ira->codegen->invalid_instruction;
8429 BigInt enum_member_count;8497
8430 bigint_init_unsigned(&enum_member_count, wanted_type->data.enumeration.src_field_count);8498 TypeEnumField *field = find_enum_field_by_tag(wanted_type, &val->data.x_bigint);
8431 if (bigint_cmp(&val->data.x_bigint, &enum_member_count) != CmpLT) {8499 if (field == nullptr) {
8432 Buf *val_buf = buf_alloc();8500 Buf *val_buf = buf_alloc();
8433 bigint_append_buf(val_buf, &val->data.x_bigint, 10);8501 bigint_append_buf(val_buf, &val->data.x_bigint, 10);
8434 ir_add_error(ira, source_instr,8502 ErrorMsg *msg = ir_add_error(ira, source_instr,
8435 buf_sprintf("integer value %s too big for enum '%s' which has %" PRIu32 " fields",8503 buf_sprintf("enum '%s' has no tag matching integer value %s",
8436 buf_ptr(val_buf), buf_ptr(&wanted_type->name), wanted_type->data.enumeration.src_field_count));8504 buf_ptr(&wanted_type->name), buf_ptr(val_buf)));
8505 add_error_note(ira->codegen, msg, wanted_type->data.enumeration.decl_node,
8506 buf_sprintf("'%s' declared here", buf_ptr(&wanted_type->name)));
8437 return ira->codegen->invalid_instruction;8507 return ira->codegen->invalid_instruction;
8438 }8508 }
84398509
...@@ -8842,7 +8912,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -8842,7 +8912,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
8842 if (actual_type->id == TypeTableEntryIdNumLitFloat ||8912 if (actual_type->id == TypeTableEntryIdNumLitFloat ||
8843 actual_type->id == TypeTableEntryIdNumLitInt)8913 actual_type->id == TypeTableEntryIdNumLitInt)
8844 {8914 {
8845 if (wanted_type->id == TypeTableEntryIdPointer &&8915 if (wanted_type->id == TypeTableEntryIdEnum) {
8916 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.enumeration.tag_int_type, value);
8917 if (type_is_invalid(cast1->value.type))
8918 return ira->codegen->invalid_instruction;
8919
8920 IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
8921 if (type_is_invalid(cast2->value.type))
8922 return ira->codegen->invalid_instruction;
8923
8924 return cast2;
8925 } else if (wanted_type->id == TypeTableEntryIdPointer &&
8846 wanted_type->data.pointer.is_const)8926 wanted_type->data.pointer.is_const)
8847 {8927 {
8848 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);8928 IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);
...@@ -8912,6 +8992,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -8912,6 +8992,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
8912 }8992 }
8913 }8993 }
89148994
8995 // explicit enum to union which has the enum as the tag type
8996 if (wanted_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum &&
8997 (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum ||
8998 wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
8999 {
9000 type_ensure_zero_bits_known(ira->codegen, wanted_type);
9001 if (wanted_type->data.unionation.tag_type == actual_type) {
9002 return ir_analyze_enum_to_union(ira, source_instr, value, wanted_type);
9003 }
9004 }
9005
8915 // explicit cast from undefined to anything9006 // explicit cast from undefined to anything
8916 if (actual_type->id == TypeTableEntryIdUndefLit) {9007 if (actual_type->id == TypeTableEntryIdUndefLit) {
8917 return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type);9008 return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type);
test/cases/enum.zig+5
...@@ -344,3 +344,8 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) {...@@ -344,3 +344,8 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) {
344 MultipleChoice2.Unspecified5 => 9,344 MultipleChoice2.Unspecified5 => 9,
345 });345 });
346}346}
347
348test "cast integer literal to enum" {
349 assert(MultipleChoice2(0) == MultipleChoice2.Unspecified1);
350 assert(MultipleChoice2(40) == MultipleChoice2.B);
351}
test/cases/union.zig+7
...@@ -190,3 +190,10 @@ test "cast union to tag type of union" {...@@ -190,3 +190,10 @@ test "cast union to tag type of union" {
190fn testCastUnionToTagType(x: &const TheUnion) {190fn testCastUnionToTagType(x: &const TheUnion) {
191 assert(TheTag(*x) == TheTag.B);191 assert(TheTag(*x) == TheTag.B);
192}192}
193
194test "cast tag type of union to union" {
195 var x: Value2 = Letter2.B;
196 assert(Letter2(x) == Letter2.B);
197}
198const Letter2 = enum { A, B, C };
199const Value2 = union(Letter2) { A: i32, B, C, };
test/compile_errors.zig+43
...@@ -2684,4 +2684,47 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -2684,4 +2684,47 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
2684 ,2684 ,
2685 ".tmp_source.zig:11:13: error: switch on union which has no attached enum",2685 ".tmp_source.zig:11:13: error: switch on union which has no attached enum",
2686 ".tmp_source.zig:1:17: note: consider 'union(enum)' here");2686 ".tmp_source.zig:1:17: note: consider 'union(enum)' here");
2687
2688 cases.add("enum in field count range but not matching tag",
2689 \\const Foo = enum(u32) {
2690 \\ A = 10,
2691 \\ B = 11,
2692 \\};
2693 \\export fn entry() {
2694 \\ var x = Foo(0);
2695 \\}
2696 ,
2697 ".tmp_source.zig:6:16: error: enum 'Foo' has no tag matching integer value 0",
2698 ".tmp_source.zig:1:13: note: 'Foo' declared here");
2699
2700 cases.add("comptime cast enum to union but field has payload",
2701 \\const Letter = enum { A, B, C };
2702 \\const Value = union(Letter) {
2703 \\ A: i32,
2704 \\ B,
2705 \\ C,
2706 \\};
2707 \\export fn entry() {
2708 \\ var x: Value = Letter.A;
2709 \\}
2710 ,
2711 ".tmp_source.zig:8:26: error: cast to union 'Value' must initialize 'i32' field 'A'",
2712 ".tmp_source.zig:3:5: note: field 'A' declared here");
2713
2714 cases.add("runtime cast to union which has non-void fields",
2715 \\const Letter = enum { A, B, C };
2716 \\const Value = union(Letter) {
2717 \\ A: i32,
2718 \\ B,
2719 \\ C,
2720 \\};
2721 \\export fn entry() {
2722 \\ foo(Letter.A);
2723 \\}
2724 \\fn foo(l: Letter) {
2725 \\ var x: Value = l;
2726 \\}
2727 ,
2728 ".tmp_source.zig:11:20: error: runtime cast to union 'Value' which has non-void fields",
2729 ".tmp_source.zig:3:5: note: field 'A' has type 'i32'");
2687}2730}