From 61ce72a38cedfcbd8450922cbf1cadc0c1682928 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sat, 26 Sep 2020 08:01:09 -0600 Subject: [PATCH 1/3] Allow enums with explicit extern-allowed tag types in extern types Closes https://github.com/ziglang/zig/issues/1467 --- src/stage1/all_types.hpp | 1 + src/stage1/analyze.cpp | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp index 7a5016d004..9f289a8f64 100644 --- a/src/stage1/all_types.hpp +++ b/src/stage1/all_types.hpp @@ -1456,6 +1456,7 @@ struct ZigTypeEnum { ContainerLayout layout; ResolveStatus resolve_status; + bool has_explicit_tag_type; bool non_exhaustive; bool resolve_loop_flag; }; diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp index 369c284684..64251c1f0c 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -1802,10 +1802,18 @@ Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) { } return type_allowed_in_extern(g, child_type, result); } - case ZigTypeIdEnum: - *result = type_entry->data.enumeration.layout == ContainerLayoutExtern || - type_entry->data.enumeration.layout == ContainerLayoutPacked; - return ErrorNone; + case ZigTypeIdEnum: { + if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) + return err; + ZigType *tag_int_type = type_entry->data.enumeration.tag_int_type; + if (type_entry->data.enumeration.has_explicit_tag_type) { + return type_allowed_in_extern(g, tag_int_type, result); + } else { + *result = type_entry->data.enumeration.layout == ContainerLayoutExtern || + type_entry->data.enumeration.layout == ContainerLayoutPacked; + return ErrorNone; + } + } case ZigTypeIdUnion: *result = type_entry->data.unionation.layout == ContainerLayoutExtern || type_entry->data.unionation.layout == ContainerLayoutPacked; @@ -2639,9 +2647,11 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { if (decl_node->type == NodeTypeContainerDecl) { if (decl_node->data.container_decl.init_arg_expr != nullptr) { wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr); + enum_type->data.enumeration.has_explicit_tag_type = true; } } else { wanted_tag_int_type = enum_type->data.enumeration.tag_int_type; + enum_type->data.enumeration.has_explicit_tag_type = true; } if (wanted_tag_int_type != nullptr) { From cae49b1b9d40e106f52c8f80c00019138961bf89 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sat, 26 Sep 2020 08:06:14 -0600 Subject: [PATCH 2/3] Add tests for enums with explicit extern-allowed tag types in extern types --- test/compile_errors.zig | 12 ++++++++++++ test/stage1/behavior/bugs/1467.zig | 7 +++++++ 2 files changed, 19 insertions(+) create mode 100644 test/stage1/behavior/bugs/1467.zig diff --git a/test/compile_errors.zig b/test/compile_errors.zig index fef0a64762..90ed504eac 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -20,6 +20,18 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:20: error: use of undefined value here causes undefined behavior", }); + cases.add("extern struct with non-extern-compatible integer tag type", + \\pub const E = enum(u31) { A, B, C }; + \\pub const S = extern struct { + \\ e: E, + \\}; + \\export fn entry() void { + \\ const s: S = undefined; + \\} + , &[_][]const u8{ + "tmp.zig:3:5: error: extern structs cannot contain fields of type 'E'", + }); + cases.add("@Type for exhaustive enum with non-integer tag type", \\const TypeInfo = @import("builtin").TypeInfo; \\const Tag = @Type(.{ diff --git a/test/stage1/behavior/bugs/1467.zig b/test/stage1/behavior/bugs/1467.zig new file mode 100644 index 0000000000..71c55dc59c --- /dev/null +++ b/test/stage1/behavior/bugs/1467.zig @@ -0,0 +1,7 @@ +pub const E = enum(u32) { A, B, C }; +pub const S = extern struct { + e: E, +}; +test "bug 1467" { + const s: S = undefined; +} From 65016dff322c9344cc5e7bf9d6ad6907de940c7f Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Sat, 26 Sep 2020 08:21:27 -0600 Subject: [PATCH 3/3] Add test for implicit extern-allowed enum tag type in extern struct --- test/compile_errors.zig | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 90ed504eac..d3be0e060b 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -50,6 +50,47 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:20: error: TypeInfo.Enum.tag_type must be an integer type, not 'bool'", }); + cases.add("extern struct with extern-compatible but inferred integer tag type", + \\pub const E = enum { + \\@"0",@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10",@"11",@"12", + \\@"13",@"14",@"15",@"16",@"17",@"18",@"19",@"20",@"21",@"22",@"23", + \\@"24",@"25",@"26",@"27",@"28",@"29",@"30",@"31",@"32",@"33",@"34", + \\@"35",@"36",@"37",@"38",@"39",@"40",@"41",@"42",@"43",@"44",@"45", + \\@"46",@"47",@"48",@"49",@"50",@"51",@"52",@"53",@"54",@"55",@"56", + \\@"57",@"58",@"59",@"60",@"61",@"62",@"63",@"64",@"65",@"66",@"67", + \\@"68",@"69",@"70",@"71",@"72",@"73",@"74",@"75",@"76",@"77",@"78", + \\@"79",@"80",@"81",@"82",@"83",@"84",@"85",@"86",@"87",@"88",@"89", + \\@"90",@"91",@"92",@"93",@"94",@"95",@"96",@"97",@"98",@"99",@"100", + \\@"101",@"102",@"103",@"104",@"105",@"106",@"107",@"108",@"109", + \\@"110",@"111",@"112",@"113",@"114",@"115",@"116",@"117",@"118", + \\@"119",@"120",@"121",@"122",@"123",@"124",@"125",@"126",@"127", + \\@"128",@"129",@"130",@"131",@"132",@"133",@"134",@"135",@"136", + \\@"137",@"138",@"139",@"140",@"141",@"142",@"143",@"144",@"145", + \\@"146",@"147",@"148",@"149",@"150",@"151",@"152",@"153",@"154", + \\@"155",@"156",@"157",@"158",@"159",@"160",@"161",@"162",@"163", + \\@"164",@"165",@"166",@"167",@"168",@"169",@"170",@"171",@"172", + \\@"173",@"174",@"175",@"176",@"177",@"178",@"179",@"180",@"181", + \\@"182",@"183",@"184",@"185",@"186",@"187",@"188",@"189",@"190", + \\@"191",@"192",@"193",@"194",@"195",@"196",@"197",@"198",@"199", + \\@"200",@"201",@"202",@"203",@"204",@"205",@"206",@"207",@"208", + \\@"209",@"210",@"211",@"212",@"213",@"214",@"215",@"216",@"217", + \\@"218",@"219",@"220",@"221",@"222",@"223",@"224",@"225",@"226", + \\@"227",@"228",@"229",@"230",@"231",@"232",@"233",@"234",@"235", + \\@"236",@"237",@"238",@"239",@"240",@"241",@"242",@"243",@"244", + \\@"245",@"246",@"247",@"248",@"249",@"250",@"251",@"252",@"253", + \\@"254",@"255" + \\}; + \\pub const S = extern struct { + \\ e: E, + \\}; + \\export fn entry() void { + \\ if (@TagType(E) != u8) @compileError("did not infer u8 tag type"); + \\ const s: S = undefined; + \\} + , &[_][]const u8{ + "tmp.zig:31:5: error: extern structs cannot contain fields of type 'E'", + }); + cases.add("@Type for tagged union with extra enum field", \\const TypeInfo = @import("builtin").TypeInfo; \\const Tag = @Type(.{