From ad3e2a5da07fbfe02e0152eb3fc408a7bcf36e3c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 26 Jan 2018 10:37:18 -0500 Subject: [PATCH 1/4] fix compiler crash on function with invalid return type closes #722 --- src/analyze.cpp | 6 +++++- test/compile_errors.zig | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 49f8e093a0..a97ec513ad 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1376,6 +1376,10 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c fn_type_id.return_type = (fn_proto->return_type == nullptr) ? g->builtin_types.entry_void : analyze_type_expr(g, child_scope, fn_proto->return_type); + if (type_is_invalid(fn_type_id.return_type)) { + return g->builtin_types.entry_invalid; + } + if (fn_type_id.cc != CallingConventionUnspecified && !type_allowed_in_extern(g, fn_type_id.return_type)) { add_node_error(g, fn_proto->return_type, buf_sprintf("return type '%s' not allowed in function with calling convention '%s'", @@ -1386,7 +1390,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c switch (fn_type_id.return_type->id) { case TypeTableEntryIdInvalid: - return g->builtin_types.entry_invalid; + zig_unreachable(); case TypeTableEntryIdUndefLit: case TypeTableEntryIdNullLit: diff --git a/test/compile_errors.zig b/test/compile_errors.zig index cc28f29f26..64ee69ba18 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,10 @@ const tests = @import("tests.zig"); pub fn addCases(cases: &tests.CompileErrorContext) void { + cases.add("function with invalid return type", + \\export fn foo() boid {} + , ".tmp_source.zig:1:17: error: use of undeclared identifier 'boid'"); + cases.add("function with non-extern enum parameter", \\const Foo = enum { A, B, C }; \\export fn entry(foo: Foo) void { } From f66ac9a5e704d9900d9e21cb482d7487a02e7b34 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 27 Jan 2018 18:30:36 -0500 Subject: [PATCH 2/4] fix crash when align 1 field before self referential... ...align 8 field as slice return type closes #723 --- src/analyze.cpp | 16 +++++++++++----- test/cases/struct.zig | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index a97ec513ad..b3684021aa 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -362,8 +362,10 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type } else { assert(bit_offset == 0); parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)]; - if (*parent_pointer) + if (*parent_pointer) { + assert((*parent_pointer)->data.pointer.alignment == byte_alignment); return *parent_pointer; + } } type_ensure_zero_bits_known(g, child_type); @@ -2356,6 +2358,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety); bool *covered_enum_fields; ZigLLVMDIEnumerator **di_enumerators; + uint32_t abi_alignment_so_far; if (create_enum_type) { occupied_tag_values.init(field_count); @@ -2377,7 +2380,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { } else { tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1); } - union_type->data.unionation.abi_alignment = get_abi_alignment(g, tag_int_type); + abi_alignment_so_far = get_abi_alignment(g, tag_int_type); tag_type = new_type_table_entry(TypeTableEntryIdEnum); buf_resize(&tag_type->name, 0); @@ -2408,9 +2411,10 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { } tag_type = enum_type; covered_enum_fields = allocate(enum_type->data.enumeration.src_field_count); - union_type->data.unionation.abi_alignment = get_abi_alignment(g, enum_type); + abi_alignment_so_far = get_abi_alignment(g, enum_type); } else { tag_type = nullptr; + abi_alignment_so_far = 0; } union_type->data.unionation.tag_type = tag_type; @@ -2508,12 +2512,14 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { uint32_t field_align_bytes = get_abi_alignment(g, field_type); if (field_align_bytes > biggest_align_bytes) { biggest_align_bytes = field_align_bytes; - if (biggest_align_bytes > union_type->data.unionation.abi_alignment) { - union_type->data.unionation.abi_alignment = biggest_align_bytes; + if (biggest_align_bytes > abi_alignment_so_far) { + abi_alignment_so_far = biggest_align_bytes; } } } + union_type->data.unionation.abi_alignment = abi_alignment_so_far; + if (union_type->data.unionation.is_invalid) return; diff --git a/test/cases/struct.zig b/test/cases/struct.zig index 7fb8421d6f..c3df97678b 100644 --- a/test/cases/struct.zig +++ b/test/cases/struct.zig @@ -404,3 +404,17 @@ test "native bit field understands endianness" { assert(bitfields.f6 == 0x6); assert(bitfields.f7 == 0x77); } + +test "align 1 field before self referential align 8 field as slice return type" { + const result = alloc(Expr); + assert(result.len == 0); +} + +const Expr = union(enum) { + Literal: u8, + Question: &Expr, +}; + +fn alloc(comptime T: type) []T { + return []T{}; +} From abe6c2d5859461900e0ceeb98800987413b3355a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 29 Jan 2018 10:57:09 -0500 Subject: [PATCH 3/4] allow packed containers in extern functions --- src/analyze.cpp | 6 +++--- test/cases/misc.zig | 16 ++++++++++++++++ test/compile_errors.zig | 6 +++--- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index b3684021aa..9afd4cedc8 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1242,16 +1242,16 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) { case TypeTableEntryIdPointer: return type_allowed_in_extern(g, type_entry->data.pointer.child_type); case TypeTableEntryIdStruct: - return type_entry->data.structure.layout == ContainerLayoutExtern; + return type_entry->data.structure.layout == ContainerLayoutExtern || type_entry->data.structure.layout == ContainerLayoutPacked; case TypeTableEntryIdMaybe: { TypeTableEntry *child_type = type_entry->data.maybe.child_type; return child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn; } case TypeTableEntryIdEnum: - return type_entry->data.enumeration.layout == ContainerLayoutExtern; + return type_entry->data.enumeration.layout == ContainerLayoutExtern || type_entry->data.enumeration.layout == ContainerLayoutPacked; case TypeTableEntryIdUnion: - return type_entry->data.unionation.layout == ContainerLayoutExtern; + return type_entry->data.unionation.layout == ContainerLayoutExtern || type_entry->data.unionation.layout == ContainerLayoutPacked; } zig_unreachable(); } diff --git a/test/cases/misc.zig b/test/cases/misc.zig index cfc3456738..85757efbb8 100644 --- a/test/cases/misc.zig +++ b/test/cases/misc.zig @@ -617,3 +617,19 @@ test "cold function" { fn thisIsAColdFn() void { @setCold(true); } + + +const PackedStruct = packed struct { a: u8, b: u8, }; +const PackedUnion = packed union { a: u8, b: u32, }; +const PackedEnum = packed enum { A, B, }; + +test "packed struct, enum, union parameters in extern function" { + testPackedStuff( + PackedStruct{.a = 1, .b = 2}, + PackedUnion{.a = 1}, + PackedEnum.A, + ); +} + +export fn testPackedStuff(a: &const PackedStruct, b: &const PackedUnion, c: PackedEnum) void { +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 64ee69ba18..fe167c472c 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -5,12 +5,12 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { \\export fn foo() boid {} , ".tmp_source.zig:1:17: error: use of undeclared identifier 'boid'"); - cases.add("function with non-extern enum parameter", + cases.add("function with non-extern non-packed enum parameter", \\const Foo = enum { A, B, C }; \\export fn entry(foo: Foo) void { } , ".tmp_source.zig:2:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'"); - cases.add("function with non-extern struct parameter", + cases.add("function with non-extern non-packed struct parameter", \\const Foo = struct { \\ A: i32, \\ B: f32, @@ -19,7 +19,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void { \\export fn entry(foo: Foo) void { } , ".tmp_source.zig:6:22: error: parameter of type 'Foo' not allowed in function with calling convention 'ccc'"); - cases.add("function with non-extern union parameter", + cases.add("function with non-extern non-packed union parameter", \\const Foo = union { \\ A: i32, \\ B: f32, From 2b5e0b66a27d2a83cb596a28c9792a86523401b3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 29 Jan 2018 10:57:27 -0500 Subject: [PATCH 4/4] std: fix fn return syntax for zen os --- std/os/zen.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/os/zen.zig b/std/os/zen.zig index f31d46e481..867bc6578f 100644 --- a/std/os/zen.zig +++ b/std/os/zen.zig @@ -42,7 +42,7 @@ pub fn map(v_addr: usize, p_addr: usize, size: usize, writable: bool) bool { return syscall4(SYS_map, v_addr, p_addr, size, usize(writable)) != 0; } -pub fn createThread(function: fn()) u16 { +pub fn createThread(function: fn()void) u16 { return u16(syscall1(SYS_createThread, @ptrToInt(function))); }