From 3f30897fdcdb6c5579bc5609dda9746f67551870 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 11 Jul 2018 13:23:37 -0400 Subject: [PATCH] add compile error for disallowed types in extern structs closes #1218 --- src/analyze.cpp | 23 ++++++++++++++++++++--- std/c/darwin.zig | 2 +- test/compile_errors.zig | 27 +++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 9b60f7374a..5635cce411 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1430,10 +1430,10 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) { case TypeTableEntryIdBoundFn: case TypeTableEntryIdArgTuple: case TypeTableEntryIdPromise: + case TypeTableEntryIdVoid: return false; case TypeTableEntryIdOpaque: case TypeTableEntryIdUnreachable: - case TypeTableEntryIdVoid: case TypeTableEntryIdBool: return true; case TypeTableEntryIdInt: @@ -1460,7 +1460,10 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) { case TypeTableEntryIdOptional: { TypeTableEntry *child_type = type_entry->data.maybe.child_type; - return child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn; + if (child_type->id != TypeTableEntryIdPointer && child_type->id != TypeTableEntryIdFn) { + return false; + } + return type_allowed_in_extern(g, child_type); } case TypeTableEntryIdEnum: return type_entry->data.enumeration.layout == ContainerLayoutExtern || type_entry->data.enumeration.layout == ContainerLayoutPacked; @@ -1637,7 +1640,10 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c fn_type_id.return_type = specified_return_type; } - if (!calling_convention_allows_zig_types(fn_type_id.cc) && !type_allowed_in_extern(g, fn_type_id.return_type)) { + if (!calling_convention_allows_zig_types(fn_type_id.cc) && + fn_type_id.return_type->id != TypeTableEntryIdVoid && + !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'", buf_ptr(&fn_type_id.return_type->name), @@ -1939,6 +1945,17 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { break; } + if (struct_type->data.structure.layout == ContainerLayoutExtern) { + if (!type_allowed_in_extern(g, field_type)) { + AstNode *field_source_node = decl_node->data.container_decl.fields.at(i); + add_node_error(g, field_source_node, + buf_sprintf("extern structs cannot contain fields of type '%s'", + buf_ptr(&field_type->name))); + struct_type->data.structure.is_invalid = true; + break; + } + } + if (!type_has_bits(field_type)) continue; diff --git a/std/c/darwin.zig b/std/c/darwin.zig index 133ef62f05..4189dfeadc 100644 --- a/std/c/darwin.zig +++ b/std/c/darwin.zig @@ -44,7 +44,7 @@ pub const timezone = extern struct { tz_dsttime: i32, }; -pub const mach_timebase_info_data = struct { +pub const mach_timebase_info_data = extern struct { numer: u32, denom: u32, }; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index a6db8d50b4..58c73b8ae4 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,33 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "optional pointer to void in extern struct", + \\const Foo = extern struct { + \\ x: ?*const void, + \\}; + \\const Bar = extern struct { + \\ foo: Foo, + \\ y: i32, + \\}; + \\export fn entry(bar: *Bar) void {} + , + ".tmp_source.zig:2:5: error: extern structs cannot contain fields of type '?*const void'", + ); + + cases.add( + "use of comptime-known undefined function value", + \\const Cmd = struct { + \\ exec: fn () void, + \\}; + \\export fn entry() void { + \\ const command = Cmd{ .exec = undefined }; + \\ command.exec(); + \\} + , + ".tmp_source.zig:6:12: error: use of undefined value", + ); + cases.add( "use of comptime-known undefined function value", \\const Cmd = struct {