improve extern enum

This commit is contained in:
Vexu 2019-12-15 00:05:13 +02:00 committed by Andrew Kelley
parent 59de23dfa0
commit 0f38410ea6
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
7 changed files with 57 additions and 3 deletions

View File

@ -282,6 +282,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
.PrivateExtern => return failDecl(c, fn_decl_loc, fn_name, "unsupported storage class: private extern", .{}),
.Auto => unreachable, // Not legal on functions
.Register => unreachable, // Not legal on functions
else => unreachable,
},
};
const proto_node = switch (ZigClangType_getTypeClass(fn_type)) {
@ -710,6 +711,7 @@ fn transBinaryOperator(
.XorAssign,
.OrAssign,
=> unreachable,
else => unreachable,
}
}
@ -1001,6 +1003,7 @@ fn transStringLiteral(
"TODO: support string literal kind {}",
.{kind},
),
else => unreachable,
}
}

View File

@ -2682,7 +2682,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
// Make sure the value is unique
auto entry = occupied_tag_values.put_unique(type_enum_field->value, field_node);
if (entry != nullptr) {
if (entry != nullptr && enum_type->data.enumeration.layout != ContainerLayoutExtern) {
enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
Buf *val_buf = buf_alloc();

View File

@ -3292,7 +3292,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,
LLVMValueRef tag_int_value = gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
instruction->target->value->type, tag_int_type, target_val);
if (ir_want_runtime_safety(g, &instruction->base)) {
if (ir_want_runtime_safety(g, &instruction->base) && wanted_type->data.enumeration.layout != ContainerLayoutExtern) {
LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue");
LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue");
size_t field_count = wanted_type->data.enumeration.src_field_count;

View File

@ -12728,7 +12728,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
return ira->codegen->invalid_instruction;
TypeEnumField *field = find_enum_field_by_tag(wanted_type, &val->data.x_bigint);
if (field == nullptr) {
if (field == nullptr && wanted_type->data.enumeration.layout != ContainerLayoutExtern) {
Buf *val_buf = buf_alloc();
bigint_append_buf(val_buf, &val->data.x_bigint, 10);
ErrorMsg *msg = ir_add_error(ira, source_instr,
@ -25791,6 +25791,10 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
}
}
if (!instruction->have_else_prong) {
if (switch_type->data.enumeration.layout == ContainerLayoutExtern) {
ir_add_error(ira, &instruction->base,
buf_sprintf("switch on an extern enum must have an else prong"));
}
for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) {
TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i];

View File

@ -10,6 +10,25 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:13: error: pointer type '[*]align(4) u8' requires aligned address",
});
cases.add("switch on extern enum missing else prong",
\\const i = extern enum {
\\ n = 0,
\\ o = 2,
\\ p = 4,
\\ q = 4,
\\};
\\pub fn main() void {
\\ var x = @intToEnum(i, 52);
\\ switch (x) {
\\ .n,
\\ .o,
\\ .p => unreachable,
\\ }
\\}
, &[_][]const u8{
"tmp.zig:9:5: error: switch on an extern enum must have an else prong",
});
cases.add("invalid float literal",
\\const std = @import("std");
\\

View File

@ -618,6 +618,7 @@ test "peer resolution of string literals" {
.b => "two",
.c => "three",
.d => "four",
else => unreachable,
};
expect(mem.eql(u8, cmd, "two"));
}

View File

@ -1,6 +1,33 @@
const expect = @import("std").testing.expect;
const mem = @import("std").mem;
test "extern enum" {
const S = struct {
const i = extern enum {
n = 0,
o = 2,
p = 4,
q = 4,
};
fn doTheTest(y: c_int) void {
var x = i.o;
expect(@enumToInt(x) == 2);
x = @intToEnum(i, 12);
expect(@enumToInt(x) == 12);
x = @intToEnum(i, y);
expect(@enumToInt(x) == 52);
switch (x) {
.n,
.o,
.p => unreachable,
else => {},
}
}
};
S.doTheTest(52);
comptime S.doTheTest(52);
}
test "enum type" {
const foo1 = Foo{ .One = 13 };
const foo2 = Foo{